diff options
Diffstat (limited to 'drivers/gpu/drm/msm')
62 files changed, 21141 insertions, 0 deletions
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig new file mode 100644 index 00000000000..f1238896785 --- /dev/null +++ b/drivers/gpu/drm/msm/Kconfig @@ -0,0 +1,35 @@ + +config DRM_MSM +	tristate "MSM DRM" +	depends on DRM +	depends on MSM_IOMMU +	depends on ARCH_QCOM || (ARM && COMPILE_TEST) +	select DRM_KMS_HELPER +	select SHMEM +	select TMPFS +	default y +	help +	  DRM/KMS driver for MSM/snapdragon. + +config DRM_MSM_FBDEV +	bool "Enable legacy fbdev support for MSM modesetting driver" +	depends on DRM_MSM +	select DRM_KMS_FB_HELPER +	select FB_SYS_FILLRECT +	select FB_SYS_COPYAREA +	select FB_SYS_IMAGEBLIT +	select FB_SYS_FOPS +	default y +	help +	  Choose this option if you have a need for the legacy fbdev +	  support. Note that this support also provide the linux console +	  support on top of the MSM modesetting driver. + +config DRM_MSM_REGISTER_LOGGING +	bool "MSM DRM register logging" +	depends on DRM_MSM +	default n +	help +	  Compile in support for logging register reads/writes in a format +	  that can be parsed by envytools demsm tool.  If enabled, register +	  logging can be switched on via msm.reglog=y module param. diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile new file mode 100644 index 00000000000..93ca49c8df4 --- /dev/null +++ b/drivers/gpu/drm/msm/Makefile @@ -0,0 +1,43 @@ +ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/msm +ifeq (, $(findstring -W,$(EXTRA_CFLAGS))) +	ccflags-y += -Werror +endif + +msm-y := \ +	adreno/adreno_gpu.o \ +	adreno/a3xx_gpu.o \ +	hdmi/hdmi.o \ +	hdmi/hdmi_audio.o \ +	hdmi/hdmi_bridge.o \ +	hdmi/hdmi_connector.o \ +	hdmi/hdmi_i2c.o \ +	hdmi/hdmi_phy_8960.o \ +	hdmi/hdmi_phy_8x60.o \ +	hdmi/hdmi_phy_8x74.o \ +	mdp/mdp_format.o \ +	mdp/mdp_kms.o \ +	mdp/mdp4/mdp4_crtc.o \ +	mdp/mdp4/mdp4_dtv_encoder.o \ +	mdp/mdp4/mdp4_irq.o \ +	mdp/mdp4/mdp4_kms.o \ +	mdp/mdp4/mdp4_plane.o \ +	mdp/mdp5/mdp5_crtc.o \ +	mdp/mdp5/mdp5_encoder.o \ +	mdp/mdp5/mdp5_irq.o \ +	mdp/mdp5/mdp5_kms.o \ +	mdp/mdp5/mdp5_plane.o \ +	mdp/mdp5/mdp5_smp.o \ +	msm_drv.o \ +	msm_fb.o \ +	msm_gem.o \ +	msm_gem_prime.o \ +	msm_gem_submit.o \ +	msm_gpu.o \ +	msm_iommu.o \ +	msm_perf.o \ +	msm_rd.o \ +	msm_ringbuffer.o + +msm-$(CONFIG_DRM_MSM_FBDEV) += msm_fbdev.o + +obj-$(CONFIG_DRM_MSM)	+= msm.o diff --git a/drivers/gpu/drm/msm/NOTES b/drivers/gpu/drm/msm/NOTES new file mode 100644 index 00000000000..9c4255b9802 --- /dev/null +++ b/drivers/gpu/drm/msm/NOTES @@ -0,0 +1,87 @@ +NOTES about msm drm/kms driver: + +In the current snapdragon SoC's, we have (at least) 3 different +display controller blocks at play: + + MDP3 - ?? seems to be what is on geeksphone peak device + + MDP4 - S3 (APQ8060, touchpad), S4-pro (APQ8064, nexus4 & ifc6410) + + MDP5 - snapdragon 800 + +(I don't have a completely clear picture on which display controller +maps to which part #) + +Plus a handful of blocks around them for HDMI/DSI/etc output. + +And on gpu side of things: + + zero, one, or two 2d cores (z180) + + and either a2xx or a3xx 3d core. + +But, HDMI/DSI/etc blocks seem like they can be shared across multiple +display controller blocks.  And I for sure don't want to have to deal +with N different kms devices from xf86-video-freedreno.  Plus, it +seems like we can do some clever tricks like use GPU to trigger +pageflip after rendering completes (ie. have the kms/crtc code build +up gpu cmdstream to update scanout and write FLUSH register after). + +So, the approach is one drm driver, with some modularity.  Different +'struct msm_kms' implementations, depending on display controller. +And one or more 'struct msm_gpu' for the various different gpu sub- +modules. + +(Second part is not implemented yet.  So far this is just basic KMS +driver, and not exposing any custom ioctls to userspace for now.) + +The kms module provides the plane, crtc, and encoder objects, and +loads whatever connectors are appropriate. + +For MDP4, the mapping is: + +  plane   -> PIPE{RGBn,VGn}              \ +  crtc    -> OVLP{n} + DMA{P,S,E} (??)   |-> MDP "device" +  encoder -> DTV/LCDC/DSI (within MDP4)  / +  connector -> HDMI/DSI/etc              --> other device(s) + +Since the irq's that drm core mostly cares about are vblank/framedone, +we'll let msm_mdp4_kms provide the irq install/uninstall/etc functions +and treat the MDP4 block's irq as "the" irq.  Even though the connectors +may have their own irqs which they install themselves.  For this reason +the display controller is the "master" device. + +For MDP5, the mapping is: + +  plane   -> PIPE{RGBn,VIGn}             \ +  crtc    -> LM (layer mixer)            |-> MDP "device" +  encoder -> INTF                        / +  connector -> HDMI/DSI/eDP/etc          --> other device(s) + +Unlike MDP4, it appears we can get by with a single encoder, rather +than needing a different implementation for DTV, DSI, etc.  (Ie. the +register interface is same, just different bases.) + +Also unlike MDP4, with MDP5 all the IRQs for other blocks (HDMI, DSI, +etc) are routed through MDP. + +And finally, MDP5 has this "Shared Memory Pool" (called "SMP"), from +which blocks need to be allocated to the active pipes based on fetch +stride. + +Each connector probably ends up being a separate device, just for the +logistics of finding/mapping io region, irq, etc.  Idealy we would +have a better way than just stashing the platform device in a global +(ie. like DT super-node.. but I don't have any snapdragon hw yet that +is using DT). + +Note that so far I've not been able to get any docs on the hw, and it +seems that access to such docs would prevent me from working on the +freedreno gallium driver.  So there may be some mistakes in register +names (I had to invent a few, since no sufficient hint was given in +the downstream android fbdev driver), bitfield sizes, etc.  My current +state of understanding the registers is given in the envytools rnndb +files at: + +  https://github.com/freedreno/envytools/tree/master/rnndb +  (the mdp4/hdmi/dsi directories) + +These files are used both for a parser tool (in the same tree) to +parse logged register reads/writes (both from downstream android fbdev +driver, and this driver with register logging enabled), as well as to +generate the register level headers. diff --git a/drivers/gpu/drm/msm/adreno/a2xx.xml.h b/drivers/gpu/drm/msm/adreno/a2xx.xml.h new file mode 100644 index 00000000000..85d615e7d62 --- /dev/null +++ b/drivers/gpu/drm/msm/adreno/a2xx.xml.h @@ -0,0 +1,1555 @@ +#ifndef A2XX_XML +#define A2XX_XML + +/* Autogenerated file, DO NOT EDIT manually! + +This file was generated by the rules-ng-ng headergen tool in this git repository: +http://github.com/freedreno/envytools/ +git clone https://github.com/freedreno/envytools.git + +The rules-ng-ng source files this header was generated from are: +- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2013-11-30 14:47:15) +- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32814 bytes, from 2013-11-30 15:07:33) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (   8900 bytes, from 2013-10-22 23:57:49) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  10574 bytes, from 2013-11-13 05:44:45) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  53644 bytes, from 2013-11-30 15:07:33) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (   8344 bytes, from 2013-11-30 14:49:47) + +Copyright (C) 2013 by the following authors: +- Rob Clark <robdclark@gmail.com> (robclark) + +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 THE COPYRIGHT OWNER(S) 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. +*/ + + +enum a2xx_rb_dither_type { +	DITHER_PIXEL = 0, +	DITHER_SUBPIXEL = 1, +}; + +enum a2xx_colorformatx { +	COLORX_4_4_4_4 = 0, +	COLORX_1_5_5_5 = 1, +	COLORX_5_6_5 = 2, +	COLORX_8 = 3, +	COLORX_8_8 = 4, +	COLORX_8_8_8_8 = 5, +	COLORX_S8_8_8_8 = 6, +	COLORX_16_FLOAT = 7, +	COLORX_16_16_FLOAT = 8, +	COLORX_16_16_16_16_FLOAT = 9, +	COLORX_32_FLOAT = 10, +	COLORX_32_32_FLOAT = 11, +	COLORX_32_32_32_32_FLOAT = 12, +	COLORX_2_3_3 = 13, +	COLORX_8_8_8 = 14, +}; + +enum a2xx_sq_surfaceformat { +	FMT_1_REVERSE = 0, +	FMT_1 = 1, +	FMT_8 = 2, +	FMT_1_5_5_5 = 3, +	FMT_5_6_5 = 4, +	FMT_6_5_5 = 5, +	FMT_8_8_8_8 = 6, +	FMT_2_10_10_10 = 7, +	FMT_8_A = 8, +	FMT_8_B = 9, +	FMT_8_8 = 10, +	FMT_Cr_Y1_Cb_Y0 = 11, +	FMT_Y1_Cr_Y0_Cb = 12, +	FMT_5_5_5_1 = 13, +	FMT_8_8_8_8_A = 14, +	FMT_4_4_4_4 = 15, +	FMT_10_11_11 = 16, +	FMT_11_11_10 = 17, +	FMT_DXT1 = 18, +	FMT_DXT2_3 = 19, +	FMT_DXT4_5 = 20, +	FMT_24_8 = 22, +	FMT_24_8_FLOAT = 23, +	FMT_16 = 24, +	FMT_16_16 = 25, +	FMT_16_16_16_16 = 26, +	FMT_16_EXPAND = 27, +	FMT_16_16_EXPAND = 28, +	FMT_16_16_16_16_EXPAND = 29, +	FMT_16_FLOAT = 30, +	FMT_16_16_FLOAT = 31, +	FMT_16_16_16_16_FLOAT = 32, +	FMT_32 = 33, +	FMT_32_32 = 34, +	FMT_32_32_32_32 = 35, +	FMT_32_FLOAT = 36, +	FMT_32_32_FLOAT = 37, +	FMT_32_32_32_32_FLOAT = 38, +	FMT_32_AS_8 = 39, +	FMT_32_AS_8_8 = 40, +	FMT_16_MPEG = 41, +	FMT_16_16_MPEG = 42, +	FMT_8_INTERLACED = 43, +	FMT_32_AS_8_INTERLACED = 44, +	FMT_32_AS_8_8_INTERLACED = 45, +	FMT_16_INTERLACED = 46, +	FMT_16_MPEG_INTERLACED = 47, +	FMT_16_16_MPEG_INTERLACED = 48, +	FMT_DXN = 49, +	FMT_8_8_8_8_AS_16_16_16_16 = 50, +	FMT_DXT1_AS_16_16_16_16 = 51, +	FMT_DXT2_3_AS_16_16_16_16 = 52, +	FMT_DXT4_5_AS_16_16_16_16 = 53, +	FMT_2_10_10_10_AS_16_16_16_16 = 54, +	FMT_10_11_11_AS_16_16_16_16 = 55, +	FMT_11_11_10_AS_16_16_16_16 = 56, +	FMT_32_32_32_FLOAT = 57, +	FMT_DXT3A = 58, +	FMT_DXT5A = 59, +	FMT_CTX1 = 60, +	FMT_DXT3A_AS_1_1_1_1 = 61, +}; + +enum a2xx_sq_ps_vtx_mode { +	POSITION_1_VECTOR = 0, +	POSITION_2_VECTORS_UNUSED = 1, +	POSITION_2_VECTORS_SPRITE = 2, +	POSITION_2_VECTORS_EDGE = 3, +	POSITION_2_VECTORS_KILL = 4, +	POSITION_2_VECTORS_SPRITE_KILL = 5, +	POSITION_2_VECTORS_EDGE_KILL = 6, +	MULTIPASS = 7, +}; + +enum a2xx_sq_sample_cntl { +	CENTROIDS_ONLY = 0, +	CENTERS_ONLY = 1, +	CENTROIDS_AND_CENTERS = 2, +}; + +enum a2xx_dx_clip_space { +	DXCLIP_OPENGL = 0, +	DXCLIP_DIRECTX = 1, +}; + +enum a2xx_pa_su_sc_polymode { +	POLY_DISABLED = 0, +	POLY_DUALMODE = 1, +}; + +enum a2xx_rb_edram_mode { +	EDRAM_NOP = 0, +	COLOR_DEPTH = 4, +	DEPTH_ONLY = 5, +	EDRAM_COPY = 6, +}; + +enum a2xx_pa_sc_pattern_bit_order { +	LITTLE = 0, +	BIG = 1, +}; + +enum a2xx_pa_sc_auto_reset_cntl { +	NEVER = 0, +	EACH_PRIMITIVE = 1, +	EACH_PACKET = 2, +}; + +enum a2xx_pa_pixcenter { +	PIXCENTER_D3D = 0, +	PIXCENTER_OGL = 1, +}; + +enum a2xx_pa_roundmode { +	TRUNCATE = 0, +	ROUND = 1, +	ROUNDTOEVEN = 2, +	ROUNDTOODD = 3, +}; + +enum a2xx_pa_quantmode { +	ONE_SIXTEENTH = 0, +	ONE_EIGTH = 1, +	ONE_QUARTER = 2, +	ONE_HALF = 3, +	ONE = 4, +}; + +enum a2xx_rb_copy_sample_select { +	SAMPLE_0 = 0, +	SAMPLE_1 = 1, +	SAMPLE_2 = 2, +	SAMPLE_3 = 3, +	SAMPLE_01 = 4, +	SAMPLE_23 = 5, +	SAMPLE_0123 = 6, +}; + +enum adreno_mmu_clnt_beh { +	BEH_NEVR = 0, +	BEH_TRAN_RNG = 1, +	BEH_TRAN_FLT = 2, +}; + +enum sq_tex_clamp { +	SQ_TEX_WRAP = 0, +	SQ_TEX_MIRROR = 1, +	SQ_TEX_CLAMP_LAST_TEXEL = 2, +	SQ_TEX_MIRROR_ONCE_LAST_TEXEL = 3, +	SQ_TEX_CLAMP_HALF_BORDER = 4, +	SQ_TEX_MIRROR_ONCE_HALF_BORDER = 5, +	SQ_TEX_CLAMP_BORDER = 6, +	SQ_TEX_MIRROR_ONCE_BORDER = 7, +}; + +enum sq_tex_swiz { +	SQ_TEX_X = 0, +	SQ_TEX_Y = 1, +	SQ_TEX_Z = 2, +	SQ_TEX_W = 3, +	SQ_TEX_ZERO = 4, +	SQ_TEX_ONE = 5, +}; + +enum sq_tex_filter { +	SQ_TEX_FILTER_POINT = 0, +	SQ_TEX_FILTER_BILINEAR = 1, +	SQ_TEX_FILTER_BICUBIC = 2, +}; + +#define REG_A2XX_RBBM_PATCH_RELEASE				0x00000001 + +#define REG_A2XX_RBBM_CNTL					0x0000003b + +#define REG_A2XX_RBBM_SOFT_RESET				0x0000003c + +#define REG_A2XX_CP_PFP_UCODE_ADDR				0x000000c0 + +#define REG_A2XX_CP_PFP_UCODE_DATA				0x000000c1 + +#define REG_A2XX_MH_MMU_CONFIG					0x00000040 +#define A2XX_MH_MMU_CONFIG_MMU_ENABLE				0x00000001 +#define A2XX_MH_MMU_CONFIG_SPLIT_MODE_ENABLE			0x00000002 +#define A2XX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__MASK		0x00000030 +#define A2XX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__SHIFT		4 +static inline uint32_t A2XX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ +	return ((val) << A2XX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__MASK; +} +#define A2XX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__MASK		0x000000c0 +#define A2XX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__SHIFT		6 +static inline uint32_t A2XX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ +	return ((val) << A2XX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__MASK; +} +#define A2XX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__MASK		0x00000300 +#define A2XX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__SHIFT		8 +static inline uint32_t A2XX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ +	return ((val) << A2XX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__MASK; +} +#define A2XX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__MASK		0x00000c00 +#define A2XX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__SHIFT		10 +static inline uint32_t A2XX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ +	return ((val) << A2XX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__MASK; +} +#define A2XX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__MASK		0x00003000 +#define A2XX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__SHIFT		12 +static inline uint32_t A2XX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ +	return ((val) << A2XX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__MASK; +} +#define A2XX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__MASK		0x0000c000 +#define A2XX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__SHIFT		14 +static inline uint32_t A2XX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ +	return ((val) << A2XX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__MASK; +} +#define A2XX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__MASK		0x00030000 +#define A2XX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__SHIFT		16 +static inline uint32_t A2XX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ +	return ((val) << A2XX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__MASK; +} +#define A2XX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__MASK		0x000c0000 +#define A2XX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__SHIFT		18 +static inline uint32_t A2XX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ +	return ((val) << A2XX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__MASK; +} +#define A2XX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__MASK		0x00300000 +#define A2XX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__SHIFT		20 +static inline uint32_t A2XX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ +	return ((val) << A2XX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__MASK; +} +#define A2XX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__MASK		0x00c00000 +#define A2XX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__SHIFT		22 +static inline uint32_t A2XX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ +	return ((val) << A2XX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__MASK; +} +#define A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__MASK		0x03000000 +#define A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__SHIFT		24 +static inline uint32_t A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ +	return ((val) << A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__MASK; +} + +#define REG_A2XX_MH_MMU_VA_RANGE				0x00000041 + +#define REG_A2XX_MH_MMU_PT_BASE					0x00000042 + +#define REG_A2XX_MH_MMU_PAGE_FAULT				0x00000043 + +#define REG_A2XX_MH_MMU_TRAN_ERROR				0x00000044 + +#define REG_A2XX_MH_MMU_INVALIDATE				0x00000045 + +#define REG_A2XX_MH_MMU_MPU_BASE				0x00000046 + +#define REG_A2XX_MH_MMU_MPU_END					0x00000047 + +#define REG_A2XX_NQWAIT_UNTIL					0x00000394 + +#define REG_A2XX_RBBM_PERFCOUNTER1_SELECT			0x00000395 + +#define REG_A2XX_RBBM_PERFCOUNTER1_LO				0x00000397 + +#define REG_A2XX_RBBM_PERFCOUNTER1_HI				0x00000398 + +#define REG_A2XX_RBBM_DEBUG					0x0000039b + +#define REG_A2XX_RBBM_PM_OVERRIDE1				0x0000039c + +#define REG_A2XX_RBBM_PM_OVERRIDE2				0x0000039d + +#define REG_A2XX_RBBM_DEBUG_OUT					0x000003a0 + +#define REG_A2XX_RBBM_DEBUG_CNTL				0x000003a1 + +#define REG_A2XX_RBBM_READ_ERROR				0x000003b3 + +#define REG_A2XX_RBBM_INT_CNTL					0x000003b4 + +#define REG_A2XX_RBBM_INT_STATUS				0x000003b5 + +#define REG_A2XX_RBBM_INT_ACK					0x000003b6 + +#define REG_A2XX_MASTER_INT_SIGNAL				0x000003b7 + +#define REG_A2XX_RBBM_PERIPHID1					0x000003f9 + +#define REG_A2XX_RBBM_PERIPHID2					0x000003fa + +#define REG_A2XX_CP_PERFMON_CNTL				0x00000444 + +#define REG_A2XX_CP_PERFCOUNTER_SELECT				0x00000445 + +#define REG_A2XX_CP_PERFCOUNTER_LO				0x00000446 + +#define REG_A2XX_CP_PERFCOUNTER_HI				0x00000447 + +#define REG_A2XX_RBBM_STATUS					0x000005d0 +#define A2XX_RBBM_STATUS_CMDFIFO_AVAIL__MASK			0x0000001f +#define A2XX_RBBM_STATUS_CMDFIFO_AVAIL__SHIFT			0 +static inline uint32_t A2XX_RBBM_STATUS_CMDFIFO_AVAIL(uint32_t val) +{ +	return ((val) << A2XX_RBBM_STATUS_CMDFIFO_AVAIL__SHIFT) & A2XX_RBBM_STATUS_CMDFIFO_AVAIL__MASK; +} +#define A2XX_RBBM_STATUS_TC_BUSY				0x00000020 +#define A2XX_RBBM_STATUS_HIRQ_PENDING				0x00000100 +#define A2XX_RBBM_STATUS_CPRQ_PENDING				0x00000200 +#define A2XX_RBBM_STATUS_CFRQ_PENDING				0x00000400 +#define A2XX_RBBM_STATUS_PFRQ_PENDING				0x00000800 +#define A2XX_RBBM_STATUS_VGT_BUSY_NO_DMA			0x00001000 +#define A2XX_RBBM_STATUS_RBBM_WU_BUSY				0x00004000 +#define A2XX_RBBM_STATUS_CP_NRT_BUSY				0x00010000 +#define A2XX_RBBM_STATUS_MH_BUSY				0x00040000 +#define A2XX_RBBM_STATUS_MH_COHERENCY_BUSY			0x00080000 +#define A2XX_RBBM_STATUS_SX_BUSY				0x00200000 +#define A2XX_RBBM_STATUS_TPC_BUSY				0x00400000 +#define A2XX_RBBM_STATUS_SC_CNTX_BUSY				0x01000000 +#define A2XX_RBBM_STATUS_PA_BUSY				0x02000000 +#define A2XX_RBBM_STATUS_VGT_BUSY				0x04000000 +#define A2XX_RBBM_STATUS_SQ_CNTX17_BUSY				0x08000000 +#define A2XX_RBBM_STATUS_SQ_CNTX0_BUSY				0x10000000 +#define A2XX_RBBM_STATUS_RB_CNTX_BUSY				0x40000000 +#define A2XX_RBBM_STATUS_GUI_ACTIVE				0x80000000 + +#define REG_A2XX_MH_ARBITER_CONFIG				0x00000a40 +#define A2XX_MH_ARBITER_CONFIG_SAME_PAGE_LIMIT__MASK		0x0000003f +#define A2XX_MH_ARBITER_CONFIG_SAME_PAGE_LIMIT__SHIFT		0 +static inline uint32_t A2XX_MH_ARBITER_CONFIG_SAME_PAGE_LIMIT(uint32_t val) +{ +	return ((val) << A2XX_MH_ARBITER_CONFIG_SAME_PAGE_LIMIT__SHIFT) & A2XX_MH_ARBITER_CONFIG_SAME_PAGE_LIMIT__MASK; +} +#define A2XX_MH_ARBITER_CONFIG_SAME_PAGE_GRANULARITY		0x00000040 +#define A2XX_MH_ARBITER_CONFIG_L1_ARB_ENABLE			0x00000080 +#define A2XX_MH_ARBITER_CONFIG_L1_ARB_HOLD_ENABLE		0x00000100 +#define A2XX_MH_ARBITER_CONFIG_L2_ARB_CONTROL			0x00000200 +#define A2XX_MH_ARBITER_CONFIG_PAGE_SIZE__MASK			0x00001c00 +#define A2XX_MH_ARBITER_CONFIG_PAGE_SIZE__SHIFT			10 +static inline uint32_t A2XX_MH_ARBITER_CONFIG_PAGE_SIZE(uint32_t val) +{ +	return ((val) << A2XX_MH_ARBITER_CONFIG_PAGE_SIZE__SHIFT) & A2XX_MH_ARBITER_CONFIG_PAGE_SIZE__MASK; +} +#define A2XX_MH_ARBITER_CONFIG_TC_REORDER_ENABLE		0x00002000 +#define A2XX_MH_ARBITER_CONFIG_TC_ARB_HOLD_ENABLE		0x00004000 +#define A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT_ENABLE		0x00008000 +#define A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT__MASK		0x003f0000 +#define A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT__SHIFT		16 +static inline uint32_t A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT(uint32_t val) +{ +	return ((val) << A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT__SHIFT) & A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT__MASK; +} +#define A2XX_MH_ARBITER_CONFIG_CP_CLNT_ENABLE			0x00400000 +#define A2XX_MH_ARBITER_CONFIG_VGT_CLNT_ENABLE			0x00800000 +#define A2XX_MH_ARBITER_CONFIG_TC_CLNT_ENABLE			0x01000000 +#define A2XX_MH_ARBITER_CONFIG_RB_CLNT_ENABLE			0x02000000 +#define A2XX_MH_ARBITER_CONFIG_PA_CLNT_ENABLE			0x04000000 + +#define REG_A2XX_A220_VSC_BIN_SIZE				0x00000c01 +#define A2XX_A220_VSC_BIN_SIZE_WIDTH__MASK			0x0000001f +#define A2XX_A220_VSC_BIN_SIZE_WIDTH__SHIFT			0 +static inline uint32_t A2XX_A220_VSC_BIN_SIZE_WIDTH(uint32_t val) +{ +	return ((val >> 5) << A2XX_A220_VSC_BIN_SIZE_WIDTH__SHIFT) & A2XX_A220_VSC_BIN_SIZE_WIDTH__MASK; +} +#define A2XX_A220_VSC_BIN_SIZE_HEIGHT__MASK			0x000003e0 +#define A2XX_A220_VSC_BIN_SIZE_HEIGHT__SHIFT			5 +static inline uint32_t A2XX_A220_VSC_BIN_SIZE_HEIGHT(uint32_t val) +{ +	return ((val >> 5) << A2XX_A220_VSC_BIN_SIZE_HEIGHT__SHIFT) & A2XX_A220_VSC_BIN_SIZE_HEIGHT__MASK; +} + +static inline uint32_t REG_A2XX_VSC_PIPE(uint32_t i0) { return 0x00000c06 + 0x3*i0; } + +static inline uint32_t REG_A2XX_VSC_PIPE_CONFIG(uint32_t i0) { return 0x00000c06 + 0x3*i0; } + +static inline uint32_t REG_A2XX_VSC_PIPE_DATA_ADDRESS(uint32_t i0) { return 0x00000c07 + 0x3*i0; } + +static inline uint32_t REG_A2XX_VSC_PIPE_DATA_LENGTH(uint32_t i0) { return 0x00000c08 + 0x3*i0; } + +#define REG_A2XX_PC_DEBUG_CNTL					0x00000c38 + +#define REG_A2XX_PC_DEBUG_DATA					0x00000c39 + +#define REG_A2XX_PA_SC_VIZ_QUERY_STATUS				0x00000c44 + +#define REG_A2XX_GRAS_DEBUG_CNTL				0x00000c80 + +#define REG_A2XX_PA_SU_DEBUG_CNTL				0x00000c80 + +#define REG_A2XX_GRAS_DEBUG_DATA				0x00000c81 + +#define REG_A2XX_PA_SU_DEBUG_DATA				0x00000c81 + +#define REG_A2XX_PA_SU_FACE_DATA				0x00000c86 + +#define REG_A2XX_SQ_GPR_MANAGEMENT				0x00000d00 + +#define REG_A2XX_SQ_FLOW_CONTROL				0x00000d01 + +#define REG_A2XX_SQ_INST_STORE_MANAGMENT			0x00000d02 + +#define REG_A2XX_SQ_DEBUG_MISC					0x00000d05 + +#define REG_A2XX_SQ_INT_CNTL					0x00000d34 + +#define REG_A2XX_SQ_INT_STATUS					0x00000d35 + +#define REG_A2XX_SQ_INT_ACK					0x00000d36 + +#define REG_A2XX_SQ_DEBUG_INPUT_FSM				0x00000dae + +#define REG_A2XX_SQ_DEBUG_CONST_MGR_FSM				0x00000daf + +#define REG_A2XX_SQ_DEBUG_TP_FSM				0x00000db0 + +#define REG_A2XX_SQ_DEBUG_FSM_ALU_0				0x00000db1 + +#define REG_A2XX_SQ_DEBUG_FSM_ALU_1				0x00000db2 + +#define REG_A2XX_SQ_DEBUG_EXP_ALLOC				0x00000db3 + +#define REG_A2XX_SQ_DEBUG_PTR_BUFF				0x00000db4 + +#define REG_A2XX_SQ_DEBUG_GPR_VTX				0x00000db5 + +#define REG_A2XX_SQ_DEBUG_GPR_PIX				0x00000db6 + +#define REG_A2XX_SQ_DEBUG_TB_STATUS_SEL				0x00000db7 + +#define REG_A2XX_SQ_DEBUG_VTX_TB_0				0x00000db8 + +#define REG_A2XX_SQ_DEBUG_VTX_TB_1				0x00000db9 + +#define REG_A2XX_SQ_DEBUG_VTX_TB_STATUS_REG			0x00000dba + +#define REG_A2XX_SQ_DEBUG_VTX_TB_STATE_MEM			0x00000dbb + +#define REG_A2XX_SQ_DEBUG_PIX_TB_0				0x00000dbc + +#define REG_A2XX_SQ_DEBUG_PIX_TB_STATUS_REG_0			0x00000dbd + +#define REG_A2XX_SQ_DEBUG_PIX_TB_STATUS_REG_1			0x00000dbe + +#define REG_A2XX_SQ_DEBUG_PIX_TB_STATUS_REG_2			0x00000dbf + +#define REG_A2XX_SQ_DEBUG_PIX_TB_STATUS_REG_3			0x00000dc0 + +#define REG_A2XX_SQ_DEBUG_PIX_TB_STATE_MEM			0x00000dc1 + +#define REG_A2XX_TC_CNTL_STATUS					0x00000e00 +#define A2XX_TC_CNTL_STATUS_L2_INVALIDATE			0x00000001 + +#define REG_A2XX_TP0_CHICKEN					0x00000e1e + +#define REG_A2XX_RB_BC_CONTROL					0x00000f01 +#define A2XX_RB_BC_CONTROL_ACCUM_LINEAR_MODE_ENABLE		0x00000001 +#define A2XX_RB_BC_CONTROL_ACCUM_TIMEOUT_SELECT__MASK		0x00000006 +#define A2XX_RB_BC_CONTROL_ACCUM_TIMEOUT_SELECT__SHIFT		1 +static inline uint32_t A2XX_RB_BC_CONTROL_ACCUM_TIMEOUT_SELECT(uint32_t val) +{ +	return ((val) << A2XX_RB_BC_CONTROL_ACCUM_TIMEOUT_SELECT__SHIFT) & A2XX_RB_BC_CONTROL_ACCUM_TIMEOUT_SELECT__MASK; +} +#define A2XX_RB_BC_CONTROL_DISABLE_EDRAM_CAM			0x00000008 +#define A2XX_RB_BC_CONTROL_DISABLE_EZ_FAST_CONTEXT_SWITCH	0x00000010 +#define A2XX_RB_BC_CONTROL_DISABLE_EZ_NULL_ZCMD_DROP		0x00000020 +#define A2XX_RB_BC_CONTROL_DISABLE_LZ_NULL_ZCMD_DROP		0x00000040 +#define A2XX_RB_BC_CONTROL_ENABLE_AZ_THROTTLE			0x00000080 +#define A2XX_RB_BC_CONTROL_AZ_THROTTLE_COUNT__MASK		0x00001f00 +#define A2XX_RB_BC_CONTROL_AZ_THROTTLE_COUNT__SHIFT		8 +static inline uint32_t A2XX_RB_BC_CONTROL_AZ_THROTTLE_COUNT(uint32_t val) +{ +	return ((val) << A2XX_RB_BC_CONTROL_AZ_THROTTLE_COUNT__SHIFT) & A2XX_RB_BC_CONTROL_AZ_THROTTLE_COUNT__MASK; +} +#define A2XX_RB_BC_CONTROL_ENABLE_CRC_UPDATE			0x00004000 +#define A2XX_RB_BC_CONTROL_CRC_MODE				0x00008000 +#define A2XX_RB_BC_CONTROL_DISABLE_SAMPLE_COUNTERS		0x00010000 +#define A2XX_RB_BC_CONTROL_DISABLE_ACCUM			0x00020000 +#define A2XX_RB_BC_CONTROL_ACCUM_ALLOC_MASK__MASK		0x003c0000 +#define A2XX_RB_BC_CONTROL_ACCUM_ALLOC_MASK__SHIFT		18 +static inline uint32_t A2XX_RB_BC_CONTROL_ACCUM_ALLOC_MASK(uint32_t val) +{ +	return ((val) << A2XX_RB_BC_CONTROL_ACCUM_ALLOC_MASK__SHIFT) & A2XX_RB_BC_CONTROL_ACCUM_ALLOC_MASK__MASK; +} +#define A2XX_RB_BC_CONTROL_LINEAR_PERFORMANCE_ENABLE		0x00400000 +#define A2XX_RB_BC_CONTROL_ACCUM_DATA_FIFO_LIMIT__MASK		0x07800000 +#define A2XX_RB_BC_CONTROL_ACCUM_DATA_FIFO_LIMIT__SHIFT		23 +static inline uint32_t A2XX_RB_BC_CONTROL_ACCUM_DATA_FIFO_LIMIT(uint32_t val) +{ +	return ((val) << A2XX_RB_BC_CONTROL_ACCUM_DATA_FIFO_LIMIT__SHIFT) & A2XX_RB_BC_CONTROL_ACCUM_DATA_FIFO_LIMIT__MASK; +} +#define A2XX_RB_BC_CONTROL_MEM_EXPORT_TIMEOUT_SELECT__MASK	0x18000000 +#define A2XX_RB_BC_CONTROL_MEM_EXPORT_TIMEOUT_SELECT__SHIFT	27 +static inline uint32_t A2XX_RB_BC_CONTROL_MEM_EXPORT_TIMEOUT_SELECT(uint32_t val) +{ +	return ((val) << A2XX_RB_BC_CONTROL_MEM_EXPORT_TIMEOUT_SELECT__SHIFT) & A2XX_RB_BC_CONTROL_MEM_EXPORT_TIMEOUT_SELECT__MASK; +} +#define A2XX_RB_BC_CONTROL_MEM_EXPORT_LINEAR_MODE_ENABLE	0x20000000 +#define A2XX_RB_BC_CONTROL_CRC_SYSTEM				0x40000000 +#define A2XX_RB_BC_CONTROL_RESERVED6				0x80000000 + +#define REG_A2XX_RB_EDRAM_INFO					0x00000f02 + +#define REG_A2XX_RB_DEBUG_CNTL					0x00000f26 + +#define REG_A2XX_RB_DEBUG_DATA					0x00000f27 + +#define REG_A2XX_RB_SURFACE_INFO				0x00002000 + +#define REG_A2XX_RB_COLOR_INFO					0x00002001 +#define A2XX_RB_COLOR_INFO_FORMAT__MASK				0x0000000f +#define A2XX_RB_COLOR_INFO_FORMAT__SHIFT			0 +static inline uint32_t A2XX_RB_COLOR_INFO_FORMAT(enum a2xx_colorformatx val) +{ +	return ((val) << A2XX_RB_COLOR_INFO_FORMAT__SHIFT) & A2XX_RB_COLOR_INFO_FORMAT__MASK; +} +#define A2XX_RB_COLOR_INFO_ROUND_MODE__MASK			0x00000030 +#define A2XX_RB_COLOR_INFO_ROUND_MODE__SHIFT			4 +static inline uint32_t A2XX_RB_COLOR_INFO_ROUND_MODE(uint32_t val) +{ +	return ((val) << A2XX_RB_COLOR_INFO_ROUND_MODE__SHIFT) & A2XX_RB_COLOR_INFO_ROUND_MODE__MASK; +} +#define A2XX_RB_COLOR_INFO_LINEAR				0x00000040 +#define A2XX_RB_COLOR_INFO_ENDIAN__MASK				0x00000180 +#define A2XX_RB_COLOR_INFO_ENDIAN__SHIFT			7 +static inline uint32_t A2XX_RB_COLOR_INFO_ENDIAN(uint32_t val) +{ +	return ((val) << A2XX_RB_COLOR_INFO_ENDIAN__SHIFT) & A2XX_RB_COLOR_INFO_ENDIAN__MASK; +} +#define A2XX_RB_COLOR_INFO_SWAP__MASK				0x00000600 +#define A2XX_RB_COLOR_INFO_SWAP__SHIFT				9 +static inline uint32_t A2XX_RB_COLOR_INFO_SWAP(uint32_t val) +{ +	return ((val) << A2XX_RB_COLOR_INFO_SWAP__SHIFT) & A2XX_RB_COLOR_INFO_SWAP__MASK; +} +#define A2XX_RB_COLOR_INFO_BASE__MASK				0xfffff000 +#define A2XX_RB_COLOR_INFO_BASE__SHIFT				12 +static inline uint32_t A2XX_RB_COLOR_INFO_BASE(uint32_t val) +{ +	return ((val >> 10) << A2XX_RB_COLOR_INFO_BASE__SHIFT) & A2XX_RB_COLOR_INFO_BASE__MASK; +} + +#define REG_A2XX_RB_DEPTH_INFO					0x00002002 +#define A2XX_RB_DEPTH_INFO_DEPTH_FORMAT__MASK			0x00000001 +#define A2XX_RB_DEPTH_INFO_DEPTH_FORMAT__SHIFT			0 +static inline uint32_t A2XX_RB_DEPTH_INFO_DEPTH_FORMAT(enum adreno_rb_depth_format val) +{ +	return ((val) << A2XX_RB_DEPTH_INFO_DEPTH_FORMAT__SHIFT) & A2XX_RB_DEPTH_INFO_DEPTH_FORMAT__MASK; +} +#define A2XX_RB_DEPTH_INFO_DEPTH_BASE__MASK			0xfffff000 +#define A2XX_RB_DEPTH_INFO_DEPTH_BASE__SHIFT			12 +static inline uint32_t A2XX_RB_DEPTH_INFO_DEPTH_BASE(uint32_t val) +{ +	return ((val >> 10) << A2XX_RB_DEPTH_INFO_DEPTH_BASE__SHIFT) & A2XX_RB_DEPTH_INFO_DEPTH_BASE__MASK; +} + +#define REG_A2XX_A225_RB_COLOR_INFO3				0x00002005 + +#define REG_A2XX_COHER_DEST_BASE_0				0x00002006 + +#define REG_A2XX_PA_SC_SCREEN_SCISSOR_TL			0x0000200e +#define A2XX_PA_SC_SCREEN_SCISSOR_TL_WINDOW_OFFSET_DISABLE	0x80000000 +#define A2XX_PA_SC_SCREEN_SCISSOR_TL_X__MASK			0x00007fff +#define A2XX_PA_SC_SCREEN_SCISSOR_TL_X__SHIFT			0 +static inline uint32_t A2XX_PA_SC_SCREEN_SCISSOR_TL_X(uint32_t val) +{ +	return ((val) << A2XX_PA_SC_SCREEN_SCISSOR_TL_X__SHIFT) & A2XX_PA_SC_SCREEN_SCISSOR_TL_X__MASK; +} +#define A2XX_PA_SC_SCREEN_SCISSOR_TL_Y__MASK			0x7fff0000 +#define A2XX_PA_SC_SCREEN_SCISSOR_TL_Y__SHIFT			16 +static inline uint32_t A2XX_PA_SC_SCREEN_SCISSOR_TL_Y(uint32_t val) +{ +	return ((val) << A2XX_PA_SC_SCREEN_SCISSOR_TL_Y__SHIFT) & A2XX_PA_SC_SCREEN_SCISSOR_TL_Y__MASK; +} + +#define REG_A2XX_PA_SC_SCREEN_SCISSOR_BR			0x0000200f +#define A2XX_PA_SC_SCREEN_SCISSOR_BR_WINDOW_OFFSET_DISABLE	0x80000000 +#define A2XX_PA_SC_SCREEN_SCISSOR_BR_X__MASK			0x00007fff +#define A2XX_PA_SC_SCREEN_SCISSOR_BR_X__SHIFT			0 +static inline uint32_t A2XX_PA_SC_SCREEN_SCISSOR_BR_X(uint32_t val) +{ +	return ((val) << A2XX_PA_SC_SCREEN_SCISSOR_BR_X__SHIFT) & A2XX_PA_SC_SCREEN_SCISSOR_BR_X__MASK; +} +#define A2XX_PA_SC_SCREEN_SCISSOR_BR_Y__MASK			0x7fff0000 +#define A2XX_PA_SC_SCREEN_SCISSOR_BR_Y__SHIFT			16 +static inline uint32_t A2XX_PA_SC_SCREEN_SCISSOR_BR_Y(uint32_t val) +{ +	return ((val) << A2XX_PA_SC_SCREEN_SCISSOR_BR_Y__SHIFT) & A2XX_PA_SC_SCREEN_SCISSOR_BR_Y__MASK; +} + +#define REG_A2XX_PA_SC_WINDOW_OFFSET				0x00002080 +#define A2XX_PA_SC_WINDOW_OFFSET_X__MASK			0x00007fff +#define A2XX_PA_SC_WINDOW_OFFSET_X__SHIFT			0 +static inline uint32_t A2XX_PA_SC_WINDOW_OFFSET_X(int32_t val) +{ +	return ((val) << A2XX_PA_SC_WINDOW_OFFSET_X__SHIFT) & A2XX_PA_SC_WINDOW_OFFSET_X__MASK; +} +#define A2XX_PA_SC_WINDOW_OFFSET_Y__MASK			0x7fff0000 +#define A2XX_PA_SC_WINDOW_OFFSET_Y__SHIFT			16 +static inline uint32_t A2XX_PA_SC_WINDOW_OFFSET_Y(int32_t val) +{ +	return ((val) << A2XX_PA_SC_WINDOW_OFFSET_Y__SHIFT) & A2XX_PA_SC_WINDOW_OFFSET_Y__MASK; +} +#define A2XX_PA_SC_WINDOW_OFFSET_DISABLE			0x80000000 + +#define REG_A2XX_PA_SC_WINDOW_SCISSOR_TL			0x00002081 +#define A2XX_PA_SC_WINDOW_SCISSOR_TL_WINDOW_OFFSET_DISABLE	0x80000000 +#define A2XX_PA_SC_WINDOW_SCISSOR_TL_X__MASK			0x00007fff +#define A2XX_PA_SC_WINDOW_SCISSOR_TL_X__SHIFT			0 +static inline uint32_t A2XX_PA_SC_WINDOW_SCISSOR_TL_X(uint32_t val) +{ +	return ((val) << A2XX_PA_SC_WINDOW_SCISSOR_TL_X__SHIFT) & A2XX_PA_SC_WINDOW_SCISSOR_TL_X__MASK; +} +#define A2XX_PA_SC_WINDOW_SCISSOR_TL_Y__MASK			0x7fff0000 +#define A2XX_PA_SC_WINDOW_SCISSOR_TL_Y__SHIFT			16 +static inline uint32_t A2XX_PA_SC_WINDOW_SCISSOR_TL_Y(uint32_t val) +{ +	return ((val) << A2XX_PA_SC_WINDOW_SCISSOR_TL_Y__SHIFT) & A2XX_PA_SC_WINDOW_SCISSOR_TL_Y__MASK; +} + +#define REG_A2XX_PA_SC_WINDOW_SCISSOR_BR			0x00002082 +#define A2XX_PA_SC_WINDOW_SCISSOR_BR_WINDOW_OFFSET_DISABLE	0x80000000 +#define A2XX_PA_SC_WINDOW_SCISSOR_BR_X__MASK			0x00007fff +#define A2XX_PA_SC_WINDOW_SCISSOR_BR_X__SHIFT			0 +static inline uint32_t A2XX_PA_SC_WINDOW_SCISSOR_BR_X(uint32_t val) +{ +	return ((val) << A2XX_PA_SC_WINDOW_SCISSOR_BR_X__SHIFT) & A2XX_PA_SC_WINDOW_SCISSOR_BR_X__MASK; +} +#define A2XX_PA_SC_WINDOW_SCISSOR_BR_Y__MASK			0x7fff0000 +#define A2XX_PA_SC_WINDOW_SCISSOR_BR_Y__SHIFT			16 +static inline uint32_t A2XX_PA_SC_WINDOW_SCISSOR_BR_Y(uint32_t val) +{ +	return ((val) << A2XX_PA_SC_WINDOW_SCISSOR_BR_Y__SHIFT) & A2XX_PA_SC_WINDOW_SCISSOR_BR_Y__MASK; +} + +#define REG_A2XX_UNKNOWN_2010					0x00002010 + +#define REG_A2XX_VGT_MAX_VTX_INDX				0x00002100 + +#define REG_A2XX_VGT_MIN_VTX_INDX				0x00002101 + +#define REG_A2XX_VGT_INDX_OFFSET				0x00002102 + +#define REG_A2XX_A225_PC_MULTI_PRIM_IB_RESET_INDX		0x00002103 + +#define REG_A2XX_RB_COLOR_MASK					0x00002104 +#define A2XX_RB_COLOR_MASK_WRITE_RED				0x00000001 +#define A2XX_RB_COLOR_MASK_WRITE_GREEN				0x00000002 +#define A2XX_RB_COLOR_MASK_WRITE_BLUE				0x00000004 +#define A2XX_RB_COLOR_MASK_WRITE_ALPHA				0x00000008 + +#define REG_A2XX_RB_BLEND_RED					0x00002105 + +#define REG_A2XX_RB_BLEND_GREEN					0x00002106 + +#define REG_A2XX_RB_BLEND_BLUE					0x00002107 + +#define REG_A2XX_RB_BLEND_ALPHA					0x00002108 + +#define REG_A2XX_RB_FOG_COLOR					0x00002109 + +#define REG_A2XX_RB_STENCILREFMASK_BF				0x0000210c +#define A2XX_RB_STENCILREFMASK_BF_STENCILREF__MASK		0x000000ff +#define A2XX_RB_STENCILREFMASK_BF_STENCILREF__SHIFT		0 +static inline uint32_t A2XX_RB_STENCILREFMASK_BF_STENCILREF(uint32_t val) +{ +	return ((val) << A2XX_RB_STENCILREFMASK_BF_STENCILREF__SHIFT) & A2XX_RB_STENCILREFMASK_BF_STENCILREF__MASK; +} +#define A2XX_RB_STENCILREFMASK_BF_STENCILMASK__MASK		0x0000ff00 +#define A2XX_RB_STENCILREFMASK_BF_STENCILMASK__SHIFT		8 +static inline uint32_t A2XX_RB_STENCILREFMASK_BF_STENCILMASK(uint32_t val) +{ +	return ((val) << A2XX_RB_STENCILREFMASK_BF_STENCILMASK__SHIFT) & A2XX_RB_STENCILREFMASK_BF_STENCILMASK__MASK; +} +#define A2XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK__MASK	0x00ff0000 +#define A2XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK__SHIFT	16 +static inline uint32_t A2XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK(uint32_t val) +{ +	return ((val) << A2XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK__SHIFT) & A2XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK__MASK; +} + +#define REG_A2XX_RB_STENCILREFMASK				0x0000210d +#define A2XX_RB_STENCILREFMASK_STENCILREF__MASK			0x000000ff +#define A2XX_RB_STENCILREFMASK_STENCILREF__SHIFT		0 +static inline uint32_t A2XX_RB_STENCILREFMASK_STENCILREF(uint32_t val) +{ +	return ((val) << A2XX_RB_STENCILREFMASK_STENCILREF__SHIFT) & A2XX_RB_STENCILREFMASK_STENCILREF__MASK; +} +#define A2XX_RB_STENCILREFMASK_STENCILMASK__MASK		0x0000ff00 +#define A2XX_RB_STENCILREFMASK_STENCILMASK__SHIFT		8 +static inline uint32_t A2XX_RB_STENCILREFMASK_STENCILMASK(uint32_t val) +{ +	return ((val) << A2XX_RB_STENCILREFMASK_STENCILMASK__SHIFT) & A2XX_RB_STENCILREFMASK_STENCILMASK__MASK; +} +#define A2XX_RB_STENCILREFMASK_STENCILWRITEMASK__MASK		0x00ff0000 +#define A2XX_RB_STENCILREFMASK_STENCILWRITEMASK__SHIFT		16 +static inline uint32_t A2XX_RB_STENCILREFMASK_STENCILWRITEMASK(uint32_t val) +{ +	return ((val) << A2XX_RB_STENCILREFMASK_STENCILWRITEMASK__SHIFT) & A2XX_RB_STENCILREFMASK_STENCILWRITEMASK__MASK; +} + +#define REG_A2XX_RB_ALPHA_REF					0x0000210e + +#define REG_A2XX_PA_CL_VPORT_XSCALE				0x0000210f +#define A2XX_PA_CL_VPORT_XSCALE__MASK				0xffffffff +#define A2XX_PA_CL_VPORT_XSCALE__SHIFT				0 +static inline uint32_t A2XX_PA_CL_VPORT_XSCALE(float val) +{ +	return ((fui(val)) << A2XX_PA_CL_VPORT_XSCALE__SHIFT) & A2XX_PA_CL_VPORT_XSCALE__MASK; +} + +#define REG_A2XX_PA_CL_VPORT_XOFFSET				0x00002110 +#define A2XX_PA_CL_VPORT_XOFFSET__MASK				0xffffffff +#define A2XX_PA_CL_VPORT_XOFFSET__SHIFT				0 +static inline uint32_t A2XX_PA_CL_VPORT_XOFFSET(float val) +{ +	return ((fui(val)) << A2XX_PA_CL_VPORT_XOFFSET__SHIFT) & A2XX_PA_CL_VPORT_XOFFSET__MASK; +} + +#define REG_A2XX_PA_CL_VPORT_YSCALE				0x00002111 +#define A2XX_PA_CL_VPORT_YSCALE__MASK				0xffffffff +#define A2XX_PA_CL_VPORT_YSCALE__SHIFT				0 +static inline uint32_t A2XX_PA_CL_VPORT_YSCALE(float val) +{ +	return ((fui(val)) << A2XX_PA_CL_VPORT_YSCALE__SHIFT) & A2XX_PA_CL_VPORT_YSCALE__MASK; +} + +#define REG_A2XX_PA_CL_VPORT_YOFFSET				0x00002112 +#define A2XX_PA_CL_VPORT_YOFFSET__MASK				0xffffffff +#define A2XX_PA_CL_VPORT_YOFFSET__SHIFT				0 +static inline uint32_t A2XX_PA_CL_VPORT_YOFFSET(float val) +{ +	return ((fui(val)) << A2XX_PA_CL_VPORT_YOFFSET__SHIFT) & A2XX_PA_CL_VPORT_YOFFSET__MASK; +} + +#define REG_A2XX_PA_CL_VPORT_ZSCALE				0x00002113 +#define A2XX_PA_CL_VPORT_ZSCALE__MASK				0xffffffff +#define A2XX_PA_CL_VPORT_ZSCALE__SHIFT				0 +static inline uint32_t A2XX_PA_CL_VPORT_ZSCALE(float val) +{ +	return ((fui(val)) << A2XX_PA_CL_VPORT_ZSCALE__SHIFT) & A2XX_PA_CL_VPORT_ZSCALE__MASK; +} + +#define REG_A2XX_PA_CL_VPORT_ZOFFSET				0x00002114 +#define A2XX_PA_CL_VPORT_ZOFFSET__MASK				0xffffffff +#define A2XX_PA_CL_VPORT_ZOFFSET__SHIFT				0 +static inline uint32_t A2XX_PA_CL_VPORT_ZOFFSET(float val) +{ +	return ((fui(val)) << A2XX_PA_CL_VPORT_ZOFFSET__SHIFT) & A2XX_PA_CL_VPORT_ZOFFSET__MASK; +} + +#define REG_A2XX_SQ_PROGRAM_CNTL				0x00002180 +#define A2XX_SQ_PROGRAM_CNTL_VS_REGS__MASK			0x000000ff +#define A2XX_SQ_PROGRAM_CNTL_VS_REGS__SHIFT			0 +static inline uint32_t A2XX_SQ_PROGRAM_CNTL_VS_REGS(uint32_t val) +{ +	return ((val) << A2XX_SQ_PROGRAM_CNTL_VS_REGS__SHIFT) & A2XX_SQ_PROGRAM_CNTL_VS_REGS__MASK; +} +#define A2XX_SQ_PROGRAM_CNTL_PS_REGS__MASK			0x0000ff00 +#define A2XX_SQ_PROGRAM_CNTL_PS_REGS__SHIFT			8 +static inline uint32_t A2XX_SQ_PROGRAM_CNTL_PS_REGS(uint32_t val) +{ +	return ((val) << A2XX_SQ_PROGRAM_CNTL_PS_REGS__SHIFT) & A2XX_SQ_PROGRAM_CNTL_PS_REGS__MASK; +} +#define A2XX_SQ_PROGRAM_CNTL_VS_RESOURCE			0x00010000 +#define A2XX_SQ_PROGRAM_CNTL_PS_RESOURCE			0x00020000 +#define A2XX_SQ_PROGRAM_CNTL_PARAM_GEN				0x00040000 +#define A2XX_SQ_PROGRAM_CNTL_GEN_INDEX_PIX			0x00080000 +#define A2XX_SQ_PROGRAM_CNTL_VS_EXPORT_COUNT__MASK		0x00f00000 +#define A2XX_SQ_PROGRAM_CNTL_VS_EXPORT_COUNT__SHIFT		20 +static inline uint32_t A2XX_SQ_PROGRAM_CNTL_VS_EXPORT_COUNT(uint32_t val) +{ +	return ((val) << A2XX_SQ_PROGRAM_CNTL_VS_EXPORT_COUNT__SHIFT) & A2XX_SQ_PROGRAM_CNTL_VS_EXPORT_COUNT__MASK; +} +#define A2XX_SQ_PROGRAM_CNTL_VS_EXPORT_MODE__MASK		0x07000000 +#define A2XX_SQ_PROGRAM_CNTL_VS_EXPORT_MODE__SHIFT		24 +static inline uint32_t A2XX_SQ_PROGRAM_CNTL_VS_EXPORT_MODE(enum a2xx_sq_ps_vtx_mode val) +{ +	return ((val) << A2XX_SQ_PROGRAM_CNTL_VS_EXPORT_MODE__SHIFT) & A2XX_SQ_PROGRAM_CNTL_VS_EXPORT_MODE__MASK; +} +#define A2XX_SQ_PROGRAM_CNTL_PS_EXPORT_MODE__MASK		0x78000000 +#define A2XX_SQ_PROGRAM_CNTL_PS_EXPORT_MODE__SHIFT		27 +static inline uint32_t A2XX_SQ_PROGRAM_CNTL_PS_EXPORT_MODE(uint32_t val) +{ +	return ((val) << A2XX_SQ_PROGRAM_CNTL_PS_EXPORT_MODE__SHIFT) & A2XX_SQ_PROGRAM_CNTL_PS_EXPORT_MODE__MASK; +} +#define A2XX_SQ_PROGRAM_CNTL_GEN_INDEX_VTX			0x80000000 + +#define REG_A2XX_SQ_CONTEXT_MISC				0x00002181 +#define A2XX_SQ_CONTEXT_MISC_INST_PRED_OPTIMIZE			0x00000001 +#define A2XX_SQ_CONTEXT_MISC_SC_OUTPUT_SCREEN_XY		0x00000002 +#define A2XX_SQ_CONTEXT_MISC_SC_SAMPLE_CNTL__MASK		0x0000000c +#define A2XX_SQ_CONTEXT_MISC_SC_SAMPLE_CNTL__SHIFT		2 +static inline uint32_t A2XX_SQ_CONTEXT_MISC_SC_SAMPLE_CNTL(enum a2xx_sq_sample_cntl val) +{ +	return ((val) << A2XX_SQ_CONTEXT_MISC_SC_SAMPLE_CNTL__SHIFT) & A2XX_SQ_CONTEXT_MISC_SC_SAMPLE_CNTL__MASK; +} +#define A2XX_SQ_CONTEXT_MISC_PARAM_GEN_POS__MASK		0x0000ff00 +#define A2XX_SQ_CONTEXT_MISC_PARAM_GEN_POS__SHIFT		8 +static inline uint32_t A2XX_SQ_CONTEXT_MISC_PARAM_GEN_POS(uint32_t val) +{ +	return ((val) << A2XX_SQ_CONTEXT_MISC_PARAM_GEN_POS__SHIFT) & A2XX_SQ_CONTEXT_MISC_PARAM_GEN_POS__MASK; +} +#define A2XX_SQ_CONTEXT_MISC_PERFCOUNTER_REF			0x00010000 +#define A2XX_SQ_CONTEXT_MISC_YEILD_OPTIMIZE			0x00020000 +#define A2XX_SQ_CONTEXT_MISC_TX_CACHE_SEL			0x00040000 + +#define REG_A2XX_SQ_INTERPOLATOR_CNTL				0x00002182 + +#define REG_A2XX_SQ_WRAPPING_0					0x00002183 + +#define REG_A2XX_SQ_WRAPPING_1					0x00002184 + +#define REG_A2XX_SQ_PS_PROGRAM					0x000021f6 + +#define REG_A2XX_SQ_VS_PROGRAM					0x000021f7 + +#define REG_A2XX_VGT_EVENT_INITIATOR				0x000021f9 + +#define REG_A2XX_VGT_DRAW_INITIATOR				0x000021fc + +#define REG_A2XX_VGT_IMMED_DATA					0x000021fd + +#define REG_A2XX_RB_DEPTHCONTROL				0x00002200 +#define A2XX_RB_DEPTHCONTROL_STENCIL_ENABLE			0x00000001 +#define A2XX_RB_DEPTHCONTROL_Z_ENABLE				0x00000002 +#define A2XX_RB_DEPTHCONTROL_Z_WRITE_ENABLE			0x00000004 +#define A2XX_RB_DEPTHCONTROL_EARLY_Z_ENABLE			0x00000008 +#define A2XX_RB_DEPTHCONTROL_ZFUNC__MASK			0x00000070 +#define A2XX_RB_DEPTHCONTROL_ZFUNC__SHIFT			4 +static inline uint32_t A2XX_RB_DEPTHCONTROL_ZFUNC(enum adreno_compare_func val) +{ +	return ((val) << A2XX_RB_DEPTHCONTROL_ZFUNC__SHIFT) & A2XX_RB_DEPTHCONTROL_ZFUNC__MASK; +} +#define A2XX_RB_DEPTHCONTROL_BACKFACE_ENABLE			0x00000080 +#define A2XX_RB_DEPTHCONTROL_STENCILFUNC__MASK			0x00000700 +#define A2XX_RB_DEPTHCONTROL_STENCILFUNC__SHIFT			8 +static inline uint32_t A2XX_RB_DEPTHCONTROL_STENCILFUNC(enum adreno_compare_func val) +{ +	return ((val) << A2XX_RB_DEPTHCONTROL_STENCILFUNC__SHIFT) & A2XX_RB_DEPTHCONTROL_STENCILFUNC__MASK; +} +#define A2XX_RB_DEPTHCONTROL_STENCILFAIL__MASK			0x00003800 +#define A2XX_RB_DEPTHCONTROL_STENCILFAIL__SHIFT			11 +static inline uint32_t A2XX_RB_DEPTHCONTROL_STENCILFAIL(enum adreno_stencil_op val) +{ +	return ((val) << A2XX_RB_DEPTHCONTROL_STENCILFAIL__SHIFT) & A2XX_RB_DEPTHCONTROL_STENCILFAIL__MASK; +} +#define A2XX_RB_DEPTHCONTROL_STENCILZPASS__MASK			0x0001c000 +#define A2XX_RB_DEPTHCONTROL_STENCILZPASS__SHIFT		14 +static inline uint32_t A2XX_RB_DEPTHCONTROL_STENCILZPASS(enum adreno_stencil_op val) +{ +	return ((val) << A2XX_RB_DEPTHCONTROL_STENCILZPASS__SHIFT) & A2XX_RB_DEPTHCONTROL_STENCILZPASS__MASK; +} +#define A2XX_RB_DEPTHCONTROL_STENCILZFAIL__MASK			0x000e0000 +#define A2XX_RB_DEPTHCONTROL_STENCILZFAIL__SHIFT		17 +static inline uint32_t A2XX_RB_DEPTHCONTROL_STENCILZFAIL(enum adreno_stencil_op val) +{ +	return ((val) << A2XX_RB_DEPTHCONTROL_STENCILZFAIL__SHIFT) & A2XX_RB_DEPTHCONTROL_STENCILZFAIL__MASK; +} +#define A2XX_RB_DEPTHCONTROL_STENCILFUNC_BF__MASK		0x00700000 +#define A2XX_RB_DEPTHCONTROL_STENCILFUNC_BF__SHIFT		20 +static inline uint32_t A2XX_RB_DEPTHCONTROL_STENCILFUNC_BF(enum adreno_compare_func val) +{ +	return ((val) << A2XX_RB_DEPTHCONTROL_STENCILFUNC_BF__SHIFT) & A2XX_RB_DEPTHCONTROL_STENCILFUNC_BF__MASK; +} +#define A2XX_RB_DEPTHCONTROL_STENCILFAIL_BF__MASK		0x03800000 +#define A2XX_RB_DEPTHCONTROL_STENCILFAIL_BF__SHIFT		23 +static inline uint32_t A2XX_RB_DEPTHCONTROL_STENCILFAIL_BF(enum adreno_stencil_op val) +{ +	return ((val) << A2XX_RB_DEPTHCONTROL_STENCILFAIL_BF__SHIFT) & A2XX_RB_DEPTHCONTROL_STENCILFAIL_BF__MASK; +} +#define A2XX_RB_DEPTHCONTROL_STENCILZPASS_BF__MASK		0x1c000000 +#define A2XX_RB_DEPTHCONTROL_STENCILZPASS_BF__SHIFT		26 +static inline uint32_t A2XX_RB_DEPTHCONTROL_STENCILZPASS_BF(enum adreno_stencil_op val) +{ +	return ((val) << A2XX_RB_DEPTHCONTROL_STENCILZPASS_BF__SHIFT) & A2XX_RB_DEPTHCONTROL_STENCILZPASS_BF__MASK; +} +#define A2XX_RB_DEPTHCONTROL_STENCILZFAIL_BF__MASK		0xe0000000 +#define A2XX_RB_DEPTHCONTROL_STENCILZFAIL_BF__SHIFT		29 +static inline uint32_t A2XX_RB_DEPTHCONTROL_STENCILZFAIL_BF(enum adreno_stencil_op val) +{ +	return ((val) << A2XX_RB_DEPTHCONTROL_STENCILZFAIL_BF__SHIFT) & A2XX_RB_DEPTHCONTROL_STENCILZFAIL_BF__MASK; +} + +#define REG_A2XX_RB_BLEND_CONTROL				0x00002201 +#define A2XX_RB_BLEND_CONTROL_COLOR_SRCBLEND__MASK		0x0000001f +#define A2XX_RB_BLEND_CONTROL_COLOR_SRCBLEND__SHIFT		0 +static inline uint32_t A2XX_RB_BLEND_CONTROL_COLOR_SRCBLEND(enum adreno_rb_blend_factor val) +{ +	return ((val) << A2XX_RB_BLEND_CONTROL_COLOR_SRCBLEND__SHIFT) & A2XX_RB_BLEND_CONTROL_COLOR_SRCBLEND__MASK; +} +#define A2XX_RB_BLEND_CONTROL_COLOR_COMB_FCN__MASK		0x000000e0 +#define A2XX_RB_BLEND_CONTROL_COLOR_COMB_FCN__SHIFT		5 +static inline uint32_t A2XX_RB_BLEND_CONTROL_COLOR_COMB_FCN(enum adreno_rb_blend_opcode val) +{ +	return ((val) << A2XX_RB_BLEND_CONTROL_COLOR_COMB_FCN__SHIFT) & A2XX_RB_BLEND_CONTROL_COLOR_COMB_FCN__MASK; +} +#define A2XX_RB_BLEND_CONTROL_COLOR_DESTBLEND__MASK		0x00001f00 +#define A2XX_RB_BLEND_CONTROL_COLOR_DESTBLEND__SHIFT		8 +static inline uint32_t A2XX_RB_BLEND_CONTROL_COLOR_DESTBLEND(enum adreno_rb_blend_factor val) +{ +	return ((val) << A2XX_RB_BLEND_CONTROL_COLOR_DESTBLEND__SHIFT) & A2XX_RB_BLEND_CONTROL_COLOR_DESTBLEND__MASK; +} +#define A2XX_RB_BLEND_CONTROL_ALPHA_SRCBLEND__MASK		0x001f0000 +#define A2XX_RB_BLEND_CONTROL_ALPHA_SRCBLEND__SHIFT		16 +static inline uint32_t A2XX_RB_BLEND_CONTROL_ALPHA_SRCBLEND(enum adreno_rb_blend_factor val) +{ +	return ((val) << A2XX_RB_BLEND_CONTROL_ALPHA_SRCBLEND__SHIFT) & A2XX_RB_BLEND_CONTROL_ALPHA_SRCBLEND__MASK; +} +#define A2XX_RB_BLEND_CONTROL_ALPHA_COMB_FCN__MASK		0x00e00000 +#define A2XX_RB_BLEND_CONTROL_ALPHA_COMB_FCN__SHIFT		21 +static inline uint32_t A2XX_RB_BLEND_CONTROL_ALPHA_COMB_FCN(enum adreno_rb_blend_opcode val) +{ +	return ((val) << A2XX_RB_BLEND_CONTROL_ALPHA_COMB_FCN__SHIFT) & A2XX_RB_BLEND_CONTROL_ALPHA_COMB_FCN__MASK; +} +#define A2XX_RB_BLEND_CONTROL_ALPHA_DESTBLEND__MASK		0x1f000000 +#define A2XX_RB_BLEND_CONTROL_ALPHA_DESTBLEND__SHIFT		24 +static inline uint32_t A2XX_RB_BLEND_CONTROL_ALPHA_DESTBLEND(enum adreno_rb_blend_factor val) +{ +	return ((val) << A2XX_RB_BLEND_CONTROL_ALPHA_DESTBLEND__SHIFT) & A2XX_RB_BLEND_CONTROL_ALPHA_DESTBLEND__MASK; +} +#define A2XX_RB_BLEND_CONTROL_BLEND_FORCE_ENABLE		0x20000000 +#define A2XX_RB_BLEND_CONTROL_BLEND_FORCE			0x40000000 + +#define REG_A2XX_RB_COLORCONTROL				0x00002202 +#define A2XX_RB_COLORCONTROL_ALPHA_FUNC__MASK			0x00000007 +#define A2XX_RB_COLORCONTROL_ALPHA_FUNC__SHIFT			0 +static inline uint32_t A2XX_RB_COLORCONTROL_ALPHA_FUNC(enum adreno_compare_func val) +{ +	return ((val) << A2XX_RB_COLORCONTROL_ALPHA_FUNC__SHIFT) & A2XX_RB_COLORCONTROL_ALPHA_FUNC__MASK; +} +#define A2XX_RB_COLORCONTROL_ALPHA_TEST_ENABLE			0x00000008 +#define A2XX_RB_COLORCONTROL_ALPHA_TO_MASK_ENABLE		0x00000010 +#define A2XX_RB_COLORCONTROL_BLEND_DISABLE			0x00000020 +#define A2XX_RB_COLORCONTROL_VOB_ENABLE				0x00000040 +#define A2XX_RB_COLORCONTROL_VS_EXPORTS_FOG			0x00000080 +#define A2XX_RB_COLORCONTROL_ROP_CODE__MASK			0x00000f00 +#define A2XX_RB_COLORCONTROL_ROP_CODE__SHIFT			8 +static inline uint32_t A2XX_RB_COLORCONTROL_ROP_CODE(uint32_t val) +{ +	return ((val) << A2XX_RB_COLORCONTROL_ROP_CODE__SHIFT) & A2XX_RB_COLORCONTROL_ROP_CODE__MASK; +} +#define A2XX_RB_COLORCONTROL_DITHER_MODE__MASK			0x00003000 +#define A2XX_RB_COLORCONTROL_DITHER_MODE__SHIFT			12 +static inline uint32_t A2XX_RB_COLORCONTROL_DITHER_MODE(enum adreno_rb_dither_mode val) +{ +	return ((val) << A2XX_RB_COLORCONTROL_DITHER_MODE__SHIFT) & A2XX_RB_COLORCONTROL_DITHER_MODE__MASK; +} +#define A2XX_RB_COLORCONTROL_DITHER_TYPE__MASK			0x0000c000 +#define A2XX_RB_COLORCONTROL_DITHER_TYPE__SHIFT			14 +static inline uint32_t A2XX_RB_COLORCONTROL_DITHER_TYPE(enum a2xx_rb_dither_type val) +{ +	return ((val) << A2XX_RB_COLORCONTROL_DITHER_TYPE__SHIFT) & A2XX_RB_COLORCONTROL_DITHER_TYPE__MASK; +} +#define A2XX_RB_COLORCONTROL_PIXEL_FOG				0x00010000 +#define A2XX_RB_COLORCONTROL_ALPHA_TO_MASK_OFFSET0__MASK	0x03000000 +#define A2XX_RB_COLORCONTROL_ALPHA_TO_MASK_OFFSET0__SHIFT	24 +static inline uint32_t A2XX_RB_COLORCONTROL_ALPHA_TO_MASK_OFFSET0(uint32_t val) +{ +	return ((val) << A2XX_RB_COLORCONTROL_ALPHA_TO_MASK_OFFSET0__SHIFT) & A2XX_RB_COLORCONTROL_ALPHA_TO_MASK_OFFSET0__MASK; +} +#define A2XX_RB_COLORCONTROL_ALPHA_TO_MASK_OFFSET1__MASK	0x0c000000 +#define A2XX_RB_COLORCONTROL_ALPHA_TO_MASK_OFFSET1__SHIFT	26 +static inline uint32_t A2XX_RB_COLORCONTROL_ALPHA_TO_MASK_OFFSET1(uint32_t val) +{ +	return ((val) << A2XX_RB_COLORCONTROL_ALPHA_TO_MASK_OFFSET1__SHIFT) & A2XX_RB_COLORCONTROL_ALPHA_TO_MASK_OFFSET1__MASK; +} +#define A2XX_RB_COLORCONTROL_ALPHA_TO_MASK_OFFSET2__MASK	0x30000000 +#define A2XX_RB_COLORCONTROL_ALPHA_TO_MASK_OFFSET2__SHIFT	28 +static inline uint32_t A2XX_RB_COLORCONTROL_ALPHA_TO_MASK_OFFSET2(uint32_t val) +{ +	return ((val) << A2XX_RB_COLORCONTROL_ALPHA_TO_MASK_OFFSET2__SHIFT) & A2XX_RB_COLORCONTROL_ALPHA_TO_MASK_OFFSET2__MASK; +} +#define A2XX_RB_COLORCONTROL_ALPHA_TO_MASK_OFFSET3__MASK	0xc0000000 +#define A2XX_RB_COLORCONTROL_ALPHA_TO_MASK_OFFSET3__SHIFT	30 +static inline uint32_t A2XX_RB_COLORCONTROL_ALPHA_TO_MASK_OFFSET3(uint32_t val) +{ +	return ((val) << A2XX_RB_COLORCONTROL_ALPHA_TO_MASK_OFFSET3__SHIFT) & A2XX_RB_COLORCONTROL_ALPHA_TO_MASK_OFFSET3__MASK; +} + +#define REG_A2XX_VGT_CURRENT_BIN_ID_MAX				0x00002203 +#define A2XX_VGT_CURRENT_BIN_ID_MAX_COLUMN__MASK		0x00000007 +#define A2XX_VGT_CURRENT_BIN_ID_MAX_COLUMN__SHIFT		0 +static inline uint32_t A2XX_VGT_CURRENT_BIN_ID_MAX_COLUMN(uint32_t val) +{ +	return ((val) << A2XX_VGT_CURRENT_BIN_ID_MAX_COLUMN__SHIFT) & A2XX_VGT_CURRENT_BIN_ID_MAX_COLUMN__MASK; +} +#define A2XX_VGT_CURRENT_BIN_ID_MAX_ROW__MASK			0x00000038 +#define A2XX_VGT_CURRENT_BIN_ID_MAX_ROW__SHIFT			3 +static inline uint32_t A2XX_VGT_CURRENT_BIN_ID_MAX_ROW(uint32_t val) +{ +	return ((val) << A2XX_VGT_CURRENT_BIN_ID_MAX_ROW__SHIFT) & A2XX_VGT_CURRENT_BIN_ID_MAX_ROW__MASK; +} +#define A2XX_VGT_CURRENT_BIN_ID_MAX_GUARD_BAND_MASK__MASK	0x000001c0 +#define A2XX_VGT_CURRENT_BIN_ID_MAX_GUARD_BAND_MASK__SHIFT	6 +static inline uint32_t A2XX_VGT_CURRENT_BIN_ID_MAX_GUARD_BAND_MASK(uint32_t val) +{ +	return ((val) << A2XX_VGT_CURRENT_BIN_ID_MAX_GUARD_BAND_MASK__SHIFT) & A2XX_VGT_CURRENT_BIN_ID_MAX_GUARD_BAND_MASK__MASK; +} + +#define REG_A2XX_PA_CL_CLIP_CNTL				0x00002204 +#define A2XX_PA_CL_CLIP_CNTL_CLIP_DISABLE			0x00010000 +#define A2XX_PA_CL_CLIP_CNTL_BOUNDARY_EDGE_FLAG_ENA		0x00040000 +#define A2XX_PA_CL_CLIP_CNTL_DX_CLIP_SPACE_DEF__MASK		0x00080000 +#define A2XX_PA_CL_CLIP_CNTL_DX_CLIP_SPACE_DEF__SHIFT		19 +static inline uint32_t A2XX_PA_CL_CLIP_CNTL_DX_CLIP_SPACE_DEF(enum a2xx_dx_clip_space val) +{ +	return ((val) << A2XX_PA_CL_CLIP_CNTL_DX_CLIP_SPACE_DEF__SHIFT) & A2XX_PA_CL_CLIP_CNTL_DX_CLIP_SPACE_DEF__MASK; +} +#define A2XX_PA_CL_CLIP_CNTL_DIS_CLIP_ERR_DETECT		0x00100000 +#define A2XX_PA_CL_CLIP_CNTL_VTX_KILL_OR			0x00200000 +#define A2XX_PA_CL_CLIP_CNTL_XY_NAN_RETAIN			0x00400000 +#define A2XX_PA_CL_CLIP_CNTL_Z_NAN_RETAIN			0x00800000 +#define A2XX_PA_CL_CLIP_CNTL_W_NAN_RETAIN			0x01000000 + +#define REG_A2XX_PA_SU_SC_MODE_CNTL				0x00002205 +#define A2XX_PA_SU_SC_MODE_CNTL_CULL_FRONT			0x00000001 +#define A2XX_PA_SU_SC_MODE_CNTL_CULL_BACK			0x00000002 +#define A2XX_PA_SU_SC_MODE_CNTL_FACE				0x00000004 +#define A2XX_PA_SU_SC_MODE_CNTL_POLYMODE__MASK			0x00000018 +#define A2XX_PA_SU_SC_MODE_CNTL_POLYMODE__SHIFT			3 +static inline uint32_t A2XX_PA_SU_SC_MODE_CNTL_POLYMODE(enum a2xx_pa_su_sc_polymode val) +{ +	return ((val) << A2XX_PA_SU_SC_MODE_CNTL_POLYMODE__SHIFT) & A2XX_PA_SU_SC_MODE_CNTL_POLYMODE__MASK; +} +#define A2XX_PA_SU_SC_MODE_CNTL_FRONT_PTYPE__MASK		0x000000e0 +#define A2XX_PA_SU_SC_MODE_CNTL_FRONT_PTYPE__SHIFT		5 +static inline uint32_t A2XX_PA_SU_SC_MODE_CNTL_FRONT_PTYPE(enum adreno_pa_su_sc_draw val) +{ +	return ((val) << A2XX_PA_SU_SC_MODE_CNTL_FRONT_PTYPE__SHIFT) & A2XX_PA_SU_SC_MODE_CNTL_FRONT_PTYPE__MASK; +} +#define A2XX_PA_SU_SC_MODE_CNTL_BACK_PTYPE__MASK		0x00000700 +#define A2XX_PA_SU_SC_MODE_CNTL_BACK_PTYPE__SHIFT		8 +static inline uint32_t A2XX_PA_SU_SC_MODE_CNTL_BACK_PTYPE(enum adreno_pa_su_sc_draw val) +{ +	return ((val) << A2XX_PA_SU_SC_MODE_CNTL_BACK_PTYPE__SHIFT) & A2XX_PA_SU_SC_MODE_CNTL_BACK_PTYPE__MASK; +} +#define A2XX_PA_SU_SC_MODE_CNTL_POLY_OFFSET_FRONT_ENABLE	0x00000800 +#define A2XX_PA_SU_SC_MODE_CNTL_POLY_OFFSET_BACK_ENABLE		0x00001000 +#define A2XX_PA_SU_SC_MODE_CNTL_POLY_OFFSET_PARA_ENABLE		0x00002000 +#define A2XX_PA_SU_SC_MODE_CNTL_MSAA_ENABLE			0x00008000 +#define A2XX_PA_SU_SC_MODE_CNTL_VTX_WINDOW_OFFSET_ENABLE	0x00010000 +#define A2XX_PA_SU_SC_MODE_CNTL_LINE_STIPPLE_ENABLE		0x00040000 +#define A2XX_PA_SU_SC_MODE_CNTL_PROVOKING_VTX_LAST		0x00080000 +#define A2XX_PA_SU_SC_MODE_CNTL_PERSP_CORR_DIS			0x00100000 +#define A2XX_PA_SU_SC_MODE_CNTL_MULTI_PRIM_IB_ENA		0x00200000 +#define A2XX_PA_SU_SC_MODE_CNTL_QUAD_ORDER_ENABLE		0x00800000 +#define A2XX_PA_SU_SC_MODE_CNTL_WAIT_RB_IDLE_ALL_TRI		0x02000000 +#define A2XX_PA_SU_SC_MODE_CNTL_WAIT_RB_IDLE_FIRST_TRI_NEW_STATE	0x04000000 +#define A2XX_PA_SU_SC_MODE_CNTL_CLAMPED_FACENESS		0x10000000 +#define A2XX_PA_SU_SC_MODE_CNTL_ZERO_AREA_FACENESS		0x20000000 +#define A2XX_PA_SU_SC_MODE_CNTL_FACE_KILL_ENABLE		0x40000000 +#define A2XX_PA_SU_SC_MODE_CNTL_FACE_WRITE_ENABLE		0x80000000 + +#define REG_A2XX_PA_CL_VTE_CNTL					0x00002206 +#define A2XX_PA_CL_VTE_CNTL_VPORT_X_SCALE_ENA			0x00000001 +#define A2XX_PA_CL_VTE_CNTL_VPORT_X_OFFSET_ENA			0x00000002 +#define A2XX_PA_CL_VTE_CNTL_VPORT_Y_SCALE_ENA			0x00000004 +#define A2XX_PA_CL_VTE_CNTL_VPORT_Y_OFFSET_ENA			0x00000008 +#define A2XX_PA_CL_VTE_CNTL_VPORT_Z_SCALE_ENA			0x00000010 +#define A2XX_PA_CL_VTE_CNTL_VPORT_Z_OFFSET_ENA			0x00000020 +#define A2XX_PA_CL_VTE_CNTL_VTX_XY_FMT				0x00000100 +#define A2XX_PA_CL_VTE_CNTL_VTX_Z_FMT				0x00000200 +#define A2XX_PA_CL_VTE_CNTL_VTX_W0_FMT				0x00000400 +#define A2XX_PA_CL_VTE_CNTL_PERFCOUNTER_REF			0x00000800 + +#define REG_A2XX_VGT_CURRENT_BIN_ID_MIN				0x00002207 +#define A2XX_VGT_CURRENT_BIN_ID_MIN_COLUMN__MASK		0x00000007 +#define A2XX_VGT_CURRENT_BIN_ID_MIN_COLUMN__SHIFT		0 +static inline uint32_t A2XX_VGT_CURRENT_BIN_ID_MIN_COLUMN(uint32_t val) +{ +	return ((val) << A2XX_VGT_CURRENT_BIN_ID_MIN_COLUMN__SHIFT) & A2XX_VGT_CURRENT_BIN_ID_MIN_COLUMN__MASK; +} +#define A2XX_VGT_CURRENT_BIN_ID_MIN_ROW__MASK			0x00000038 +#define A2XX_VGT_CURRENT_BIN_ID_MIN_ROW__SHIFT			3 +static inline uint32_t A2XX_VGT_CURRENT_BIN_ID_MIN_ROW(uint32_t val) +{ +	return ((val) << A2XX_VGT_CURRENT_BIN_ID_MIN_ROW__SHIFT) & A2XX_VGT_CURRENT_BIN_ID_MIN_ROW__MASK; +} +#define A2XX_VGT_CURRENT_BIN_ID_MIN_GUARD_BAND_MASK__MASK	0x000001c0 +#define A2XX_VGT_CURRENT_BIN_ID_MIN_GUARD_BAND_MASK__SHIFT	6 +static inline uint32_t A2XX_VGT_CURRENT_BIN_ID_MIN_GUARD_BAND_MASK(uint32_t val) +{ +	return ((val) << A2XX_VGT_CURRENT_BIN_ID_MIN_GUARD_BAND_MASK__SHIFT) & A2XX_VGT_CURRENT_BIN_ID_MIN_GUARD_BAND_MASK__MASK; +} + +#define REG_A2XX_RB_MODECONTROL					0x00002208 +#define A2XX_RB_MODECONTROL_EDRAM_MODE__MASK			0x00000007 +#define A2XX_RB_MODECONTROL_EDRAM_MODE__SHIFT			0 +static inline uint32_t A2XX_RB_MODECONTROL_EDRAM_MODE(enum a2xx_rb_edram_mode val) +{ +	return ((val) << A2XX_RB_MODECONTROL_EDRAM_MODE__SHIFT) & A2XX_RB_MODECONTROL_EDRAM_MODE__MASK; +} + +#define REG_A2XX_A220_RB_LRZ_VSC_CONTROL			0x00002209 + +#define REG_A2XX_RB_SAMPLE_POS					0x0000220a + +#define REG_A2XX_CLEAR_COLOR					0x0000220b +#define A2XX_CLEAR_COLOR_RED__MASK				0x000000ff +#define A2XX_CLEAR_COLOR_RED__SHIFT				0 +static inline uint32_t A2XX_CLEAR_COLOR_RED(uint32_t val) +{ +	return ((val) << A2XX_CLEAR_COLOR_RED__SHIFT) & A2XX_CLEAR_COLOR_RED__MASK; +} +#define A2XX_CLEAR_COLOR_GREEN__MASK				0x0000ff00 +#define A2XX_CLEAR_COLOR_GREEN__SHIFT				8 +static inline uint32_t A2XX_CLEAR_COLOR_GREEN(uint32_t val) +{ +	return ((val) << A2XX_CLEAR_COLOR_GREEN__SHIFT) & A2XX_CLEAR_COLOR_GREEN__MASK; +} +#define A2XX_CLEAR_COLOR_BLUE__MASK				0x00ff0000 +#define A2XX_CLEAR_COLOR_BLUE__SHIFT				16 +static inline uint32_t A2XX_CLEAR_COLOR_BLUE(uint32_t val) +{ +	return ((val) << A2XX_CLEAR_COLOR_BLUE__SHIFT) & A2XX_CLEAR_COLOR_BLUE__MASK; +} +#define A2XX_CLEAR_COLOR_ALPHA__MASK				0xff000000 +#define A2XX_CLEAR_COLOR_ALPHA__SHIFT				24 +static inline uint32_t A2XX_CLEAR_COLOR_ALPHA(uint32_t val) +{ +	return ((val) << A2XX_CLEAR_COLOR_ALPHA__SHIFT) & A2XX_CLEAR_COLOR_ALPHA__MASK; +} + +#define REG_A2XX_A220_GRAS_CONTROL				0x00002210 + +#define REG_A2XX_PA_SU_POINT_SIZE				0x00002280 +#define A2XX_PA_SU_POINT_SIZE_HEIGHT__MASK			0x0000ffff +#define A2XX_PA_SU_POINT_SIZE_HEIGHT__SHIFT			0 +static inline uint32_t A2XX_PA_SU_POINT_SIZE_HEIGHT(float val) +{ +	return ((((uint32_t)(val * 8.0))) << A2XX_PA_SU_POINT_SIZE_HEIGHT__SHIFT) & A2XX_PA_SU_POINT_SIZE_HEIGHT__MASK; +} +#define A2XX_PA_SU_POINT_SIZE_WIDTH__MASK			0xffff0000 +#define A2XX_PA_SU_POINT_SIZE_WIDTH__SHIFT			16 +static inline uint32_t A2XX_PA_SU_POINT_SIZE_WIDTH(float val) +{ +	return ((((uint32_t)(val * 8.0))) << A2XX_PA_SU_POINT_SIZE_WIDTH__SHIFT) & A2XX_PA_SU_POINT_SIZE_WIDTH__MASK; +} + +#define REG_A2XX_PA_SU_POINT_MINMAX				0x00002281 +#define A2XX_PA_SU_POINT_MINMAX_MIN__MASK			0x0000ffff +#define A2XX_PA_SU_POINT_MINMAX_MIN__SHIFT			0 +static inline uint32_t A2XX_PA_SU_POINT_MINMAX_MIN(float val) +{ +	return ((((uint32_t)(val * 8.0))) << A2XX_PA_SU_POINT_MINMAX_MIN__SHIFT) & A2XX_PA_SU_POINT_MINMAX_MIN__MASK; +} +#define A2XX_PA_SU_POINT_MINMAX_MAX__MASK			0xffff0000 +#define A2XX_PA_SU_POINT_MINMAX_MAX__SHIFT			16 +static inline uint32_t A2XX_PA_SU_POINT_MINMAX_MAX(float val) +{ +	return ((((uint32_t)(val * 8.0))) << A2XX_PA_SU_POINT_MINMAX_MAX__SHIFT) & A2XX_PA_SU_POINT_MINMAX_MAX__MASK; +} + +#define REG_A2XX_PA_SU_LINE_CNTL				0x00002282 +#define A2XX_PA_SU_LINE_CNTL_WIDTH__MASK			0x0000ffff +#define A2XX_PA_SU_LINE_CNTL_WIDTH__SHIFT			0 +static inline uint32_t A2XX_PA_SU_LINE_CNTL_WIDTH(float val) +{ +	return ((((uint32_t)(val * 8.0))) << A2XX_PA_SU_LINE_CNTL_WIDTH__SHIFT) & A2XX_PA_SU_LINE_CNTL_WIDTH__MASK; +} + +#define REG_A2XX_PA_SC_LINE_STIPPLE				0x00002283 +#define A2XX_PA_SC_LINE_STIPPLE_LINE_PATTERN__MASK		0x0000ffff +#define A2XX_PA_SC_LINE_STIPPLE_LINE_PATTERN__SHIFT		0 +static inline uint32_t A2XX_PA_SC_LINE_STIPPLE_LINE_PATTERN(uint32_t val) +{ +	return ((val) << A2XX_PA_SC_LINE_STIPPLE_LINE_PATTERN__SHIFT) & A2XX_PA_SC_LINE_STIPPLE_LINE_PATTERN__MASK; +} +#define A2XX_PA_SC_LINE_STIPPLE_REPEAT_COUNT__MASK		0x00ff0000 +#define A2XX_PA_SC_LINE_STIPPLE_REPEAT_COUNT__SHIFT		16 +static inline uint32_t A2XX_PA_SC_LINE_STIPPLE_REPEAT_COUNT(uint32_t val) +{ +	return ((val) << A2XX_PA_SC_LINE_STIPPLE_REPEAT_COUNT__SHIFT) & A2XX_PA_SC_LINE_STIPPLE_REPEAT_COUNT__MASK; +} +#define A2XX_PA_SC_LINE_STIPPLE_PATTERN_BIT_ORDER__MASK		0x10000000 +#define A2XX_PA_SC_LINE_STIPPLE_PATTERN_BIT_ORDER__SHIFT	28 +static inline uint32_t A2XX_PA_SC_LINE_STIPPLE_PATTERN_BIT_ORDER(enum a2xx_pa_sc_pattern_bit_order val) +{ +	return ((val) << A2XX_PA_SC_LINE_STIPPLE_PATTERN_BIT_ORDER__SHIFT) & A2XX_PA_SC_LINE_STIPPLE_PATTERN_BIT_ORDER__MASK; +} +#define A2XX_PA_SC_LINE_STIPPLE_AUTO_RESET_CNTL__MASK		0x60000000 +#define A2XX_PA_SC_LINE_STIPPLE_AUTO_RESET_CNTL__SHIFT		29 +static inline uint32_t A2XX_PA_SC_LINE_STIPPLE_AUTO_RESET_CNTL(enum a2xx_pa_sc_auto_reset_cntl val) +{ +	return ((val) << A2XX_PA_SC_LINE_STIPPLE_AUTO_RESET_CNTL__SHIFT) & A2XX_PA_SC_LINE_STIPPLE_AUTO_RESET_CNTL__MASK; +} + +#define REG_A2XX_PA_SC_VIZ_QUERY				0x00002293 + +#define REG_A2XX_VGT_ENHANCE					0x00002294 + +#define REG_A2XX_PA_SC_LINE_CNTL				0x00002300 +#define A2XX_PA_SC_LINE_CNTL_BRES_CNTL__MASK			0x0000ffff +#define A2XX_PA_SC_LINE_CNTL_BRES_CNTL__SHIFT			0 +static inline uint32_t A2XX_PA_SC_LINE_CNTL_BRES_CNTL(uint32_t val) +{ +	return ((val) << A2XX_PA_SC_LINE_CNTL_BRES_CNTL__SHIFT) & A2XX_PA_SC_LINE_CNTL_BRES_CNTL__MASK; +} +#define A2XX_PA_SC_LINE_CNTL_USE_BRES_CNTL			0x00000100 +#define A2XX_PA_SC_LINE_CNTL_EXPAND_LINE_WIDTH			0x00000200 +#define A2XX_PA_SC_LINE_CNTL_LAST_PIXEL				0x00000400 + +#define REG_A2XX_PA_SC_AA_CONFIG				0x00002301 + +#define REG_A2XX_PA_SU_VTX_CNTL					0x00002302 +#define A2XX_PA_SU_VTX_CNTL_PIX_CENTER__MASK			0x00000001 +#define A2XX_PA_SU_VTX_CNTL_PIX_CENTER__SHIFT			0 +static inline uint32_t A2XX_PA_SU_VTX_CNTL_PIX_CENTER(enum a2xx_pa_pixcenter val) +{ +	return ((val) << A2XX_PA_SU_VTX_CNTL_PIX_CENTER__SHIFT) & A2XX_PA_SU_VTX_CNTL_PIX_CENTER__MASK; +} +#define A2XX_PA_SU_VTX_CNTL_ROUND_MODE__MASK			0x00000006 +#define A2XX_PA_SU_VTX_CNTL_ROUND_MODE__SHIFT			1 +static inline uint32_t A2XX_PA_SU_VTX_CNTL_ROUND_MODE(enum a2xx_pa_roundmode val) +{ +	return ((val) << A2XX_PA_SU_VTX_CNTL_ROUND_MODE__SHIFT) & A2XX_PA_SU_VTX_CNTL_ROUND_MODE__MASK; +} +#define A2XX_PA_SU_VTX_CNTL_QUANT_MODE__MASK			0x00000380 +#define A2XX_PA_SU_VTX_CNTL_QUANT_MODE__SHIFT			7 +static inline uint32_t A2XX_PA_SU_VTX_CNTL_QUANT_MODE(enum a2xx_pa_quantmode val) +{ +	return ((val) << A2XX_PA_SU_VTX_CNTL_QUANT_MODE__SHIFT) & A2XX_PA_SU_VTX_CNTL_QUANT_MODE__MASK; +} + +#define REG_A2XX_PA_CL_GB_VERT_CLIP_ADJ				0x00002303 +#define A2XX_PA_CL_GB_VERT_CLIP_ADJ__MASK			0xffffffff +#define A2XX_PA_CL_GB_VERT_CLIP_ADJ__SHIFT			0 +static inline uint32_t A2XX_PA_CL_GB_VERT_CLIP_ADJ(float val) +{ +	return ((fui(val)) << A2XX_PA_CL_GB_VERT_CLIP_ADJ__SHIFT) & A2XX_PA_CL_GB_VERT_CLIP_ADJ__MASK; +} + +#define REG_A2XX_PA_CL_GB_VERT_DISC_ADJ				0x00002304 +#define A2XX_PA_CL_GB_VERT_DISC_ADJ__MASK			0xffffffff +#define A2XX_PA_CL_GB_VERT_DISC_ADJ__SHIFT			0 +static inline uint32_t A2XX_PA_CL_GB_VERT_DISC_ADJ(float val) +{ +	return ((fui(val)) << A2XX_PA_CL_GB_VERT_DISC_ADJ__SHIFT) & A2XX_PA_CL_GB_VERT_DISC_ADJ__MASK; +} + +#define REG_A2XX_PA_CL_GB_HORZ_CLIP_ADJ				0x00002305 +#define A2XX_PA_CL_GB_HORZ_CLIP_ADJ__MASK			0xffffffff +#define A2XX_PA_CL_GB_HORZ_CLIP_ADJ__SHIFT			0 +static inline uint32_t A2XX_PA_CL_GB_HORZ_CLIP_ADJ(float val) +{ +	return ((fui(val)) << A2XX_PA_CL_GB_HORZ_CLIP_ADJ__SHIFT) & A2XX_PA_CL_GB_HORZ_CLIP_ADJ__MASK; +} + +#define REG_A2XX_PA_CL_GB_HORZ_DISC_ADJ				0x00002306 +#define A2XX_PA_CL_GB_HORZ_DISC_ADJ__MASK			0xffffffff +#define A2XX_PA_CL_GB_HORZ_DISC_ADJ__SHIFT			0 +static inline uint32_t A2XX_PA_CL_GB_HORZ_DISC_ADJ(float val) +{ +	return ((fui(val)) << A2XX_PA_CL_GB_HORZ_DISC_ADJ__SHIFT) & A2XX_PA_CL_GB_HORZ_DISC_ADJ__MASK; +} + +#define REG_A2XX_SQ_VS_CONST					0x00002307 +#define A2XX_SQ_VS_CONST_BASE__MASK				0x000001ff +#define A2XX_SQ_VS_CONST_BASE__SHIFT				0 +static inline uint32_t A2XX_SQ_VS_CONST_BASE(uint32_t val) +{ +	return ((val) << A2XX_SQ_VS_CONST_BASE__SHIFT) & A2XX_SQ_VS_CONST_BASE__MASK; +} +#define A2XX_SQ_VS_CONST_SIZE__MASK				0x001ff000 +#define A2XX_SQ_VS_CONST_SIZE__SHIFT				12 +static inline uint32_t A2XX_SQ_VS_CONST_SIZE(uint32_t val) +{ +	return ((val) << A2XX_SQ_VS_CONST_SIZE__SHIFT) & A2XX_SQ_VS_CONST_SIZE__MASK; +} + +#define REG_A2XX_SQ_PS_CONST					0x00002308 +#define A2XX_SQ_PS_CONST_BASE__MASK				0x000001ff +#define A2XX_SQ_PS_CONST_BASE__SHIFT				0 +static inline uint32_t A2XX_SQ_PS_CONST_BASE(uint32_t val) +{ +	return ((val) << A2XX_SQ_PS_CONST_BASE__SHIFT) & A2XX_SQ_PS_CONST_BASE__MASK; +} +#define A2XX_SQ_PS_CONST_SIZE__MASK				0x001ff000 +#define A2XX_SQ_PS_CONST_SIZE__SHIFT				12 +static inline uint32_t A2XX_SQ_PS_CONST_SIZE(uint32_t val) +{ +	return ((val) << A2XX_SQ_PS_CONST_SIZE__SHIFT) & A2XX_SQ_PS_CONST_SIZE__MASK; +} + +#define REG_A2XX_SQ_DEBUG_MISC_0				0x00002309 + +#define REG_A2XX_SQ_DEBUG_MISC_1				0x0000230a + +#define REG_A2XX_PA_SC_AA_MASK					0x00002312 + +#define REG_A2XX_VGT_VERTEX_REUSE_BLOCK_CNTL			0x00002316 + +#define REG_A2XX_VGT_OUT_DEALLOC_CNTL				0x00002317 + +#define REG_A2XX_RB_COPY_CONTROL				0x00002318 +#define A2XX_RB_COPY_CONTROL_COPY_SAMPLE_SELECT__MASK		0x00000007 +#define A2XX_RB_COPY_CONTROL_COPY_SAMPLE_SELECT__SHIFT		0 +static inline uint32_t A2XX_RB_COPY_CONTROL_COPY_SAMPLE_SELECT(enum a2xx_rb_copy_sample_select val) +{ +	return ((val) << A2XX_RB_COPY_CONTROL_COPY_SAMPLE_SELECT__SHIFT) & A2XX_RB_COPY_CONTROL_COPY_SAMPLE_SELECT__MASK; +} +#define A2XX_RB_COPY_CONTROL_DEPTH_CLEAR_ENABLE			0x00000008 +#define A2XX_RB_COPY_CONTROL_CLEAR_MASK__MASK			0x000000f0 +#define A2XX_RB_COPY_CONTROL_CLEAR_MASK__SHIFT			4 +static inline uint32_t A2XX_RB_COPY_CONTROL_CLEAR_MASK(uint32_t val) +{ +	return ((val) << A2XX_RB_COPY_CONTROL_CLEAR_MASK__SHIFT) & A2XX_RB_COPY_CONTROL_CLEAR_MASK__MASK; +} + +#define REG_A2XX_RB_COPY_DEST_BASE				0x00002319 + +#define REG_A2XX_RB_COPY_DEST_PITCH				0x0000231a +#define A2XX_RB_COPY_DEST_PITCH__MASK				0xffffffff +#define A2XX_RB_COPY_DEST_PITCH__SHIFT				0 +static inline uint32_t A2XX_RB_COPY_DEST_PITCH(uint32_t val) +{ +	return ((val >> 5) << A2XX_RB_COPY_DEST_PITCH__SHIFT) & A2XX_RB_COPY_DEST_PITCH__MASK; +} + +#define REG_A2XX_RB_COPY_DEST_INFO				0x0000231b +#define A2XX_RB_COPY_DEST_INFO_DEST_ENDIAN__MASK		0x00000007 +#define A2XX_RB_COPY_DEST_INFO_DEST_ENDIAN__SHIFT		0 +static inline uint32_t A2XX_RB_COPY_DEST_INFO_DEST_ENDIAN(enum adreno_rb_surface_endian val) +{ +	return ((val) << A2XX_RB_COPY_DEST_INFO_DEST_ENDIAN__SHIFT) & A2XX_RB_COPY_DEST_INFO_DEST_ENDIAN__MASK; +} +#define A2XX_RB_COPY_DEST_INFO_LINEAR				0x00000008 +#define A2XX_RB_COPY_DEST_INFO_FORMAT__MASK			0x000000f0 +#define A2XX_RB_COPY_DEST_INFO_FORMAT__SHIFT			4 +static inline uint32_t A2XX_RB_COPY_DEST_INFO_FORMAT(enum a2xx_colorformatx val) +{ +	return ((val) << A2XX_RB_COPY_DEST_INFO_FORMAT__SHIFT) & A2XX_RB_COPY_DEST_INFO_FORMAT__MASK; +} +#define A2XX_RB_COPY_DEST_INFO_SWAP__MASK			0x00000300 +#define A2XX_RB_COPY_DEST_INFO_SWAP__SHIFT			8 +static inline uint32_t A2XX_RB_COPY_DEST_INFO_SWAP(uint32_t val) +{ +	return ((val) << A2XX_RB_COPY_DEST_INFO_SWAP__SHIFT) & A2XX_RB_COPY_DEST_INFO_SWAP__MASK; +} +#define A2XX_RB_COPY_DEST_INFO_DITHER_MODE__MASK		0x00000c00 +#define A2XX_RB_COPY_DEST_INFO_DITHER_MODE__SHIFT		10 +static inline uint32_t A2XX_RB_COPY_DEST_INFO_DITHER_MODE(enum adreno_rb_dither_mode val) +{ +	return ((val) << A2XX_RB_COPY_DEST_INFO_DITHER_MODE__SHIFT) & A2XX_RB_COPY_DEST_INFO_DITHER_MODE__MASK; +} +#define A2XX_RB_COPY_DEST_INFO_DITHER_TYPE__MASK		0x00003000 +#define A2XX_RB_COPY_DEST_INFO_DITHER_TYPE__SHIFT		12 +static inline uint32_t A2XX_RB_COPY_DEST_INFO_DITHER_TYPE(enum a2xx_rb_dither_type val) +{ +	return ((val) << A2XX_RB_COPY_DEST_INFO_DITHER_TYPE__SHIFT) & A2XX_RB_COPY_DEST_INFO_DITHER_TYPE__MASK; +} +#define A2XX_RB_COPY_DEST_INFO_WRITE_RED			0x00004000 +#define A2XX_RB_COPY_DEST_INFO_WRITE_GREEN			0x00008000 +#define A2XX_RB_COPY_DEST_INFO_WRITE_BLUE			0x00010000 +#define A2XX_RB_COPY_DEST_INFO_WRITE_ALPHA			0x00020000 + +#define REG_A2XX_RB_COPY_DEST_OFFSET				0x0000231c +#define A2XX_RB_COPY_DEST_OFFSET_X__MASK			0x00001fff +#define A2XX_RB_COPY_DEST_OFFSET_X__SHIFT			0 +static inline uint32_t A2XX_RB_COPY_DEST_OFFSET_X(uint32_t val) +{ +	return ((val) << A2XX_RB_COPY_DEST_OFFSET_X__SHIFT) & A2XX_RB_COPY_DEST_OFFSET_X__MASK; +} +#define A2XX_RB_COPY_DEST_OFFSET_Y__MASK			0x03ffe000 +#define A2XX_RB_COPY_DEST_OFFSET_Y__SHIFT			13 +static inline uint32_t A2XX_RB_COPY_DEST_OFFSET_Y(uint32_t val) +{ +	return ((val) << A2XX_RB_COPY_DEST_OFFSET_Y__SHIFT) & A2XX_RB_COPY_DEST_OFFSET_Y__MASK; +} + +#define REG_A2XX_RB_DEPTH_CLEAR					0x0000231d + +#define REG_A2XX_RB_SAMPLE_COUNT_CTL				0x00002324 + +#define REG_A2XX_RB_COLOR_DEST_MASK				0x00002326 + +#define REG_A2XX_A225_GRAS_UCP0X				0x00002340 + +#define REG_A2XX_A225_GRAS_UCP5W				0x00002357 + +#define REG_A2XX_A225_GRAS_UCP_ENABLED				0x00002360 + +#define REG_A2XX_PA_SU_POLY_OFFSET_FRONT_SCALE			0x00002380 + +#define REG_A2XX_PA_SU_POLY_OFFSET_BACK_OFFSET			0x00002383 + +#define REG_A2XX_SQ_CONSTANT_0					0x00004000 + +#define REG_A2XX_SQ_FETCH_0					0x00004800 + +#define REG_A2XX_SQ_CF_BOOLEANS					0x00004900 + +#define REG_A2XX_SQ_CF_LOOP					0x00004908 + +#define REG_A2XX_COHER_SIZE_PM4					0x00000a29 + +#define REG_A2XX_COHER_BASE_PM4					0x00000a2a + +#define REG_A2XX_COHER_STATUS_PM4				0x00000a2b + +#define REG_A2XX_SQ_TEX_0					0x00000000 +#define A2XX_SQ_TEX_0_CLAMP_X__MASK				0x00001c00 +#define A2XX_SQ_TEX_0_CLAMP_X__SHIFT				10 +static inline uint32_t A2XX_SQ_TEX_0_CLAMP_X(enum sq_tex_clamp val) +{ +	return ((val) << A2XX_SQ_TEX_0_CLAMP_X__SHIFT) & A2XX_SQ_TEX_0_CLAMP_X__MASK; +} +#define A2XX_SQ_TEX_0_CLAMP_Y__MASK				0x0000e000 +#define A2XX_SQ_TEX_0_CLAMP_Y__SHIFT				13 +static inline uint32_t A2XX_SQ_TEX_0_CLAMP_Y(enum sq_tex_clamp val) +{ +	return ((val) << A2XX_SQ_TEX_0_CLAMP_Y__SHIFT) & A2XX_SQ_TEX_0_CLAMP_Y__MASK; +} +#define A2XX_SQ_TEX_0_CLAMP_Z__MASK				0x00070000 +#define A2XX_SQ_TEX_0_CLAMP_Z__SHIFT				16 +static inline uint32_t A2XX_SQ_TEX_0_CLAMP_Z(enum sq_tex_clamp val) +{ +	return ((val) << A2XX_SQ_TEX_0_CLAMP_Z__SHIFT) & A2XX_SQ_TEX_0_CLAMP_Z__MASK; +} +#define A2XX_SQ_TEX_0_PITCH__MASK				0xffc00000 +#define A2XX_SQ_TEX_0_PITCH__SHIFT				22 +static inline uint32_t A2XX_SQ_TEX_0_PITCH(uint32_t val) +{ +	return ((val >> 5) << A2XX_SQ_TEX_0_PITCH__SHIFT) & A2XX_SQ_TEX_0_PITCH__MASK; +} + +#define REG_A2XX_SQ_TEX_1					0x00000001 + +#define REG_A2XX_SQ_TEX_2					0x00000002 +#define A2XX_SQ_TEX_2_WIDTH__MASK				0x00001fff +#define A2XX_SQ_TEX_2_WIDTH__SHIFT				0 +static inline uint32_t A2XX_SQ_TEX_2_WIDTH(uint32_t val) +{ +	return ((val) << A2XX_SQ_TEX_2_WIDTH__SHIFT) & A2XX_SQ_TEX_2_WIDTH__MASK; +} +#define A2XX_SQ_TEX_2_HEIGHT__MASK				0x03ffe000 +#define A2XX_SQ_TEX_2_HEIGHT__SHIFT				13 +static inline uint32_t A2XX_SQ_TEX_2_HEIGHT(uint32_t val) +{ +	return ((val) << A2XX_SQ_TEX_2_HEIGHT__SHIFT) & A2XX_SQ_TEX_2_HEIGHT__MASK; +} + +#define REG_A2XX_SQ_TEX_3					0x00000003 +#define A2XX_SQ_TEX_3_SWIZ_X__MASK				0x0000000e +#define A2XX_SQ_TEX_3_SWIZ_X__SHIFT				1 +static inline uint32_t A2XX_SQ_TEX_3_SWIZ_X(enum sq_tex_swiz val) +{ +	return ((val) << A2XX_SQ_TEX_3_SWIZ_X__SHIFT) & A2XX_SQ_TEX_3_SWIZ_X__MASK; +} +#define A2XX_SQ_TEX_3_SWIZ_Y__MASK				0x00000070 +#define A2XX_SQ_TEX_3_SWIZ_Y__SHIFT				4 +static inline uint32_t A2XX_SQ_TEX_3_SWIZ_Y(enum sq_tex_swiz val) +{ +	return ((val) << A2XX_SQ_TEX_3_SWIZ_Y__SHIFT) & A2XX_SQ_TEX_3_SWIZ_Y__MASK; +} +#define A2XX_SQ_TEX_3_SWIZ_Z__MASK				0x00000380 +#define A2XX_SQ_TEX_3_SWIZ_Z__SHIFT				7 +static inline uint32_t A2XX_SQ_TEX_3_SWIZ_Z(enum sq_tex_swiz val) +{ +	return ((val) << A2XX_SQ_TEX_3_SWIZ_Z__SHIFT) & A2XX_SQ_TEX_3_SWIZ_Z__MASK; +} +#define A2XX_SQ_TEX_3_SWIZ_W__MASK				0x00001c00 +#define A2XX_SQ_TEX_3_SWIZ_W__SHIFT				10 +static inline uint32_t A2XX_SQ_TEX_3_SWIZ_W(enum sq_tex_swiz val) +{ +	return ((val) << A2XX_SQ_TEX_3_SWIZ_W__SHIFT) & A2XX_SQ_TEX_3_SWIZ_W__MASK; +} +#define A2XX_SQ_TEX_3_XY_MAG_FILTER__MASK			0x00180000 +#define A2XX_SQ_TEX_3_XY_MAG_FILTER__SHIFT			19 +static inline uint32_t A2XX_SQ_TEX_3_XY_MAG_FILTER(enum sq_tex_filter val) +{ +	return ((val) << A2XX_SQ_TEX_3_XY_MAG_FILTER__SHIFT) & A2XX_SQ_TEX_3_XY_MAG_FILTER__MASK; +} +#define A2XX_SQ_TEX_3_XY_MIN_FILTER__MASK			0x00600000 +#define A2XX_SQ_TEX_3_XY_MIN_FILTER__SHIFT			21 +static inline uint32_t A2XX_SQ_TEX_3_XY_MIN_FILTER(enum sq_tex_filter val) +{ +	return ((val) << A2XX_SQ_TEX_3_XY_MIN_FILTER__SHIFT) & A2XX_SQ_TEX_3_XY_MIN_FILTER__MASK; +} + + +#endif /* A2XX_XML */ diff --git a/drivers/gpu/drm/msm/adreno/a3xx.xml.h b/drivers/gpu/drm/msm/adreno/a3xx.xml.h new file mode 100644 index 00000000000..a7be56163d2 --- /dev/null +++ b/drivers/gpu/drm/msm/adreno/a3xx.xml.h @@ -0,0 +1,2259 @@ +#ifndef A3XX_XML +#define A3XX_XML + +/* Autogenerated file, DO NOT EDIT manually! + +This file was generated by the rules-ng-ng headergen tool in this git repository: +http://github.com/freedreno/envytools/ +git clone https://github.com/freedreno/envytools.git + +The rules-ng-ng source files this header was generated from are: +- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2013-11-30 14:47:15) +- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32814 bytes, from 2013-11-30 15:07:33) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (   8900 bytes, from 2013-10-22 23:57:49) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  10574 bytes, from 2013-11-13 05:44:45) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  53644 bytes, from 2013-11-30 15:07:33) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (   8344 bytes, from 2013-11-30 14:49:47) + +Copyright (C) 2013 by the following authors: +- Rob Clark <robdclark@gmail.com> (robclark) + +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 THE COPYRIGHT OWNER(S) 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. +*/ + + +enum a3xx_render_mode { +	RB_RENDERING_PASS = 0, +	RB_TILING_PASS = 1, +	RB_RESOLVE_PASS = 2, +}; + +enum a3xx_tile_mode { +	LINEAR = 0, +	TILE_32X32 = 2, +}; + +enum a3xx_threadmode { +	MULTI = 0, +	SINGLE = 1, +}; + +enum a3xx_instrbuffermode { +	BUFFER = 1, +}; + +enum a3xx_threadsize { +	TWO_QUADS = 0, +	FOUR_QUADS = 1, +}; + +enum a3xx_state_block_id { +	HLSQ_BLOCK_ID_TP_TEX = 2, +	HLSQ_BLOCK_ID_TP_MIPMAP = 3, +	HLSQ_BLOCK_ID_SP_VS = 4, +	HLSQ_BLOCK_ID_SP_FS = 6, +}; + +enum a3xx_cache_opcode { +	INVALIDATE = 1, +}; + +enum a3xx_vtx_fmt { +	VFMT_FLOAT_32 = 0, +	VFMT_FLOAT_32_32 = 1, +	VFMT_FLOAT_32_32_32 = 2, +	VFMT_FLOAT_32_32_32_32 = 3, +	VFMT_FLOAT_16 = 4, +	VFMT_FLOAT_16_16 = 5, +	VFMT_FLOAT_16_16_16 = 6, +	VFMT_FLOAT_16_16_16_16 = 7, +	VFMT_FIXED_32 = 8, +	VFMT_FIXED_32_32 = 9, +	VFMT_FIXED_32_32_32 = 10, +	VFMT_FIXED_32_32_32_32 = 11, +	VFMT_SHORT_16 = 16, +	VFMT_SHORT_16_16 = 17, +	VFMT_SHORT_16_16_16 = 18, +	VFMT_SHORT_16_16_16_16 = 19, +	VFMT_USHORT_16 = 20, +	VFMT_USHORT_16_16 = 21, +	VFMT_USHORT_16_16_16 = 22, +	VFMT_USHORT_16_16_16_16 = 23, +	VFMT_NORM_SHORT_16 = 24, +	VFMT_NORM_SHORT_16_16 = 25, +	VFMT_NORM_SHORT_16_16_16 = 26, +	VFMT_NORM_SHORT_16_16_16_16 = 27, +	VFMT_NORM_USHORT_16 = 28, +	VFMT_NORM_USHORT_16_16 = 29, +	VFMT_NORM_USHORT_16_16_16 = 30, +	VFMT_NORM_USHORT_16_16_16_16 = 31, +	VFMT_UBYTE_8 = 40, +	VFMT_UBYTE_8_8 = 41, +	VFMT_UBYTE_8_8_8 = 42, +	VFMT_UBYTE_8_8_8_8 = 43, +	VFMT_NORM_UBYTE_8 = 44, +	VFMT_NORM_UBYTE_8_8 = 45, +	VFMT_NORM_UBYTE_8_8_8 = 46, +	VFMT_NORM_UBYTE_8_8_8_8 = 47, +	VFMT_BYTE_8 = 48, +	VFMT_BYTE_8_8 = 49, +	VFMT_BYTE_8_8_8 = 50, +	VFMT_BYTE_8_8_8_8 = 51, +	VFMT_NORM_BYTE_8 = 52, +	VFMT_NORM_BYTE_8_8 = 53, +	VFMT_NORM_BYTE_8_8_8 = 54, +	VFMT_NORM_BYTE_8_8_8_8 = 55, +	VFMT_UINT_10_10_10_2 = 60, +	VFMT_NORM_UINT_10_10_10_2 = 61, +	VFMT_INT_10_10_10_2 = 62, +	VFMT_NORM_INT_10_10_10_2 = 63, +}; + +enum a3xx_tex_fmt { +	TFMT_NORM_USHORT_565 = 4, +	TFMT_NORM_USHORT_5551 = 6, +	TFMT_NORM_USHORT_4444 = 7, +	TFMT_NORM_UINT_X8Z24 = 10, +	TFMT_NORM_UINT_NV12_UV_TILED = 17, +	TFMT_NORM_UINT_NV12_Y_TILED = 19, +	TFMT_NORM_UINT_NV12_UV = 21, +	TFMT_NORM_UINT_NV12_Y = 23, +	TFMT_NORM_UINT_I420_Y = 24, +	TFMT_NORM_UINT_I420_U = 26, +	TFMT_NORM_UINT_I420_V = 27, +	TFMT_NORM_UINT_2_10_10_10 = 41, +	TFMT_NORM_UINT_A8 = 44, +	TFMT_NORM_UINT_L8_A8 = 47, +	TFMT_NORM_UINT_8 = 48, +	TFMT_NORM_UINT_8_8 = 49, +	TFMT_NORM_UINT_8_8_8 = 50, +	TFMT_NORM_UINT_8_8_8_8 = 51, +	TFMT_FLOAT_16 = 64, +	TFMT_FLOAT_16_16 = 65, +	TFMT_FLOAT_16_16_16_16 = 67, +	TFMT_FLOAT_32 = 84, +	TFMT_FLOAT_32_32 = 85, +	TFMT_FLOAT_32_32_32_32 = 87, +}; + +enum a3xx_tex_fetchsize { +	TFETCH_DISABLE = 0, +	TFETCH_1_BYTE = 1, +	TFETCH_2_BYTE = 2, +	TFETCH_4_BYTE = 3, +	TFETCH_8_BYTE = 4, +	TFETCH_16_BYTE = 5, +}; + +enum a3xx_color_fmt { +	RB_R8G8B8_UNORM = 4, +	RB_R8G8B8A8_UNORM = 8, +	RB_Z16_UNORM = 12, +	RB_A8_UNORM = 20, +}; + +enum a3xx_color_swap { +	WZYX = 0, +	WXYZ = 1, +	ZYXW = 2, +	XYZW = 3, +}; + +enum a3xx_msaa_samples { +	MSAA_ONE = 0, +	MSAA_TWO = 1, +	MSAA_FOUR = 2, +}; + +enum a3xx_sp_perfcounter_select { +	SP_FS_CFLOW_INSTRUCTIONS = 12, +	SP_FS_FULL_ALU_INSTRUCTIONS = 14, +	SP0_ICL1_MISSES = 26, +	SP_ALU_ACTIVE_CYCLES = 29, +}; + +enum adreno_rb_copy_control_mode { +	RB_COPY_RESOLVE = 1, +	RB_COPY_DEPTH_STENCIL = 5, +}; + +enum a3xx_tex_filter { +	A3XX_TEX_NEAREST = 0, +	A3XX_TEX_LINEAR = 1, +}; + +enum a3xx_tex_clamp { +	A3XX_TEX_REPEAT = 0, +	A3XX_TEX_CLAMP_TO_EDGE = 1, +	A3XX_TEX_MIRROR_REPEAT = 2, +	A3XX_TEX_CLAMP_NONE = 3, +}; + +enum a3xx_tex_swiz { +	A3XX_TEX_X = 0, +	A3XX_TEX_Y = 1, +	A3XX_TEX_Z = 2, +	A3XX_TEX_W = 3, +	A3XX_TEX_ZERO = 4, +	A3XX_TEX_ONE = 5, +}; + +enum a3xx_tex_type { +	A3XX_TEX_1D = 0, +	A3XX_TEX_2D = 1, +	A3XX_TEX_CUBE = 2, +	A3XX_TEX_3D = 3, +}; + +#define A3XX_INT0_RBBM_GPU_IDLE					0x00000001 +#define A3XX_INT0_RBBM_AHB_ERROR				0x00000002 +#define A3XX_INT0_RBBM_REG_TIMEOUT				0x00000004 +#define A3XX_INT0_RBBM_ME_MS_TIMEOUT				0x00000008 +#define A3XX_INT0_RBBM_PFP_MS_TIMEOUT				0x00000010 +#define A3XX_INT0_RBBM_ATB_BUS_OVERFLOW				0x00000020 +#define A3XX_INT0_VFD_ERROR					0x00000040 +#define A3XX_INT0_CP_SW_INT					0x00000080 +#define A3XX_INT0_CP_T0_PACKET_IN_IB				0x00000100 +#define A3XX_INT0_CP_OPCODE_ERROR				0x00000200 +#define A3XX_INT0_CP_RESERVED_BIT_ERROR				0x00000400 +#define A3XX_INT0_CP_HW_FAULT					0x00000800 +#define A3XX_INT0_CP_DMA					0x00001000 +#define A3XX_INT0_CP_IB2_INT					0x00002000 +#define A3XX_INT0_CP_IB1_INT					0x00004000 +#define A3XX_INT0_CP_RB_INT					0x00008000 +#define A3XX_INT0_CP_REG_PROTECT_FAULT				0x00010000 +#define A3XX_INT0_CP_RB_DONE_TS					0x00020000 +#define A3XX_INT0_CP_VS_DONE_TS					0x00040000 +#define A3XX_INT0_CP_PS_DONE_TS					0x00080000 +#define A3XX_INT0_CACHE_FLUSH_TS				0x00100000 +#define A3XX_INT0_CP_AHB_ERROR_HALT				0x00200000 +#define A3XX_INT0_MISC_HANG_DETECT				0x01000000 +#define A3XX_INT0_UCHE_OOB_ACCESS				0x02000000 +#define REG_A3XX_RBBM_HW_VERSION				0x00000000 + +#define REG_A3XX_RBBM_HW_RELEASE				0x00000001 + +#define REG_A3XX_RBBM_HW_CONFIGURATION				0x00000002 + +#define REG_A3XX_RBBM_CLOCK_CTL					0x00000010 + +#define REG_A3XX_RBBM_SP_HYST_CNT				0x00000012 + +#define REG_A3XX_RBBM_SW_RESET_CMD				0x00000018 + +#define REG_A3XX_RBBM_AHB_CTL0					0x00000020 + +#define REG_A3XX_RBBM_AHB_CTL1					0x00000021 + +#define REG_A3XX_RBBM_AHB_CMD					0x00000022 + +#define REG_A3XX_RBBM_AHB_ERROR_STATUS				0x00000027 + +#define REG_A3XX_RBBM_GPR0_CTL					0x0000002e + +#define REG_A3XX_RBBM_STATUS					0x00000030 +#define A3XX_RBBM_STATUS_HI_BUSY				0x00000001 +#define A3XX_RBBM_STATUS_CP_ME_BUSY				0x00000002 +#define A3XX_RBBM_STATUS_CP_PFP_BUSY				0x00000004 +#define A3XX_RBBM_STATUS_CP_NRT_BUSY				0x00004000 +#define A3XX_RBBM_STATUS_VBIF_BUSY				0x00008000 +#define A3XX_RBBM_STATUS_TSE_BUSY				0x00010000 +#define A3XX_RBBM_STATUS_RAS_BUSY				0x00020000 +#define A3XX_RBBM_STATUS_RB_BUSY				0x00040000 +#define A3XX_RBBM_STATUS_PC_DCALL_BUSY				0x00080000 +#define A3XX_RBBM_STATUS_PC_VSD_BUSY				0x00100000 +#define A3XX_RBBM_STATUS_VFD_BUSY				0x00200000 +#define A3XX_RBBM_STATUS_VPC_BUSY				0x00400000 +#define A3XX_RBBM_STATUS_UCHE_BUSY				0x00800000 +#define A3XX_RBBM_STATUS_SP_BUSY				0x01000000 +#define A3XX_RBBM_STATUS_TPL1_BUSY				0x02000000 +#define A3XX_RBBM_STATUS_MARB_BUSY				0x04000000 +#define A3XX_RBBM_STATUS_VSC_BUSY				0x08000000 +#define A3XX_RBBM_STATUS_ARB_BUSY				0x10000000 +#define A3XX_RBBM_STATUS_HLSQ_BUSY				0x20000000 +#define A3XX_RBBM_STATUS_GPU_BUSY_NOHC				0x40000000 +#define A3XX_RBBM_STATUS_GPU_BUSY				0x80000000 + +#define REG_A3XX_RBBM_NQWAIT_UNTIL				0x00000040 + +#define REG_A3XX_RBBM_WAIT_IDLE_CLOCKS_CTL			0x00000033 + +#define REG_A3XX_RBBM_INTERFACE_HANG_INT_CTL			0x00000050 + +#define REG_A3XX_RBBM_INTERFACE_HANG_MASK_CTL0			0x00000051 + +#define REG_A3XX_RBBM_INTERFACE_HANG_MASK_CTL1			0x00000054 + +#define REG_A3XX_RBBM_INTERFACE_HANG_MASK_CTL2			0x00000057 + +#define REG_A3XX_RBBM_INTERFACE_HANG_MASK_CTL3			0x0000005a + +#define REG_A3XX_RBBM_INT_SET_CMD				0x00000060 + +#define REG_A3XX_RBBM_INT_CLEAR_CMD				0x00000061 + +#define REG_A3XX_RBBM_INT_0_MASK				0x00000063 + +#define REG_A3XX_RBBM_INT_0_STATUS				0x00000064 + +#define REG_A3XX_RBBM_PERFCTR_CTL				0x00000080 + +#define REG_A3XX_RBBM_PERFCTR_LOAD_CMD0				0x00000081 + +#define REG_A3XX_RBBM_PERFCTR_LOAD_CMD1				0x00000082 + +#define REG_A3XX_RBBM_PERFCTR_LOAD_VALUE_LO			0x00000084 + +#define REG_A3XX_RBBM_PERFCTR_LOAD_VALUE_HI			0x00000085 + +#define REG_A3XX_RBBM_PERFCOUNTER0_SELECT			0x00000086 + +#define REG_A3XX_RBBM_PERFCOUNTER1_SELECT			0x00000087 + +#define REG_A3XX_RBBM_GPU_BUSY_MASKED				0x00000088 + +#define REG_A3XX_RBBM_PERFCTR_CP_0_LO				0x00000090 + +#define REG_A3XX_RBBM_PERFCTR_CP_0_HI				0x00000091 + +#define REG_A3XX_RBBM_PERFCTR_RBBM_0_LO				0x00000092 + +#define REG_A3XX_RBBM_PERFCTR_RBBM_0_HI				0x00000093 + +#define REG_A3XX_RBBM_PERFCTR_RBBM_1_LO				0x00000094 + +#define REG_A3XX_RBBM_PERFCTR_RBBM_1_HI				0x00000095 + +#define REG_A3XX_RBBM_PERFCTR_PC_0_LO				0x00000096 + +#define REG_A3XX_RBBM_PERFCTR_PC_0_HI				0x00000097 + +#define REG_A3XX_RBBM_PERFCTR_PC_1_LO				0x00000098 + +#define REG_A3XX_RBBM_PERFCTR_PC_1_HI				0x00000099 + +#define REG_A3XX_RBBM_PERFCTR_PC_2_LO				0x0000009a + +#define REG_A3XX_RBBM_PERFCTR_PC_2_HI				0x0000009b + +#define REG_A3XX_RBBM_PERFCTR_PC_3_LO				0x0000009c + +#define REG_A3XX_RBBM_PERFCTR_PC_3_HI				0x0000009d + +#define REG_A3XX_RBBM_PERFCTR_VFD_0_LO				0x0000009e + +#define REG_A3XX_RBBM_PERFCTR_VFD_0_HI				0x0000009f + +#define REG_A3XX_RBBM_PERFCTR_VFD_1_LO				0x000000a0 + +#define REG_A3XX_RBBM_PERFCTR_VFD_1_HI				0x000000a1 + +#define REG_A3XX_RBBM_PERFCTR_HLSQ_0_LO				0x000000a2 + +#define REG_A3XX_RBBM_PERFCTR_HLSQ_0_HI				0x000000a3 + +#define REG_A3XX_RBBM_PERFCTR_HLSQ_1_LO				0x000000a4 + +#define REG_A3XX_RBBM_PERFCTR_HLSQ_1_HI				0x000000a5 + +#define REG_A3XX_RBBM_PERFCTR_HLSQ_2_LO				0x000000a6 + +#define REG_A3XX_RBBM_PERFCTR_HLSQ_2_HI				0x000000a7 + +#define REG_A3XX_RBBM_PERFCTR_HLSQ_3_LO				0x000000a8 + +#define REG_A3XX_RBBM_PERFCTR_HLSQ_3_HI				0x000000a9 + +#define REG_A3XX_RBBM_PERFCTR_HLSQ_4_LO				0x000000aa + +#define REG_A3XX_RBBM_PERFCTR_HLSQ_4_HI				0x000000ab + +#define REG_A3XX_RBBM_PERFCTR_HLSQ_5_LO				0x000000ac + +#define REG_A3XX_RBBM_PERFCTR_HLSQ_5_HI				0x000000ad + +#define REG_A3XX_RBBM_PERFCTR_VPC_0_LO				0x000000ae + +#define REG_A3XX_RBBM_PERFCTR_VPC_0_HI				0x000000af + +#define REG_A3XX_RBBM_PERFCTR_VPC_1_LO				0x000000b0 + +#define REG_A3XX_RBBM_PERFCTR_VPC_1_HI				0x000000b1 + +#define REG_A3XX_RBBM_PERFCTR_TSE_0_LO				0x000000b2 + +#define REG_A3XX_RBBM_PERFCTR_TSE_0_HI				0x000000b3 + +#define REG_A3XX_RBBM_PERFCTR_TSE_1_LO				0x000000b4 + +#define REG_A3XX_RBBM_PERFCTR_TSE_1_HI				0x000000b5 + +#define REG_A3XX_RBBM_PERFCTR_RAS_0_LO				0x000000b6 + +#define REG_A3XX_RBBM_PERFCTR_RAS_0_HI				0x000000b7 + +#define REG_A3XX_RBBM_PERFCTR_RAS_1_LO				0x000000b8 + +#define REG_A3XX_RBBM_PERFCTR_RAS_1_HI				0x000000b9 + +#define REG_A3XX_RBBM_PERFCTR_UCHE_0_LO				0x000000ba + +#define REG_A3XX_RBBM_PERFCTR_UCHE_0_HI				0x000000bb + +#define REG_A3XX_RBBM_PERFCTR_UCHE_1_LO				0x000000bc + +#define REG_A3XX_RBBM_PERFCTR_UCHE_1_HI				0x000000bd + +#define REG_A3XX_RBBM_PERFCTR_UCHE_2_LO				0x000000be + +#define REG_A3XX_RBBM_PERFCTR_UCHE_2_HI				0x000000bf + +#define REG_A3XX_RBBM_PERFCTR_UCHE_3_LO				0x000000c0 + +#define REG_A3XX_RBBM_PERFCTR_UCHE_3_HI				0x000000c1 + +#define REG_A3XX_RBBM_PERFCTR_UCHE_4_LO				0x000000c2 + +#define REG_A3XX_RBBM_PERFCTR_UCHE_4_HI				0x000000c3 + +#define REG_A3XX_RBBM_PERFCTR_UCHE_5_LO				0x000000c4 + +#define REG_A3XX_RBBM_PERFCTR_UCHE_5_HI				0x000000c5 + +#define REG_A3XX_RBBM_PERFCTR_TP_0_LO				0x000000c6 + +#define REG_A3XX_RBBM_PERFCTR_TP_0_HI				0x000000c7 + +#define REG_A3XX_RBBM_PERFCTR_TP_1_LO				0x000000c8 + +#define REG_A3XX_RBBM_PERFCTR_TP_1_HI				0x000000c9 + +#define REG_A3XX_RBBM_PERFCTR_TP_2_LO				0x000000ca + +#define REG_A3XX_RBBM_PERFCTR_TP_2_HI				0x000000cb + +#define REG_A3XX_RBBM_PERFCTR_TP_3_LO				0x000000cc + +#define REG_A3XX_RBBM_PERFCTR_TP_3_HI				0x000000cd + +#define REG_A3XX_RBBM_PERFCTR_TP_4_LO				0x000000ce + +#define REG_A3XX_RBBM_PERFCTR_TP_4_HI				0x000000cf + +#define REG_A3XX_RBBM_PERFCTR_TP_5_LO				0x000000d0 + +#define REG_A3XX_RBBM_PERFCTR_TP_5_HI				0x000000d1 + +#define REG_A3XX_RBBM_PERFCTR_SP_0_LO				0x000000d2 + +#define REG_A3XX_RBBM_PERFCTR_SP_0_HI				0x000000d3 + +#define REG_A3XX_RBBM_PERFCTR_SP_1_LO				0x000000d4 + +#define REG_A3XX_RBBM_PERFCTR_SP_1_HI				0x000000d5 + +#define REG_A3XX_RBBM_PERFCTR_SP_2_LO				0x000000d6 + +#define REG_A3XX_RBBM_PERFCTR_SP_2_HI				0x000000d7 + +#define REG_A3XX_RBBM_PERFCTR_SP_3_LO				0x000000d8 + +#define REG_A3XX_RBBM_PERFCTR_SP_3_HI				0x000000d9 + +#define REG_A3XX_RBBM_PERFCTR_SP_4_LO				0x000000da + +#define REG_A3XX_RBBM_PERFCTR_SP_4_HI				0x000000db + +#define REG_A3XX_RBBM_PERFCTR_SP_5_LO				0x000000dc + +#define REG_A3XX_RBBM_PERFCTR_SP_5_HI				0x000000dd + +#define REG_A3XX_RBBM_PERFCTR_SP_6_LO				0x000000de + +#define REG_A3XX_RBBM_PERFCTR_SP_6_HI				0x000000df + +#define REG_A3XX_RBBM_PERFCTR_SP_7_LO				0x000000e0 + +#define REG_A3XX_RBBM_PERFCTR_SP_7_HI				0x000000e1 + +#define REG_A3XX_RBBM_PERFCTR_RB_0_LO				0x000000e2 + +#define REG_A3XX_RBBM_PERFCTR_RB_0_HI				0x000000e3 + +#define REG_A3XX_RBBM_PERFCTR_RB_1_LO				0x000000e4 + +#define REG_A3XX_RBBM_PERFCTR_RB_1_HI				0x000000e5 + +#define REG_A3XX_RBBM_PERFCTR_PWR_0_LO				0x000000ea + +#define REG_A3XX_RBBM_PERFCTR_PWR_0_HI				0x000000eb + +#define REG_A3XX_RBBM_PERFCTR_PWR_1_LO				0x000000ec + +#define REG_A3XX_RBBM_PERFCTR_PWR_1_HI				0x000000ed + +#define REG_A3XX_RBBM_RBBM_CTL					0x00000100 + +#define REG_A3XX_RBBM_DEBUG_BUS_CTL				0x00000111 + +#define REG_A3XX_RBBM_DEBUG_BUS_DATA_STATUS			0x00000112 + +#define REG_A3XX_CP_PFP_UCODE_ADDR				0x000001c9 + +#define REG_A3XX_CP_PFP_UCODE_DATA				0x000001ca + +#define REG_A3XX_CP_ROQ_ADDR					0x000001cc + +#define REG_A3XX_CP_ROQ_DATA					0x000001cd + +#define REG_A3XX_CP_MERCIU_ADDR					0x000001d1 + +#define REG_A3XX_CP_MERCIU_DATA					0x000001d2 + +#define REG_A3XX_CP_MERCIU_DATA2				0x000001d3 + +#define REG_A3XX_CP_MEQ_ADDR					0x000001da + +#define REG_A3XX_CP_MEQ_DATA					0x000001db + +#define REG_A3XX_CP_PERFCOUNTER_SELECT				0x00000445 + +#define REG_A3XX_CP_HW_FAULT					0x0000045c + +#define REG_A3XX_CP_PROTECT_CTRL				0x0000045e + +#define REG_A3XX_CP_PROTECT_STATUS				0x0000045f + +static inline uint32_t REG_A3XX_CP_PROTECT(uint32_t i0) { return 0x00000460 + 0x1*i0; } + +static inline uint32_t REG_A3XX_CP_PROTECT_REG(uint32_t i0) { return 0x00000460 + 0x1*i0; } + +#define REG_A3XX_CP_AHB_FAULT					0x0000054d + +#define REG_A3XX_GRAS_CL_CLIP_CNTL				0x00002040 +#define A3XX_GRAS_CL_CLIP_CNTL_IJ_PERSP_CENTER			0x00001000 +#define A3XX_GRAS_CL_CLIP_CNTL_CLIP_DISABLE			0x00010000 +#define A3XX_GRAS_CL_CLIP_CNTL_ZFAR_CLIP_DISABLE		0x00020000 +#define A3XX_GRAS_CL_CLIP_CNTL_VP_CLIP_CODE_IGNORE		0x00080000 +#define A3XX_GRAS_CL_CLIP_CNTL_VP_XFORM_DISABLE			0x00100000 +#define A3XX_GRAS_CL_CLIP_CNTL_PERSP_DIVISION_DISABLE		0x00200000 + +#define REG_A3XX_GRAS_CL_GB_CLIP_ADJ				0x00002044 +#define A3XX_GRAS_CL_GB_CLIP_ADJ_HORZ__MASK			0x000003ff +#define A3XX_GRAS_CL_GB_CLIP_ADJ_HORZ__SHIFT			0 +static inline uint32_t A3XX_GRAS_CL_GB_CLIP_ADJ_HORZ(uint32_t val) +{ +	return ((val) << A3XX_GRAS_CL_GB_CLIP_ADJ_HORZ__SHIFT) & A3XX_GRAS_CL_GB_CLIP_ADJ_HORZ__MASK; +} +#define A3XX_GRAS_CL_GB_CLIP_ADJ_VERT__MASK			0x000ffc00 +#define A3XX_GRAS_CL_GB_CLIP_ADJ_VERT__SHIFT			10 +static inline uint32_t A3XX_GRAS_CL_GB_CLIP_ADJ_VERT(uint32_t val) +{ +	return ((val) << A3XX_GRAS_CL_GB_CLIP_ADJ_VERT__SHIFT) & A3XX_GRAS_CL_GB_CLIP_ADJ_VERT__MASK; +} + +#define REG_A3XX_GRAS_CL_VPORT_XOFFSET				0x00002048 +#define A3XX_GRAS_CL_VPORT_XOFFSET__MASK			0xffffffff +#define A3XX_GRAS_CL_VPORT_XOFFSET__SHIFT			0 +static inline uint32_t A3XX_GRAS_CL_VPORT_XOFFSET(float val) +{ +	return ((fui(val)) << A3XX_GRAS_CL_VPORT_XOFFSET__SHIFT) & A3XX_GRAS_CL_VPORT_XOFFSET__MASK; +} + +#define REG_A3XX_GRAS_CL_VPORT_XSCALE				0x00002049 +#define A3XX_GRAS_CL_VPORT_XSCALE__MASK				0xffffffff +#define A3XX_GRAS_CL_VPORT_XSCALE__SHIFT			0 +static inline uint32_t A3XX_GRAS_CL_VPORT_XSCALE(float val) +{ +	return ((fui(val)) << A3XX_GRAS_CL_VPORT_XSCALE__SHIFT) & A3XX_GRAS_CL_VPORT_XSCALE__MASK; +} + +#define REG_A3XX_GRAS_CL_VPORT_YOFFSET				0x0000204a +#define A3XX_GRAS_CL_VPORT_YOFFSET__MASK			0xffffffff +#define A3XX_GRAS_CL_VPORT_YOFFSET__SHIFT			0 +static inline uint32_t A3XX_GRAS_CL_VPORT_YOFFSET(float val) +{ +	return ((fui(val)) << A3XX_GRAS_CL_VPORT_YOFFSET__SHIFT) & A3XX_GRAS_CL_VPORT_YOFFSET__MASK; +} + +#define REG_A3XX_GRAS_CL_VPORT_YSCALE				0x0000204b +#define A3XX_GRAS_CL_VPORT_YSCALE__MASK				0xffffffff +#define A3XX_GRAS_CL_VPORT_YSCALE__SHIFT			0 +static inline uint32_t A3XX_GRAS_CL_VPORT_YSCALE(float val) +{ +	return ((fui(val)) << A3XX_GRAS_CL_VPORT_YSCALE__SHIFT) & A3XX_GRAS_CL_VPORT_YSCALE__MASK; +} + +#define REG_A3XX_GRAS_CL_VPORT_ZOFFSET				0x0000204c +#define A3XX_GRAS_CL_VPORT_ZOFFSET__MASK			0xffffffff +#define A3XX_GRAS_CL_VPORT_ZOFFSET__SHIFT			0 +static inline uint32_t A3XX_GRAS_CL_VPORT_ZOFFSET(float val) +{ +	return ((fui(val)) << A3XX_GRAS_CL_VPORT_ZOFFSET__SHIFT) & A3XX_GRAS_CL_VPORT_ZOFFSET__MASK; +} + +#define REG_A3XX_GRAS_CL_VPORT_ZSCALE				0x0000204d +#define A3XX_GRAS_CL_VPORT_ZSCALE__MASK				0xffffffff +#define A3XX_GRAS_CL_VPORT_ZSCALE__SHIFT			0 +static inline uint32_t A3XX_GRAS_CL_VPORT_ZSCALE(float val) +{ +	return ((fui(val)) << A3XX_GRAS_CL_VPORT_ZSCALE__SHIFT) & A3XX_GRAS_CL_VPORT_ZSCALE__MASK; +} + +#define REG_A3XX_GRAS_SU_POINT_MINMAX				0x00002068 + +#define REG_A3XX_GRAS_SU_POINT_SIZE				0x00002069 + +#define REG_A3XX_GRAS_SU_POLY_OFFSET_SCALE			0x0000206c +#define A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__MASK		0x00ffffff +#define A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__SHIFT		0 +static inline uint32_t A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL(float val) +{ +	return ((((uint32_t)(val * 40.0))) << A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__SHIFT) & A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__MASK; +} + +#define REG_A3XX_GRAS_SU_POLY_OFFSET_OFFSET			0x0000206d +#define A3XX_GRAS_SU_POLY_OFFSET_OFFSET__MASK			0xffffffff +#define A3XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT			0 +static inline uint32_t A3XX_GRAS_SU_POLY_OFFSET_OFFSET(float val) +{ +	return ((((uint32_t)(val * 44.0))) << A3XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT) & A3XX_GRAS_SU_POLY_OFFSET_OFFSET__MASK; +} + +#define REG_A3XX_GRAS_SU_MODE_CONTROL				0x00002070 +#define A3XX_GRAS_SU_MODE_CONTROL_CULL_FRONT			0x00000001 +#define A3XX_GRAS_SU_MODE_CONTROL_CULL_BACK			0x00000002 +#define A3XX_GRAS_SU_MODE_CONTROL_FRONT_CW			0x00000004 +#define A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__MASK		0x000007f8 +#define A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__SHIFT		3 +static inline uint32_t A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH(float val) +{ +	return ((((uint32_t)(val * 4.0))) << A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__SHIFT) & A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__MASK; +} +#define A3XX_GRAS_SU_MODE_CONTROL_POLY_OFFSET			0x00000800 + +#define REG_A3XX_GRAS_SC_CONTROL				0x00002072 +#define A3XX_GRAS_SC_CONTROL_RENDER_MODE__MASK			0x000000f0 +#define A3XX_GRAS_SC_CONTROL_RENDER_MODE__SHIFT			4 +static inline uint32_t A3XX_GRAS_SC_CONTROL_RENDER_MODE(enum a3xx_render_mode val) +{ +	return ((val) << A3XX_GRAS_SC_CONTROL_RENDER_MODE__SHIFT) & A3XX_GRAS_SC_CONTROL_RENDER_MODE__MASK; +} +#define A3XX_GRAS_SC_CONTROL_MSAA_SAMPLES__MASK			0x00000f00 +#define A3XX_GRAS_SC_CONTROL_MSAA_SAMPLES__SHIFT		8 +static inline uint32_t A3XX_GRAS_SC_CONTROL_MSAA_SAMPLES(enum a3xx_msaa_samples val) +{ +	return ((val) << A3XX_GRAS_SC_CONTROL_MSAA_SAMPLES__SHIFT) & A3XX_GRAS_SC_CONTROL_MSAA_SAMPLES__MASK; +} +#define A3XX_GRAS_SC_CONTROL_RASTER_MODE__MASK			0x0000f000 +#define A3XX_GRAS_SC_CONTROL_RASTER_MODE__SHIFT			12 +static inline uint32_t A3XX_GRAS_SC_CONTROL_RASTER_MODE(uint32_t val) +{ +	return ((val) << A3XX_GRAS_SC_CONTROL_RASTER_MODE__SHIFT) & A3XX_GRAS_SC_CONTROL_RASTER_MODE__MASK; +} + +#define REG_A3XX_GRAS_SC_SCREEN_SCISSOR_TL			0x00002074 +#define A3XX_GRAS_SC_SCREEN_SCISSOR_TL_WINDOW_OFFSET_DISABLE	0x80000000 +#define A3XX_GRAS_SC_SCREEN_SCISSOR_TL_X__MASK			0x00007fff +#define A3XX_GRAS_SC_SCREEN_SCISSOR_TL_X__SHIFT			0 +static inline uint32_t A3XX_GRAS_SC_SCREEN_SCISSOR_TL_X(uint32_t val) +{ +	return ((val) << A3XX_GRAS_SC_SCREEN_SCISSOR_TL_X__SHIFT) & A3XX_GRAS_SC_SCREEN_SCISSOR_TL_X__MASK; +} +#define A3XX_GRAS_SC_SCREEN_SCISSOR_TL_Y__MASK			0x7fff0000 +#define A3XX_GRAS_SC_SCREEN_SCISSOR_TL_Y__SHIFT			16 +static inline uint32_t A3XX_GRAS_SC_SCREEN_SCISSOR_TL_Y(uint32_t val) +{ +	return ((val) << A3XX_GRAS_SC_SCREEN_SCISSOR_TL_Y__SHIFT) & A3XX_GRAS_SC_SCREEN_SCISSOR_TL_Y__MASK; +} + +#define REG_A3XX_GRAS_SC_SCREEN_SCISSOR_BR			0x00002075 +#define A3XX_GRAS_SC_SCREEN_SCISSOR_BR_WINDOW_OFFSET_DISABLE	0x80000000 +#define A3XX_GRAS_SC_SCREEN_SCISSOR_BR_X__MASK			0x00007fff +#define A3XX_GRAS_SC_SCREEN_SCISSOR_BR_X__SHIFT			0 +static inline uint32_t A3XX_GRAS_SC_SCREEN_SCISSOR_BR_X(uint32_t val) +{ +	return ((val) << A3XX_GRAS_SC_SCREEN_SCISSOR_BR_X__SHIFT) & A3XX_GRAS_SC_SCREEN_SCISSOR_BR_X__MASK; +} +#define A3XX_GRAS_SC_SCREEN_SCISSOR_BR_Y__MASK			0x7fff0000 +#define A3XX_GRAS_SC_SCREEN_SCISSOR_BR_Y__SHIFT			16 +static inline uint32_t A3XX_GRAS_SC_SCREEN_SCISSOR_BR_Y(uint32_t val) +{ +	return ((val) << A3XX_GRAS_SC_SCREEN_SCISSOR_BR_Y__SHIFT) & A3XX_GRAS_SC_SCREEN_SCISSOR_BR_Y__MASK; +} + +#define REG_A3XX_GRAS_SC_WINDOW_SCISSOR_TL			0x00002079 +#define A3XX_GRAS_SC_WINDOW_SCISSOR_TL_WINDOW_OFFSET_DISABLE	0x80000000 +#define A3XX_GRAS_SC_WINDOW_SCISSOR_TL_X__MASK			0x00007fff +#define A3XX_GRAS_SC_WINDOW_SCISSOR_TL_X__SHIFT			0 +static inline uint32_t A3XX_GRAS_SC_WINDOW_SCISSOR_TL_X(uint32_t val) +{ +	return ((val) << A3XX_GRAS_SC_WINDOW_SCISSOR_TL_X__SHIFT) & A3XX_GRAS_SC_WINDOW_SCISSOR_TL_X__MASK; +} +#define A3XX_GRAS_SC_WINDOW_SCISSOR_TL_Y__MASK			0x7fff0000 +#define A3XX_GRAS_SC_WINDOW_SCISSOR_TL_Y__SHIFT			16 +static inline uint32_t A3XX_GRAS_SC_WINDOW_SCISSOR_TL_Y(uint32_t val) +{ +	return ((val) << A3XX_GRAS_SC_WINDOW_SCISSOR_TL_Y__SHIFT) & A3XX_GRAS_SC_WINDOW_SCISSOR_TL_Y__MASK; +} + +#define REG_A3XX_GRAS_SC_WINDOW_SCISSOR_BR			0x0000207a +#define A3XX_GRAS_SC_WINDOW_SCISSOR_BR_WINDOW_OFFSET_DISABLE	0x80000000 +#define A3XX_GRAS_SC_WINDOW_SCISSOR_BR_X__MASK			0x00007fff +#define A3XX_GRAS_SC_WINDOW_SCISSOR_BR_X__SHIFT			0 +static inline uint32_t A3XX_GRAS_SC_WINDOW_SCISSOR_BR_X(uint32_t val) +{ +	return ((val) << A3XX_GRAS_SC_WINDOW_SCISSOR_BR_X__SHIFT) & A3XX_GRAS_SC_WINDOW_SCISSOR_BR_X__MASK; +} +#define A3XX_GRAS_SC_WINDOW_SCISSOR_BR_Y__MASK			0x7fff0000 +#define A3XX_GRAS_SC_WINDOW_SCISSOR_BR_Y__SHIFT			16 +static inline uint32_t A3XX_GRAS_SC_WINDOW_SCISSOR_BR_Y(uint32_t val) +{ +	return ((val) << A3XX_GRAS_SC_WINDOW_SCISSOR_BR_Y__SHIFT) & A3XX_GRAS_SC_WINDOW_SCISSOR_BR_Y__MASK; +} + +#define REG_A3XX_RB_MODE_CONTROL				0x000020c0 +#define A3XX_RB_MODE_CONTROL_GMEM_BYPASS			0x00000080 +#define A3XX_RB_MODE_CONTROL_RENDER_MODE__MASK			0x00000700 +#define A3XX_RB_MODE_CONTROL_RENDER_MODE__SHIFT			8 +static inline uint32_t A3XX_RB_MODE_CONTROL_RENDER_MODE(enum a3xx_render_mode val) +{ +	return ((val) << A3XX_RB_MODE_CONTROL_RENDER_MODE__SHIFT) & A3XX_RB_MODE_CONTROL_RENDER_MODE__MASK; +} +#define A3XX_RB_MODE_CONTROL_MARB_CACHE_SPLIT_MODE		0x00008000 +#define A3XX_RB_MODE_CONTROL_PACKER_TIMER_ENABLE		0x00010000 + +#define REG_A3XX_RB_RENDER_CONTROL				0x000020c1 +#define A3XX_RB_RENDER_CONTROL_BIN_WIDTH__MASK			0x00000ff0 +#define A3XX_RB_RENDER_CONTROL_BIN_WIDTH__SHIFT			4 +static inline uint32_t A3XX_RB_RENDER_CONTROL_BIN_WIDTH(uint32_t val) +{ +	return ((val >> 5) << A3XX_RB_RENDER_CONTROL_BIN_WIDTH__SHIFT) & A3XX_RB_RENDER_CONTROL_BIN_WIDTH__MASK; +} +#define A3XX_RB_RENDER_CONTROL_DISABLE_COLOR_PIPE		0x00001000 +#define A3XX_RB_RENDER_CONTROL_ENABLE_GMEM			0x00002000 +#define A3XX_RB_RENDER_CONTROL_ALPHA_TEST			0x00400000 +#define A3XX_RB_RENDER_CONTROL_ALPHA_TEST_FUNC__MASK		0x07000000 +#define A3XX_RB_RENDER_CONTROL_ALPHA_TEST_FUNC__SHIFT		24 +static inline uint32_t A3XX_RB_RENDER_CONTROL_ALPHA_TEST_FUNC(enum adreno_compare_func val) +{ +	return ((val) << A3XX_RB_RENDER_CONTROL_ALPHA_TEST_FUNC__SHIFT) & A3XX_RB_RENDER_CONTROL_ALPHA_TEST_FUNC__MASK; +} + +#define REG_A3XX_RB_MSAA_CONTROL				0x000020c2 +#define A3XX_RB_MSAA_CONTROL_DISABLE				0x00000400 +#define A3XX_RB_MSAA_CONTROL_SAMPLES__MASK			0x0000f000 +#define A3XX_RB_MSAA_CONTROL_SAMPLES__SHIFT			12 +static inline uint32_t A3XX_RB_MSAA_CONTROL_SAMPLES(enum a3xx_msaa_samples val) +{ +	return ((val) << A3XX_RB_MSAA_CONTROL_SAMPLES__SHIFT) & A3XX_RB_MSAA_CONTROL_SAMPLES__MASK; +} +#define A3XX_RB_MSAA_CONTROL_SAMPLE_MASK__MASK			0xffff0000 +#define A3XX_RB_MSAA_CONTROL_SAMPLE_MASK__SHIFT			16 +static inline uint32_t A3XX_RB_MSAA_CONTROL_SAMPLE_MASK(uint32_t val) +{ +	return ((val) << A3XX_RB_MSAA_CONTROL_SAMPLE_MASK__SHIFT) & A3XX_RB_MSAA_CONTROL_SAMPLE_MASK__MASK; +} + +#define REG_A3XX_RB_ALPHA_REF					0x000020c3 +#define A3XX_RB_ALPHA_REF_UINT__MASK				0x0000ff00 +#define A3XX_RB_ALPHA_REF_UINT__SHIFT				8 +static inline uint32_t A3XX_RB_ALPHA_REF_UINT(uint32_t val) +{ +	return ((val) << A3XX_RB_ALPHA_REF_UINT__SHIFT) & A3XX_RB_ALPHA_REF_UINT__MASK; +} +#define A3XX_RB_ALPHA_REF_FLOAT__MASK				0xffff0000 +#define A3XX_RB_ALPHA_REF_FLOAT__SHIFT				16 +static inline uint32_t A3XX_RB_ALPHA_REF_FLOAT(float val) +{ +	return ((util_float_to_half(val)) << A3XX_RB_ALPHA_REF_FLOAT__SHIFT) & A3XX_RB_ALPHA_REF_FLOAT__MASK; +} + +static inline uint32_t REG_A3XX_RB_MRT(uint32_t i0) { return 0x000020c4 + 0x4*i0; } + +static inline uint32_t REG_A3XX_RB_MRT_CONTROL(uint32_t i0) { return 0x000020c4 + 0x4*i0; } +#define A3XX_RB_MRT_CONTROL_READ_DEST_ENABLE			0x00000008 +#define A3XX_RB_MRT_CONTROL_BLEND				0x00000010 +#define A3XX_RB_MRT_CONTROL_BLEND2				0x00000020 +#define A3XX_RB_MRT_CONTROL_ROP_CODE__MASK			0x00000f00 +#define A3XX_RB_MRT_CONTROL_ROP_CODE__SHIFT			8 +static inline uint32_t A3XX_RB_MRT_CONTROL_ROP_CODE(uint32_t val) +{ +	return ((val) << A3XX_RB_MRT_CONTROL_ROP_CODE__SHIFT) & A3XX_RB_MRT_CONTROL_ROP_CODE__MASK; +} +#define A3XX_RB_MRT_CONTROL_DITHER_MODE__MASK			0x00003000 +#define A3XX_RB_MRT_CONTROL_DITHER_MODE__SHIFT			12 +static inline uint32_t A3XX_RB_MRT_CONTROL_DITHER_MODE(enum adreno_rb_dither_mode val) +{ +	return ((val) << A3XX_RB_MRT_CONTROL_DITHER_MODE__SHIFT) & A3XX_RB_MRT_CONTROL_DITHER_MODE__MASK; +} +#define A3XX_RB_MRT_CONTROL_COMPONENT_ENABLE__MASK		0x0f000000 +#define A3XX_RB_MRT_CONTROL_COMPONENT_ENABLE__SHIFT		24 +static inline uint32_t A3XX_RB_MRT_CONTROL_COMPONENT_ENABLE(uint32_t val) +{ +	return ((val) << A3XX_RB_MRT_CONTROL_COMPONENT_ENABLE__SHIFT) & A3XX_RB_MRT_CONTROL_COMPONENT_ENABLE__MASK; +} + +static inline uint32_t REG_A3XX_RB_MRT_BUF_INFO(uint32_t i0) { return 0x000020c5 + 0x4*i0; } +#define A3XX_RB_MRT_BUF_INFO_COLOR_FORMAT__MASK			0x0000003f +#define A3XX_RB_MRT_BUF_INFO_COLOR_FORMAT__SHIFT		0 +static inline uint32_t A3XX_RB_MRT_BUF_INFO_COLOR_FORMAT(enum a3xx_color_fmt val) +{ +	return ((val) << A3XX_RB_MRT_BUF_INFO_COLOR_FORMAT__SHIFT) & A3XX_RB_MRT_BUF_INFO_COLOR_FORMAT__MASK; +} +#define A3XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE__MASK		0x000000c0 +#define A3XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE__SHIFT		6 +static inline uint32_t A3XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE(enum a3xx_tile_mode val) +{ +	return ((val) << A3XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE__SHIFT) & A3XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE__MASK; +} +#define A3XX_RB_MRT_BUF_INFO_COLOR_SWAP__MASK			0x00000c00 +#define A3XX_RB_MRT_BUF_INFO_COLOR_SWAP__SHIFT			10 +static inline uint32_t A3XX_RB_MRT_BUF_INFO_COLOR_SWAP(enum a3xx_color_swap val) +{ +	return ((val) << A3XX_RB_MRT_BUF_INFO_COLOR_SWAP__SHIFT) & A3XX_RB_MRT_BUF_INFO_COLOR_SWAP__MASK; +} +#define A3XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH__MASK		0xfffe0000 +#define A3XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH__SHIFT		17 +static inline uint32_t A3XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH(uint32_t val) +{ +	return ((val >> 5) << A3XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH__SHIFT) & A3XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH__MASK; +} + +static inline uint32_t REG_A3XX_RB_MRT_BUF_BASE(uint32_t i0) { return 0x000020c6 + 0x4*i0; } +#define A3XX_RB_MRT_BUF_BASE_COLOR_BUF_BASE__MASK		0xfffffff0 +#define A3XX_RB_MRT_BUF_BASE_COLOR_BUF_BASE__SHIFT		4 +static inline uint32_t A3XX_RB_MRT_BUF_BASE_COLOR_BUF_BASE(uint32_t val) +{ +	return ((val >> 5) << A3XX_RB_MRT_BUF_BASE_COLOR_BUF_BASE__SHIFT) & A3XX_RB_MRT_BUF_BASE_COLOR_BUF_BASE__MASK; +} + +static inline uint32_t REG_A3XX_RB_MRT_BLEND_CONTROL(uint32_t i0) { return 0x000020c7 + 0x4*i0; } +#define A3XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR__MASK		0x0000001f +#define A3XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR__SHIFT		0 +static inline uint32_t A3XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR(enum adreno_rb_blend_factor val) +{ +	return ((val) << A3XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR__SHIFT) & A3XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR__MASK; +} +#define A3XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE__MASK	0x000000e0 +#define A3XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE__SHIFT	5 +static inline uint32_t A3XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE(enum adreno_rb_blend_opcode val) +{ +	return ((val) << A3XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE__SHIFT) & A3XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE__MASK; +} +#define A3XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR__MASK		0x00001f00 +#define A3XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR__SHIFT	8 +static inline uint32_t A3XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR(enum adreno_rb_blend_factor val) +{ +	return ((val) << A3XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR__SHIFT) & A3XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR__MASK; +} +#define A3XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR__MASK	0x001f0000 +#define A3XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR__SHIFT	16 +static inline uint32_t A3XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR(enum adreno_rb_blend_factor val) +{ +	return ((val) << A3XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR__SHIFT) & A3XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR__MASK; +} +#define A3XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE__MASK	0x00e00000 +#define A3XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE__SHIFT	21 +static inline uint32_t A3XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE(enum adreno_rb_blend_opcode val) +{ +	return ((val) << A3XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE__SHIFT) & A3XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE__MASK; +} +#define A3XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR__MASK	0x1f000000 +#define A3XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR__SHIFT	24 +static inline uint32_t A3XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR(enum adreno_rb_blend_factor val) +{ +	return ((val) << A3XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR__SHIFT) & A3XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR__MASK; +} +#define A3XX_RB_MRT_BLEND_CONTROL_CLAMP_ENABLE			0x20000000 + +#define REG_A3XX_RB_BLEND_RED					0x000020e4 +#define A3XX_RB_BLEND_RED_UINT__MASK				0x000000ff +#define A3XX_RB_BLEND_RED_UINT__SHIFT				0 +static inline uint32_t A3XX_RB_BLEND_RED_UINT(uint32_t val) +{ +	return ((val) << A3XX_RB_BLEND_RED_UINT__SHIFT) & A3XX_RB_BLEND_RED_UINT__MASK; +} +#define A3XX_RB_BLEND_RED_FLOAT__MASK				0xffff0000 +#define A3XX_RB_BLEND_RED_FLOAT__SHIFT				16 +static inline uint32_t A3XX_RB_BLEND_RED_FLOAT(float val) +{ +	return ((util_float_to_half(val)) << A3XX_RB_BLEND_RED_FLOAT__SHIFT) & A3XX_RB_BLEND_RED_FLOAT__MASK; +} + +#define REG_A3XX_RB_BLEND_GREEN					0x000020e5 +#define A3XX_RB_BLEND_GREEN_UINT__MASK				0x000000ff +#define A3XX_RB_BLEND_GREEN_UINT__SHIFT				0 +static inline uint32_t A3XX_RB_BLEND_GREEN_UINT(uint32_t val) +{ +	return ((val) << A3XX_RB_BLEND_GREEN_UINT__SHIFT) & A3XX_RB_BLEND_GREEN_UINT__MASK; +} +#define A3XX_RB_BLEND_GREEN_FLOAT__MASK				0xffff0000 +#define A3XX_RB_BLEND_GREEN_FLOAT__SHIFT			16 +static inline uint32_t A3XX_RB_BLEND_GREEN_FLOAT(float val) +{ +	return ((util_float_to_half(val)) << A3XX_RB_BLEND_GREEN_FLOAT__SHIFT) & A3XX_RB_BLEND_GREEN_FLOAT__MASK; +} + +#define REG_A3XX_RB_BLEND_BLUE					0x000020e6 +#define A3XX_RB_BLEND_BLUE_UINT__MASK				0x000000ff +#define A3XX_RB_BLEND_BLUE_UINT__SHIFT				0 +static inline uint32_t A3XX_RB_BLEND_BLUE_UINT(uint32_t val) +{ +	return ((val) << A3XX_RB_BLEND_BLUE_UINT__SHIFT) & A3XX_RB_BLEND_BLUE_UINT__MASK; +} +#define A3XX_RB_BLEND_BLUE_FLOAT__MASK				0xffff0000 +#define A3XX_RB_BLEND_BLUE_FLOAT__SHIFT				16 +static inline uint32_t A3XX_RB_BLEND_BLUE_FLOAT(float val) +{ +	return ((util_float_to_half(val)) << A3XX_RB_BLEND_BLUE_FLOAT__SHIFT) & A3XX_RB_BLEND_BLUE_FLOAT__MASK; +} + +#define REG_A3XX_RB_BLEND_ALPHA					0x000020e7 +#define A3XX_RB_BLEND_ALPHA_UINT__MASK				0x000000ff +#define A3XX_RB_BLEND_ALPHA_UINT__SHIFT				0 +static inline uint32_t A3XX_RB_BLEND_ALPHA_UINT(uint32_t val) +{ +	return ((val) << A3XX_RB_BLEND_ALPHA_UINT__SHIFT) & A3XX_RB_BLEND_ALPHA_UINT__MASK; +} +#define A3XX_RB_BLEND_ALPHA_FLOAT__MASK				0xffff0000 +#define A3XX_RB_BLEND_ALPHA_FLOAT__SHIFT			16 +static inline uint32_t A3XX_RB_BLEND_ALPHA_FLOAT(float val) +{ +	return ((util_float_to_half(val)) << A3XX_RB_BLEND_ALPHA_FLOAT__SHIFT) & A3XX_RB_BLEND_ALPHA_FLOAT__MASK; +} + +#define REG_A3XX_RB_CLEAR_COLOR_DW0				0x000020e8 + +#define REG_A3XX_RB_CLEAR_COLOR_DW1				0x000020e9 + +#define REG_A3XX_RB_CLEAR_COLOR_DW2				0x000020ea + +#define REG_A3XX_RB_CLEAR_COLOR_DW3				0x000020eb + +#define REG_A3XX_RB_COPY_CONTROL				0x000020ec +#define A3XX_RB_COPY_CONTROL_MSAA_RESOLVE__MASK			0x00000003 +#define A3XX_RB_COPY_CONTROL_MSAA_RESOLVE__SHIFT		0 +static inline uint32_t A3XX_RB_COPY_CONTROL_MSAA_RESOLVE(enum a3xx_msaa_samples val) +{ +	return ((val) << A3XX_RB_COPY_CONTROL_MSAA_RESOLVE__SHIFT) & A3XX_RB_COPY_CONTROL_MSAA_RESOLVE__MASK; +} +#define A3XX_RB_COPY_CONTROL_MODE__MASK				0x00000070 +#define A3XX_RB_COPY_CONTROL_MODE__SHIFT			4 +static inline uint32_t A3XX_RB_COPY_CONTROL_MODE(enum adreno_rb_copy_control_mode val) +{ +	return ((val) << A3XX_RB_COPY_CONTROL_MODE__SHIFT) & A3XX_RB_COPY_CONTROL_MODE__MASK; +} +#define A3XX_RB_COPY_CONTROL_GMEM_BASE__MASK			0xfffffc00 +#define A3XX_RB_COPY_CONTROL_GMEM_BASE__SHIFT			10 +static inline uint32_t A3XX_RB_COPY_CONTROL_GMEM_BASE(uint32_t val) +{ +	return ((val >> 10) << A3XX_RB_COPY_CONTROL_GMEM_BASE__SHIFT) & A3XX_RB_COPY_CONTROL_GMEM_BASE__MASK; +} + +#define REG_A3XX_RB_COPY_DEST_BASE				0x000020ed +#define A3XX_RB_COPY_DEST_BASE_BASE__MASK			0xfffffff0 +#define A3XX_RB_COPY_DEST_BASE_BASE__SHIFT			4 +static inline uint32_t A3XX_RB_COPY_DEST_BASE_BASE(uint32_t val) +{ +	return ((val >> 5) << A3XX_RB_COPY_DEST_BASE_BASE__SHIFT) & A3XX_RB_COPY_DEST_BASE_BASE__MASK; +} + +#define REG_A3XX_RB_COPY_DEST_PITCH				0x000020ee +#define A3XX_RB_COPY_DEST_PITCH_PITCH__MASK			0xffffffff +#define A3XX_RB_COPY_DEST_PITCH_PITCH__SHIFT			0 +static inline uint32_t A3XX_RB_COPY_DEST_PITCH_PITCH(uint32_t val) +{ +	return ((val >> 5) << A3XX_RB_COPY_DEST_PITCH_PITCH__SHIFT) & A3XX_RB_COPY_DEST_PITCH_PITCH__MASK; +} + +#define REG_A3XX_RB_COPY_DEST_INFO				0x000020ef +#define A3XX_RB_COPY_DEST_INFO_TILE__MASK			0x00000003 +#define A3XX_RB_COPY_DEST_INFO_TILE__SHIFT			0 +static inline uint32_t A3XX_RB_COPY_DEST_INFO_TILE(enum a3xx_tile_mode val) +{ +	return ((val) << A3XX_RB_COPY_DEST_INFO_TILE__SHIFT) & A3XX_RB_COPY_DEST_INFO_TILE__MASK; +} +#define A3XX_RB_COPY_DEST_INFO_FORMAT__MASK			0x000000fc +#define A3XX_RB_COPY_DEST_INFO_FORMAT__SHIFT			2 +static inline uint32_t A3XX_RB_COPY_DEST_INFO_FORMAT(enum a3xx_color_fmt val) +{ +	return ((val) << A3XX_RB_COPY_DEST_INFO_FORMAT__SHIFT) & A3XX_RB_COPY_DEST_INFO_FORMAT__MASK; +} +#define A3XX_RB_COPY_DEST_INFO_SWAP__MASK			0x00000300 +#define A3XX_RB_COPY_DEST_INFO_SWAP__SHIFT			8 +static inline uint32_t A3XX_RB_COPY_DEST_INFO_SWAP(enum a3xx_color_swap val) +{ +	return ((val) << A3XX_RB_COPY_DEST_INFO_SWAP__SHIFT) & A3XX_RB_COPY_DEST_INFO_SWAP__MASK; +} +#define A3XX_RB_COPY_DEST_INFO_COMPONENT_ENABLE__MASK		0x0003c000 +#define A3XX_RB_COPY_DEST_INFO_COMPONENT_ENABLE__SHIFT		14 +static inline uint32_t A3XX_RB_COPY_DEST_INFO_COMPONENT_ENABLE(uint32_t val) +{ +	return ((val) << A3XX_RB_COPY_DEST_INFO_COMPONENT_ENABLE__SHIFT) & A3XX_RB_COPY_DEST_INFO_COMPONENT_ENABLE__MASK; +} +#define A3XX_RB_COPY_DEST_INFO_ENDIAN__MASK			0x001c0000 +#define A3XX_RB_COPY_DEST_INFO_ENDIAN__SHIFT			18 +static inline uint32_t A3XX_RB_COPY_DEST_INFO_ENDIAN(enum adreno_rb_surface_endian val) +{ +	return ((val) << A3XX_RB_COPY_DEST_INFO_ENDIAN__SHIFT) & A3XX_RB_COPY_DEST_INFO_ENDIAN__MASK; +} + +#define REG_A3XX_RB_DEPTH_CONTROL				0x00002100 +#define A3XX_RB_DEPTH_CONTROL_Z_ENABLE				0x00000002 +#define A3XX_RB_DEPTH_CONTROL_Z_WRITE_ENABLE			0x00000004 +#define A3XX_RB_DEPTH_CONTROL_EARLY_Z_DISABLE			0x00000008 +#define A3XX_RB_DEPTH_CONTROL_ZFUNC__MASK			0x00000070 +#define A3XX_RB_DEPTH_CONTROL_ZFUNC__SHIFT			4 +static inline uint32_t A3XX_RB_DEPTH_CONTROL_ZFUNC(enum adreno_compare_func val) +{ +	return ((val) << A3XX_RB_DEPTH_CONTROL_ZFUNC__SHIFT) & A3XX_RB_DEPTH_CONTROL_ZFUNC__MASK; +} +#define A3XX_RB_DEPTH_CONTROL_BF_ENABLE				0x00000080 +#define A3XX_RB_DEPTH_CONTROL_Z_TEST_ENABLE			0x80000000 + +#define REG_A3XX_RB_DEPTH_CLEAR					0x00002101 + +#define REG_A3XX_RB_DEPTH_INFO					0x00002102 +#define A3XX_RB_DEPTH_INFO_DEPTH_FORMAT__MASK			0x00000001 +#define A3XX_RB_DEPTH_INFO_DEPTH_FORMAT__SHIFT			0 +static inline uint32_t A3XX_RB_DEPTH_INFO_DEPTH_FORMAT(enum adreno_rb_depth_format val) +{ +	return ((val) << A3XX_RB_DEPTH_INFO_DEPTH_FORMAT__SHIFT) & A3XX_RB_DEPTH_INFO_DEPTH_FORMAT__MASK; +} +#define A3XX_RB_DEPTH_INFO_DEPTH_BASE__MASK			0xfffff800 +#define A3XX_RB_DEPTH_INFO_DEPTH_BASE__SHIFT			11 +static inline uint32_t A3XX_RB_DEPTH_INFO_DEPTH_BASE(uint32_t val) +{ +	return ((val >> 10) << A3XX_RB_DEPTH_INFO_DEPTH_BASE__SHIFT) & A3XX_RB_DEPTH_INFO_DEPTH_BASE__MASK; +} + +#define REG_A3XX_RB_DEPTH_PITCH					0x00002103 +#define A3XX_RB_DEPTH_PITCH__MASK				0xffffffff +#define A3XX_RB_DEPTH_PITCH__SHIFT				0 +static inline uint32_t A3XX_RB_DEPTH_PITCH(uint32_t val) +{ +	return ((val >> 3) << A3XX_RB_DEPTH_PITCH__SHIFT) & A3XX_RB_DEPTH_PITCH__MASK; +} + +#define REG_A3XX_RB_STENCIL_CONTROL				0x00002104 +#define A3XX_RB_STENCIL_CONTROL_STENCIL_ENABLE			0x00000001 +#define A3XX_RB_STENCIL_CONTROL_STENCIL_ENABLE_BF		0x00000002 +#define A3XX_RB_STENCIL_CONTROL_STENCIL_READ			0x00000004 +#define A3XX_RB_STENCIL_CONTROL_FUNC__MASK			0x00000700 +#define A3XX_RB_STENCIL_CONTROL_FUNC__SHIFT			8 +static inline uint32_t A3XX_RB_STENCIL_CONTROL_FUNC(enum adreno_compare_func val) +{ +	return ((val) << A3XX_RB_STENCIL_CONTROL_FUNC__SHIFT) & A3XX_RB_STENCIL_CONTROL_FUNC__MASK; +} +#define A3XX_RB_STENCIL_CONTROL_FAIL__MASK			0x00003800 +#define A3XX_RB_STENCIL_CONTROL_FAIL__SHIFT			11 +static inline uint32_t A3XX_RB_STENCIL_CONTROL_FAIL(enum adreno_stencil_op val) +{ +	return ((val) << A3XX_RB_STENCIL_CONTROL_FAIL__SHIFT) & A3XX_RB_STENCIL_CONTROL_FAIL__MASK; +} +#define A3XX_RB_STENCIL_CONTROL_ZPASS__MASK			0x0001c000 +#define A3XX_RB_STENCIL_CONTROL_ZPASS__SHIFT			14 +static inline uint32_t A3XX_RB_STENCIL_CONTROL_ZPASS(enum adreno_stencil_op val) +{ +	return ((val) << A3XX_RB_STENCIL_CONTROL_ZPASS__SHIFT) & A3XX_RB_STENCIL_CONTROL_ZPASS__MASK; +} +#define A3XX_RB_STENCIL_CONTROL_ZFAIL__MASK			0x000e0000 +#define A3XX_RB_STENCIL_CONTROL_ZFAIL__SHIFT			17 +static inline uint32_t A3XX_RB_STENCIL_CONTROL_ZFAIL(enum adreno_stencil_op val) +{ +	return ((val) << A3XX_RB_STENCIL_CONTROL_ZFAIL__SHIFT) & A3XX_RB_STENCIL_CONTROL_ZFAIL__MASK; +} +#define A3XX_RB_STENCIL_CONTROL_FUNC_BF__MASK			0x00700000 +#define A3XX_RB_STENCIL_CONTROL_FUNC_BF__SHIFT			20 +static inline uint32_t A3XX_RB_STENCIL_CONTROL_FUNC_BF(enum adreno_compare_func val) +{ +	return ((val) << A3XX_RB_STENCIL_CONTROL_FUNC_BF__SHIFT) & A3XX_RB_STENCIL_CONTROL_FUNC_BF__MASK; +} +#define A3XX_RB_STENCIL_CONTROL_FAIL_BF__MASK			0x03800000 +#define A3XX_RB_STENCIL_CONTROL_FAIL_BF__SHIFT			23 +static inline uint32_t A3XX_RB_STENCIL_CONTROL_FAIL_BF(enum adreno_stencil_op val) +{ +	return ((val) << A3XX_RB_STENCIL_CONTROL_FAIL_BF__SHIFT) & A3XX_RB_STENCIL_CONTROL_FAIL_BF__MASK; +} +#define A3XX_RB_STENCIL_CONTROL_ZPASS_BF__MASK			0x1c000000 +#define A3XX_RB_STENCIL_CONTROL_ZPASS_BF__SHIFT			26 +static inline uint32_t A3XX_RB_STENCIL_CONTROL_ZPASS_BF(enum adreno_stencil_op val) +{ +	return ((val) << A3XX_RB_STENCIL_CONTROL_ZPASS_BF__SHIFT) & A3XX_RB_STENCIL_CONTROL_ZPASS_BF__MASK; +} +#define A3XX_RB_STENCIL_CONTROL_ZFAIL_BF__MASK			0xe0000000 +#define A3XX_RB_STENCIL_CONTROL_ZFAIL_BF__SHIFT			29 +static inline uint32_t A3XX_RB_STENCIL_CONTROL_ZFAIL_BF(enum adreno_stencil_op val) +{ +	return ((val) << A3XX_RB_STENCIL_CONTROL_ZFAIL_BF__SHIFT) & A3XX_RB_STENCIL_CONTROL_ZFAIL_BF__MASK; +} + +#define REG_A3XX_RB_STENCIL_CLEAR				0x00002105 + +#define REG_A3XX_RB_STENCIL_BUF_INFO				0x00002106 + +#define REG_A3XX_RB_STENCIL_BUF_PITCH				0x00002107 + +#define REG_A3XX_RB_STENCILREFMASK				0x00002108 +#define A3XX_RB_STENCILREFMASK_STENCILREF__MASK			0x000000ff +#define A3XX_RB_STENCILREFMASK_STENCILREF__SHIFT		0 +static inline uint32_t A3XX_RB_STENCILREFMASK_STENCILREF(uint32_t val) +{ +	return ((val) << A3XX_RB_STENCILREFMASK_STENCILREF__SHIFT) & A3XX_RB_STENCILREFMASK_STENCILREF__MASK; +} +#define A3XX_RB_STENCILREFMASK_STENCILMASK__MASK		0x0000ff00 +#define A3XX_RB_STENCILREFMASK_STENCILMASK__SHIFT		8 +static inline uint32_t A3XX_RB_STENCILREFMASK_STENCILMASK(uint32_t val) +{ +	return ((val) << A3XX_RB_STENCILREFMASK_STENCILMASK__SHIFT) & A3XX_RB_STENCILREFMASK_STENCILMASK__MASK; +} +#define A3XX_RB_STENCILREFMASK_STENCILWRITEMASK__MASK		0x00ff0000 +#define A3XX_RB_STENCILREFMASK_STENCILWRITEMASK__SHIFT		16 +static inline uint32_t A3XX_RB_STENCILREFMASK_STENCILWRITEMASK(uint32_t val) +{ +	return ((val) << A3XX_RB_STENCILREFMASK_STENCILWRITEMASK__SHIFT) & A3XX_RB_STENCILREFMASK_STENCILWRITEMASK__MASK; +} + +#define REG_A3XX_RB_STENCILREFMASK_BF				0x00002109 +#define A3XX_RB_STENCILREFMASK_BF_STENCILREF__MASK		0x000000ff +#define A3XX_RB_STENCILREFMASK_BF_STENCILREF__SHIFT		0 +static inline uint32_t A3XX_RB_STENCILREFMASK_BF_STENCILREF(uint32_t val) +{ +	return ((val) << A3XX_RB_STENCILREFMASK_BF_STENCILREF__SHIFT) & A3XX_RB_STENCILREFMASK_BF_STENCILREF__MASK; +} +#define A3XX_RB_STENCILREFMASK_BF_STENCILMASK__MASK		0x0000ff00 +#define A3XX_RB_STENCILREFMASK_BF_STENCILMASK__SHIFT		8 +static inline uint32_t A3XX_RB_STENCILREFMASK_BF_STENCILMASK(uint32_t val) +{ +	return ((val) << A3XX_RB_STENCILREFMASK_BF_STENCILMASK__SHIFT) & A3XX_RB_STENCILREFMASK_BF_STENCILMASK__MASK; +} +#define A3XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK__MASK	0x00ff0000 +#define A3XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK__SHIFT	16 +static inline uint32_t A3XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK(uint32_t val) +{ +	return ((val) << A3XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK__SHIFT) & A3XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK__MASK; +} + +#define REG_A3XX_RB_LRZ_VSC_CONTROL				0x0000210c +#define A3XX_RB_LRZ_VSC_CONTROL_BINNING_ENABLE			0x00000002 + +#define REG_A3XX_RB_WINDOW_OFFSET				0x0000210e +#define A3XX_RB_WINDOW_OFFSET_X__MASK				0x0000ffff +#define A3XX_RB_WINDOW_OFFSET_X__SHIFT				0 +static inline uint32_t A3XX_RB_WINDOW_OFFSET_X(uint32_t val) +{ +	return ((val) << A3XX_RB_WINDOW_OFFSET_X__SHIFT) & A3XX_RB_WINDOW_OFFSET_X__MASK; +} +#define A3XX_RB_WINDOW_OFFSET_Y__MASK				0xffff0000 +#define A3XX_RB_WINDOW_OFFSET_Y__SHIFT				16 +static inline uint32_t A3XX_RB_WINDOW_OFFSET_Y(uint32_t val) +{ +	return ((val) << A3XX_RB_WINDOW_OFFSET_Y__SHIFT) & A3XX_RB_WINDOW_OFFSET_Y__MASK; +} + +#define REG_A3XX_RB_SAMPLE_COUNT_CONTROL			0x00002110 + +#define REG_A3XX_RB_SAMPLE_COUNT_ADDR				0x00002111 + +#define REG_A3XX_RB_Z_CLAMP_MIN					0x00002114 + +#define REG_A3XX_RB_Z_CLAMP_MAX					0x00002115 + +#define REG_A3XX_PC_VSTREAM_CONTROL				0x000021e4 + +#define REG_A3XX_PC_VERTEX_REUSE_BLOCK_CNTL			0x000021ea + +#define REG_A3XX_PC_PRIM_VTX_CNTL				0x000021ec +#define A3XX_PC_PRIM_VTX_CNTL_STRIDE_IN_VPC__MASK		0x0000001f +#define A3XX_PC_PRIM_VTX_CNTL_STRIDE_IN_VPC__SHIFT		0 +static inline uint32_t A3XX_PC_PRIM_VTX_CNTL_STRIDE_IN_VPC(uint32_t val) +{ +	return ((val) << A3XX_PC_PRIM_VTX_CNTL_STRIDE_IN_VPC__SHIFT) & A3XX_PC_PRIM_VTX_CNTL_STRIDE_IN_VPC__MASK; +} +#define A3XX_PC_PRIM_VTX_CNTL_POLYMODE_FRONT_PTYPE__MASK	0x000000e0 +#define A3XX_PC_PRIM_VTX_CNTL_POLYMODE_FRONT_PTYPE__SHIFT	5 +static inline uint32_t A3XX_PC_PRIM_VTX_CNTL_POLYMODE_FRONT_PTYPE(enum adreno_pa_su_sc_draw val) +{ +	return ((val) << A3XX_PC_PRIM_VTX_CNTL_POLYMODE_FRONT_PTYPE__SHIFT) & A3XX_PC_PRIM_VTX_CNTL_POLYMODE_FRONT_PTYPE__MASK; +} +#define A3XX_PC_PRIM_VTX_CNTL_POLYMODE_BACK_PTYPE__MASK		0x00000700 +#define A3XX_PC_PRIM_VTX_CNTL_POLYMODE_BACK_PTYPE__SHIFT	8 +static inline uint32_t A3XX_PC_PRIM_VTX_CNTL_POLYMODE_BACK_PTYPE(enum adreno_pa_su_sc_draw val) +{ +	return ((val) << A3XX_PC_PRIM_VTX_CNTL_POLYMODE_BACK_PTYPE__SHIFT) & A3XX_PC_PRIM_VTX_CNTL_POLYMODE_BACK_PTYPE__MASK; +} +#define A3XX_PC_PRIM_VTX_CNTL_PROVOKING_VTX_LAST		0x02000000 + +#define REG_A3XX_PC_RESTART_INDEX				0x000021ed + +#define REG_A3XX_HLSQ_CONTROL_0_REG				0x00002200 +#define A3XX_HLSQ_CONTROL_0_REG_FSTHREADSIZE__MASK		0x00000010 +#define A3XX_HLSQ_CONTROL_0_REG_FSTHREADSIZE__SHIFT		4 +static inline uint32_t A3XX_HLSQ_CONTROL_0_REG_FSTHREADSIZE(enum a3xx_threadsize val) +{ +	return ((val) << A3XX_HLSQ_CONTROL_0_REG_FSTHREADSIZE__SHIFT) & A3XX_HLSQ_CONTROL_0_REG_FSTHREADSIZE__MASK; +} +#define A3XX_HLSQ_CONTROL_0_REG_FSSUPERTHREADENABLE		0x00000040 +#define A3XX_HLSQ_CONTROL_0_REG_SPSHADERRESTART			0x00000200 +#define A3XX_HLSQ_CONTROL_0_REG_RESERVED2			0x00000400 +#define A3XX_HLSQ_CONTROL_0_REG_CHUNKDISABLE			0x04000000 +#define A3XX_HLSQ_CONTROL_0_REG_CONSTSWITCHMODE			0x08000000 +#define A3XX_HLSQ_CONTROL_0_REG_LAZYUPDATEDISABLE		0x10000000 +#define A3XX_HLSQ_CONTROL_0_REG_SPCONSTFULLUPDATE		0x20000000 +#define A3XX_HLSQ_CONTROL_0_REG_TPFULLUPDATE			0x40000000 +#define A3XX_HLSQ_CONTROL_0_REG_SINGLECONTEXT			0x80000000 + +#define REG_A3XX_HLSQ_CONTROL_1_REG				0x00002201 +#define A3XX_HLSQ_CONTROL_1_REG_VSTHREADSIZE__MASK		0x00000040 +#define A3XX_HLSQ_CONTROL_1_REG_VSTHREADSIZE__SHIFT		6 +static inline uint32_t A3XX_HLSQ_CONTROL_1_REG_VSTHREADSIZE(enum a3xx_threadsize val) +{ +	return ((val) << A3XX_HLSQ_CONTROL_1_REG_VSTHREADSIZE__SHIFT) & A3XX_HLSQ_CONTROL_1_REG_VSTHREADSIZE__MASK; +} +#define A3XX_HLSQ_CONTROL_1_REG_VSSUPERTHREADENABLE		0x00000100 +#define A3XX_HLSQ_CONTROL_1_REG_RESERVED1			0x00000200 + +#define REG_A3XX_HLSQ_CONTROL_2_REG				0x00002202 +#define A3XX_HLSQ_CONTROL_2_REG_PRIMALLOCTHRESHOLD__MASK	0xfc000000 +#define A3XX_HLSQ_CONTROL_2_REG_PRIMALLOCTHRESHOLD__SHIFT	26 +static inline uint32_t A3XX_HLSQ_CONTROL_2_REG_PRIMALLOCTHRESHOLD(uint32_t val) +{ +	return ((val) << A3XX_HLSQ_CONTROL_2_REG_PRIMALLOCTHRESHOLD__SHIFT) & A3XX_HLSQ_CONTROL_2_REG_PRIMALLOCTHRESHOLD__MASK; +} + +#define REG_A3XX_HLSQ_CONTROL_3_REG				0x00002203 + +#define REG_A3XX_HLSQ_VS_CONTROL_REG				0x00002204 +#define A3XX_HLSQ_VS_CONTROL_REG_CONSTLENGTH__MASK		0x00000fff +#define A3XX_HLSQ_VS_CONTROL_REG_CONSTLENGTH__SHIFT		0 +static inline uint32_t A3XX_HLSQ_VS_CONTROL_REG_CONSTLENGTH(uint32_t val) +{ +	return ((val) << A3XX_HLSQ_VS_CONTROL_REG_CONSTLENGTH__SHIFT) & A3XX_HLSQ_VS_CONTROL_REG_CONSTLENGTH__MASK; +} +#define A3XX_HLSQ_VS_CONTROL_REG_CONSTSTARTOFFSET__MASK		0x00fff000 +#define A3XX_HLSQ_VS_CONTROL_REG_CONSTSTARTOFFSET__SHIFT	12 +static inline uint32_t A3XX_HLSQ_VS_CONTROL_REG_CONSTSTARTOFFSET(uint32_t val) +{ +	return ((val) << A3XX_HLSQ_VS_CONTROL_REG_CONSTSTARTOFFSET__SHIFT) & A3XX_HLSQ_VS_CONTROL_REG_CONSTSTARTOFFSET__MASK; +} +#define A3XX_HLSQ_VS_CONTROL_REG_INSTRLENGTH__MASK		0xff000000 +#define A3XX_HLSQ_VS_CONTROL_REG_INSTRLENGTH__SHIFT		24 +static inline uint32_t A3XX_HLSQ_VS_CONTROL_REG_INSTRLENGTH(uint32_t val) +{ +	return ((val) << A3XX_HLSQ_VS_CONTROL_REG_INSTRLENGTH__SHIFT) & A3XX_HLSQ_VS_CONTROL_REG_INSTRLENGTH__MASK; +} + +#define REG_A3XX_HLSQ_FS_CONTROL_REG				0x00002205 +#define A3XX_HLSQ_FS_CONTROL_REG_CONSTLENGTH__MASK		0x00000fff +#define A3XX_HLSQ_FS_CONTROL_REG_CONSTLENGTH__SHIFT		0 +static inline uint32_t A3XX_HLSQ_FS_CONTROL_REG_CONSTLENGTH(uint32_t val) +{ +	return ((val) << A3XX_HLSQ_FS_CONTROL_REG_CONSTLENGTH__SHIFT) & A3XX_HLSQ_FS_CONTROL_REG_CONSTLENGTH__MASK; +} +#define A3XX_HLSQ_FS_CONTROL_REG_CONSTSTARTOFFSET__MASK		0x00fff000 +#define A3XX_HLSQ_FS_CONTROL_REG_CONSTSTARTOFFSET__SHIFT	12 +static inline uint32_t A3XX_HLSQ_FS_CONTROL_REG_CONSTSTARTOFFSET(uint32_t val) +{ +	return ((val) << A3XX_HLSQ_FS_CONTROL_REG_CONSTSTARTOFFSET__SHIFT) & A3XX_HLSQ_FS_CONTROL_REG_CONSTSTARTOFFSET__MASK; +} +#define A3XX_HLSQ_FS_CONTROL_REG_INSTRLENGTH__MASK		0xff000000 +#define A3XX_HLSQ_FS_CONTROL_REG_INSTRLENGTH__SHIFT		24 +static inline uint32_t A3XX_HLSQ_FS_CONTROL_REG_INSTRLENGTH(uint32_t val) +{ +	return ((val) << A3XX_HLSQ_FS_CONTROL_REG_INSTRLENGTH__SHIFT) & A3XX_HLSQ_FS_CONTROL_REG_INSTRLENGTH__MASK; +} + +#define REG_A3XX_HLSQ_CONST_VSPRESV_RANGE_REG			0x00002206 +#define A3XX_HLSQ_CONST_VSPRESV_RANGE_REG_STARTENTRY__MASK	0x0000ffff +#define A3XX_HLSQ_CONST_VSPRESV_RANGE_REG_STARTENTRY__SHIFT	0 +static inline uint32_t A3XX_HLSQ_CONST_VSPRESV_RANGE_REG_STARTENTRY(uint32_t val) +{ +	return ((val) << A3XX_HLSQ_CONST_VSPRESV_RANGE_REG_STARTENTRY__SHIFT) & A3XX_HLSQ_CONST_VSPRESV_RANGE_REG_STARTENTRY__MASK; +} +#define A3XX_HLSQ_CONST_VSPRESV_RANGE_REG_ENDENTRY__MASK	0xffff0000 +#define A3XX_HLSQ_CONST_VSPRESV_RANGE_REG_ENDENTRY__SHIFT	16 +static inline uint32_t A3XX_HLSQ_CONST_VSPRESV_RANGE_REG_ENDENTRY(uint32_t val) +{ +	return ((val) << A3XX_HLSQ_CONST_VSPRESV_RANGE_REG_ENDENTRY__SHIFT) & A3XX_HLSQ_CONST_VSPRESV_RANGE_REG_ENDENTRY__MASK; +} + +#define REG_A3XX_HLSQ_CONST_FSPRESV_RANGE_REG			0x00002207 +#define A3XX_HLSQ_CONST_FSPRESV_RANGE_REG_STARTENTRY__MASK	0x0000ffff +#define A3XX_HLSQ_CONST_FSPRESV_RANGE_REG_STARTENTRY__SHIFT	0 +static inline uint32_t A3XX_HLSQ_CONST_FSPRESV_RANGE_REG_STARTENTRY(uint32_t val) +{ +	return ((val) << A3XX_HLSQ_CONST_FSPRESV_RANGE_REG_STARTENTRY__SHIFT) & A3XX_HLSQ_CONST_FSPRESV_RANGE_REG_STARTENTRY__MASK; +} +#define A3XX_HLSQ_CONST_FSPRESV_RANGE_REG_ENDENTRY__MASK	0xffff0000 +#define A3XX_HLSQ_CONST_FSPRESV_RANGE_REG_ENDENTRY__SHIFT	16 +static inline uint32_t A3XX_HLSQ_CONST_FSPRESV_RANGE_REG_ENDENTRY(uint32_t val) +{ +	return ((val) << A3XX_HLSQ_CONST_FSPRESV_RANGE_REG_ENDENTRY__SHIFT) & A3XX_HLSQ_CONST_FSPRESV_RANGE_REG_ENDENTRY__MASK; +} + +#define REG_A3XX_HLSQ_CL_NDRANGE_0_REG				0x0000220a + +#define REG_A3XX_HLSQ_CL_NDRANGE_1_REG				0x0000220b + +#define REG_A3XX_HLSQ_CL_NDRANGE_2_REG				0x0000220c + +#define REG_A3XX_HLSQ_CL_CONTROL_0_REG				0x00002211 + +#define REG_A3XX_HLSQ_CL_CONTROL_1_REG				0x00002212 + +#define REG_A3XX_HLSQ_CL_KERNEL_CONST_REG			0x00002214 + +#define REG_A3XX_HLSQ_CL_KERNEL_GROUP_X_REG			0x00002215 + +#define REG_A3XX_HLSQ_CL_KERNEL_GROUP_Y_REG			0x00002216 + +#define REG_A3XX_HLSQ_CL_KERNEL_GROUP_Z_REG			0x00002217 + +#define REG_A3XX_HLSQ_CL_WG_OFFSET_REG				0x0000221a + +#define REG_A3XX_VFD_CONTROL_0					0x00002240 +#define A3XX_VFD_CONTROL_0_TOTALATTRTOVS__MASK			0x0003ffff +#define A3XX_VFD_CONTROL_0_TOTALATTRTOVS__SHIFT			0 +static inline uint32_t A3XX_VFD_CONTROL_0_TOTALATTRTOVS(uint32_t val) +{ +	return ((val) << A3XX_VFD_CONTROL_0_TOTALATTRTOVS__SHIFT) & A3XX_VFD_CONTROL_0_TOTALATTRTOVS__MASK; +} +#define A3XX_VFD_CONTROL_0_PACKETSIZE__MASK			0x003c0000 +#define A3XX_VFD_CONTROL_0_PACKETSIZE__SHIFT			18 +static inline uint32_t A3XX_VFD_CONTROL_0_PACKETSIZE(uint32_t val) +{ +	return ((val) << A3XX_VFD_CONTROL_0_PACKETSIZE__SHIFT) & A3XX_VFD_CONTROL_0_PACKETSIZE__MASK; +} +#define A3XX_VFD_CONTROL_0_STRMDECINSTRCNT__MASK		0x07c00000 +#define A3XX_VFD_CONTROL_0_STRMDECINSTRCNT__SHIFT		22 +static inline uint32_t A3XX_VFD_CONTROL_0_STRMDECINSTRCNT(uint32_t val) +{ +	return ((val) << A3XX_VFD_CONTROL_0_STRMDECINSTRCNT__SHIFT) & A3XX_VFD_CONTROL_0_STRMDECINSTRCNT__MASK; +} +#define A3XX_VFD_CONTROL_0_STRMFETCHINSTRCNT__MASK		0xf8000000 +#define A3XX_VFD_CONTROL_0_STRMFETCHINSTRCNT__SHIFT		27 +static inline uint32_t A3XX_VFD_CONTROL_0_STRMFETCHINSTRCNT(uint32_t val) +{ +	return ((val) << A3XX_VFD_CONTROL_0_STRMFETCHINSTRCNT__SHIFT) & A3XX_VFD_CONTROL_0_STRMFETCHINSTRCNT__MASK; +} + +#define REG_A3XX_VFD_CONTROL_1					0x00002241 +#define A3XX_VFD_CONTROL_1_MAXSTORAGE__MASK			0x0000ffff +#define A3XX_VFD_CONTROL_1_MAXSTORAGE__SHIFT			0 +static inline uint32_t A3XX_VFD_CONTROL_1_MAXSTORAGE(uint32_t val) +{ +	return ((val) << A3XX_VFD_CONTROL_1_MAXSTORAGE__SHIFT) & A3XX_VFD_CONTROL_1_MAXSTORAGE__MASK; +} +#define A3XX_VFD_CONTROL_1_REGID4VTX__MASK			0x00ff0000 +#define A3XX_VFD_CONTROL_1_REGID4VTX__SHIFT			16 +static inline uint32_t A3XX_VFD_CONTROL_1_REGID4VTX(uint32_t val) +{ +	return ((val) << A3XX_VFD_CONTROL_1_REGID4VTX__SHIFT) & A3XX_VFD_CONTROL_1_REGID4VTX__MASK; +} +#define A3XX_VFD_CONTROL_1_REGID4INST__MASK			0xff000000 +#define A3XX_VFD_CONTROL_1_REGID4INST__SHIFT			24 +static inline uint32_t A3XX_VFD_CONTROL_1_REGID4INST(uint32_t val) +{ +	return ((val) << A3XX_VFD_CONTROL_1_REGID4INST__SHIFT) & A3XX_VFD_CONTROL_1_REGID4INST__MASK; +} + +#define REG_A3XX_VFD_INDEX_MIN					0x00002242 + +#define REG_A3XX_VFD_INDEX_MAX					0x00002243 + +#define REG_A3XX_VFD_INSTANCEID_OFFSET				0x00002244 + +#define REG_A3XX_VFD_INDEX_OFFSET				0x00002245 + +static inline uint32_t REG_A3XX_VFD_FETCH(uint32_t i0) { return 0x00002246 + 0x2*i0; } + +static inline uint32_t REG_A3XX_VFD_FETCH_INSTR_0(uint32_t i0) { return 0x00002246 + 0x2*i0; } +#define A3XX_VFD_FETCH_INSTR_0_FETCHSIZE__MASK			0x0000007f +#define A3XX_VFD_FETCH_INSTR_0_FETCHSIZE__SHIFT			0 +static inline uint32_t A3XX_VFD_FETCH_INSTR_0_FETCHSIZE(uint32_t val) +{ +	return ((val) << A3XX_VFD_FETCH_INSTR_0_FETCHSIZE__SHIFT) & A3XX_VFD_FETCH_INSTR_0_FETCHSIZE__MASK; +} +#define A3XX_VFD_FETCH_INSTR_0_BUFSTRIDE__MASK			0x0001ff80 +#define A3XX_VFD_FETCH_INSTR_0_BUFSTRIDE__SHIFT			7 +static inline uint32_t A3XX_VFD_FETCH_INSTR_0_BUFSTRIDE(uint32_t val) +{ +	return ((val) << A3XX_VFD_FETCH_INSTR_0_BUFSTRIDE__SHIFT) & A3XX_VFD_FETCH_INSTR_0_BUFSTRIDE__MASK; +} +#define A3XX_VFD_FETCH_INSTR_0_SWITCHNEXT			0x00020000 +#define A3XX_VFD_FETCH_INSTR_0_INDEXCODE__MASK			0x00fc0000 +#define A3XX_VFD_FETCH_INSTR_0_INDEXCODE__SHIFT			18 +static inline uint32_t A3XX_VFD_FETCH_INSTR_0_INDEXCODE(uint32_t val) +{ +	return ((val) << A3XX_VFD_FETCH_INSTR_0_INDEXCODE__SHIFT) & A3XX_VFD_FETCH_INSTR_0_INDEXCODE__MASK; +} +#define A3XX_VFD_FETCH_INSTR_0_STEPRATE__MASK			0xff000000 +#define A3XX_VFD_FETCH_INSTR_0_STEPRATE__SHIFT			24 +static inline uint32_t A3XX_VFD_FETCH_INSTR_0_STEPRATE(uint32_t val) +{ +	return ((val) << A3XX_VFD_FETCH_INSTR_0_STEPRATE__SHIFT) & A3XX_VFD_FETCH_INSTR_0_STEPRATE__MASK; +} + +static inline uint32_t REG_A3XX_VFD_FETCH_INSTR_1(uint32_t i0) { return 0x00002247 + 0x2*i0; } + +static inline uint32_t REG_A3XX_VFD_DECODE(uint32_t i0) { return 0x00002266 + 0x1*i0; } + +static inline uint32_t REG_A3XX_VFD_DECODE_INSTR(uint32_t i0) { return 0x00002266 + 0x1*i0; } +#define A3XX_VFD_DECODE_INSTR_WRITEMASK__MASK			0x0000000f +#define A3XX_VFD_DECODE_INSTR_WRITEMASK__SHIFT			0 +static inline uint32_t A3XX_VFD_DECODE_INSTR_WRITEMASK(uint32_t val) +{ +	return ((val) << A3XX_VFD_DECODE_INSTR_WRITEMASK__SHIFT) & A3XX_VFD_DECODE_INSTR_WRITEMASK__MASK; +} +#define A3XX_VFD_DECODE_INSTR_CONSTFILL				0x00000010 +#define A3XX_VFD_DECODE_INSTR_FORMAT__MASK			0x00000fc0 +#define A3XX_VFD_DECODE_INSTR_FORMAT__SHIFT			6 +static inline uint32_t A3XX_VFD_DECODE_INSTR_FORMAT(enum a3xx_vtx_fmt val) +{ +	return ((val) << A3XX_VFD_DECODE_INSTR_FORMAT__SHIFT) & A3XX_VFD_DECODE_INSTR_FORMAT__MASK; +} +#define A3XX_VFD_DECODE_INSTR_REGID__MASK			0x000ff000 +#define A3XX_VFD_DECODE_INSTR_REGID__SHIFT			12 +static inline uint32_t A3XX_VFD_DECODE_INSTR_REGID(uint32_t val) +{ +	return ((val) << A3XX_VFD_DECODE_INSTR_REGID__SHIFT) & A3XX_VFD_DECODE_INSTR_REGID__MASK; +} +#define A3XX_VFD_DECODE_INSTR_SHIFTCNT__MASK			0x1f000000 +#define A3XX_VFD_DECODE_INSTR_SHIFTCNT__SHIFT			24 +static inline uint32_t A3XX_VFD_DECODE_INSTR_SHIFTCNT(uint32_t val) +{ +	return ((val) << A3XX_VFD_DECODE_INSTR_SHIFTCNT__SHIFT) & A3XX_VFD_DECODE_INSTR_SHIFTCNT__MASK; +} +#define A3XX_VFD_DECODE_INSTR_LASTCOMPVALID			0x20000000 +#define A3XX_VFD_DECODE_INSTR_SWITCHNEXT			0x40000000 + +#define REG_A3XX_VFD_VS_THREADING_THRESHOLD			0x0000227e +#define A3XX_VFD_VS_THREADING_THRESHOLD_REGID_THRESHOLD__MASK	0x0000000f +#define A3XX_VFD_VS_THREADING_THRESHOLD_REGID_THRESHOLD__SHIFT	0 +static inline uint32_t A3XX_VFD_VS_THREADING_THRESHOLD_REGID_THRESHOLD(uint32_t val) +{ +	return ((val) << A3XX_VFD_VS_THREADING_THRESHOLD_REGID_THRESHOLD__SHIFT) & A3XX_VFD_VS_THREADING_THRESHOLD_REGID_THRESHOLD__MASK; +} +#define A3XX_VFD_VS_THREADING_THRESHOLD_REGID_VTXCNT__MASK	0x0000ff00 +#define A3XX_VFD_VS_THREADING_THRESHOLD_REGID_VTXCNT__SHIFT	8 +static inline uint32_t A3XX_VFD_VS_THREADING_THRESHOLD_REGID_VTXCNT(uint32_t val) +{ +	return ((val) << A3XX_VFD_VS_THREADING_THRESHOLD_REGID_VTXCNT__SHIFT) & A3XX_VFD_VS_THREADING_THRESHOLD_REGID_VTXCNT__MASK; +} + +#define REG_A3XX_VPC_ATTR					0x00002280 +#define A3XX_VPC_ATTR_TOTALATTR__MASK				0x00000fff +#define A3XX_VPC_ATTR_TOTALATTR__SHIFT				0 +static inline uint32_t A3XX_VPC_ATTR_TOTALATTR(uint32_t val) +{ +	return ((val) << A3XX_VPC_ATTR_TOTALATTR__SHIFT) & A3XX_VPC_ATTR_TOTALATTR__MASK; +} +#define A3XX_VPC_ATTR_THRDASSIGN__MASK				0x0ffff000 +#define A3XX_VPC_ATTR_THRDASSIGN__SHIFT				12 +static inline uint32_t A3XX_VPC_ATTR_THRDASSIGN(uint32_t val) +{ +	return ((val) << A3XX_VPC_ATTR_THRDASSIGN__SHIFT) & A3XX_VPC_ATTR_THRDASSIGN__MASK; +} +#define A3XX_VPC_ATTR_LMSIZE__MASK				0xf0000000 +#define A3XX_VPC_ATTR_LMSIZE__SHIFT				28 +static inline uint32_t A3XX_VPC_ATTR_LMSIZE(uint32_t val) +{ +	return ((val) << A3XX_VPC_ATTR_LMSIZE__SHIFT) & A3XX_VPC_ATTR_LMSIZE__MASK; +} + +#define REG_A3XX_VPC_PACK					0x00002281 +#define A3XX_VPC_PACK_NUMFPNONPOSVAR__MASK			0x0000ff00 +#define A3XX_VPC_PACK_NUMFPNONPOSVAR__SHIFT			8 +static inline uint32_t A3XX_VPC_PACK_NUMFPNONPOSVAR(uint32_t val) +{ +	return ((val) << A3XX_VPC_PACK_NUMFPNONPOSVAR__SHIFT) & A3XX_VPC_PACK_NUMFPNONPOSVAR__MASK; +} +#define A3XX_VPC_PACK_NUMNONPOSVSVAR__MASK			0x00ff0000 +#define A3XX_VPC_PACK_NUMNONPOSVSVAR__SHIFT			16 +static inline uint32_t A3XX_VPC_PACK_NUMNONPOSVSVAR(uint32_t val) +{ +	return ((val) << A3XX_VPC_PACK_NUMNONPOSVSVAR__SHIFT) & A3XX_VPC_PACK_NUMNONPOSVSVAR__MASK; +} + +static inline uint32_t REG_A3XX_VPC_VARYING_INTERP(uint32_t i0) { return 0x00002282 + 0x1*i0; } + +static inline uint32_t REG_A3XX_VPC_VARYING_INTERP_MODE(uint32_t i0) { return 0x00002282 + 0x1*i0; } + +static inline uint32_t REG_A3XX_VPC_VARYING_PS_REPL(uint32_t i0) { return 0x00002286 + 0x1*i0; } + +static inline uint32_t REG_A3XX_VPC_VARYING_PS_REPL_MODE(uint32_t i0) { return 0x00002286 + 0x1*i0; } + +#define REG_A3XX_VPC_VARY_CYLWRAP_ENABLE_0			0x0000228a + +#define REG_A3XX_VPC_VARY_CYLWRAP_ENABLE_1			0x0000228b + +#define REG_A3XX_SP_SP_CTRL_REG					0x000022c0 +#define A3XX_SP_SP_CTRL_REG_RESOLVE				0x00010000 +#define A3XX_SP_SP_CTRL_REG_CONSTMODE__MASK			0x00040000 +#define A3XX_SP_SP_CTRL_REG_CONSTMODE__SHIFT			18 +static inline uint32_t A3XX_SP_SP_CTRL_REG_CONSTMODE(uint32_t val) +{ +	return ((val) << A3XX_SP_SP_CTRL_REG_CONSTMODE__SHIFT) & A3XX_SP_SP_CTRL_REG_CONSTMODE__MASK; +} +#define A3XX_SP_SP_CTRL_REG_BINNING				0x00080000 +#define A3XX_SP_SP_CTRL_REG_SLEEPMODE__MASK			0x00300000 +#define A3XX_SP_SP_CTRL_REG_SLEEPMODE__SHIFT			20 +static inline uint32_t A3XX_SP_SP_CTRL_REG_SLEEPMODE(uint32_t val) +{ +	return ((val) << A3XX_SP_SP_CTRL_REG_SLEEPMODE__SHIFT) & A3XX_SP_SP_CTRL_REG_SLEEPMODE__MASK; +} +#define A3XX_SP_SP_CTRL_REG_LOMODE__MASK			0x00c00000 +#define A3XX_SP_SP_CTRL_REG_LOMODE__SHIFT			22 +static inline uint32_t A3XX_SP_SP_CTRL_REG_LOMODE(uint32_t val) +{ +	return ((val) << A3XX_SP_SP_CTRL_REG_LOMODE__SHIFT) & A3XX_SP_SP_CTRL_REG_LOMODE__MASK; +} + +#define REG_A3XX_SP_VS_CTRL_REG0				0x000022c4 +#define A3XX_SP_VS_CTRL_REG0_THREADMODE__MASK			0x00000001 +#define A3XX_SP_VS_CTRL_REG0_THREADMODE__SHIFT			0 +static inline uint32_t A3XX_SP_VS_CTRL_REG0_THREADMODE(enum a3xx_threadmode val) +{ +	return ((val) << A3XX_SP_VS_CTRL_REG0_THREADMODE__SHIFT) & A3XX_SP_VS_CTRL_REG0_THREADMODE__MASK; +} +#define A3XX_SP_VS_CTRL_REG0_INSTRBUFFERMODE__MASK		0x00000002 +#define A3XX_SP_VS_CTRL_REG0_INSTRBUFFERMODE__SHIFT		1 +static inline uint32_t A3XX_SP_VS_CTRL_REG0_INSTRBUFFERMODE(enum a3xx_instrbuffermode val) +{ +	return ((val) << A3XX_SP_VS_CTRL_REG0_INSTRBUFFERMODE__SHIFT) & A3XX_SP_VS_CTRL_REG0_INSTRBUFFERMODE__MASK; +} +#define A3XX_SP_VS_CTRL_REG0_CACHEINVALID			0x00000004 +#define A3XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT__MASK		0x000003f0 +#define A3XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT		4 +static inline uint32_t A3XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT(uint32_t val) +{ +	return ((val) << A3XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT) & A3XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT__MASK; +} +#define A3XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT__MASK		0x0003fc00 +#define A3XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT		10 +static inline uint32_t A3XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT(uint32_t val) +{ +	return ((val) << A3XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT) & A3XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT__MASK; +} +#define A3XX_SP_VS_CTRL_REG0_INOUTREGOVERLAP__MASK		0x000c0000 +#define A3XX_SP_VS_CTRL_REG0_INOUTREGOVERLAP__SHIFT		18 +static inline uint32_t A3XX_SP_VS_CTRL_REG0_INOUTREGOVERLAP(uint32_t val) +{ +	return ((val) << A3XX_SP_VS_CTRL_REG0_INOUTREGOVERLAP__SHIFT) & A3XX_SP_VS_CTRL_REG0_INOUTREGOVERLAP__MASK; +} +#define A3XX_SP_VS_CTRL_REG0_THREADSIZE__MASK			0x00100000 +#define A3XX_SP_VS_CTRL_REG0_THREADSIZE__SHIFT			20 +static inline uint32_t A3XX_SP_VS_CTRL_REG0_THREADSIZE(enum a3xx_threadsize val) +{ +	return ((val) << A3XX_SP_VS_CTRL_REG0_THREADSIZE__SHIFT) & A3XX_SP_VS_CTRL_REG0_THREADSIZE__MASK; +} +#define A3XX_SP_VS_CTRL_REG0_SUPERTHREADMODE			0x00200000 +#define A3XX_SP_VS_CTRL_REG0_PIXLODENABLE			0x00400000 +#define A3XX_SP_VS_CTRL_REG0_LENGTH__MASK			0xff000000 +#define A3XX_SP_VS_CTRL_REG0_LENGTH__SHIFT			24 +static inline uint32_t A3XX_SP_VS_CTRL_REG0_LENGTH(uint32_t val) +{ +	return ((val) << A3XX_SP_VS_CTRL_REG0_LENGTH__SHIFT) & A3XX_SP_VS_CTRL_REG0_LENGTH__MASK; +} + +#define REG_A3XX_SP_VS_CTRL_REG1				0x000022c5 +#define A3XX_SP_VS_CTRL_REG1_CONSTLENGTH__MASK			0x000003ff +#define A3XX_SP_VS_CTRL_REG1_CONSTLENGTH__SHIFT			0 +static inline uint32_t A3XX_SP_VS_CTRL_REG1_CONSTLENGTH(uint32_t val) +{ +	return ((val) << A3XX_SP_VS_CTRL_REG1_CONSTLENGTH__SHIFT) & A3XX_SP_VS_CTRL_REG1_CONSTLENGTH__MASK; +} +#define A3XX_SP_VS_CTRL_REG1_CONSTFOOTPRINT__MASK		0x000ffc00 +#define A3XX_SP_VS_CTRL_REG1_CONSTFOOTPRINT__SHIFT		10 +static inline uint32_t A3XX_SP_VS_CTRL_REG1_CONSTFOOTPRINT(uint32_t val) +{ +	return ((val) << A3XX_SP_VS_CTRL_REG1_CONSTFOOTPRINT__SHIFT) & A3XX_SP_VS_CTRL_REG1_CONSTFOOTPRINT__MASK; +} +#define A3XX_SP_VS_CTRL_REG1_INITIALOUTSTANDING__MASK		0x3f000000 +#define A3XX_SP_VS_CTRL_REG1_INITIALOUTSTANDING__SHIFT		24 +static inline uint32_t A3XX_SP_VS_CTRL_REG1_INITIALOUTSTANDING(uint32_t val) +{ +	return ((val) << A3XX_SP_VS_CTRL_REG1_INITIALOUTSTANDING__SHIFT) & A3XX_SP_VS_CTRL_REG1_INITIALOUTSTANDING__MASK; +} + +#define REG_A3XX_SP_VS_PARAM_REG				0x000022c6 +#define A3XX_SP_VS_PARAM_REG_POSREGID__MASK			0x000000ff +#define A3XX_SP_VS_PARAM_REG_POSREGID__SHIFT			0 +static inline uint32_t A3XX_SP_VS_PARAM_REG_POSREGID(uint32_t val) +{ +	return ((val) << A3XX_SP_VS_PARAM_REG_POSREGID__SHIFT) & A3XX_SP_VS_PARAM_REG_POSREGID__MASK; +} +#define A3XX_SP_VS_PARAM_REG_PSIZEREGID__MASK			0x0000ff00 +#define A3XX_SP_VS_PARAM_REG_PSIZEREGID__SHIFT			8 +static inline uint32_t A3XX_SP_VS_PARAM_REG_PSIZEREGID(uint32_t val) +{ +	return ((val) << A3XX_SP_VS_PARAM_REG_PSIZEREGID__SHIFT) & A3XX_SP_VS_PARAM_REG_PSIZEREGID__MASK; +} +#define A3XX_SP_VS_PARAM_REG_TOTALVSOUTVAR__MASK		0xfff00000 +#define A3XX_SP_VS_PARAM_REG_TOTALVSOUTVAR__SHIFT		20 +static inline uint32_t A3XX_SP_VS_PARAM_REG_TOTALVSOUTVAR(uint32_t val) +{ +	return ((val) << A3XX_SP_VS_PARAM_REG_TOTALVSOUTVAR__SHIFT) & A3XX_SP_VS_PARAM_REG_TOTALVSOUTVAR__MASK; +} + +static inline uint32_t REG_A3XX_SP_VS_OUT(uint32_t i0) { return 0x000022c7 + 0x1*i0; } + +static inline uint32_t REG_A3XX_SP_VS_OUT_REG(uint32_t i0) { return 0x000022c7 + 0x1*i0; } +#define A3XX_SP_VS_OUT_REG_A_REGID__MASK			0x000001ff +#define A3XX_SP_VS_OUT_REG_A_REGID__SHIFT			0 +static inline uint32_t A3XX_SP_VS_OUT_REG_A_REGID(uint32_t val) +{ +	return ((val) << A3XX_SP_VS_OUT_REG_A_REGID__SHIFT) & A3XX_SP_VS_OUT_REG_A_REGID__MASK; +} +#define A3XX_SP_VS_OUT_REG_A_COMPMASK__MASK			0x00001e00 +#define A3XX_SP_VS_OUT_REG_A_COMPMASK__SHIFT			9 +static inline uint32_t A3XX_SP_VS_OUT_REG_A_COMPMASK(uint32_t val) +{ +	return ((val) << A3XX_SP_VS_OUT_REG_A_COMPMASK__SHIFT) & A3XX_SP_VS_OUT_REG_A_COMPMASK__MASK; +} +#define A3XX_SP_VS_OUT_REG_B_REGID__MASK			0x01ff0000 +#define A3XX_SP_VS_OUT_REG_B_REGID__SHIFT			16 +static inline uint32_t A3XX_SP_VS_OUT_REG_B_REGID(uint32_t val) +{ +	return ((val) << A3XX_SP_VS_OUT_REG_B_REGID__SHIFT) & A3XX_SP_VS_OUT_REG_B_REGID__MASK; +} +#define A3XX_SP_VS_OUT_REG_B_COMPMASK__MASK			0x1e000000 +#define A3XX_SP_VS_OUT_REG_B_COMPMASK__SHIFT			25 +static inline uint32_t A3XX_SP_VS_OUT_REG_B_COMPMASK(uint32_t val) +{ +	return ((val) << A3XX_SP_VS_OUT_REG_B_COMPMASK__SHIFT) & A3XX_SP_VS_OUT_REG_B_COMPMASK__MASK; +} + +static inline uint32_t REG_A3XX_SP_VS_VPC_DST(uint32_t i0) { return 0x000022d0 + 0x1*i0; } + +static inline uint32_t REG_A3XX_SP_VS_VPC_DST_REG(uint32_t i0) { return 0x000022d0 + 0x1*i0; } +#define A3XX_SP_VS_VPC_DST_REG_OUTLOC0__MASK			0x000000ff +#define A3XX_SP_VS_VPC_DST_REG_OUTLOC0__SHIFT			0 +static inline uint32_t A3XX_SP_VS_VPC_DST_REG_OUTLOC0(uint32_t val) +{ +	return ((val) << A3XX_SP_VS_VPC_DST_REG_OUTLOC0__SHIFT) & A3XX_SP_VS_VPC_DST_REG_OUTLOC0__MASK; +} +#define A3XX_SP_VS_VPC_DST_REG_OUTLOC1__MASK			0x0000ff00 +#define A3XX_SP_VS_VPC_DST_REG_OUTLOC1__SHIFT			8 +static inline uint32_t A3XX_SP_VS_VPC_DST_REG_OUTLOC1(uint32_t val) +{ +	return ((val) << A3XX_SP_VS_VPC_DST_REG_OUTLOC1__SHIFT) & A3XX_SP_VS_VPC_DST_REG_OUTLOC1__MASK; +} +#define A3XX_SP_VS_VPC_DST_REG_OUTLOC2__MASK			0x00ff0000 +#define A3XX_SP_VS_VPC_DST_REG_OUTLOC2__SHIFT			16 +static inline uint32_t A3XX_SP_VS_VPC_DST_REG_OUTLOC2(uint32_t val) +{ +	return ((val) << A3XX_SP_VS_VPC_DST_REG_OUTLOC2__SHIFT) & A3XX_SP_VS_VPC_DST_REG_OUTLOC2__MASK; +} +#define A3XX_SP_VS_VPC_DST_REG_OUTLOC3__MASK			0xff000000 +#define A3XX_SP_VS_VPC_DST_REG_OUTLOC3__SHIFT			24 +static inline uint32_t A3XX_SP_VS_VPC_DST_REG_OUTLOC3(uint32_t val) +{ +	return ((val) << A3XX_SP_VS_VPC_DST_REG_OUTLOC3__SHIFT) & A3XX_SP_VS_VPC_DST_REG_OUTLOC3__MASK; +} + +#define REG_A3XX_SP_VS_OBJ_OFFSET_REG				0x000022d4 +#define A3XX_SP_VS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK	0x01ff0000 +#define A3XX_SP_VS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__SHIFT	16 +static inline uint32_t A3XX_SP_VS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET(uint32_t val) +{ +	return ((val) << A3XX_SP_VS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__SHIFT) & A3XX_SP_VS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK; +} +#define A3XX_SP_VS_OBJ_OFFSET_REG_SHADEROBJOFFSET__MASK		0xfe000000 +#define A3XX_SP_VS_OBJ_OFFSET_REG_SHADEROBJOFFSET__SHIFT	25 +static inline uint32_t A3XX_SP_VS_OBJ_OFFSET_REG_SHADEROBJOFFSET(uint32_t val) +{ +	return ((val) << A3XX_SP_VS_OBJ_OFFSET_REG_SHADEROBJOFFSET__SHIFT) & A3XX_SP_VS_OBJ_OFFSET_REG_SHADEROBJOFFSET__MASK; +} + +#define REG_A3XX_SP_VS_OBJ_START_REG				0x000022d5 + +#define REG_A3XX_SP_VS_PVT_MEM_PARAM_REG			0x000022d6 + +#define REG_A3XX_SP_VS_PVT_MEM_ADDR_REG				0x000022d7 + +#define REG_A3XX_SP_VS_PVT_MEM_SIZE_REG				0x000022d8 + +#define REG_A3XX_SP_VS_LENGTH_REG				0x000022df +#define A3XX_SP_VS_LENGTH_REG_SHADERLENGTH__MASK		0xffffffff +#define A3XX_SP_VS_LENGTH_REG_SHADERLENGTH__SHIFT		0 +static inline uint32_t A3XX_SP_VS_LENGTH_REG_SHADERLENGTH(uint32_t val) +{ +	return ((val) << A3XX_SP_VS_LENGTH_REG_SHADERLENGTH__SHIFT) & A3XX_SP_VS_LENGTH_REG_SHADERLENGTH__MASK; +} + +#define REG_A3XX_SP_FS_CTRL_REG0				0x000022e0 +#define A3XX_SP_FS_CTRL_REG0_THREADMODE__MASK			0x00000001 +#define A3XX_SP_FS_CTRL_REG0_THREADMODE__SHIFT			0 +static inline uint32_t A3XX_SP_FS_CTRL_REG0_THREADMODE(enum a3xx_threadmode val) +{ +	return ((val) << A3XX_SP_FS_CTRL_REG0_THREADMODE__SHIFT) & A3XX_SP_FS_CTRL_REG0_THREADMODE__MASK; +} +#define A3XX_SP_FS_CTRL_REG0_INSTRBUFFERMODE__MASK		0x00000002 +#define A3XX_SP_FS_CTRL_REG0_INSTRBUFFERMODE__SHIFT		1 +static inline uint32_t A3XX_SP_FS_CTRL_REG0_INSTRBUFFERMODE(enum a3xx_instrbuffermode val) +{ +	return ((val) << A3XX_SP_FS_CTRL_REG0_INSTRBUFFERMODE__SHIFT) & A3XX_SP_FS_CTRL_REG0_INSTRBUFFERMODE__MASK; +} +#define A3XX_SP_FS_CTRL_REG0_CACHEINVALID			0x00000004 +#define A3XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT__MASK		0x000003f0 +#define A3XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT		4 +static inline uint32_t A3XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT(uint32_t val) +{ +	return ((val) << A3XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT) & A3XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT__MASK; +} +#define A3XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT__MASK		0x0003fc00 +#define A3XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT		10 +static inline uint32_t A3XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT(uint32_t val) +{ +	return ((val) << A3XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT) & A3XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT__MASK; +} +#define A3XX_SP_FS_CTRL_REG0_INOUTREGOVERLAP__MASK		0x000c0000 +#define A3XX_SP_FS_CTRL_REG0_INOUTREGOVERLAP__SHIFT		18 +static inline uint32_t A3XX_SP_FS_CTRL_REG0_INOUTREGOVERLAP(uint32_t val) +{ +	return ((val) << A3XX_SP_FS_CTRL_REG0_INOUTREGOVERLAP__SHIFT) & A3XX_SP_FS_CTRL_REG0_INOUTREGOVERLAP__MASK; +} +#define A3XX_SP_FS_CTRL_REG0_THREADSIZE__MASK			0x00100000 +#define A3XX_SP_FS_CTRL_REG0_THREADSIZE__SHIFT			20 +static inline uint32_t A3XX_SP_FS_CTRL_REG0_THREADSIZE(enum a3xx_threadsize val) +{ +	return ((val) << A3XX_SP_FS_CTRL_REG0_THREADSIZE__SHIFT) & A3XX_SP_FS_CTRL_REG0_THREADSIZE__MASK; +} +#define A3XX_SP_FS_CTRL_REG0_SUPERTHREADMODE			0x00200000 +#define A3XX_SP_FS_CTRL_REG0_PIXLODENABLE			0x00400000 +#define A3XX_SP_FS_CTRL_REG0_LENGTH__MASK			0xff000000 +#define A3XX_SP_FS_CTRL_REG0_LENGTH__SHIFT			24 +static inline uint32_t A3XX_SP_FS_CTRL_REG0_LENGTH(uint32_t val) +{ +	return ((val) << A3XX_SP_FS_CTRL_REG0_LENGTH__SHIFT) & A3XX_SP_FS_CTRL_REG0_LENGTH__MASK; +} + +#define REG_A3XX_SP_FS_CTRL_REG1				0x000022e1 +#define A3XX_SP_FS_CTRL_REG1_CONSTLENGTH__MASK			0x000003ff +#define A3XX_SP_FS_CTRL_REG1_CONSTLENGTH__SHIFT			0 +static inline uint32_t A3XX_SP_FS_CTRL_REG1_CONSTLENGTH(uint32_t val) +{ +	return ((val) << A3XX_SP_FS_CTRL_REG1_CONSTLENGTH__SHIFT) & A3XX_SP_FS_CTRL_REG1_CONSTLENGTH__MASK; +} +#define A3XX_SP_FS_CTRL_REG1_CONSTFOOTPRINT__MASK		0x000ffc00 +#define A3XX_SP_FS_CTRL_REG1_CONSTFOOTPRINT__SHIFT		10 +static inline uint32_t A3XX_SP_FS_CTRL_REG1_CONSTFOOTPRINT(uint32_t val) +{ +	return ((val) << A3XX_SP_FS_CTRL_REG1_CONSTFOOTPRINT__SHIFT) & A3XX_SP_FS_CTRL_REG1_CONSTFOOTPRINT__MASK; +} +#define A3XX_SP_FS_CTRL_REG1_INITIALOUTSTANDING__MASK		0x00f00000 +#define A3XX_SP_FS_CTRL_REG1_INITIALOUTSTANDING__SHIFT		20 +static inline uint32_t A3XX_SP_FS_CTRL_REG1_INITIALOUTSTANDING(uint32_t val) +{ +	return ((val) << A3XX_SP_FS_CTRL_REG1_INITIALOUTSTANDING__SHIFT) & A3XX_SP_FS_CTRL_REG1_INITIALOUTSTANDING__MASK; +} +#define A3XX_SP_FS_CTRL_REG1_HALFPRECVAROFFSET__MASK		0x3f000000 +#define A3XX_SP_FS_CTRL_REG1_HALFPRECVAROFFSET__SHIFT		24 +static inline uint32_t A3XX_SP_FS_CTRL_REG1_HALFPRECVAROFFSET(uint32_t val) +{ +	return ((val) << A3XX_SP_FS_CTRL_REG1_HALFPRECVAROFFSET__SHIFT) & A3XX_SP_FS_CTRL_REG1_HALFPRECVAROFFSET__MASK; +} + +#define REG_A3XX_SP_FS_OBJ_OFFSET_REG				0x000022e2 +#define A3XX_SP_FS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK	0x01ff0000 +#define A3XX_SP_FS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__SHIFT	16 +static inline uint32_t A3XX_SP_FS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET(uint32_t val) +{ +	return ((val) << A3XX_SP_FS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__SHIFT) & A3XX_SP_FS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK; +} +#define A3XX_SP_FS_OBJ_OFFSET_REG_SHADEROBJOFFSET__MASK		0xfe000000 +#define A3XX_SP_FS_OBJ_OFFSET_REG_SHADEROBJOFFSET__SHIFT	25 +static inline uint32_t A3XX_SP_FS_OBJ_OFFSET_REG_SHADEROBJOFFSET(uint32_t val) +{ +	return ((val) << A3XX_SP_FS_OBJ_OFFSET_REG_SHADEROBJOFFSET__SHIFT) & A3XX_SP_FS_OBJ_OFFSET_REG_SHADEROBJOFFSET__MASK; +} + +#define REG_A3XX_SP_FS_OBJ_START_REG				0x000022e3 + +#define REG_A3XX_SP_FS_PVT_MEM_PARAM_REG			0x000022e4 + +#define REG_A3XX_SP_FS_PVT_MEM_ADDR_REG				0x000022e5 + +#define REG_A3XX_SP_FS_PVT_MEM_SIZE_REG				0x000022e6 + +#define REG_A3XX_SP_FS_FLAT_SHAD_MODE_REG_0			0x000022e8 + +#define REG_A3XX_SP_FS_FLAT_SHAD_MODE_REG_1			0x000022e9 + +#define REG_A3XX_SP_FS_OUTPUT_REG				0x000022ec + +static inline uint32_t REG_A3XX_SP_FS_MRT(uint32_t i0) { return 0x000022f0 + 0x1*i0; } + +static inline uint32_t REG_A3XX_SP_FS_MRT_REG(uint32_t i0) { return 0x000022f0 + 0x1*i0; } +#define A3XX_SP_FS_MRT_REG_REGID__MASK				0x000000ff +#define A3XX_SP_FS_MRT_REG_REGID__SHIFT				0 +static inline uint32_t A3XX_SP_FS_MRT_REG_REGID(uint32_t val) +{ +	return ((val) << A3XX_SP_FS_MRT_REG_REGID__SHIFT) & A3XX_SP_FS_MRT_REG_REGID__MASK; +} +#define A3XX_SP_FS_MRT_REG_HALF_PRECISION			0x00000100 + +static inline uint32_t REG_A3XX_SP_FS_IMAGE_OUTPUT(uint32_t i0) { return 0x000022f4 + 0x1*i0; } + +static inline uint32_t REG_A3XX_SP_FS_IMAGE_OUTPUT_REG(uint32_t i0) { return 0x000022f4 + 0x1*i0; } +#define A3XX_SP_FS_IMAGE_OUTPUT_REG_MRTFORMAT__MASK		0x0000003f +#define A3XX_SP_FS_IMAGE_OUTPUT_REG_MRTFORMAT__SHIFT		0 +static inline uint32_t A3XX_SP_FS_IMAGE_OUTPUT_REG_MRTFORMAT(enum a3xx_color_fmt val) +{ +	return ((val) << A3XX_SP_FS_IMAGE_OUTPUT_REG_MRTFORMAT__SHIFT) & A3XX_SP_FS_IMAGE_OUTPUT_REG_MRTFORMAT__MASK; +} + +#define REG_A3XX_SP_FS_LENGTH_REG				0x000022ff +#define A3XX_SP_FS_LENGTH_REG_SHADERLENGTH__MASK		0xffffffff +#define A3XX_SP_FS_LENGTH_REG_SHADERLENGTH__SHIFT		0 +static inline uint32_t A3XX_SP_FS_LENGTH_REG_SHADERLENGTH(uint32_t val) +{ +	return ((val) << A3XX_SP_FS_LENGTH_REG_SHADERLENGTH__SHIFT) & A3XX_SP_FS_LENGTH_REG_SHADERLENGTH__MASK; +} + +#define REG_A3XX_TPL1_TP_VS_TEX_OFFSET				0x00002340 +#define A3XX_TPL1_TP_VS_TEX_OFFSET_SAMPLEROFFSET__MASK		0x000000ff +#define A3XX_TPL1_TP_VS_TEX_OFFSET_SAMPLEROFFSET__SHIFT		0 +static inline uint32_t A3XX_TPL1_TP_VS_TEX_OFFSET_SAMPLEROFFSET(uint32_t val) +{ +	return ((val) << A3XX_TPL1_TP_VS_TEX_OFFSET_SAMPLEROFFSET__SHIFT) & A3XX_TPL1_TP_VS_TEX_OFFSET_SAMPLEROFFSET__MASK; +} +#define A3XX_TPL1_TP_VS_TEX_OFFSET_MEMOBJOFFSET__MASK		0x0000ff00 +#define A3XX_TPL1_TP_VS_TEX_OFFSET_MEMOBJOFFSET__SHIFT		8 +static inline uint32_t A3XX_TPL1_TP_VS_TEX_OFFSET_MEMOBJOFFSET(uint32_t val) +{ +	return ((val) << A3XX_TPL1_TP_VS_TEX_OFFSET_MEMOBJOFFSET__SHIFT) & A3XX_TPL1_TP_VS_TEX_OFFSET_MEMOBJOFFSET__MASK; +} +#define A3XX_TPL1_TP_VS_TEX_OFFSET_BASETABLEPTR__MASK		0xffff0000 +#define A3XX_TPL1_TP_VS_TEX_OFFSET_BASETABLEPTR__SHIFT		16 +static inline uint32_t A3XX_TPL1_TP_VS_TEX_OFFSET_BASETABLEPTR(uint32_t val) +{ +	return ((val) << A3XX_TPL1_TP_VS_TEX_OFFSET_BASETABLEPTR__SHIFT) & A3XX_TPL1_TP_VS_TEX_OFFSET_BASETABLEPTR__MASK; +} + +#define REG_A3XX_TPL1_TP_VS_BORDER_COLOR_BASE_ADDR		0x00002341 + +#define REG_A3XX_TPL1_TP_FS_TEX_OFFSET				0x00002342 +#define A3XX_TPL1_TP_FS_TEX_OFFSET_SAMPLEROFFSET__MASK		0x000000ff +#define A3XX_TPL1_TP_FS_TEX_OFFSET_SAMPLEROFFSET__SHIFT		0 +static inline uint32_t A3XX_TPL1_TP_FS_TEX_OFFSET_SAMPLEROFFSET(uint32_t val) +{ +	return ((val) << A3XX_TPL1_TP_FS_TEX_OFFSET_SAMPLEROFFSET__SHIFT) & A3XX_TPL1_TP_FS_TEX_OFFSET_SAMPLEROFFSET__MASK; +} +#define A3XX_TPL1_TP_FS_TEX_OFFSET_MEMOBJOFFSET__MASK		0x0000ff00 +#define A3XX_TPL1_TP_FS_TEX_OFFSET_MEMOBJOFFSET__SHIFT		8 +static inline uint32_t A3XX_TPL1_TP_FS_TEX_OFFSET_MEMOBJOFFSET(uint32_t val) +{ +	return ((val) << A3XX_TPL1_TP_FS_TEX_OFFSET_MEMOBJOFFSET__SHIFT) & A3XX_TPL1_TP_FS_TEX_OFFSET_MEMOBJOFFSET__MASK; +} +#define A3XX_TPL1_TP_FS_TEX_OFFSET_BASETABLEPTR__MASK		0xffff0000 +#define A3XX_TPL1_TP_FS_TEX_OFFSET_BASETABLEPTR__SHIFT		16 +static inline uint32_t A3XX_TPL1_TP_FS_TEX_OFFSET_BASETABLEPTR(uint32_t val) +{ +	return ((val) << A3XX_TPL1_TP_FS_TEX_OFFSET_BASETABLEPTR__SHIFT) & A3XX_TPL1_TP_FS_TEX_OFFSET_BASETABLEPTR__MASK; +} + +#define REG_A3XX_TPL1_TP_FS_BORDER_COLOR_BASE_ADDR		0x00002343 + +#define REG_A3XX_VBIF_CLKON					0x00003001 + +#define REG_A3XX_VBIF_FIXED_SORT_EN				0x0000300c + +#define REG_A3XX_VBIF_FIXED_SORT_SEL0				0x0000300d + +#define REG_A3XX_VBIF_FIXED_SORT_SEL1				0x0000300e + +#define REG_A3XX_VBIF_ABIT_SORT					0x0000301c + +#define REG_A3XX_VBIF_ABIT_SORT_CONF				0x0000301d + +#define REG_A3XX_VBIF_GATE_OFF_WRREQ_EN				0x0000302a + +#define REG_A3XX_VBIF_IN_RD_LIM_CONF0				0x0000302c + +#define REG_A3XX_VBIF_IN_RD_LIM_CONF1				0x0000302d + +#define REG_A3XX_VBIF_IN_WR_LIM_CONF0				0x00003030 + +#define REG_A3XX_VBIF_IN_WR_LIM_CONF1				0x00003031 + +#define REG_A3XX_VBIF_OUT_RD_LIM_CONF0				0x00003034 + +#define REG_A3XX_VBIF_OUT_WR_LIM_CONF0				0x00003035 + +#define REG_A3XX_VBIF_DDR_OUT_MAX_BURST				0x00003036 + +#define REG_A3XX_VBIF_ARB_CTL					0x0000303c + +#define REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB			0x00003049 + +#define REG_A3XX_VBIF_OUT_AXI_AMEMTYPE_CONF0			0x00003058 + +#define REG_A3XX_VBIF_OUT_AXI_AOOO_EN				0x0000305e + +#define REG_A3XX_VBIF_OUT_AXI_AOOO				0x0000305f + +#define REG_A3XX_VSC_BIN_SIZE					0x00000c01 +#define A3XX_VSC_BIN_SIZE_WIDTH__MASK				0x0000001f +#define A3XX_VSC_BIN_SIZE_WIDTH__SHIFT				0 +static inline uint32_t A3XX_VSC_BIN_SIZE_WIDTH(uint32_t val) +{ +	return ((val >> 5) << A3XX_VSC_BIN_SIZE_WIDTH__SHIFT) & A3XX_VSC_BIN_SIZE_WIDTH__MASK; +} +#define A3XX_VSC_BIN_SIZE_HEIGHT__MASK				0x000003e0 +#define A3XX_VSC_BIN_SIZE_HEIGHT__SHIFT				5 +static inline uint32_t A3XX_VSC_BIN_SIZE_HEIGHT(uint32_t val) +{ +	return ((val >> 5) << A3XX_VSC_BIN_SIZE_HEIGHT__SHIFT) & A3XX_VSC_BIN_SIZE_HEIGHT__MASK; +} + +#define REG_A3XX_VSC_SIZE_ADDRESS				0x00000c02 + +static inline uint32_t REG_A3XX_VSC_PIPE(uint32_t i0) { return 0x00000c06 + 0x3*i0; } + +static inline uint32_t REG_A3XX_VSC_PIPE_CONFIG(uint32_t i0) { return 0x00000c06 + 0x3*i0; } +#define A3XX_VSC_PIPE_CONFIG_X__MASK				0x000003ff +#define A3XX_VSC_PIPE_CONFIG_X__SHIFT				0 +static inline uint32_t A3XX_VSC_PIPE_CONFIG_X(uint32_t val) +{ +	return ((val) << A3XX_VSC_PIPE_CONFIG_X__SHIFT) & A3XX_VSC_PIPE_CONFIG_X__MASK; +} +#define A3XX_VSC_PIPE_CONFIG_Y__MASK				0x000ffc00 +#define A3XX_VSC_PIPE_CONFIG_Y__SHIFT				10 +static inline uint32_t A3XX_VSC_PIPE_CONFIG_Y(uint32_t val) +{ +	return ((val) << A3XX_VSC_PIPE_CONFIG_Y__SHIFT) & A3XX_VSC_PIPE_CONFIG_Y__MASK; +} +#define A3XX_VSC_PIPE_CONFIG_W__MASK				0x00f00000 +#define A3XX_VSC_PIPE_CONFIG_W__SHIFT				20 +static inline uint32_t A3XX_VSC_PIPE_CONFIG_W(uint32_t val) +{ +	return ((val) << A3XX_VSC_PIPE_CONFIG_W__SHIFT) & A3XX_VSC_PIPE_CONFIG_W__MASK; +} +#define A3XX_VSC_PIPE_CONFIG_H__MASK				0x0f000000 +#define A3XX_VSC_PIPE_CONFIG_H__SHIFT				24 +static inline uint32_t A3XX_VSC_PIPE_CONFIG_H(uint32_t val) +{ +	return ((val) << A3XX_VSC_PIPE_CONFIG_H__SHIFT) & A3XX_VSC_PIPE_CONFIG_H__MASK; +} + +static inline uint32_t REG_A3XX_VSC_PIPE_DATA_ADDRESS(uint32_t i0) { return 0x00000c07 + 0x3*i0; } + +static inline uint32_t REG_A3XX_VSC_PIPE_DATA_LENGTH(uint32_t i0) { return 0x00000c08 + 0x3*i0; } + +#define REG_A3XX_VSC_BIN_CONTROL				0x00000c3c +#define A3XX_VSC_BIN_CONTROL_BINNING_ENABLE			0x00000001 + +#define REG_A3XX_UNKNOWN_0C3D					0x00000c3d + +#define REG_A3XX_PC_PERFCOUNTER0_SELECT				0x00000c48 + +#define REG_A3XX_PC_PERFCOUNTER1_SELECT				0x00000c49 + +#define REG_A3XX_PC_PERFCOUNTER2_SELECT				0x00000c4a + +#define REG_A3XX_PC_PERFCOUNTER3_SELECT				0x00000c4b + +#define REG_A3XX_GRAS_TSE_DEBUG_ECO				0x00000c81 + +#define REG_A3XX_GRAS_PERFCOUNTER0_SELECT			0x00000c88 + +#define REG_A3XX_GRAS_PERFCOUNTER1_SELECT			0x00000c89 + +#define REG_A3XX_GRAS_PERFCOUNTER2_SELECT			0x00000c8a + +#define REG_A3XX_GRAS_PERFCOUNTER3_SELECT			0x00000c8b + +static inline uint32_t REG_A3XX_GRAS_CL_USER_PLANE(uint32_t i0) { return 0x00000ca0 + 0x4*i0; } + +static inline uint32_t REG_A3XX_GRAS_CL_USER_PLANE_X(uint32_t i0) { return 0x00000ca0 + 0x4*i0; } + +static inline uint32_t REG_A3XX_GRAS_CL_USER_PLANE_Y(uint32_t i0) { return 0x00000ca1 + 0x4*i0; } + +static inline uint32_t REG_A3XX_GRAS_CL_USER_PLANE_Z(uint32_t i0) { return 0x00000ca2 + 0x4*i0; } + +static inline uint32_t REG_A3XX_GRAS_CL_USER_PLANE_W(uint32_t i0) { return 0x00000ca3 + 0x4*i0; } + +#define REG_A3XX_RB_GMEM_BASE_ADDR				0x00000cc0 + +#define REG_A3XX_RB_DEBUG_ECO_CONTROLS_ADDR			0x00000cc1 + +#define REG_A3XX_RB_PERFCOUNTER0_SELECT				0x00000cc6 + +#define REG_A3XX_RB_PERFCOUNTER1_SELECT				0x00000cc7 + +#define REG_A3XX_RB_FRAME_BUFFER_DIMENSION			0x00000ce0 +#define A3XX_RB_FRAME_BUFFER_DIMENSION_WIDTH__MASK		0x00003fff +#define A3XX_RB_FRAME_BUFFER_DIMENSION_WIDTH__SHIFT		0 +static inline uint32_t A3XX_RB_FRAME_BUFFER_DIMENSION_WIDTH(uint32_t val) +{ +	return ((val) << A3XX_RB_FRAME_BUFFER_DIMENSION_WIDTH__SHIFT) & A3XX_RB_FRAME_BUFFER_DIMENSION_WIDTH__MASK; +} +#define A3XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT__MASK		0x0fffc000 +#define A3XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT__SHIFT		14 +static inline uint32_t A3XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT(uint32_t val) +{ +	return ((val) << A3XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT__SHIFT) & A3XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT__MASK; +} + +#define REG_A3XX_HLSQ_PERFCOUNTER0_SELECT			0x00000e00 + +#define REG_A3XX_HLSQ_PERFCOUNTER1_SELECT			0x00000e01 + +#define REG_A3XX_HLSQ_PERFCOUNTER2_SELECT			0x00000e02 + +#define REG_A3XX_HLSQ_PERFCOUNTER3_SELECT			0x00000e03 + +#define REG_A3XX_HLSQ_PERFCOUNTER4_SELECT			0x00000e04 + +#define REG_A3XX_HLSQ_PERFCOUNTER5_SELECT			0x00000e05 + +#define REG_A3XX_UNKNOWN_0E43					0x00000e43 + +#define REG_A3XX_VFD_PERFCOUNTER0_SELECT			0x00000e44 + +#define REG_A3XX_VFD_PERFCOUNTER1_SELECT			0x00000e45 + +#define REG_A3XX_VPC_VPC_DEBUG_RAM_SEL				0x00000e61 + +#define REG_A3XX_VPC_VPC_DEBUG_RAM_READ				0x00000e62 + +#define REG_A3XX_VPC_PERFCOUNTER0_SELECT			0x00000e64 + +#define REG_A3XX_VPC_PERFCOUNTER1_SELECT			0x00000e65 + +#define REG_A3XX_UCHE_CACHE_MODE_CONTROL_REG			0x00000e82 + +#define REG_A3XX_UCHE_PERFCOUNTER0_SELECT			0x00000e84 + +#define REG_A3XX_UCHE_PERFCOUNTER1_SELECT			0x00000e85 + +#define REG_A3XX_UCHE_PERFCOUNTER2_SELECT			0x00000e86 + +#define REG_A3XX_UCHE_PERFCOUNTER3_SELECT			0x00000e87 + +#define REG_A3XX_UCHE_PERFCOUNTER4_SELECT			0x00000e88 + +#define REG_A3XX_UCHE_PERFCOUNTER5_SELECT			0x00000e89 + +#define REG_A3XX_UCHE_CACHE_INVALIDATE0_REG			0x00000ea0 +#define A3XX_UCHE_CACHE_INVALIDATE0_REG_ADDR__MASK		0x0fffffff +#define A3XX_UCHE_CACHE_INVALIDATE0_REG_ADDR__SHIFT		0 +static inline uint32_t A3XX_UCHE_CACHE_INVALIDATE0_REG_ADDR(uint32_t val) +{ +	return ((val) << A3XX_UCHE_CACHE_INVALIDATE0_REG_ADDR__SHIFT) & A3XX_UCHE_CACHE_INVALIDATE0_REG_ADDR__MASK; +} + +#define REG_A3XX_UCHE_CACHE_INVALIDATE1_REG			0x00000ea1 +#define A3XX_UCHE_CACHE_INVALIDATE1_REG_ADDR__MASK		0x0fffffff +#define A3XX_UCHE_CACHE_INVALIDATE1_REG_ADDR__SHIFT		0 +static inline uint32_t A3XX_UCHE_CACHE_INVALIDATE1_REG_ADDR(uint32_t val) +{ +	return ((val) << A3XX_UCHE_CACHE_INVALIDATE1_REG_ADDR__SHIFT) & A3XX_UCHE_CACHE_INVALIDATE1_REG_ADDR__MASK; +} +#define A3XX_UCHE_CACHE_INVALIDATE1_REG_OPCODE__MASK		0x30000000 +#define A3XX_UCHE_CACHE_INVALIDATE1_REG_OPCODE__SHIFT		28 +static inline uint32_t A3XX_UCHE_CACHE_INVALIDATE1_REG_OPCODE(enum a3xx_cache_opcode val) +{ +	return ((val) << A3XX_UCHE_CACHE_INVALIDATE1_REG_OPCODE__SHIFT) & A3XX_UCHE_CACHE_INVALIDATE1_REG_OPCODE__MASK; +} +#define A3XX_UCHE_CACHE_INVALIDATE1_REG_ENTIRE_CACHE		0x80000000 + +#define REG_A3XX_SP_PERFCOUNTER0_SELECT				0x00000ec4 + +#define REG_A3XX_SP_PERFCOUNTER1_SELECT				0x00000ec5 + +#define REG_A3XX_SP_PERFCOUNTER2_SELECT				0x00000ec6 + +#define REG_A3XX_SP_PERFCOUNTER3_SELECT				0x00000ec7 + +#define REG_A3XX_SP_PERFCOUNTER4_SELECT				0x00000ec8 + +#define REG_A3XX_SP_PERFCOUNTER5_SELECT				0x00000ec9 + +#define REG_A3XX_SP_PERFCOUNTER6_SELECT				0x00000eca + +#define REG_A3XX_SP_PERFCOUNTER7_SELECT				0x00000ecb + +#define REG_A3XX_UNKNOWN_0EE0					0x00000ee0 + +#define REG_A3XX_UNKNOWN_0F03					0x00000f03 + +#define REG_A3XX_TP_PERFCOUNTER0_SELECT				0x00000f04 + +#define REG_A3XX_TP_PERFCOUNTER1_SELECT				0x00000f05 + +#define REG_A3XX_TP_PERFCOUNTER2_SELECT				0x00000f06 + +#define REG_A3XX_TP_PERFCOUNTER3_SELECT				0x00000f07 + +#define REG_A3XX_TP_PERFCOUNTER4_SELECT				0x00000f08 + +#define REG_A3XX_TP_PERFCOUNTER5_SELECT				0x00000f09 + +#define REG_A3XX_VGT_CL_INITIATOR				0x000021f0 + +#define REG_A3XX_VGT_EVENT_INITIATOR				0x000021f9 + +#define REG_A3XX_VGT_DRAW_INITIATOR				0x000021fc + +#define REG_A3XX_VGT_IMMED_DATA					0x000021fd + +#define REG_A3XX_TEX_SAMP_0					0x00000000 +#define A3XX_TEX_SAMP_0_MIPFILTER_LINEAR			0x00000002 +#define A3XX_TEX_SAMP_0_XY_MAG__MASK				0x0000000c +#define A3XX_TEX_SAMP_0_XY_MAG__SHIFT				2 +static inline uint32_t A3XX_TEX_SAMP_0_XY_MAG(enum a3xx_tex_filter val) +{ +	return ((val) << A3XX_TEX_SAMP_0_XY_MAG__SHIFT) & A3XX_TEX_SAMP_0_XY_MAG__MASK; +} +#define A3XX_TEX_SAMP_0_XY_MIN__MASK				0x00000030 +#define A3XX_TEX_SAMP_0_XY_MIN__SHIFT				4 +static inline uint32_t A3XX_TEX_SAMP_0_XY_MIN(enum a3xx_tex_filter val) +{ +	return ((val) << A3XX_TEX_SAMP_0_XY_MIN__SHIFT) & A3XX_TEX_SAMP_0_XY_MIN__MASK; +} +#define A3XX_TEX_SAMP_0_WRAP_S__MASK				0x000001c0 +#define A3XX_TEX_SAMP_0_WRAP_S__SHIFT				6 +static inline uint32_t A3XX_TEX_SAMP_0_WRAP_S(enum a3xx_tex_clamp val) +{ +	return ((val) << A3XX_TEX_SAMP_0_WRAP_S__SHIFT) & A3XX_TEX_SAMP_0_WRAP_S__MASK; +} +#define A3XX_TEX_SAMP_0_WRAP_T__MASK				0x00000e00 +#define A3XX_TEX_SAMP_0_WRAP_T__SHIFT				9 +static inline uint32_t A3XX_TEX_SAMP_0_WRAP_T(enum a3xx_tex_clamp val) +{ +	return ((val) << A3XX_TEX_SAMP_0_WRAP_T__SHIFT) & A3XX_TEX_SAMP_0_WRAP_T__MASK; +} +#define A3XX_TEX_SAMP_0_WRAP_R__MASK				0x00007000 +#define A3XX_TEX_SAMP_0_WRAP_R__SHIFT				12 +static inline uint32_t A3XX_TEX_SAMP_0_WRAP_R(enum a3xx_tex_clamp val) +{ +	return ((val) << A3XX_TEX_SAMP_0_WRAP_R__SHIFT) & A3XX_TEX_SAMP_0_WRAP_R__MASK; +} +#define A3XX_TEX_SAMP_0_UNNORM_COORDS				0x80000000 + +#define REG_A3XX_TEX_SAMP_1					0x00000001 +#define A3XX_TEX_SAMP_1_MAX_LOD__MASK				0x003ff000 +#define A3XX_TEX_SAMP_1_MAX_LOD__SHIFT				12 +static inline uint32_t A3XX_TEX_SAMP_1_MAX_LOD(float val) +{ +	return ((((uint32_t)(val * 12.0))) << A3XX_TEX_SAMP_1_MAX_LOD__SHIFT) & A3XX_TEX_SAMP_1_MAX_LOD__MASK; +} +#define A3XX_TEX_SAMP_1_MIN_LOD__MASK				0xffc00000 +#define A3XX_TEX_SAMP_1_MIN_LOD__SHIFT				22 +static inline uint32_t A3XX_TEX_SAMP_1_MIN_LOD(float val) +{ +	return ((((uint32_t)(val * 12.0))) << A3XX_TEX_SAMP_1_MIN_LOD__SHIFT) & A3XX_TEX_SAMP_1_MIN_LOD__MASK; +} + +#define REG_A3XX_TEX_CONST_0					0x00000000 +#define A3XX_TEX_CONST_0_TILED					0x00000001 +#define A3XX_TEX_CONST_0_SWIZ_X__MASK				0x00000070 +#define A3XX_TEX_CONST_0_SWIZ_X__SHIFT				4 +static inline uint32_t A3XX_TEX_CONST_0_SWIZ_X(enum a3xx_tex_swiz val) +{ +	return ((val) << A3XX_TEX_CONST_0_SWIZ_X__SHIFT) & A3XX_TEX_CONST_0_SWIZ_X__MASK; +} +#define A3XX_TEX_CONST_0_SWIZ_Y__MASK				0x00000380 +#define A3XX_TEX_CONST_0_SWIZ_Y__SHIFT				7 +static inline uint32_t A3XX_TEX_CONST_0_SWIZ_Y(enum a3xx_tex_swiz val) +{ +	return ((val) << A3XX_TEX_CONST_0_SWIZ_Y__SHIFT) & A3XX_TEX_CONST_0_SWIZ_Y__MASK; +} +#define A3XX_TEX_CONST_0_SWIZ_Z__MASK				0x00001c00 +#define A3XX_TEX_CONST_0_SWIZ_Z__SHIFT				10 +static inline uint32_t A3XX_TEX_CONST_0_SWIZ_Z(enum a3xx_tex_swiz val) +{ +	return ((val) << A3XX_TEX_CONST_0_SWIZ_Z__SHIFT) & A3XX_TEX_CONST_0_SWIZ_Z__MASK; +} +#define A3XX_TEX_CONST_0_SWIZ_W__MASK				0x0000e000 +#define A3XX_TEX_CONST_0_SWIZ_W__SHIFT				13 +static inline uint32_t A3XX_TEX_CONST_0_SWIZ_W(enum a3xx_tex_swiz val) +{ +	return ((val) << A3XX_TEX_CONST_0_SWIZ_W__SHIFT) & A3XX_TEX_CONST_0_SWIZ_W__MASK; +} +#define A3XX_TEX_CONST_0_MIPLVLS__MASK				0x000f0000 +#define A3XX_TEX_CONST_0_MIPLVLS__SHIFT				16 +static inline uint32_t A3XX_TEX_CONST_0_MIPLVLS(uint32_t val) +{ +	return ((val) << A3XX_TEX_CONST_0_MIPLVLS__SHIFT) & A3XX_TEX_CONST_0_MIPLVLS__MASK; +} +#define A3XX_TEX_CONST_0_FMT__MASK				0x1fc00000 +#define A3XX_TEX_CONST_0_FMT__SHIFT				22 +static inline uint32_t A3XX_TEX_CONST_0_FMT(enum a3xx_tex_fmt val) +{ +	return ((val) << A3XX_TEX_CONST_0_FMT__SHIFT) & A3XX_TEX_CONST_0_FMT__MASK; +} +#define A3XX_TEX_CONST_0_TYPE__MASK				0xc0000000 +#define A3XX_TEX_CONST_0_TYPE__SHIFT				30 +static inline uint32_t A3XX_TEX_CONST_0_TYPE(enum a3xx_tex_type val) +{ +	return ((val) << A3XX_TEX_CONST_0_TYPE__SHIFT) & A3XX_TEX_CONST_0_TYPE__MASK; +} + +#define REG_A3XX_TEX_CONST_1					0x00000001 +#define A3XX_TEX_CONST_1_HEIGHT__MASK				0x00003fff +#define A3XX_TEX_CONST_1_HEIGHT__SHIFT				0 +static inline uint32_t A3XX_TEX_CONST_1_HEIGHT(uint32_t val) +{ +	return ((val) << A3XX_TEX_CONST_1_HEIGHT__SHIFT) & A3XX_TEX_CONST_1_HEIGHT__MASK; +} +#define A3XX_TEX_CONST_1_WIDTH__MASK				0x0fffc000 +#define A3XX_TEX_CONST_1_WIDTH__SHIFT				14 +static inline uint32_t A3XX_TEX_CONST_1_WIDTH(uint32_t val) +{ +	return ((val) << A3XX_TEX_CONST_1_WIDTH__SHIFT) & A3XX_TEX_CONST_1_WIDTH__MASK; +} +#define A3XX_TEX_CONST_1_FETCHSIZE__MASK			0xf0000000 +#define A3XX_TEX_CONST_1_FETCHSIZE__SHIFT			28 +static inline uint32_t A3XX_TEX_CONST_1_FETCHSIZE(enum a3xx_tex_fetchsize val) +{ +	return ((val) << A3XX_TEX_CONST_1_FETCHSIZE__SHIFT) & A3XX_TEX_CONST_1_FETCHSIZE__MASK; +} + +#define REG_A3XX_TEX_CONST_2					0x00000002 +#define A3XX_TEX_CONST_2_INDX__MASK				0x000000ff +#define A3XX_TEX_CONST_2_INDX__SHIFT				0 +static inline uint32_t A3XX_TEX_CONST_2_INDX(uint32_t val) +{ +	return ((val) << A3XX_TEX_CONST_2_INDX__SHIFT) & A3XX_TEX_CONST_2_INDX__MASK; +} +#define A3XX_TEX_CONST_2_PITCH__MASK				0x3ffff000 +#define A3XX_TEX_CONST_2_PITCH__SHIFT				12 +static inline uint32_t A3XX_TEX_CONST_2_PITCH(uint32_t val) +{ +	return ((val) << A3XX_TEX_CONST_2_PITCH__SHIFT) & A3XX_TEX_CONST_2_PITCH__MASK; +} +#define A3XX_TEX_CONST_2_SWAP__MASK				0xc0000000 +#define A3XX_TEX_CONST_2_SWAP__SHIFT				30 +static inline uint32_t A3XX_TEX_CONST_2_SWAP(enum a3xx_color_swap val) +{ +	return ((val) << A3XX_TEX_CONST_2_SWAP__SHIFT) & A3XX_TEX_CONST_2_SWAP__MASK; +} + +#define REG_A3XX_TEX_CONST_3					0x00000003 + + +#endif /* A3XX_XML */ diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c new file mode 100644 index 00000000000..942e09d898a --- /dev/null +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -0,0 +1,709 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#ifdef CONFIG_MSM_OCMEM +#  include <mach/ocmem.h> +#endif + +#include "a3xx_gpu.h" + +#define A3XX_INT0_MASK \ +	(A3XX_INT0_RBBM_AHB_ERROR |        \ +	 A3XX_INT0_RBBM_ATB_BUS_OVERFLOW | \ +	 A3XX_INT0_CP_T0_PACKET_IN_IB |    \ +	 A3XX_INT0_CP_OPCODE_ERROR |       \ +	 A3XX_INT0_CP_RESERVED_BIT_ERROR | \ +	 A3XX_INT0_CP_HW_FAULT |           \ +	 A3XX_INT0_CP_IB1_INT |            \ +	 A3XX_INT0_CP_IB2_INT |            \ +	 A3XX_INT0_CP_RB_INT |             \ +	 A3XX_INT0_CP_REG_PROTECT_FAULT |  \ +	 A3XX_INT0_CP_AHB_ERROR_HALT |     \ +	 A3XX_INT0_UCHE_OOB_ACCESS) + + +static bool hang_debug = false; +MODULE_PARM_DESC(hang_debug, "Dump registers when hang is detected (can be slow!)"); +module_param_named(hang_debug, hang_debug, bool, 0600); +static void a3xx_dump(struct msm_gpu *gpu); + +static void a3xx_me_init(struct msm_gpu *gpu) +{ +	struct msm_ringbuffer *ring = gpu->rb; + +	OUT_PKT3(ring, CP_ME_INIT, 17); +	OUT_RING(ring, 0x000003f7); +	OUT_RING(ring, 0x00000000); +	OUT_RING(ring, 0x00000000); +	OUT_RING(ring, 0x00000000); +	OUT_RING(ring, 0x00000080); +	OUT_RING(ring, 0x00000100); +	OUT_RING(ring, 0x00000180); +	OUT_RING(ring, 0x00006600); +	OUT_RING(ring, 0x00000150); +	OUT_RING(ring, 0x0000014e); +	OUT_RING(ring, 0x00000154); +	OUT_RING(ring, 0x00000001); +	OUT_RING(ring, 0x00000000); +	OUT_RING(ring, 0x00000000); +	OUT_RING(ring, 0x00000000); +	OUT_RING(ring, 0x00000000); +	OUT_RING(ring, 0x00000000); + +	gpu->funcs->flush(gpu); +	gpu->funcs->idle(gpu); +} + +static int a3xx_hw_init(struct msm_gpu *gpu) +{ +	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); +	struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(adreno_gpu); +	uint32_t *ptr, len; +	int i, ret; + +	DBG("%s", gpu->name); + +	if (adreno_is_a305(adreno_gpu)) { +		/* Set up 16 deep read/write request queues: */ +		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010); +		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010); +		gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010); +		gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010); +		gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303); +		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010); +		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010); +		/* Enable WR-REQ: */ +		gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000ff); +		/* Set up round robin arbitration between both AXI ports: */ +		gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030); +		/* Set up AOOO: */ +		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003c); +		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003c003c); + +	} else if (adreno_is_a320(adreno_gpu)) { +		/* Set up 16 deep read/write request queues: */ +		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010); +		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010); +		gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010); +		gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010); +		gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303); +		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010); +		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010); +		/* Enable WR-REQ: */ +		gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000ff); +		/* Set up round robin arbitration between both AXI ports: */ +		gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030); +		/* Set up AOOO: */ +		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003c); +		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003c003c); +		/* Enable 1K sort: */ +		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x000000ff); +		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4); + +	} else if (adreno_is_a330v2(adreno_gpu)) { +		/* +		 * Most of the VBIF registers on 8974v2 have the correct +		 * values at power on, so we won't modify those if we don't +		 * need to +		 */ +		/* Enable 1k sort: */ +		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f); +		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4); +		/* Enable WR-REQ: */ +		gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003f); +		gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303); +		/* Set up VBIF_ROUND_ROBIN_QOS_ARB: */ +		gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003); + +	} else if (adreno_is_a330(adreno_gpu)) { +		/* Set up 16 deep read/write request queues: */ +		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818); +		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x18181818); +		gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x18181818); +		gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x18181818); +		gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303); +		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x18181818); +		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x18181818); +		/* Enable WR-REQ: */ +		gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003f); +		/* Set up round robin arbitration between both AXI ports: */ +		gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030); +		/* Set up VBIF_ROUND_ROBIN_QOS_ARB: */ +		gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001); +		/* Set up AOOO: */ +		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003f); +		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003f003f); +		/* Enable 1K sort: */ +		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f); +		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4); +		/* Disable VBIF clock gating. This is to enable AXI running +		 * higher frequency than GPU: +		 */ +		gpu_write(gpu, REG_A3XX_VBIF_CLKON, 0x00000001); + +	} else { +		BUG(); +	} + +	/* Make all blocks contribute to the GPU BUSY perf counter: */ +	gpu_write(gpu, REG_A3XX_RBBM_GPU_BUSY_MASKED, 0xffffffff); + +	/* Tune the hystersis counters for SP and CP idle detection: */ +	gpu_write(gpu, REG_A3XX_RBBM_SP_HYST_CNT, 0x10); +	gpu_write(gpu, REG_A3XX_RBBM_WAIT_IDLE_CLOCKS_CTL, 0x10); + +	/* Enable the RBBM error reporting bits.  This lets us get +	 * useful information on failure: +	 */ +	gpu_write(gpu, REG_A3XX_RBBM_AHB_CTL0, 0x00000001); + +	/* Enable AHB error reporting: */ +	gpu_write(gpu, REG_A3XX_RBBM_AHB_CTL1, 0xa6ffffff); + +	/* Turn on the power counters: */ +	gpu_write(gpu, REG_A3XX_RBBM_RBBM_CTL, 0x00030000); + +	/* Turn on hang detection - this spews a lot of useful information +	 * into the RBBM registers on a hang: +	 */ +	gpu_write(gpu, REG_A3XX_RBBM_INTERFACE_HANG_INT_CTL, 0x00010fff); + +	/* Enable 64-byte cacheline size. HW Default is 32-byte (0x000000E0): */ +	gpu_write(gpu, REG_A3XX_UCHE_CACHE_MODE_CONTROL_REG, 0x00000001); + +	/* Enable Clock gating: */ +	if (adreno_is_a320(adreno_gpu)) +		gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbfffffff); +	else if (adreno_is_a330v2(adreno_gpu)) +		gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xaaaaaaaa); +	else if (adreno_is_a330(adreno_gpu)) +		gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbffcffff); + +	if (adreno_is_a330v2(adreno_gpu)) +		gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x05515455); +	else if (adreno_is_a330(adreno_gpu)) +		gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x00000000); + +	/* Set the OCMEM base address for A330, etc */ +	if (a3xx_gpu->ocmem_hdl) { +		gpu_write(gpu, REG_A3XX_RB_GMEM_BASE_ADDR, +			(unsigned int)(a3xx_gpu->ocmem_base >> 14)); +	} + +	/* Turn on performance counters: */ +	gpu_write(gpu, REG_A3XX_RBBM_PERFCTR_CTL, 0x01); + +	/* Enable the perfcntrs that we use.. */ +	for (i = 0; i < gpu->num_perfcntrs; i++) { +		const struct msm_gpu_perfcntr *perfcntr = &gpu->perfcntrs[i]; +		gpu_write(gpu, perfcntr->select_reg, perfcntr->select_val); +	} + +	gpu_write(gpu, REG_A3XX_RBBM_INT_0_MASK, A3XX_INT0_MASK); + +	ret = adreno_hw_init(gpu); +	if (ret) +		return ret; + +	/* setup access protection: */ +	gpu_write(gpu, REG_A3XX_CP_PROTECT_CTRL, 0x00000007); + +	/* RBBM registers */ +	gpu_write(gpu, REG_A3XX_CP_PROTECT(0), 0x63000040); +	gpu_write(gpu, REG_A3XX_CP_PROTECT(1), 0x62000080); +	gpu_write(gpu, REG_A3XX_CP_PROTECT(2), 0x600000cc); +	gpu_write(gpu, REG_A3XX_CP_PROTECT(3), 0x60000108); +	gpu_write(gpu, REG_A3XX_CP_PROTECT(4), 0x64000140); +	gpu_write(gpu, REG_A3XX_CP_PROTECT(5), 0x66000400); + +	/* CP registers */ +	gpu_write(gpu, REG_A3XX_CP_PROTECT(6), 0x65000700); +	gpu_write(gpu, REG_A3XX_CP_PROTECT(7), 0x610007d8); +	gpu_write(gpu, REG_A3XX_CP_PROTECT(8), 0x620007e0); +	gpu_write(gpu, REG_A3XX_CP_PROTECT(9), 0x61001178); +	gpu_write(gpu, REG_A3XX_CP_PROTECT(10), 0x64001180); + +	/* RB registers */ +	gpu_write(gpu, REG_A3XX_CP_PROTECT(11), 0x60003300); + +	/* VBIF registers */ +	gpu_write(gpu, REG_A3XX_CP_PROTECT(12), 0x6b00c000); + +	/* NOTE: PM4/micro-engine firmware registers look to be the same +	 * for a2xx and a3xx.. we could possibly push that part down to +	 * adreno_gpu base class.  Or push both PM4 and PFP but +	 * parameterize the pfp ucode addr/data registers.. +	 */ + +	/* Load PM4: */ +	ptr = (uint32_t *)(adreno_gpu->pm4->data); +	len = adreno_gpu->pm4->size / 4; +	DBG("loading PM4 ucode version: %x", ptr[1]); + +	gpu_write(gpu, REG_AXXX_CP_DEBUG, +			AXXX_CP_DEBUG_DYNAMIC_CLK_DISABLE | +			AXXX_CP_DEBUG_MIU_128BIT_WRITE_ENABLE); +	gpu_write(gpu, REG_AXXX_CP_ME_RAM_WADDR, 0); +	for (i = 1; i < len; i++) +		gpu_write(gpu, REG_AXXX_CP_ME_RAM_DATA, ptr[i]); + +	/* Load PFP: */ +	ptr = (uint32_t *)(adreno_gpu->pfp->data); +	len = adreno_gpu->pfp->size / 4; +	DBG("loading PFP ucode version: %x", ptr[5]); + +	gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_ADDR, 0); +	for (i = 1; i < len; i++) +		gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_DATA, ptr[i]); + +	/* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */ +	if (adreno_is_a305(adreno_gpu) || adreno_is_a320(adreno_gpu)) { +		gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, +				AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB1_START(2) | +				AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB2_START(6) | +				AXXX_CP_QUEUE_THRESHOLDS_CSQ_ST_START(14)); +	} else if (adreno_is_a330(adreno_gpu)) { +		/* NOTE: this (value take from downstream android driver) +		 * includes some bits outside of the known bitfields.  But +		 * A330 has this "MERCIU queue" thing too, which might +		 * explain a new bitfield or reshuffling: +		 */ +		gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, 0x003e2008); +	} + +	/* clear ME_HALT to start micro engine */ +	gpu_write(gpu, REG_AXXX_CP_ME_CNTL, 0); + +	a3xx_me_init(gpu); + +	return 0; +} + +static void a3xx_recover(struct msm_gpu *gpu) +{ +	/* dump registers before resetting gpu, if enabled: */ +	if (hang_debug) +		a3xx_dump(gpu); +	gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 1); +	gpu_read(gpu, REG_A3XX_RBBM_SW_RESET_CMD); +	gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 0); +	adreno_recover(gpu); +} + +static void a3xx_destroy(struct msm_gpu *gpu) +{ +	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); +	struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(adreno_gpu); + +	DBG("%s", gpu->name); + +	adreno_gpu_cleanup(adreno_gpu); + +#ifdef CONFIG_MSM_OCMEM +	if (a3xx_gpu->ocmem_base) +		ocmem_free(OCMEM_GRAPHICS, a3xx_gpu->ocmem_hdl); +#endif + +	kfree(a3xx_gpu); +} + +static void a3xx_idle(struct msm_gpu *gpu) +{ +	/* wait for ringbuffer to drain: */ +	adreno_idle(gpu); + +	/* then wait for GPU to finish: */ +	if (spin_until(!(gpu_read(gpu, REG_A3XX_RBBM_STATUS) & +			A3XX_RBBM_STATUS_GPU_BUSY))) +		DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name); + +	/* TODO maybe we need to reset GPU here to recover from hang? */ +} + +static irqreturn_t a3xx_irq(struct msm_gpu *gpu) +{ +	uint32_t status; + +	status = gpu_read(gpu, REG_A3XX_RBBM_INT_0_STATUS); +	DBG("%s: %08x", gpu->name, status); + +	// TODO + +	gpu_write(gpu, REG_A3XX_RBBM_INT_CLEAR_CMD, status); + +	msm_gpu_retire(gpu); + +	return IRQ_HANDLED; +} + +static const unsigned int a3xx_registers[] = { +	0x0000, 0x0002, 0x0010, 0x0012, 0x0018, 0x0018, 0x0020, 0x0027, +	0x0029, 0x002b, 0x002e, 0x0033, 0x0040, 0x0042, 0x0050, 0x005c, +	0x0060, 0x006c, 0x0080, 0x0082, 0x0084, 0x0088, 0x0090, 0x00e5, +	0x00ea, 0x00ed, 0x0100, 0x0100, 0x0110, 0x0123, 0x01c0, 0x01c1, +	0x01c3, 0x01c5, 0x01c7, 0x01c7, 0x01d5, 0x01d9, 0x01dc, 0x01dd, +	0x01ea, 0x01ea, 0x01ee, 0x01f1, 0x01f5, 0x01f5, 0x01fc, 0x01ff, +	0x0440, 0x0440, 0x0443, 0x0443, 0x0445, 0x0445, 0x044d, 0x044f, +	0x0452, 0x0452, 0x0454, 0x046f, 0x047c, 0x047c, 0x047f, 0x047f, +	0x0578, 0x057f, 0x0600, 0x0602, 0x0605, 0x0607, 0x060a, 0x060e, +	0x0612, 0x0614, 0x0c01, 0x0c02, 0x0c06, 0x0c1d, 0x0c3d, 0x0c3f, +	0x0c48, 0x0c4b, 0x0c80, 0x0c80, 0x0c88, 0x0c8b, 0x0ca0, 0x0cb7, +	0x0cc0, 0x0cc1, 0x0cc6, 0x0cc7, 0x0ce4, 0x0ce5, 0x0e00, 0x0e05, +	0x0e0c, 0x0e0c, 0x0e22, 0x0e23, 0x0e41, 0x0e45, 0x0e64, 0x0e65, +	0x0e80, 0x0e82, 0x0e84, 0x0e89, 0x0ea0, 0x0ea1, 0x0ea4, 0x0ea7, +	0x0ec4, 0x0ecb, 0x0ee0, 0x0ee0, 0x0f00, 0x0f01, 0x0f03, 0x0f09, +	0x2040, 0x2040, 0x2044, 0x2044, 0x2048, 0x204d, 0x2068, 0x2069, +	0x206c, 0x206d, 0x2070, 0x2070, 0x2072, 0x2072, 0x2074, 0x2075, +	0x2079, 0x207a, 0x20c0, 0x20d3, 0x20e4, 0x20ef, 0x2100, 0x2109, +	0x210c, 0x210c, 0x210e, 0x210e, 0x2110, 0x2111, 0x2114, 0x2115, +	0x21e4, 0x21e4, 0x21ea, 0x21ea, 0x21ec, 0x21ed, 0x21f0, 0x21f0, +	0x2200, 0x2212, 0x2214, 0x2217, 0x221a, 0x221a, 0x2240, 0x227e, +	0x2280, 0x228b, 0x22c0, 0x22c0, 0x22c4, 0x22ce, 0x22d0, 0x22d8, +	0x22df, 0x22e6, 0x22e8, 0x22e9, 0x22ec, 0x22ec, 0x22f0, 0x22f7, +	0x22ff, 0x22ff, 0x2340, 0x2343, 0x2348, 0x2349, 0x2350, 0x2356, +	0x2360, 0x2360, 0x2440, 0x2440, 0x2444, 0x2444, 0x2448, 0x244d, +	0x2468, 0x2469, 0x246c, 0x246d, 0x2470, 0x2470, 0x2472, 0x2472, +	0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3, 0x24e4, 0x24ef, +	0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e, 0x2510, 0x2511, +	0x2514, 0x2515, 0x25e4, 0x25e4, 0x25ea, 0x25ea, 0x25ec, 0x25ed, +	0x25f0, 0x25f0, 0x2600, 0x2612, 0x2614, 0x2617, 0x261a, 0x261a, +	0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0, 0x26c4, 0x26ce, +	0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9, 0x26ec, 0x26ec, +	0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743, 0x2748, 0x2749, +	0x2750, 0x2756, 0x2760, 0x2760, 0x300c, 0x300e, 0x301c, 0x301d, +	0x302a, 0x302a, 0x302c, 0x302d, 0x3030, 0x3031, 0x3034, 0x3036, +	0x303c, 0x303c, 0x305e, 0x305f, +}; + +#ifdef CONFIG_DEBUG_FS +static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m) +{ +	struct drm_device *dev = gpu->dev; +	int i; + +	adreno_show(gpu, m); + +	mutex_lock(&dev->struct_mutex); + +	gpu->funcs->pm_resume(gpu); + +	seq_printf(m, "status:   %08x\n", +			gpu_read(gpu, REG_A3XX_RBBM_STATUS)); + +	/* dump these out in a form that can be parsed by demsm: */ +	seq_printf(m, "IO:region %s 00000000 00020000\n", gpu->name); +	for (i = 0; i < ARRAY_SIZE(a3xx_registers); i += 2) { +		uint32_t start = a3xx_registers[i]; +		uint32_t end   = a3xx_registers[i+1]; +		uint32_t addr; + +		for (addr = start; addr <= end; addr++) { +			uint32_t val = gpu_read(gpu, addr); +			seq_printf(m, "IO:R %08x %08x\n", addr<<2, val); +		} +	} + +	gpu->funcs->pm_suspend(gpu); + +	mutex_unlock(&dev->struct_mutex); +} +#endif + +/* would be nice to not have to duplicate the _show() stuff with printk(): */ +static void a3xx_dump(struct msm_gpu *gpu) +{ +	int i; + +	adreno_dump(gpu); +	printk("status:   %08x\n", +			gpu_read(gpu, REG_A3XX_RBBM_STATUS)); + +	/* dump these out in a form that can be parsed by demsm: */ +	printk("IO:region %s 00000000 00020000\n", gpu->name); +	for (i = 0; i < ARRAY_SIZE(a3xx_registers); i += 2) { +		uint32_t start = a3xx_registers[i]; +		uint32_t end   = a3xx_registers[i+1]; +		uint32_t addr; + +		for (addr = start; addr <= end; addr++) { +			uint32_t val = gpu_read(gpu, addr); +			printk("IO:R %08x %08x\n", addr<<2, val); +		} +	} +} + +static const struct adreno_gpu_funcs funcs = { +	.base = { +		.get_param = adreno_get_param, +		.hw_init = a3xx_hw_init, +		.pm_suspend = msm_gpu_pm_suspend, +		.pm_resume = msm_gpu_pm_resume, +		.recover = a3xx_recover, +		.last_fence = adreno_last_fence, +		.submit = adreno_submit, +		.flush = adreno_flush, +		.idle = a3xx_idle, +		.irq = a3xx_irq, +		.destroy = a3xx_destroy, +#ifdef CONFIG_DEBUG_FS +		.show = a3xx_show, +#endif +	}, +}; + +static const struct msm_gpu_perfcntr perfcntrs[] = { +	{ REG_A3XX_SP_PERFCOUNTER6_SELECT, REG_A3XX_RBBM_PERFCTR_SP_6_LO, +			SP_ALU_ACTIVE_CYCLES, "ALUACTIVE" }, +	{ REG_A3XX_SP_PERFCOUNTER7_SELECT, REG_A3XX_RBBM_PERFCTR_SP_7_LO, +			SP_FS_FULL_ALU_INSTRUCTIONS, "ALUFULL" }, +}; + +struct msm_gpu *a3xx_gpu_init(struct drm_device *dev) +{ +	struct a3xx_gpu *a3xx_gpu = NULL; +	struct adreno_gpu *adreno_gpu; +	struct msm_gpu *gpu; +	struct msm_drm_private *priv = dev->dev_private; +	struct platform_device *pdev = priv->gpu_pdev; +	struct adreno_platform_config *config; +	int ret; + +	if (!pdev) { +		dev_err(dev->dev, "no a3xx device\n"); +		ret = -ENXIO; +		goto fail; +	} + +	config = pdev->dev.platform_data; + +	a3xx_gpu = kzalloc(sizeof(*a3xx_gpu), GFP_KERNEL); +	if (!a3xx_gpu) { +		ret = -ENOMEM; +		goto fail; +	} + +	adreno_gpu = &a3xx_gpu->base; +	gpu = &adreno_gpu->base; + +	a3xx_gpu->pdev = pdev; + +	gpu->fast_rate = config->fast_rate; +	gpu->slow_rate = config->slow_rate; +	gpu->bus_freq  = config->bus_freq; +#ifdef CONFIG_MSM_BUS_SCALING +	gpu->bus_scale_table = config->bus_scale_table; +#endif + +	DBG("fast_rate=%u, slow_rate=%u, bus_freq=%u", +			gpu->fast_rate, gpu->slow_rate, gpu->bus_freq); + +	gpu->perfcntrs = perfcntrs; +	gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs); + +	ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, config->rev); +	if (ret) +		goto fail; + +	/* if needed, allocate gmem: */ +	if (adreno_is_a330(adreno_gpu)) { +#ifdef CONFIG_MSM_OCMEM +		/* TODO this is different/missing upstream: */ +		struct ocmem_buf *ocmem_hdl = +				ocmem_allocate(OCMEM_GRAPHICS, adreno_gpu->gmem); + +		a3xx_gpu->ocmem_hdl = ocmem_hdl; +		a3xx_gpu->ocmem_base = ocmem_hdl->addr; +		adreno_gpu->gmem = ocmem_hdl->len; +		DBG("using %dK of OCMEM at 0x%08x", adreno_gpu->gmem / 1024, +				a3xx_gpu->ocmem_base); +#endif +	} + +	if (!gpu->mmu) { +		/* TODO we think it is possible to configure the GPU to +		 * restrict access to VRAM carveout.  But the required +		 * registers are unknown.  For now just bail out and +		 * limp along with just modesetting.  If it turns out +		 * to not be possible to restrict access, then we must +		 * implement a cmdstream validator. +		 */ +		dev_err(dev->dev, "No memory protection without IOMMU\n"); +		ret = -ENXIO; +		goto fail; +	} + +	return gpu; + +fail: +	if (a3xx_gpu) +		a3xx_destroy(&a3xx_gpu->base.base); + +	return ERR_PTR(ret); +} + +/* + * The a3xx device: + */ + +#if defined(CONFIG_MSM_BUS_SCALING) && !defined(CONFIG_OF) +#  include <mach/kgsl.h> +#endif + +static void set_gpu_pdev(struct drm_device *dev, +		struct platform_device *pdev) +{ +	struct msm_drm_private *priv = dev->dev_private; +	priv->gpu_pdev = pdev; +} + +static int a3xx_bind(struct device *dev, struct device *master, void *data) +{ +	static struct adreno_platform_config config = {}; +#ifdef CONFIG_OF +	struct device_node *child, *node = dev->of_node; +	u32 val; +	int ret; + +	ret = of_property_read_u32(node, "qcom,chipid", &val); +	if (ret) { +		dev_err(dev, "could not find chipid: %d\n", ret); +		return ret; +	} + +	config.rev = ADRENO_REV((val >> 24) & 0xff, +			(val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff); + +	/* find clock rates: */ +	config.fast_rate = 0; +	config.slow_rate = ~0; +	for_each_child_of_node(node, child) { +		if (of_device_is_compatible(child, "qcom,gpu-pwrlevels")) { +			struct device_node *pwrlvl; +			for_each_child_of_node(child, pwrlvl) { +				ret = of_property_read_u32(pwrlvl, "qcom,gpu-freq", &val); +				if (ret) { +					dev_err(dev, "could not find gpu-freq: %d\n", ret); +					return ret; +				} +				config.fast_rate = max(config.fast_rate, val); +				config.slow_rate = min(config.slow_rate, val); +			} +		} +	} + +	if (!config.fast_rate) { +		dev_err(dev, "could not find clk rates\n"); +		return -ENXIO; +	} + +#else +	struct kgsl_device_platform_data *pdata = dev->platform_data; +	uint32_t version = socinfo_get_version(); +	if (cpu_is_apq8064ab()) { +		config.fast_rate = 450000000; +		config.slow_rate = 27000000; +		config.bus_freq  = 4; +		config.rev = ADRENO_REV(3, 2, 1, 0); +	} else if (cpu_is_apq8064()) { +		config.fast_rate = 400000000; +		config.slow_rate = 27000000; +		config.bus_freq  = 4; + +		if (SOCINFO_VERSION_MAJOR(version) == 2) +			config.rev = ADRENO_REV(3, 2, 0, 2); +		else if ((SOCINFO_VERSION_MAJOR(version) == 1) && +				(SOCINFO_VERSION_MINOR(version) == 1)) +			config.rev = ADRENO_REV(3, 2, 0, 1); +		else +			config.rev = ADRENO_REV(3, 2, 0, 0); + +	} else if (cpu_is_msm8960ab()) { +		config.fast_rate = 400000000; +		config.slow_rate = 320000000; +		config.bus_freq  = 4; + +		if (SOCINFO_VERSION_MINOR(version) == 0) +			config.rev = ADRENO_REV(3, 2, 1, 0); +		else +			config.rev = ADRENO_REV(3, 2, 1, 1); + +	} else if (cpu_is_msm8930()) { +		config.fast_rate = 400000000; +		config.slow_rate = 27000000; +		config.bus_freq  = 3; + +		if ((SOCINFO_VERSION_MAJOR(version) == 1) && +			(SOCINFO_VERSION_MINOR(version) == 2)) +			config.rev = ADRENO_REV(3, 0, 5, 2); +		else +			config.rev = ADRENO_REV(3, 0, 5, 0); + +	} +#  ifdef CONFIG_MSM_BUS_SCALING +	config.bus_scale_table = pdata->bus_scale_table; +#  endif +#endif +	dev->platform_data = &config; +	set_gpu_pdev(dev_get_drvdata(master), to_platform_device(dev)); +	return 0; +} + +static void a3xx_unbind(struct device *dev, struct device *master, +		void *data) +{ +	set_gpu_pdev(dev_get_drvdata(master), NULL); +} + +static const struct component_ops a3xx_ops = { +		.bind   = a3xx_bind, +		.unbind = a3xx_unbind, +}; + +static int a3xx_probe(struct platform_device *pdev) +{ +	return component_add(&pdev->dev, &a3xx_ops); +} + +static int a3xx_remove(struct platform_device *pdev) +{ +	component_del(&pdev->dev, &a3xx_ops); +	return 0; +} + +static const struct of_device_id dt_match[] = { +	{ .compatible = "qcom,kgsl-3d0" }, +	{} +}; + +static struct platform_driver a3xx_driver = { +	.probe = a3xx_probe, +	.remove = a3xx_remove, +	.driver = { +		.name = "kgsl-3d0", +		.of_match_table = dt_match, +	}, +}; + +void __init a3xx_register(void) +{ +	platform_driver_register(&a3xx_driver); +} + +void __exit a3xx_unregister(void) +{ +	platform_driver_unregister(&a3xx_driver); +} diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.h b/drivers/gpu/drm/msm/adreno/a3xx_gpu.h new file mode 100644 index 00000000000..bb9a8ca0507 --- /dev/null +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __A3XX_GPU_H__ +#define __A3XX_GPU_H__ + +#include "adreno_gpu.h" +#include "a3xx.xml.h" + +struct a3xx_gpu { +	struct adreno_gpu base; +	struct platform_device *pdev; + +	/* if OCMEM is used for GMEM: */ +	uint32_t ocmem_base; +	void *ocmem_hdl; +}; +#define to_a3xx_gpu(x) container_of(x, struct a3xx_gpu, base) + +#endif /* __A3XX_GPU_H__ */ diff --git a/drivers/gpu/drm/msm/adreno/adreno_common.xml.h b/drivers/gpu/drm/msm/adreno/adreno_common.xml.h new file mode 100644 index 00000000000..d6e6ce2d1ab --- /dev/null +++ b/drivers/gpu/drm/msm/adreno/adreno_common.xml.h @@ -0,0 +1,411 @@ +#ifndef ADRENO_COMMON_XML +#define ADRENO_COMMON_XML + +/* Autogenerated file, DO NOT EDIT manually! + +This file was generated by the rules-ng-ng headergen tool in this git repository: +http://github.com/freedreno/envytools/ +git clone https://github.com/freedreno/envytools.git + +The rules-ng-ng source files this header was generated from are: +- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2013-11-30 14:47:15) +- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32814 bytes, from 2013-11-30 15:07:33) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (   8900 bytes, from 2013-10-22 23:57:49) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  10574 bytes, from 2013-11-13 05:44:45) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  53644 bytes, from 2013-11-30 15:07:33) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (   8344 bytes, from 2013-11-30 14:49:47) + +Copyright (C) 2013 by the following authors: +- Rob Clark <robdclark@gmail.com> (robclark) + +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 THE COPYRIGHT OWNER(S) 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. +*/ + + +enum adreno_pa_su_sc_draw { +	PC_DRAW_POINTS = 0, +	PC_DRAW_LINES = 1, +	PC_DRAW_TRIANGLES = 2, +}; + +enum adreno_compare_func { +	FUNC_NEVER = 0, +	FUNC_LESS = 1, +	FUNC_EQUAL = 2, +	FUNC_LEQUAL = 3, +	FUNC_GREATER = 4, +	FUNC_NOTEQUAL = 5, +	FUNC_GEQUAL = 6, +	FUNC_ALWAYS = 7, +}; + +enum adreno_stencil_op { +	STENCIL_KEEP = 0, +	STENCIL_ZERO = 1, +	STENCIL_REPLACE = 2, +	STENCIL_INCR_CLAMP = 3, +	STENCIL_DECR_CLAMP = 4, +	STENCIL_INVERT = 5, +	STENCIL_INCR_WRAP = 6, +	STENCIL_DECR_WRAP = 7, +}; + +enum adreno_rb_blend_factor { +	FACTOR_ZERO = 0, +	FACTOR_ONE = 1, +	FACTOR_SRC_COLOR = 4, +	FACTOR_ONE_MINUS_SRC_COLOR = 5, +	FACTOR_SRC_ALPHA = 6, +	FACTOR_ONE_MINUS_SRC_ALPHA = 7, +	FACTOR_DST_COLOR = 8, +	FACTOR_ONE_MINUS_DST_COLOR = 9, +	FACTOR_DST_ALPHA = 10, +	FACTOR_ONE_MINUS_DST_ALPHA = 11, +	FACTOR_CONSTANT_COLOR = 12, +	FACTOR_ONE_MINUS_CONSTANT_COLOR = 13, +	FACTOR_CONSTANT_ALPHA = 14, +	FACTOR_ONE_MINUS_CONSTANT_ALPHA = 15, +	FACTOR_SRC_ALPHA_SATURATE = 16, +}; + +enum adreno_rb_blend_opcode { +	BLEND_DST_PLUS_SRC = 0, +	BLEND_SRC_MINUS_DST = 1, +	BLEND_MIN_DST_SRC = 2, +	BLEND_MAX_DST_SRC = 3, +	BLEND_DST_MINUS_SRC = 4, +	BLEND_DST_PLUS_SRC_BIAS = 5, +}; + +enum adreno_rb_surface_endian { +	ENDIAN_NONE = 0, +	ENDIAN_8IN16 = 1, +	ENDIAN_8IN32 = 2, +	ENDIAN_16IN32 = 3, +	ENDIAN_8IN64 = 4, +	ENDIAN_8IN128 = 5, +}; + +enum adreno_rb_dither_mode { +	DITHER_DISABLE = 0, +	DITHER_ALWAYS = 1, +	DITHER_IF_ALPHA_OFF = 2, +}; + +enum adreno_rb_depth_format { +	DEPTHX_16 = 0, +	DEPTHX_24_8 = 1, +}; + +#define REG_AXXX_CP_RB_BASE					0x000001c0 + +#define REG_AXXX_CP_RB_CNTL					0x000001c1 +#define AXXX_CP_RB_CNTL_BUFSZ__MASK				0x0000003f +#define AXXX_CP_RB_CNTL_BUFSZ__SHIFT				0 +static inline uint32_t AXXX_CP_RB_CNTL_BUFSZ(uint32_t val) +{ +	return ((val) << AXXX_CP_RB_CNTL_BUFSZ__SHIFT) & AXXX_CP_RB_CNTL_BUFSZ__MASK; +} +#define AXXX_CP_RB_CNTL_BLKSZ__MASK				0x00003f00 +#define AXXX_CP_RB_CNTL_BLKSZ__SHIFT				8 +static inline uint32_t AXXX_CP_RB_CNTL_BLKSZ(uint32_t val) +{ +	return ((val) << AXXX_CP_RB_CNTL_BLKSZ__SHIFT) & AXXX_CP_RB_CNTL_BLKSZ__MASK; +} +#define AXXX_CP_RB_CNTL_BUF_SWAP__MASK				0x00030000 +#define AXXX_CP_RB_CNTL_BUF_SWAP__SHIFT				16 +static inline uint32_t AXXX_CP_RB_CNTL_BUF_SWAP(uint32_t val) +{ +	return ((val) << AXXX_CP_RB_CNTL_BUF_SWAP__SHIFT) & AXXX_CP_RB_CNTL_BUF_SWAP__MASK; +} +#define AXXX_CP_RB_CNTL_POLL_EN					0x00100000 +#define AXXX_CP_RB_CNTL_NO_UPDATE				0x08000000 +#define AXXX_CP_RB_CNTL_RPTR_WR_EN				0x80000000 + +#define REG_AXXX_CP_RB_RPTR_ADDR				0x000001c3 +#define AXXX_CP_RB_RPTR_ADDR_SWAP__MASK				0x00000003 +#define AXXX_CP_RB_RPTR_ADDR_SWAP__SHIFT			0 +static inline uint32_t AXXX_CP_RB_RPTR_ADDR_SWAP(uint32_t val) +{ +	return ((val) << AXXX_CP_RB_RPTR_ADDR_SWAP__SHIFT) & AXXX_CP_RB_RPTR_ADDR_SWAP__MASK; +} +#define AXXX_CP_RB_RPTR_ADDR_ADDR__MASK				0xfffffffc +#define AXXX_CP_RB_RPTR_ADDR_ADDR__SHIFT			2 +static inline uint32_t AXXX_CP_RB_RPTR_ADDR_ADDR(uint32_t val) +{ +	return ((val >> 2) << AXXX_CP_RB_RPTR_ADDR_ADDR__SHIFT) & AXXX_CP_RB_RPTR_ADDR_ADDR__MASK; +} + +#define REG_AXXX_CP_RB_RPTR					0x000001c4 + +#define REG_AXXX_CP_RB_WPTR					0x000001c5 + +#define REG_AXXX_CP_RB_WPTR_DELAY				0x000001c6 + +#define REG_AXXX_CP_RB_RPTR_WR					0x000001c7 + +#define REG_AXXX_CP_RB_WPTR_BASE				0x000001c8 + +#define REG_AXXX_CP_QUEUE_THRESHOLDS				0x000001d5 +#define AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB1_START__MASK		0x0000000f +#define AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB1_START__SHIFT		0 +static inline uint32_t AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB1_START(uint32_t val) +{ +	return ((val) << AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB1_START__SHIFT) & AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB1_START__MASK; +} +#define AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB2_START__MASK		0x00000f00 +#define AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB2_START__SHIFT		8 +static inline uint32_t AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB2_START(uint32_t val) +{ +	return ((val) << AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB2_START__SHIFT) & AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB2_START__MASK; +} +#define AXXX_CP_QUEUE_THRESHOLDS_CSQ_ST_START__MASK		0x000f0000 +#define AXXX_CP_QUEUE_THRESHOLDS_CSQ_ST_START__SHIFT		16 +static inline uint32_t AXXX_CP_QUEUE_THRESHOLDS_CSQ_ST_START(uint32_t val) +{ +	return ((val) << AXXX_CP_QUEUE_THRESHOLDS_CSQ_ST_START__SHIFT) & AXXX_CP_QUEUE_THRESHOLDS_CSQ_ST_START__MASK; +} + +#define REG_AXXX_CP_MEQ_THRESHOLDS				0x000001d6 +#define AXXX_CP_MEQ_THRESHOLDS_MEQ_END__MASK			0x001f0000 +#define AXXX_CP_MEQ_THRESHOLDS_MEQ_END__SHIFT			16 +static inline uint32_t AXXX_CP_MEQ_THRESHOLDS_MEQ_END(uint32_t val) +{ +	return ((val) << AXXX_CP_MEQ_THRESHOLDS_MEQ_END__SHIFT) & AXXX_CP_MEQ_THRESHOLDS_MEQ_END__MASK; +} +#define AXXX_CP_MEQ_THRESHOLDS_ROQ_END__MASK			0x1f000000 +#define AXXX_CP_MEQ_THRESHOLDS_ROQ_END__SHIFT			24 +static inline uint32_t AXXX_CP_MEQ_THRESHOLDS_ROQ_END(uint32_t val) +{ +	return ((val) << AXXX_CP_MEQ_THRESHOLDS_ROQ_END__SHIFT) & AXXX_CP_MEQ_THRESHOLDS_ROQ_END__MASK; +} + +#define REG_AXXX_CP_CSQ_AVAIL					0x000001d7 +#define AXXX_CP_CSQ_AVAIL_RING__MASK				0x0000007f +#define AXXX_CP_CSQ_AVAIL_RING__SHIFT				0 +static inline uint32_t AXXX_CP_CSQ_AVAIL_RING(uint32_t val) +{ +	return ((val) << AXXX_CP_CSQ_AVAIL_RING__SHIFT) & AXXX_CP_CSQ_AVAIL_RING__MASK; +} +#define AXXX_CP_CSQ_AVAIL_IB1__MASK				0x00007f00 +#define AXXX_CP_CSQ_AVAIL_IB1__SHIFT				8 +static inline uint32_t AXXX_CP_CSQ_AVAIL_IB1(uint32_t val) +{ +	return ((val) << AXXX_CP_CSQ_AVAIL_IB1__SHIFT) & AXXX_CP_CSQ_AVAIL_IB1__MASK; +} +#define AXXX_CP_CSQ_AVAIL_IB2__MASK				0x007f0000 +#define AXXX_CP_CSQ_AVAIL_IB2__SHIFT				16 +static inline uint32_t AXXX_CP_CSQ_AVAIL_IB2(uint32_t val) +{ +	return ((val) << AXXX_CP_CSQ_AVAIL_IB2__SHIFT) & AXXX_CP_CSQ_AVAIL_IB2__MASK; +} + +#define REG_AXXX_CP_STQ_AVAIL					0x000001d8 +#define AXXX_CP_STQ_AVAIL_ST__MASK				0x0000007f +#define AXXX_CP_STQ_AVAIL_ST__SHIFT				0 +static inline uint32_t AXXX_CP_STQ_AVAIL_ST(uint32_t val) +{ +	return ((val) << AXXX_CP_STQ_AVAIL_ST__SHIFT) & AXXX_CP_STQ_AVAIL_ST__MASK; +} + +#define REG_AXXX_CP_MEQ_AVAIL					0x000001d9 +#define AXXX_CP_MEQ_AVAIL_MEQ__MASK				0x0000001f +#define AXXX_CP_MEQ_AVAIL_MEQ__SHIFT				0 +static inline uint32_t AXXX_CP_MEQ_AVAIL_MEQ(uint32_t val) +{ +	return ((val) << AXXX_CP_MEQ_AVAIL_MEQ__SHIFT) & AXXX_CP_MEQ_AVAIL_MEQ__MASK; +} + +#define REG_AXXX_SCRATCH_UMSK					0x000001dc +#define AXXX_SCRATCH_UMSK_UMSK__MASK				0x000000ff +#define AXXX_SCRATCH_UMSK_UMSK__SHIFT				0 +static inline uint32_t AXXX_SCRATCH_UMSK_UMSK(uint32_t val) +{ +	return ((val) << AXXX_SCRATCH_UMSK_UMSK__SHIFT) & AXXX_SCRATCH_UMSK_UMSK__MASK; +} +#define AXXX_SCRATCH_UMSK_SWAP__MASK				0x00030000 +#define AXXX_SCRATCH_UMSK_SWAP__SHIFT				16 +static inline uint32_t AXXX_SCRATCH_UMSK_SWAP(uint32_t val) +{ +	return ((val) << AXXX_SCRATCH_UMSK_SWAP__SHIFT) & AXXX_SCRATCH_UMSK_SWAP__MASK; +} + +#define REG_AXXX_SCRATCH_ADDR					0x000001dd + +#define REG_AXXX_CP_ME_RDADDR					0x000001ea + +#define REG_AXXX_CP_STATE_DEBUG_INDEX				0x000001ec + +#define REG_AXXX_CP_STATE_DEBUG_DATA				0x000001ed + +#define REG_AXXX_CP_INT_CNTL					0x000001f2 + +#define REG_AXXX_CP_INT_STATUS					0x000001f3 + +#define REG_AXXX_CP_INT_ACK					0x000001f4 + +#define REG_AXXX_CP_ME_CNTL					0x000001f6 + +#define REG_AXXX_CP_ME_STATUS					0x000001f7 + +#define REG_AXXX_CP_ME_RAM_WADDR				0x000001f8 + +#define REG_AXXX_CP_ME_RAM_RADDR				0x000001f9 + +#define REG_AXXX_CP_ME_RAM_DATA					0x000001fa + +#define REG_AXXX_CP_DEBUG					0x000001fc +#define AXXX_CP_DEBUG_PREDICATE_DISABLE				0x00800000 +#define AXXX_CP_DEBUG_PROG_END_PTR_ENABLE			0x01000000 +#define AXXX_CP_DEBUG_MIU_128BIT_WRITE_ENABLE			0x02000000 +#define AXXX_CP_DEBUG_PREFETCH_PASS_NOPS			0x04000000 +#define AXXX_CP_DEBUG_DYNAMIC_CLK_DISABLE			0x08000000 +#define AXXX_CP_DEBUG_PREFETCH_MATCH_DISABLE			0x10000000 +#define AXXX_CP_DEBUG_SIMPLE_ME_FLOW_CONTROL			0x40000000 +#define AXXX_CP_DEBUG_MIU_WRITE_PACK_DISABLE			0x80000000 + +#define REG_AXXX_CP_CSQ_RB_STAT					0x000001fd +#define AXXX_CP_CSQ_RB_STAT_RPTR__MASK				0x0000007f +#define AXXX_CP_CSQ_RB_STAT_RPTR__SHIFT				0 +static inline uint32_t AXXX_CP_CSQ_RB_STAT_RPTR(uint32_t val) +{ +	return ((val) << AXXX_CP_CSQ_RB_STAT_RPTR__SHIFT) & AXXX_CP_CSQ_RB_STAT_RPTR__MASK; +} +#define AXXX_CP_CSQ_RB_STAT_WPTR__MASK				0x007f0000 +#define AXXX_CP_CSQ_RB_STAT_WPTR__SHIFT				16 +static inline uint32_t AXXX_CP_CSQ_RB_STAT_WPTR(uint32_t val) +{ +	return ((val) << AXXX_CP_CSQ_RB_STAT_WPTR__SHIFT) & AXXX_CP_CSQ_RB_STAT_WPTR__MASK; +} + +#define REG_AXXX_CP_CSQ_IB1_STAT				0x000001fe +#define AXXX_CP_CSQ_IB1_STAT_RPTR__MASK				0x0000007f +#define AXXX_CP_CSQ_IB1_STAT_RPTR__SHIFT			0 +static inline uint32_t AXXX_CP_CSQ_IB1_STAT_RPTR(uint32_t val) +{ +	return ((val) << AXXX_CP_CSQ_IB1_STAT_RPTR__SHIFT) & AXXX_CP_CSQ_IB1_STAT_RPTR__MASK; +} +#define AXXX_CP_CSQ_IB1_STAT_WPTR__MASK				0x007f0000 +#define AXXX_CP_CSQ_IB1_STAT_WPTR__SHIFT			16 +static inline uint32_t AXXX_CP_CSQ_IB1_STAT_WPTR(uint32_t val) +{ +	return ((val) << AXXX_CP_CSQ_IB1_STAT_WPTR__SHIFT) & AXXX_CP_CSQ_IB1_STAT_WPTR__MASK; +} + +#define REG_AXXX_CP_CSQ_IB2_STAT				0x000001ff +#define AXXX_CP_CSQ_IB2_STAT_RPTR__MASK				0x0000007f +#define AXXX_CP_CSQ_IB2_STAT_RPTR__SHIFT			0 +static inline uint32_t AXXX_CP_CSQ_IB2_STAT_RPTR(uint32_t val) +{ +	return ((val) << AXXX_CP_CSQ_IB2_STAT_RPTR__SHIFT) & AXXX_CP_CSQ_IB2_STAT_RPTR__MASK; +} +#define AXXX_CP_CSQ_IB2_STAT_WPTR__MASK				0x007f0000 +#define AXXX_CP_CSQ_IB2_STAT_WPTR__SHIFT			16 +static inline uint32_t AXXX_CP_CSQ_IB2_STAT_WPTR(uint32_t val) +{ +	return ((val) << AXXX_CP_CSQ_IB2_STAT_WPTR__SHIFT) & AXXX_CP_CSQ_IB2_STAT_WPTR__MASK; +} + +#define REG_AXXX_CP_NON_PREFETCH_CNTRS				0x00000440 + +#define REG_AXXX_CP_STQ_ST_STAT					0x00000443 + +#define REG_AXXX_CP_ST_BASE					0x0000044d + +#define REG_AXXX_CP_ST_BUFSZ					0x0000044e + +#define REG_AXXX_CP_MEQ_STAT					0x0000044f + +#define REG_AXXX_CP_MIU_TAG_STAT				0x00000452 + +#define REG_AXXX_CP_BIN_MASK_LO					0x00000454 + +#define REG_AXXX_CP_BIN_MASK_HI					0x00000455 + +#define REG_AXXX_CP_BIN_SELECT_LO				0x00000456 + +#define REG_AXXX_CP_BIN_SELECT_HI				0x00000457 + +#define REG_AXXX_CP_IB1_BASE					0x00000458 + +#define REG_AXXX_CP_IB1_BUFSZ					0x00000459 + +#define REG_AXXX_CP_IB2_BASE					0x0000045a + +#define REG_AXXX_CP_IB2_BUFSZ					0x0000045b + +#define REG_AXXX_CP_STAT					0x0000047f + +#define REG_AXXX_CP_SCRATCH_REG0				0x00000578 + +#define REG_AXXX_CP_SCRATCH_REG1				0x00000579 + +#define REG_AXXX_CP_SCRATCH_REG2				0x0000057a + +#define REG_AXXX_CP_SCRATCH_REG3				0x0000057b + +#define REG_AXXX_CP_SCRATCH_REG4				0x0000057c + +#define REG_AXXX_CP_SCRATCH_REG5				0x0000057d + +#define REG_AXXX_CP_SCRATCH_REG6				0x0000057e + +#define REG_AXXX_CP_SCRATCH_REG7				0x0000057f + +#define REG_AXXX_CP_ME_VS_EVENT_SRC				0x00000600 + +#define REG_AXXX_CP_ME_VS_EVENT_ADDR				0x00000601 + +#define REG_AXXX_CP_ME_VS_EVENT_DATA				0x00000602 + +#define REG_AXXX_CP_ME_VS_EVENT_ADDR_SWM			0x00000603 + +#define REG_AXXX_CP_ME_VS_EVENT_DATA_SWM			0x00000604 + +#define REG_AXXX_CP_ME_PS_EVENT_SRC				0x00000605 + +#define REG_AXXX_CP_ME_PS_EVENT_ADDR				0x00000606 + +#define REG_AXXX_CP_ME_PS_EVENT_DATA				0x00000607 + +#define REG_AXXX_CP_ME_PS_EVENT_ADDR_SWM			0x00000608 + +#define REG_AXXX_CP_ME_PS_EVENT_DATA_SWM			0x00000609 + +#define REG_AXXX_CP_ME_CF_EVENT_SRC				0x0000060a + +#define REG_AXXX_CP_ME_CF_EVENT_ADDR				0x0000060b + +#define REG_AXXX_CP_ME_CF_EVENT_DATA				0x0000060c + +#define REG_AXXX_CP_ME_NRT_ADDR					0x0000060d + +#define REG_AXXX_CP_ME_NRT_DATA					0x0000060e + +#define REG_AXXX_CP_ME_VS_FETCH_DONE_SRC			0x00000612 + +#define REG_AXXX_CP_ME_VS_FETCH_DONE_ADDR			0x00000613 + +#define REG_AXXX_CP_ME_VS_FETCH_DONE_DATA			0x00000614 + + +#endif /* ADRENO_COMMON_XML */ diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c new file mode 100644 index 00000000000..28ca8cd8b09 --- /dev/null +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -0,0 +1,402 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include "adreno_gpu.h" +#include "msm_gem.h" +#include "msm_mmu.h" + +struct adreno_info { +	struct adreno_rev rev; +	uint32_t revn; +	const char *name; +	const char *pm4fw, *pfpfw; +	uint32_t gmem; +}; + +#define ANY_ID 0xff + +static const struct adreno_info gpulist[] = { +	{ +		.rev   = ADRENO_REV(3, 0, 5, ANY_ID), +		.revn  = 305, +		.name  = "A305", +		.pm4fw = "a300_pm4.fw", +		.pfpfw = "a300_pfp.fw", +		.gmem  = SZ_256K, +	}, { +		.rev   = ADRENO_REV(3, 2, ANY_ID, ANY_ID), +		.revn  = 320, +		.name  = "A320", +		.pm4fw = "a300_pm4.fw", +		.pfpfw = "a300_pfp.fw", +		.gmem  = SZ_512K, +	}, { +		.rev   = ADRENO_REV(3, 3, 0, ANY_ID), +		.revn  = 330, +		.name  = "A330", +		.pm4fw = "a330_pm4.fw", +		.pfpfw = "a330_pfp.fw", +		.gmem  = SZ_1M, +	}, +}; + +MODULE_FIRMWARE("a300_pm4.fw"); +MODULE_FIRMWARE("a300_pfp.fw"); +MODULE_FIRMWARE("a330_pm4.fw"); +MODULE_FIRMWARE("a330_pfp.fw"); + +#define RB_SIZE    SZ_32K +#define RB_BLKSIZE 16 + +int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value) +{ +	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + +	switch (param) { +	case MSM_PARAM_GPU_ID: +		*value = adreno_gpu->info->revn; +		return 0; +	case MSM_PARAM_GMEM_SIZE: +		*value = adreno_gpu->gmem; +		return 0; +	case MSM_PARAM_CHIP_ID: +		*value = adreno_gpu->rev.patchid | +				(adreno_gpu->rev.minor << 8) | +				(adreno_gpu->rev.major << 16) | +				(adreno_gpu->rev.core << 24); +		return 0; +	default: +		DBG("%s: invalid param: %u", gpu->name, param); +		return -EINVAL; +	} +} + +#define rbmemptr(adreno_gpu, member)  \ +	((adreno_gpu)->memptrs_iova + offsetof(struct adreno_rbmemptrs, member)) + +int adreno_hw_init(struct msm_gpu *gpu) +{ +	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + +	DBG("%s", gpu->name); + +	/* Setup REG_CP_RB_CNTL: */ +	gpu_write(gpu, REG_AXXX_CP_RB_CNTL, +			/* size is log2(quad-words): */ +			AXXX_CP_RB_CNTL_BUFSZ(ilog2(gpu->rb->size / 8)) | +			AXXX_CP_RB_CNTL_BLKSZ(ilog2(RB_BLKSIZE / 8))); + +	/* Setup ringbuffer address: */ +	gpu_write(gpu, REG_AXXX_CP_RB_BASE, gpu->rb_iova); +	gpu_write(gpu, REG_AXXX_CP_RB_RPTR_ADDR, rbmemptr(adreno_gpu, rptr)); + +	/* Setup scratch/timestamp: */ +	gpu_write(gpu, REG_AXXX_SCRATCH_ADDR, rbmemptr(adreno_gpu, fence)); + +	gpu_write(gpu, REG_AXXX_SCRATCH_UMSK, 0x1); + +	return 0; +} + +static uint32_t get_wptr(struct msm_ringbuffer *ring) +{ +	return ring->cur - ring->start; +} + +uint32_t adreno_last_fence(struct msm_gpu *gpu) +{ +	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); +	return adreno_gpu->memptrs->fence; +} + +void adreno_recover(struct msm_gpu *gpu) +{ +	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); +	struct drm_device *dev = gpu->dev; +	int ret; + +	gpu->funcs->pm_suspend(gpu); + +	/* reset ringbuffer: */ +	gpu->rb->cur = gpu->rb->start; + +	/* reset completed fence seqno, just discard anything pending: */ +	adreno_gpu->memptrs->fence = gpu->submitted_fence; +	adreno_gpu->memptrs->rptr  = 0; +	adreno_gpu->memptrs->wptr  = 0; + +	gpu->funcs->pm_resume(gpu); +	ret = gpu->funcs->hw_init(gpu); +	if (ret) { +		dev_err(dev->dev, "gpu hw init failed: %d\n", ret); +		/* hmm, oh well? */ +	} +} + +int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, +		struct msm_file_private *ctx) +{ +	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); +	struct msm_drm_private *priv = gpu->dev->dev_private; +	struct msm_ringbuffer *ring = gpu->rb; +	unsigned i, ibs = 0; + +	for (i = 0; i < submit->nr_cmds; i++) { +		switch (submit->cmd[i].type) { +		case MSM_SUBMIT_CMD_IB_TARGET_BUF: +			/* ignore IB-targets */ +			break; +		case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: +			/* ignore if there has not been a ctx switch: */ +			if (priv->lastctx == ctx) +				break; +		case MSM_SUBMIT_CMD_BUF: +			OUT_PKT3(ring, CP_INDIRECT_BUFFER_PFD, 2); +			OUT_RING(ring, submit->cmd[i].iova); +			OUT_RING(ring, submit->cmd[i].size); +			ibs++; +			break; +		} +	} + +	/* on a320, at least, we seem to need to pad things out to an +	 * even number of qwords to avoid issue w/ CP hanging on wrap- +	 * around: +	 */ +	if (ibs % 2) +		OUT_PKT2(ring); + +	OUT_PKT0(ring, REG_AXXX_CP_SCRATCH_REG2, 1); +	OUT_RING(ring, submit->fence); + +	if (adreno_is_a3xx(adreno_gpu)) { +		/* Flush HLSQ lazy updates to make sure there is nothing +		 * pending for indirect loads after the timestamp has +		 * passed: +		 */ +		OUT_PKT3(ring, CP_EVENT_WRITE, 1); +		OUT_RING(ring, HLSQ_FLUSH); + +		OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1); +		OUT_RING(ring, 0x00000000); +	} + +	OUT_PKT3(ring, CP_EVENT_WRITE, 3); +	OUT_RING(ring, CACHE_FLUSH_TS); +	OUT_RING(ring, rbmemptr(adreno_gpu, fence)); +	OUT_RING(ring, submit->fence); + +	/* we could maybe be clever and only CP_COND_EXEC the interrupt: */ +	OUT_PKT3(ring, CP_INTERRUPT, 1); +	OUT_RING(ring, 0x80000000); + +#if 0 +	if (adreno_is_a3xx(adreno_gpu)) { +		/* Dummy set-constant to trigger context rollover */ +		OUT_PKT3(ring, CP_SET_CONSTANT, 2); +		OUT_RING(ring, CP_REG(REG_A3XX_HLSQ_CL_KERNEL_GROUP_X_REG)); +		OUT_RING(ring, 0x00000000); +	} +#endif + +	gpu->funcs->flush(gpu); + +	return 0; +} + +void adreno_flush(struct msm_gpu *gpu) +{ +	uint32_t wptr = get_wptr(gpu->rb); + +	/* ensure writes to ringbuffer have hit system memory: */ +	mb(); + +	gpu_write(gpu, REG_AXXX_CP_RB_WPTR, wptr); +} + +void adreno_idle(struct msm_gpu *gpu) +{ +	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); +	uint32_t wptr = get_wptr(gpu->rb); + +	/* wait for CP to drain ringbuffer: */ +	if (spin_until(adreno_gpu->memptrs->rptr == wptr)) +		DRM_ERROR("%s: timeout waiting to drain ringbuffer!\n", gpu->name); + +	/* TODO maybe we need to reset GPU here to recover from hang? */ +} + +#ifdef CONFIG_DEBUG_FS +void adreno_show(struct msm_gpu *gpu, struct seq_file *m) +{ +	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + +	seq_printf(m, "revision: %d (%d.%d.%d.%d)\n", +			adreno_gpu->info->revn, adreno_gpu->rev.core, +			adreno_gpu->rev.major, adreno_gpu->rev.minor, +			adreno_gpu->rev.patchid); + +	seq_printf(m, "fence:    %d/%d\n", adreno_gpu->memptrs->fence, +			gpu->submitted_fence); +	seq_printf(m, "rptr:     %d\n", adreno_gpu->memptrs->rptr); +	seq_printf(m, "wptr:     %d\n", adreno_gpu->memptrs->wptr); +	seq_printf(m, "rb wptr:  %d\n", get_wptr(gpu->rb)); +} +#endif + +/* would be nice to not have to duplicate the _show() stuff with printk(): */ +void adreno_dump(struct msm_gpu *gpu) +{ +	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + +	printk("revision: %d (%d.%d.%d.%d)\n", +			adreno_gpu->info->revn, adreno_gpu->rev.core, +			adreno_gpu->rev.major, adreno_gpu->rev.minor, +			adreno_gpu->rev.patchid); + +	printk("fence:    %d/%d\n", adreno_gpu->memptrs->fence, +			gpu->submitted_fence); +	printk("rptr:     %d\n", adreno_gpu->memptrs->rptr); +	printk("wptr:     %d\n", adreno_gpu->memptrs->wptr); +	printk("rb wptr:  %d\n", get_wptr(gpu->rb)); + +} + +static uint32_t ring_freewords(struct msm_gpu *gpu) +{ +	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); +	uint32_t size = gpu->rb->size / 4; +	uint32_t wptr = get_wptr(gpu->rb); +	uint32_t rptr = adreno_gpu->memptrs->rptr; +	return (rptr + (size - 1) - wptr) % size; +} + +void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords) +{ +	if (spin_until(ring_freewords(gpu) >= ndwords)) +		DRM_ERROR("%s: timeout waiting for ringbuffer space\n", gpu->name); +} + +static const char *iommu_ports[] = { +		"gfx3d_user", "gfx3d_priv", +		"gfx3d1_user", "gfx3d1_priv", +}; + +static inline bool _rev_match(uint8_t entry, uint8_t id) +{ +	return (entry == ANY_ID) || (entry == id); +} + +int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, +		struct adreno_gpu *gpu, const struct adreno_gpu_funcs *funcs, +		struct adreno_rev rev) +{ +	struct msm_mmu *mmu; +	int i, ret; + +	/* identify gpu: */ +	for (i = 0; i < ARRAY_SIZE(gpulist); i++) { +		const struct adreno_info *info = &gpulist[i]; +		if (_rev_match(info->rev.core, rev.core) && +				_rev_match(info->rev.major, rev.major) && +				_rev_match(info->rev.minor, rev.minor) && +				_rev_match(info->rev.patchid, rev.patchid)) { +			gpu->info = info; +			gpu->revn = info->revn; +			break; +		} +	} + +	if (i == ARRAY_SIZE(gpulist)) { +		dev_err(drm->dev, "Unknown GPU revision: %u.%u.%u.%u\n", +				rev.core, rev.major, rev.minor, rev.patchid); +		return -ENXIO; +	} + +	DBG("Found GPU: %s (%u.%u.%u.%u)", gpu->info->name, +			rev.core, rev.major, rev.minor, rev.patchid); + +	gpu->funcs = funcs; +	gpu->gmem = gpu->info->gmem; +	gpu->rev = rev; + +	ret = request_firmware(&gpu->pm4, gpu->info->pm4fw, drm->dev); +	if (ret) { +		dev_err(drm->dev, "failed to load %s PM4 firmware: %d\n", +				gpu->info->pm4fw, ret); +		return ret; +	} + +	ret = request_firmware(&gpu->pfp, gpu->info->pfpfw, drm->dev); +	if (ret) { +		dev_err(drm->dev, "failed to load %s PFP firmware: %d\n", +				gpu->info->pfpfw, ret); +		return ret; +	} + +	ret = msm_gpu_init(drm, pdev, &gpu->base, &funcs->base, +			gpu->info->name, "kgsl_3d0_reg_memory", "kgsl_3d0_irq", +			RB_SIZE); +	if (ret) +		return ret; + +	mmu = gpu->base.mmu; +	if (mmu) { +		ret = mmu->funcs->attach(mmu, iommu_ports, +				ARRAY_SIZE(iommu_ports)); +		if (ret) +			return ret; +	} + +	gpu->memptrs_bo = msm_gem_new(drm, sizeof(*gpu->memptrs), +			MSM_BO_UNCACHED); +	if (IS_ERR(gpu->memptrs_bo)) { +		ret = PTR_ERR(gpu->memptrs_bo); +		gpu->memptrs_bo = NULL; +		dev_err(drm->dev, "could not allocate memptrs: %d\n", ret); +		return ret; +	} + +	gpu->memptrs = msm_gem_vaddr_locked(gpu->memptrs_bo); +	if (!gpu->memptrs) { +		dev_err(drm->dev, "could not vmap memptrs\n"); +		return -ENOMEM; +	} + +	ret = msm_gem_get_iova_locked(gpu->memptrs_bo, gpu->base.id, +			&gpu->memptrs_iova); +	if (ret) { +		dev_err(drm->dev, "could not map memptrs: %d\n", ret); +		return ret; +	} + +	return 0; +} + +void adreno_gpu_cleanup(struct adreno_gpu *gpu) +{ +	if (gpu->memptrs_bo) { +		if (gpu->memptrs_iova) +			msm_gem_put_iova(gpu->memptrs_bo, gpu->base.id); +		drm_gem_object_unreference(gpu->memptrs_bo); +	} +	if (gpu->pm4) +		release_firmware(gpu->pm4); +	if (gpu->pfp) +		release_firmware(gpu->pfp); +	msm_gpu_cleanup(&gpu->base); +} diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h new file mode 100644 index 00000000000..63c36ce3302 --- /dev/null +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __ADRENO_GPU_H__ +#define __ADRENO_GPU_H__ + +#include <linux/firmware.h> + +#include "msm_gpu.h" + +#include "adreno_common.xml.h" +#include "adreno_pm4.xml.h" + +struct adreno_rev { +	uint8_t  core; +	uint8_t  major; +	uint8_t  minor; +	uint8_t  patchid; +}; + +#define ADRENO_REV(core, major, minor, patchid) \ +	((struct adreno_rev){ core, major, minor, patchid }) + +struct adreno_gpu_funcs { +	struct msm_gpu_funcs base; +}; + +struct adreno_info; + +struct adreno_rbmemptrs { +	volatile uint32_t rptr; +	volatile uint32_t wptr; +	volatile uint32_t fence; +}; + +struct adreno_gpu { +	struct msm_gpu base; +	struct adreno_rev rev; +	const struct adreno_info *info; +	uint32_t gmem;  /* actual gmem size */ +	uint32_t revn;  /* numeric revision name */ +	const struct adreno_gpu_funcs *funcs; + +	/* firmware: */ +	const struct firmware *pm4, *pfp; + +	/* ringbuffer rptr/wptr: */ +	// TODO should this be in msm_ringbuffer?  I think it would be +	// different for z180.. +	struct adreno_rbmemptrs *memptrs; +	struct drm_gem_object *memptrs_bo; +	uint32_t memptrs_iova; +}; +#define to_adreno_gpu(x) container_of(x, struct adreno_gpu, base) + +/* platform config data (ie. from DT, or pdata) */ +struct adreno_platform_config { +	struct adreno_rev rev; +	uint32_t fast_rate, slow_rate, bus_freq; +#ifdef CONFIG_MSM_BUS_SCALING +	struct msm_bus_scale_pdata *bus_scale_table; +#endif +}; + +#define ADRENO_IDLE_TIMEOUT msecs_to_jiffies(1000) + +#define spin_until(X) ({                                   \ +	int __ret = -ETIMEDOUT;                            \ +	unsigned long __t = jiffies + ADRENO_IDLE_TIMEOUT; \ +	do {                                               \ +		if (X) {                                   \ +			__ret = 0;                         \ +			break;                             \ +		}                                          \ +	} while (time_before(jiffies, __t));               \ +	__ret;                                             \ +}) + + +static inline bool adreno_is_a3xx(struct adreno_gpu *gpu) +{ +	return (gpu->revn >= 300) && (gpu->revn < 400); +} + +static inline bool adreno_is_a305(struct adreno_gpu *gpu) +{ +	return gpu->revn == 305; +} + +static inline bool adreno_is_a320(struct adreno_gpu *gpu) +{ +	return gpu->revn == 320; +} + +static inline bool adreno_is_a330(struct adreno_gpu *gpu) +{ +	return gpu->revn == 330; +} + +static inline bool adreno_is_a330v2(struct adreno_gpu *gpu) +{ +	return adreno_is_a330(gpu) && (gpu->rev.patchid > 0); +} + +int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value); +int adreno_hw_init(struct msm_gpu *gpu); +uint32_t adreno_last_fence(struct msm_gpu *gpu); +void adreno_recover(struct msm_gpu *gpu); +int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, +		struct msm_file_private *ctx); +void adreno_flush(struct msm_gpu *gpu); +void adreno_idle(struct msm_gpu *gpu); +#ifdef CONFIG_DEBUG_FS +void adreno_show(struct msm_gpu *gpu, struct seq_file *m); +#endif +void adreno_dump(struct msm_gpu *gpu); +void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords); + +int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, +		struct adreno_gpu *gpu, const struct adreno_gpu_funcs *funcs, +		struct adreno_rev rev); +void adreno_gpu_cleanup(struct adreno_gpu *gpu); + + +/* ringbuffer helpers (the parts that are adreno specific) */ + +static inline void +OUT_PKT0(struct msm_ringbuffer *ring, uint16_t regindx, uint16_t cnt) +{ +	adreno_wait_ring(ring->gpu, cnt+1); +	OUT_RING(ring, CP_TYPE0_PKT | ((cnt-1) << 16) | (regindx & 0x7FFF)); +} + +/* no-op packet: */ +static inline void +OUT_PKT2(struct msm_ringbuffer *ring) +{ +	adreno_wait_ring(ring->gpu, 1); +	OUT_RING(ring, CP_TYPE2_PKT); +} + +static inline void +OUT_PKT3(struct msm_ringbuffer *ring, uint8_t opcode, uint16_t cnt) +{ +	adreno_wait_ring(ring->gpu, cnt+1); +	OUT_RING(ring, CP_TYPE3_PKT | ((cnt-1) << 16) | ((opcode & 0xFF) << 8)); +} + + +#endif /* __ADRENO_GPU_H__ */ diff --git a/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h b/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h new file mode 100644 index 00000000000..ae992c71703 --- /dev/null +++ b/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h @@ -0,0 +1,266 @@ +#ifndef ADRENO_PM4_XML +#define ADRENO_PM4_XML + +/* Autogenerated file, DO NOT EDIT manually! + +This file was generated by the rules-ng-ng headergen tool in this git repository: +http://github.com/freedreno/envytools/ +git clone https://github.com/freedreno/envytools.git + +The rules-ng-ng source files this header was generated from are: +- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2013-11-30 14:47:15) +- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32814 bytes, from 2013-11-30 15:07:33) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (   8900 bytes, from 2013-10-22 23:57:49) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  10574 bytes, from 2013-11-13 05:44:45) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  53644 bytes, from 2013-11-30 15:07:33) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (   8344 bytes, from 2013-11-30 14:49:47) + +Copyright (C) 2013 by the following authors: +- Rob Clark <robdclark@gmail.com> (robclark) + +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 THE COPYRIGHT OWNER(S) 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. +*/ + + +enum vgt_event_type { +	VS_DEALLOC = 0, +	PS_DEALLOC = 1, +	VS_DONE_TS = 2, +	PS_DONE_TS = 3, +	CACHE_FLUSH_TS = 4, +	CONTEXT_DONE = 5, +	CACHE_FLUSH = 6, +	HLSQ_FLUSH = 7, +	VIZQUERY_START = 7, +	VIZQUERY_END = 8, +	SC_WAIT_WC = 9, +	RST_PIX_CNT = 13, +	RST_VTX_CNT = 14, +	TILE_FLUSH = 15, +	CACHE_FLUSH_AND_INV_TS_EVENT = 20, +	ZPASS_DONE = 21, +	CACHE_FLUSH_AND_INV_EVENT = 22, +	PERFCOUNTER_START = 23, +	PERFCOUNTER_STOP = 24, +	VS_FETCH_DONE = 27, +	FACENESS_FLUSH = 28, +}; + +enum pc_di_primtype { +	DI_PT_NONE = 0, +	DI_PT_POINTLIST_A2XX = 1, +	DI_PT_LINELIST = 2, +	DI_PT_LINESTRIP = 3, +	DI_PT_TRILIST = 4, +	DI_PT_TRIFAN = 5, +	DI_PT_TRISTRIP = 6, +	DI_PT_LINELOOP = 7, +	DI_PT_RECTLIST = 8, +	DI_PT_POINTLIST_A3XX = 9, +	DI_PT_QUADLIST = 13, +	DI_PT_QUADSTRIP = 14, +	DI_PT_POLYGON = 15, +	DI_PT_2D_COPY_RECT_LIST_V0 = 16, +	DI_PT_2D_COPY_RECT_LIST_V1 = 17, +	DI_PT_2D_COPY_RECT_LIST_V2 = 18, +	DI_PT_2D_COPY_RECT_LIST_V3 = 19, +	DI_PT_2D_FILL_RECT_LIST = 20, +	DI_PT_2D_LINE_STRIP = 21, +	DI_PT_2D_TRI_STRIP = 22, +}; + +enum pc_di_src_sel { +	DI_SRC_SEL_DMA = 0, +	DI_SRC_SEL_IMMEDIATE = 1, +	DI_SRC_SEL_AUTO_INDEX = 2, +	DI_SRC_SEL_RESERVED = 3, +}; + +enum pc_di_index_size { +	INDEX_SIZE_IGN = 0, +	INDEX_SIZE_16_BIT = 0, +	INDEX_SIZE_32_BIT = 1, +	INDEX_SIZE_8_BIT = 2, +	INDEX_SIZE_INVALID = 0, +}; + +enum pc_di_vis_cull_mode { +	IGNORE_VISIBILITY = 0, +}; + +enum adreno_pm4_packet_type { +	CP_TYPE0_PKT = 0, +	CP_TYPE1_PKT = 0x40000000, +	CP_TYPE2_PKT = 0x80000000, +	CP_TYPE3_PKT = 0xc0000000, +}; + +enum adreno_pm4_type3_packets { +	CP_ME_INIT = 72, +	CP_NOP = 16, +	CP_INDIRECT_BUFFER = 63, +	CP_INDIRECT_BUFFER_PFD = 55, +	CP_WAIT_FOR_IDLE = 38, +	CP_WAIT_REG_MEM = 60, +	CP_WAIT_REG_EQ = 82, +	CP_WAIT_REG_GTE = 83, +	CP_WAIT_UNTIL_READ = 92, +	CP_WAIT_IB_PFD_COMPLETE = 93, +	CP_REG_RMW = 33, +	CP_SET_BIN_DATA = 47, +	CP_REG_TO_MEM = 62, +	CP_MEM_WRITE = 61, +	CP_MEM_WRITE_CNTR = 79, +	CP_COND_EXEC = 68, +	CP_COND_WRITE = 69, +	CP_EVENT_WRITE = 70, +	CP_EVENT_WRITE_SHD = 88, +	CP_EVENT_WRITE_CFL = 89, +	CP_EVENT_WRITE_ZPD = 91, +	CP_RUN_OPENCL = 49, +	CP_DRAW_INDX = 34, +	CP_DRAW_INDX_2 = 54, +	CP_DRAW_INDX_BIN = 52, +	CP_DRAW_INDX_2_BIN = 53, +	CP_VIZ_QUERY = 35, +	CP_SET_STATE = 37, +	CP_SET_CONSTANT = 45, +	CP_IM_LOAD = 39, +	CP_IM_LOAD_IMMEDIATE = 43, +	CP_LOAD_CONSTANT_CONTEXT = 46, +	CP_INVALIDATE_STATE = 59, +	CP_SET_SHADER_BASES = 74, +	CP_SET_BIN_MASK = 80, +	CP_SET_BIN_SELECT = 81, +	CP_CONTEXT_UPDATE = 94, +	CP_INTERRUPT = 64, +	CP_IM_STORE = 44, +	CP_SET_DRAW_INIT_FLAGS = 75, +	CP_SET_PROTECTED_MODE = 95, +	CP_LOAD_STATE = 48, +	CP_COND_INDIRECT_BUFFER_PFE = 58, +	CP_COND_INDIRECT_BUFFER_PFD = 50, +	CP_INDIRECT_BUFFER_PFE = 63, +	CP_SET_BIN = 76, +	CP_TEST_TWO_MEMS = 113, +	CP_WAIT_FOR_ME = 19, +	IN_IB_PREFETCH_END = 23, +	IN_SUBBLK_PREFETCH = 31, +	IN_INSTR_PREFETCH = 32, +	IN_INSTR_MATCH = 71, +	IN_CONST_PREFETCH = 73, +	IN_INCR_UPDT_STATE = 85, +	IN_INCR_UPDT_CONST = 86, +	IN_INCR_UPDT_INSTR = 87, +}; + +enum adreno_state_block { +	SB_VERT_TEX = 0, +	SB_VERT_MIPADDR = 1, +	SB_FRAG_TEX = 2, +	SB_FRAG_MIPADDR = 3, +	SB_VERT_SHADER = 4, +	SB_FRAG_SHADER = 6, +}; + +enum adreno_state_type { +	ST_SHADER = 0, +	ST_CONSTANTS = 1, +}; + +enum adreno_state_src { +	SS_DIRECT = 0, +	SS_INDIRECT = 4, +}; + +#define REG_CP_LOAD_STATE_0					0x00000000 +#define CP_LOAD_STATE_0_DST_OFF__MASK				0x0000ffff +#define CP_LOAD_STATE_0_DST_OFF__SHIFT				0 +static inline uint32_t CP_LOAD_STATE_0_DST_OFF(uint32_t val) +{ +	return ((val) << CP_LOAD_STATE_0_DST_OFF__SHIFT) & CP_LOAD_STATE_0_DST_OFF__MASK; +} +#define CP_LOAD_STATE_0_STATE_SRC__MASK				0x00070000 +#define CP_LOAD_STATE_0_STATE_SRC__SHIFT			16 +static inline uint32_t CP_LOAD_STATE_0_STATE_SRC(enum adreno_state_src val) +{ +	return ((val) << CP_LOAD_STATE_0_STATE_SRC__SHIFT) & CP_LOAD_STATE_0_STATE_SRC__MASK; +} +#define CP_LOAD_STATE_0_STATE_BLOCK__MASK			0x00380000 +#define CP_LOAD_STATE_0_STATE_BLOCK__SHIFT			19 +static inline uint32_t CP_LOAD_STATE_0_STATE_BLOCK(enum adreno_state_block val) +{ +	return ((val) << CP_LOAD_STATE_0_STATE_BLOCK__SHIFT) & CP_LOAD_STATE_0_STATE_BLOCK__MASK; +} +#define CP_LOAD_STATE_0_NUM_UNIT__MASK				0x7fc00000 +#define CP_LOAD_STATE_0_NUM_UNIT__SHIFT				22 +static inline uint32_t CP_LOAD_STATE_0_NUM_UNIT(uint32_t val) +{ +	return ((val) << CP_LOAD_STATE_0_NUM_UNIT__SHIFT) & CP_LOAD_STATE_0_NUM_UNIT__MASK; +} + +#define REG_CP_LOAD_STATE_1					0x00000001 +#define CP_LOAD_STATE_1_STATE_TYPE__MASK			0x00000003 +#define CP_LOAD_STATE_1_STATE_TYPE__SHIFT			0 +static inline uint32_t CP_LOAD_STATE_1_STATE_TYPE(enum adreno_state_type val) +{ +	return ((val) << CP_LOAD_STATE_1_STATE_TYPE__SHIFT) & CP_LOAD_STATE_1_STATE_TYPE__MASK; +} +#define CP_LOAD_STATE_1_EXT_SRC_ADDR__MASK			0xfffffffc +#define CP_LOAD_STATE_1_EXT_SRC_ADDR__SHIFT			2 +static inline uint32_t CP_LOAD_STATE_1_EXT_SRC_ADDR(uint32_t val) +{ +	return ((val >> 2) << CP_LOAD_STATE_1_EXT_SRC_ADDR__SHIFT) & CP_LOAD_STATE_1_EXT_SRC_ADDR__MASK; +} + +#define REG_CP_SET_BIN_0					0x00000000 + +#define REG_CP_SET_BIN_1					0x00000001 +#define CP_SET_BIN_1_X1__MASK					0x0000ffff +#define CP_SET_BIN_1_X1__SHIFT					0 +static inline uint32_t CP_SET_BIN_1_X1(uint32_t val) +{ +	return ((val) << CP_SET_BIN_1_X1__SHIFT) & CP_SET_BIN_1_X1__MASK; +} +#define CP_SET_BIN_1_Y1__MASK					0xffff0000 +#define CP_SET_BIN_1_Y1__SHIFT					16 +static inline uint32_t CP_SET_BIN_1_Y1(uint32_t val) +{ +	return ((val) << CP_SET_BIN_1_Y1__SHIFT) & CP_SET_BIN_1_Y1__MASK; +} + +#define REG_CP_SET_BIN_2					0x00000002 +#define CP_SET_BIN_2_X2__MASK					0x0000ffff +#define CP_SET_BIN_2_X2__SHIFT					0 +static inline uint32_t CP_SET_BIN_2_X2(uint32_t val) +{ +	return ((val) << CP_SET_BIN_2_X2__SHIFT) & CP_SET_BIN_2_X2__MASK; +} +#define CP_SET_BIN_2_Y2__MASK					0xffff0000 +#define CP_SET_BIN_2_Y2__SHIFT					16 +static inline uint32_t CP_SET_BIN_2_Y2(uint32_t val) +{ +	return ((val) << CP_SET_BIN_2_Y2__SHIFT) & CP_SET_BIN_2_Y2__MASK; +} + + +#endif /* ADRENO_PM4_XML */ diff --git a/drivers/gpu/drm/msm/dsi/dsi.xml.h b/drivers/gpu/drm/msm/dsi/dsi.xml.h new file mode 100644 index 00000000000..87be647e382 --- /dev/null +++ b/drivers/gpu/drm/msm/dsi/dsi.xml.h @@ -0,0 +1,504 @@ +#ifndef DSI_XML +#define DSI_XML + +/* Autogenerated file, DO NOT EDIT manually! + +This file was generated by the rules-ng-ng headergen tool in this git repository: +http://github.com/freedreno/envytools/ +git clone https://github.com/freedreno/envytools.git + +The rules-ng-ng source files this header was generated from are: +- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    647 bytes, from 2013-11-30 14:45:35) +- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  17996 bytes, from 2013-12-01 19:10:31) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2013-11-30 15:00:52) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2013-12-03 20:59:13) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  20932 bytes, from 2013-12-01 15:13:04) + +Copyright (C) 2013 by the following authors: +- Rob Clark <robdclark@gmail.com> (robclark) + +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 THE COPYRIGHT OWNER(S) 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. +*/ + + +enum dsi_traffic_mode { +	NON_BURST_SYNCH_PULSE = 0, +	NON_BURST_SYNCH_EVENT = 1, +	BURST_MODE = 2, +}; + +enum dsi_dst_format { +	DST_FORMAT_RGB565 = 0, +	DST_FORMAT_RGB666 = 1, +	DST_FORMAT_RGB666_LOOSE = 2, +	DST_FORMAT_RGB888 = 3, +}; + +enum dsi_rgb_swap { +	SWAP_RGB = 0, +	SWAP_RBG = 1, +	SWAP_BGR = 2, +	SWAP_BRG = 3, +	SWAP_GRB = 4, +	SWAP_GBR = 5, +}; + +enum dsi_cmd_trigger { +	TRIGGER_NONE = 0, +	TRIGGER_TE = 2, +	TRIGGER_SW = 4, +	TRIGGER_SW_SEOF = 5, +	TRIGGER_SW_TE = 6, +}; + +#define DSI_IRQ_CMD_DMA_DONE					0x00000001 +#define DSI_IRQ_MASK_CMD_DMA_DONE				0x00000002 +#define DSI_IRQ_CMD_MDP_DONE					0x00000100 +#define DSI_IRQ_MASK_CMD_MDP_DONE				0x00000200 +#define DSI_IRQ_VIDEO_DONE					0x00010000 +#define DSI_IRQ_MASK_VIDEO_DONE					0x00020000 +#define DSI_IRQ_ERROR						0x01000000 +#define DSI_IRQ_MASK_ERROR					0x02000000 +#define REG_DSI_CTRL						0x00000000 +#define DSI_CTRL_ENABLE						0x00000001 +#define DSI_CTRL_VID_MODE_EN					0x00000002 +#define DSI_CTRL_CMD_MODE_EN					0x00000004 +#define DSI_CTRL_LANE0						0x00000010 +#define DSI_CTRL_LANE1						0x00000020 +#define DSI_CTRL_LANE2						0x00000040 +#define DSI_CTRL_LANE3						0x00000080 +#define DSI_CTRL_CLK_EN						0x00000100 +#define DSI_CTRL_ECC_CHECK					0x00100000 +#define DSI_CTRL_CRC_CHECK					0x01000000 + +#define REG_DSI_STATUS0						0x00000004 +#define DSI_STATUS0_CMD_MODE_DMA_BUSY				0x00000002 +#define DSI_STATUS0_VIDEO_MODE_ENGINE_BUSY			0x00000008 +#define DSI_STATUS0_DSI_BUSY					0x00000010 + +#define REG_DSI_FIFO_STATUS					0x00000008 + +#define REG_DSI_VID_CFG0					0x0000000c +#define DSI_VID_CFG0_VIRT_CHANNEL__MASK				0x00000003 +#define DSI_VID_CFG0_VIRT_CHANNEL__SHIFT			0 +static inline uint32_t DSI_VID_CFG0_VIRT_CHANNEL(uint32_t val) +{ +	return ((val) << DSI_VID_CFG0_VIRT_CHANNEL__SHIFT) & DSI_VID_CFG0_VIRT_CHANNEL__MASK; +} +#define DSI_VID_CFG0_DST_FORMAT__MASK				0x00000030 +#define DSI_VID_CFG0_DST_FORMAT__SHIFT				4 +static inline uint32_t DSI_VID_CFG0_DST_FORMAT(enum dsi_dst_format val) +{ +	return ((val) << DSI_VID_CFG0_DST_FORMAT__SHIFT) & DSI_VID_CFG0_DST_FORMAT__MASK; +} +#define DSI_VID_CFG0_TRAFFIC_MODE__MASK				0x00000300 +#define DSI_VID_CFG0_TRAFFIC_MODE__SHIFT			8 +static inline uint32_t DSI_VID_CFG0_TRAFFIC_MODE(enum dsi_traffic_mode val) +{ +	return ((val) << DSI_VID_CFG0_TRAFFIC_MODE__SHIFT) & DSI_VID_CFG0_TRAFFIC_MODE__MASK; +} +#define DSI_VID_CFG0_BLLP_POWER_STOP				0x00001000 +#define DSI_VID_CFG0_EOF_BLLP_POWER_STOP			0x00008000 +#define DSI_VID_CFG0_HSA_POWER_STOP				0x00010000 +#define DSI_VID_CFG0_HBP_POWER_STOP				0x00100000 +#define DSI_VID_CFG0_HFP_POWER_STOP				0x01000000 +#define DSI_VID_CFG0_PULSE_MODE_HSA_HE				0x10000000 + +#define REG_DSI_VID_CFG1					0x0000001c +#define DSI_VID_CFG1_R_SEL					0x00000010 +#define DSI_VID_CFG1_G_SEL					0x00000100 +#define DSI_VID_CFG1_B_SEL					0x00001000 +#define DSI_VID_CFG1_RGB_SWAP__MASK				0x00070000 +#define DSI_VID_CFG1_RGB_SWAP__SHIFT				16 +static inline uint32_t DSI_VID_CFG1_RGB_SWAP(enum dsi_rgb_swap val) +{ +	return ((val) << DSI_VID_CFG1_RGB_SWAP__SHIFT) & DSI_VID_CFG1_RGB_SWAP__MASK; +} +#define DSI_VID_CFG1_INTERLEAVE_MAX__MASK			0x00f00000 +#define DSI_VID_CFG1_INTERLEAVE_MAX__SHIFT			20 +static inline uint32_t DSI_VID_CFG1_INTERLEAVE_MAX(uint32_t val) +{ +	return ((val) << DSI_VID_CFG1_INTERLEAVE_MAX__SHIFT) & DSI_VID_CFG1_INTERLEAVE_MAX__MASK; +} + +#define REG_DSI_ACTIVE_H					0x00000020 +#define DSI_ACTIVE_H_START__MASK				0x00000fff +#define DSI_ACTIVE_H_START__SHIFT				0 +static inline uint32_t DSI_ACTIVE_H_START(uint32_t val) +{ +	return ((val) << DSI_ACTIVE_H_START__SHIFT) & DSI_ACTIVE_H_START__MASK; +} +#define DSI_ACTIVE_H_END__MASK					0x0fff0000 +#define DSI_ACTIVE_H_END__SHIFT					16 +static inline uint32_t DSI_ACTIVE_H_END(uint32_t val) +{ +	return ((val) << DSI_ACTIVE_H_END__SHIFT) & DSI_ACTIVE_H_END__MASK; +} + +#define REG_DSI_ACTIVE_V					0x00000024 +#define DSI_ACTIVE_V_START__MASK				0x00000fff +#define DSI_ACTIVE_V_START__SHIFT				0 +static inline uint32_t DSI_ACTIVE_V_START(uint32_t val) +{ +	return ((val) << DSI_ACTIVE_V_START__SHIFT) & DSI_ACTIVE_V_START__MASK; +} +#define DSI_ACTIVE_V_END__MASK					0x0fff0000 +#define DSI_ACTIVE_V_END__SHIFT					16 +static inline uint32_t DSI_ACTIVE_V_END(uint32_t val) +{ +	return ((val) << DSI_ACTIVE_V_END__SHIFT) & DSI_ACTIVE_V_END__MASK; +} + +#define REG_DSI_TOTAL						0x00000028 +#define DSI_TOTAL_H_TOTAL__MASK					0x00000fff +#define DSI_TOTAL_H_TOTAL__SHIFT				0 +static inline uint32_t DSI_TOTAL_H_TOTAL(uint32_t val) +{ +	return ((val) << DSI_TOTAL_H_TOTAL__SHIFT) & DSI_TOTAL_H_TOTAL__MASK; +} +#define DSI_TOTAL_V_TOTAL__MASK					0x0fff0000 +#define DSI_TOTAL_V_TOTAL__SHIFT				16 +static inline uint32_t DSI_TOTAL_V_TOTAL(uint32_t val) +{ +	return ((val) << DSI_TOTAL_V_TOTAL__SHIFT) & DSI_TOTAL_V_TOTAL__MASK; +} + +#define REG_DSI_ACTIVE_HSYNC					0x0000002c +#define DSI_ACTIVE_HSYNC_START__MASK				0x00000fff +#define DSI_ACTIVE_HSYNC_START__SHIFT				0 +static inline uint32_t DSI_ACTIVE_HSYNC_START(uint32_t val) +{ +	return ((val) << DSI_ACTIVE_HSYNC_START__SHIFT) & DSI_ACTIVE_HSYNC_START__MASK; +} +#define DSI_ACTIVE_HSYNC_END__MASK				0x0fff0000 +#define DSI_ACTIVE_HSYNC_END__SHIFT				16 +static inline uint32_t DSI_ACTIVE_HSYNC_END(uint32_t val) +{ +	return ((val) << DSI_ACTIVE_HSYNC_END__SHIFT) & DSI_ACTIVE_HSYNC_END__MASK; +} + +#define REG_DSI_ACTIVE_VSYNC					0x00000034 +#define DSI_ACTIVE_VSYNC_START__MASK				0x00000fff +#define DSI_ACTIVE_VSYNC_START__SHIFT				0 +static inline uint32_t DSI_ACTIVE_VSYNC_START(uint32_t val) +{ +	return ((val) << DSI_ACTIVE_VSYNC_START__SHIFT) & DSI_ACTIVE_VSYNC_START__MASK; +} +#define DSI_ACTIVE_VSYNC_END__MASK				0x0fff0000 +#define DSI_ACTIVE_VSYNC_END__SHIFT				16 +static inline uint32_t DSI_ACTIVE_VSYNC_END(uint32_t val) +{ +	return ((val) << DSI_ACTIVE_VSYNC_END__SHIFT) & DSI_ACTIVE_VSYNC_END__MASK; +} + +#define REG_DSI_CMD_DMA_CTRL					0x00000038 +#define DSI_CMD_DMA_CTRL_FROM_FRAME_BUFFER			0x10000000 +#define DSI_CMD_DMA_CTRL_LOW_POWER				0x04000000 + +#define REG_DSI_CMD_CFG0					0x0000003c + +#define REG_DSI_CMD_CFG1					0x00000040 + +#define REG_DSI_DMA_BASE					0x00000044 + +#define REG_DSI_DMA_LEN						0x00000048 + +#define REG_DSI_ACK_ERR_STATUS					0x00000064 + +static inline uint32_t REG_DSI_RDBK(uint32_t i0) { return 0x00000068 + 0x4*i0; } + +static inline uint32_t REG_DSI_RDBK_DATA(uint32_t i0) { return 0x00000068 + 0x4*i0; } + +#define REG_DSI_TRIG_CTRL					0x00000080 +#define DSI_TRIG_CTRL_DMA_TRIGGER__MASK				0x0000000f +#define DSI_TRIG_CTRL_DMA_TRIGGER__SHIFT			0 +static inline uint32_t DSI_TRIG_CTRL_DMA_TRIGGER(enum dsi_cmd_trigger val) +{ +	return ((val) << DSI_TRIG_CTRL_DMA_TRIGGER__SHIFT) & DSI_TRIG_CTRL_DMA_TRIGGER__MASK; +} +#define DSI_TRIG_CTRL_MDP_TRIGGER__MASK				0x000000f0 +#define DSI_TRIG_CTRL_MDP_TRIGGER__SHIFT			4 +static inline uint32_t DSI_TRIG_CTRL_MDP_TRIGGER(enum dsi_cmd_trigger val) +{ +	return ((val) << DSI_TRIG_CTRL_MDP_TRIGGER__SHIFT) & DSI_TRIG_CTRL_MDP_TRIGGER__MASK; +} +#define DSI_TRIG_CTRL_STREAM					0x00000100 +#define DSI_TRIG_CTRL_TE					0x80000000 + +#define REG_DSI_TRIG_DMA					0x0000008c + +#define REG_DSI_DLN0_PHY_ERR					0x000000b0 + +#define REG_DSI_TIMEOUT_STATUS					0x000000bc + +#define REG_DSI_CLKOUT_TIMING_CTRL				0x000000c0 +#define DSI_CLKOUT_TIMING_CTRL_T_CLK_PRE__MASK			0x0000003f +#define DSI_CLKOUT_TIMING_CTRL_T_CLK_PRE__SHIFT			0 +static inline uint32_t DSI_CLKOUT_TIMING_CTRL_T_CLK_PRE(uint32_t val) +{ +	return ((val) << DSI_CLKOUT_TIMING_CTRL_T_CLK_PRE__SHIFT) & DSI_CLKOUT_TIMING_CTRL_T_CLK_PRE__MASK; +} +#define DSI_CLKOUT_TIMING_CTRL_T_CLK_POST__MASK			0x00003f00 +#define DSI_CLKOUT_TIMING_CTRL_T_CLK_POST__SHIFT		8 +static inline uint32_t DSI_CLKOUT_TIMING_CTRL_T_CLK_POST(uint32_t val) +{ +	return ((val) << DSI_CLKOUT_TIMING_CTRL_T_CLK_POST__SHIFT) & DSI_CLKOUT_TIMING_CTRL_T_CLK_POST__MASK; +} + +#define REG_DSI_EOT_PACKET_CTRL					0x000000c8 +#define DSI_EOT_PACKET_CTRL_TX_EOT_APPEND			0x00000001 +#define DSI_EOT_PACKET_CTRL_RX_EOT_IGNORE			0x00000010 + +#define REG_DSI_LANE_SWAP_CTRL					0x000000ac + +#define REG_DSI_ERR_INT_MASK0					0x00000108 + +#define REG_DSI_INTR_CTRL					0x0000010c + +#define REG_DSI_RESET						0x00000114 + +#define REG_DSI_CLK_CTRL					0x00000118 + +#define REG_DSI_PHY_RESET					0x00000128 + +#define REG_DSI_PHY_PLL_CTRL_0					0x00000200 +#define DSI_PHY_PLL_CTRL_0_ENABLE				0x00000001 + +#define REG_DSI_PHY_PLL_CTRL_1					0x00000204 + +#define REG_DSI_PHY_PLL_CTRL_2					0x00000208 + +#define REG_DSI_PHY_PLL_CTRL_3					0x0000020c + +#define REG_DSI_PHY_PLL_CTRL_4					0x00000210 + +#define REG_DSI_PHY_PLL_CTRL_5					0x00000214 + +#define REG_DSI_PHY_PLL_CTRL_6					0x00000218 + +#define REG_DSI_PHY_PLL_CTRL_7					0x0000021c + +#define REG_DSI_PHY_PLL_CTRL_8					0x00000220 + +#define REG_DSI_PHY_PLL_CTRL_9					0x00000224 + +#define REG_DSI_PHY_PLL_CTRL_10					0x00000228 + +#define REG_DSI_PHY_PLL_CTRL_11					0x0000022c + +#define REG_DSI_PHY_PLL_CTRL_12					0x00000230 + +#define REG_DSI_PHY_PLL_CTRL_13					0x00000234 + +#define REG_DSI_PHY_PLL_CTRL_14					0x00000238 + +#define REG_DSI_PHY_PLL_CTRL_15					0x0000023c + +#define REG_DSI_PHY_PLL_CTRL_16					0x00000240 + +#define REG_DSI_PHY_PLL_CTRL_17					0x00000244 + +#define REG_DSI_PHY_PLL_CTRL_18					0x00000248 + +#define REG_DSI_PHY_PLL_CTRL_19					0x0000024c + +#define REG_DSI_PHY_PLL_CTRL_20					0x00000250 + +#define REG_DSI_PHY_PLL_STATUS					0x00000280 +#define DSI_PHY_PLL_STATUS_PLL_BUSY				0x00000001 + +#define REG_DSI_8x60_PHY_TPA_CTRL_1				0x00000258 + +#define REG_DSI_8x60_PHY_TPA_CTRL_2				0x0000025c + +#define REG_DSI_8x60_PHY_TIMING_CTRL_0				0x00000260 + +#define REG_DSI_8x60_PHY_TIMING_CTRL_1				0x00000264 + +#define REG_DSI_8x60_PHY_TIMING_CTRL_2				0x00000268 + +#define REG_DSI_8x60_PHY_TIMING_CTRL_3				0x0000026c + +#define REG_DSI_8x60_PHY_TIMING_CTRL_4				0x00000270 + +#define REG_DSI_8x60_PHY_TIMING_CTRL_5				0x00000274 + +#define REG_DSI_8x60_PHY_TIMING_CTRL_6				0x00000278 + +#define REG_DSI_8x60_PHY_TIMING_CTRL_7				0x0000027c + +#define REG_DSI_8x60_PHY_TIMING_CTRL_8				0x00000280 + +#define REG_DSI_8x60_PHY_TIMING_CTRL_9				0x00000284 + +#define REG_DSI_8x60_PHY_TIMING_CTRL_10				0x00000288 + +#define REG_DSI_8x60_PHY_TIMING_CTRL_11				0x0000028c + +#define REG_DSI_8x60_PHY_CTRL_0					0x00000290 + +#define REG_DSI_8x60_PHY_CTRL_1					0x00000294 + +#define REG_DSI_8x60_PHY_CTRL_2					0x00000298 + +#define REG_DSI_8x60_PHY_CTRL_3					0x0000029c + +#define REG_DSI_8x60_PHY_STRENGTH_0				0x000002a0 + +#define REG_DSI_8x60_PHY_STRENGTH_1				0x000002a4 + +#define REG_DSI_8x60_PHY_STRENGTH_2				0x000002a8 + +#define REG_DSI_8x60_PHY_STRENGTH_3				0x000002ac + +#define REG_DSI_8x60_PHY_REGULATOR_CTRL_0			0x000002cc + +#define REG_DSI_8x60_PHY_REGULATOR_CTRL_1			0x000002d0 + +#define REG_DSI_8x60_PHY_REGULATOR_CTRL_2			0x000002d4 + +#define REG_DSI_8x60_PHY_REGULATOR_CTRL_3			0x000002d8 + +#define REG_DSI_8x60_PHY_REGULATOR_CTRL_4			0x000002dc + +#define REG_DSI_8x60_PHY_CAL_HW_TRIGGER				0x000000f0 + +#define REG_DSI_8x60_PHY_CAL_CTRL				0x000000f4 + +#define REG_DSI_8x60_PHY_CAL_STATUS				0x000000fc +#define DSI_8x60_PHY_CAL_STATUS_CAL_BUSY			0x10000000 + +static inline uint32_t REG_DSI_8960_LN(uint32_t i0) { return 0x00000300 + 0x40*i0; } + +static inline uint32_t REG_DSI_8960_LN_CFG_0(uint32_t i0) { return 0x00000300 + 0x40*i0; } + +static inline uint32_t REG_DSI_8960_LN_CFG_1(uint32_t i0) { return 0x00000304 + 0x40*i0; } + +static inline uint32_t REG_DSI_8960_LN_CFG_2(uint32_t i0) { return 0x00000308 + 0x40*i0; } + +static inline uint32_t REG_DSI_8960_LN_TEST_DATAPATH(uint32_t i0) { return 0x0000030c + 0x40*i0; } + +static inline uint32_t REG_DSI_8960_LN_TEST_STR_0(uint32_t i0) { return 0x00000314 + 0x40*i0; } + +static inline uint32_t REG_DSI_8960_LN_TEST_STR_1(uint32_t i0) { return 0x00000318 + 0x40*i0; } + +#define REG_DSI_8960_PHY_LNCK_CFG_0				0x00000400 + +#define REG_DSI_8960_PHY_LNCK_CFG_1				0x00000404 + +#define REG_DSI_8960_PHY_LNCK_CFG_2				0x00000408 + +#define REG_DSI_8960_PHY_LNCK_TEST_DATAPATH			0x0000040c + +#define REG_DSI_8960_PHY_LNCK_TEST_STR0				0x00000414 + +#define REG_DSI_8960_PHY_LNCK_TEST_STR1				0x00000418 + +#define REG_DSI_8960_PHY_TIMING_CTRL_0				0x00000440 + +#define REG_DSI_8960_PHY_TIMING_CTRL_1				0x00000444 + +#define REG_DSI_8960_PHY_TIMING_CTRL_2				0x00000448 + +#define REG_DSI_8960_PHY_TIMING_CTRL_3				0x0000044c + +#define REG_DSI_8960_PHY_TIMING_CTRL_4				0x00000450 + +#define REG_DSI_8960_PHY_TIMING_CTRL_5				0x00000454 + +#define REG_DSI_8960_PHY_TIMING_CTRL_6				0x00000458 + +#define REG_DSI_8960_PHY_TIMING_CTRL_7				0x0000045c + +#define REG_DSI_8960_PHY_TIMING_CTRL_8				0x00000460 + +#define REG_DSI_8960_PHY_TIMING_CTRL_9				0x00000464 + +#define REG_DSI_8960_PHY_TIMING_CTRL_10				0x00000468 + +#define REG_DSI_8960_PHY_TIMING_CTRL_11				0x0000046c + +#define REG_DSI_8960_PHY_CTRL_0					0x00000470 + +#define REG_DSI_8960_PHY_CTRL_1					0x00000474 + +#define REG_DSI_8960_PHY_CTRL_2					0x00000478 + +#define REG_DSI_8960_PHY_CTRL_3					0x0000047c + +#define REG_DSI_8960_PHY_STRENGTH_0				0x00000480 + +#define REG_DSI_8960_PHY_STRENGTH_1				0x00000484 + +#define REG_DSI_8960_PHY_STRENGTH_2				0x00000488 + +#define REG_DSI_8960_PHY_BIST_CTRL_0				0x0000048c + +#define REG_DSI_8960_PHY_BIST_CTRL_1				0x00000490 + +#define REG_DSI_8960_PHY_BIST_CTRL_2				0x00000494 + +#define REG_DSI_8960_PHY_BIST_CTRL_3				0x00000498 + +#define REG_DSI_8960_PHY_BIST_CTRL_4				0x0000049c + +#define REG_DSI_8960_PHY_LDO_CTRL				0x000004b0 + +#define REG_DSI_8960_PHY_REGULATOR_CTRL_0			0x00000500 + +#define REG_DSI_8960_PHY_REGULATOR_CTRL_1			0x00000504 + +#define REG_DSI_8960_PHY_REGULATOR_CTRL_2			0x00000508 + +#define REG_DSI_8960_PHY_REGULATOR_CTRL_3			0x0000050c + +#define REG_DSI_8960_PHY_REGULATOR_CTRL_4			0x00000510 + +#define REG_DSI_8960_PHY_REGULATOR_CAL_PWR_CFG			0x00000518 + +#define REG_DSI_8960_PHY_CAL_HW_TRIGGER				0x00000528 + +#define REG_DSI_8960_PHY_CAL_SW_CFG_0				0x0000052c + +#define REG_DSI_8960_PHY_CAL_SW_CFG_1				0x00000530 + +#define REG_DSI_8960_PHY_CAL_SW_CFG_2				0x00000534 + +#define REG_DSI_8960_PHY_CAL_HW_CFG_0				0x00000538 + +#define REG_DSI_8960_PHY_CAL_HW_CFG_1				0x0000053c + +#define REG_DSI_8960_PHY_CAL_HW_CFG_2				0x00000540 + +#define REG_DSI_8960_PHY_CAL_HW_CFG_3				0x00000544 + +#define REG_DSI_8960_PHY_CAL_HW_CFG_4				0x00000548 + +#define REG_DSI_8960_PHY_CAL_STATUS				0x00000550 +#define DSI_8960_PHY_CAL_STATUS_CAL_BUSY			0x00000010 + + +#endif /* DSI_XML */ diff --git a/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h b/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h new file mode 100644 index 00000000000..747a6ef4211 --- /dev/null +++ b/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h @@ -0,0 +1,116 @@ +#ifndef MMSS_CC_XML +#define MMSS_CC_XML + +/* Autogenerated file, DO NOT EDIT manually! + +This file was generated by the rules-ng-ng headergen tool in this git repository: +http://github.com/freedreno/envytools/ +git clone https://github.com/freedreno/envytools.git + +The rules-ng-ng source files this header was generated from are: +- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    647 bytes, from 2013-11-30 14:45:35) +- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  17996 bytes, from 2013-12-01 19:10:31) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2013-11-30 15:00:52) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2013-12-03 20:59:13) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  20932 bytes, from 2013-12-01 15:13:04) + +Copyright (C) 2013 by the following authors: +- Rob Clark <robdclark@gmail.com> (robclark) + +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 THE COPYRIGHT OWNER(S) 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. +*/ + + +enum mmss_cc_clk { +	CLK = 0, +	PCLK = 1, +}; + +#define REG_MMSS_CC_AHB						0x00000008 + +static inline uint32_t __offset_CLK(enum mmss_cc_clk idx) +{ +	switch (idx) { +		case CLK: return 0x0000004c; +		case PCLK: return 0x00000130; +		default: return INVALID_IDX(idx); +	} +} +static inline uint32_t REG_MMSS_CC_CLK(enum mmss_cc_clk i0) { return 0x00000000 + __offset_CLK(i0); } + +static inline uint32_t REG_MMSS_CC_CLK_CC(enum mmss_cc_clk i0) { return 0x00000000 + __offset_CLK(i0); } +#define MMSS_CC_CLK_CC_CLK_EN					0x00000001 +#define MMSS_CC_CLK_CC_ROOT_EN					0x00000004 +#define MMSS_CC_CLK_CC_MND_EN					0x00000020 +#define MMSS_CC_CLK_CC_MND_MODE__MASK				0x000000c0 +#define MMSS_CC_CLK_CC_MND_MODE__SHIFT				6 +static inline uint32_t MMSS_CC_CLK_CC_MND_MODE(uint32_t val) +{ +	return ((val) << MMSS_CC_CLK_CC_MND_MODE__SHIFT) & MMSS_CC_CLK_CC_MND_MODE__MASK; +} +#define MMSS_CC_CLK_CC_PMXO_SEL__MASK				0x00000300 +#define MMSS_CC_CLK_CC_PMXO_SEL__SHIFT				8 +static inline uint32_t MMSS_CC_CLK_CC_PMXO_SEL(uint32_t val) +{ +	return ((val) << MMSS_CC_CLK_CC_PMXO_SEL__SHIFT) & MMSS_CC_CLK_CC_PMXO_SEL__MASK; +} + +static inline uint32_t REG_MMSS_CC_CLK_MD(enum mmss_cc_clk i0) { return 0x00000004 + __offset_CLK(i0); } +#define MMSS_CC_CLK_MD_D__MASK					0x000000ff +#define MMSS_CC_CLK_MD_D__SHIFT					0 +static inline uint32_t MMSS_CC_CLK_MD_D(uint32_t val) +{ +	return ((val) << MMSS_CC_CLK_MD_D__SHIFT) & MMSS_CC_CLK_MD_D__MASK; +} +#define MMSS_CC_CLK_MD_M__MASK					0x0000ff00 +#define MMSS_CC_CLK_MD_M__SHIFT					8 +static inline uint32_t MMSS_CC_CLK_MD_M(uint32_t val) +{ +	return ((val) << MMSS_CC_CLK_MD_M__SHIFT) & MMSS_CC_CLK_MD_M__MASK; +} + +static inline uint32_t REG_MMSS_CC_CLK_NS(enum mmss_cc_clk i0) { return 0x00000008 + __offset_CLK(i0); } +#define MMSS_CC_CLK_NS_SRC__MASK				0x0000000f +#define MMSS_CC_CLK_NS_SRC__SHIFT				0 +static inline uint32_t MMSS_CC_CLK_NS_SRC(uint32_t val) +{ +	return ((val) << MMSS_CC_CLK_NS_SRC__SHIFT) & MMSS_CC_CLK_NS_SRC__MASK; +} +#define MMSS_CC_CLK_NS_PRE_DIV_FUNC__MASK			0x00fff000 +#define MMSS_CC_CLK_NS_PRE_DIV_FUNC__SHIFT			12 +static inline uint32_t MMSS_CC_CLK_NS_PRE_DIV_FUNC(uint32_t val) +{ +	return ((val) << MMSS_CC_CLK_NS_PRE_DIV_FUNC__SHIFT) & MMSS_CC_CLK_NS_PRE_DIV_FUNC__MASK; +} +#define MMSS_CC_CLK_NS_VAL__MASK				0xff000000 +#define MMSS_CC_CLK_NS_VAL__SHIFT				24 +static inline uint32_t MMSS_CC_CLK_NS_VAL(uint32_t val) +{ +	return ((val) << MMSS_CC_CLK_NS_VAL__SHIFT) & MMSS_CC_CLK_NS_VAL__MASK; +} + + +#endif /* MMSS_CC_XML */ diff --git a/drivers/gpu/drm/msm/dsi/sfpb.xml.h b/drivers/gpu/drm/msm/dsi/sfpb.xml.h new file mode 100644 index 00000000000..48e03acf19b --- /dev/null +++ b/drivers/gpu/drm/msm/dsi/sfpb.xml.h @@ -0,0 +1,50 @@ +#ifndef SFPB_XML +#define SFPB_XML + +/* Autogenerated file, DO NOT EDIT manually! + +This file was generated by the rules-ng-ng headergen tool in this git repository: +http://github.com/freedreno/envytools/ +git clone https://github.com/freedreno/envytools.git + +The rules-ng-ng source files this header was generated from are: +- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    647 bytes, from 2013-11-30 14:45:35) +- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  17996 bytes, from 2013-12-01 19:10:31) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2013-11-30 15:00:52) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2013-12-03 20:59:13) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  20932 bytes, from 2013-12-01 15:13:04) + +Copyright (C) 2013 by the following authors: +- Rob Clark <robdclark@gmail.com> (robclark) + +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 THE COPYRIGHT OWNER(S) 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. +*/ + + +#define REG_SFPB_CFG						0x00000058 + + +#endif /* SFPB_XML */ diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c new file mode 100644 index 00000000000..7f7aadef8a8 --- /dev/null +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -0,0 +1,397 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include "hdmi.h" + +void hdmi_set_mode(struct hdmi *hdmi, bool power_on) +{ +	uint32_t ctrl = 0; + +	if (power_on) { +		ctrl |= HDMI_CTRL_ENABLE; +		if (!hdmi->hdmi_mode) { +			ctrl |= HDMI_CTRL_HDMI; +			hdmi_write(hdmi, REG_HDMI_CTRL, ctrl); +			ctrl &= ~HDMI_CTRL_HDMI; +		} else { +			ctrl |= HDMI_CTRL_HDMI; +		} +	} else { +		ctrl = HDMI_CTRL_HDMI; +	} + +	hdmi_write(hdmi, REG_HDMI_CTRL, ctrl); +	DBG("HDMI Core: %s, HDMI_CTRL=0x%08x", +			power_on ? "Enable" : "Disable", ctrl); +} + +irqreturn_t hdmi_irq(int irq, void *dev_id) +{ +	struct hdmi *hdmi = dev_id; + +	/* Process HPD: */ +	hdmi_connector_irq(hdmi->connector); + +	/* Process DDC: */ +	hdmi_i2c_irq(hdmi->i2c); + +	/* TODO audio.. */ + +	return IRQ_HANDLED; +} + +void hdmi_destroy(struct kref *kref) +{ +	struct hdmi *hdmi = container_of(kref, struct hdmi, refcount); +	struct hdmi_phy *phy = hdmi->phy; + +	if (phy) +		phy->funcs->destroy(phy); + +	if (hdmi->i2c) +		hdmi_i2c_destroy(hdmi->i2c); + +	platform_set_drvdata(hdmi->pdev, NULL); +} + +/* initialize connector */ +struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder) +{ +	struct hdmi *hdmi = NULL; +	struct msm_drm_private *priv = dev->dev_private; +	struct platform_device *pdev = priv->hdmi_pdev; +	struct hdmi_platform_config *config; +	int i, ret; + +	if (!pdev) { +		dev_err(dev->dev, "no hdmi device\n"); +		ret = -ENXIO; +		goto fail; +	} + +	config = pdev->dev.platform_data; + +	hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL); +	if (!hdmi) { +		ret = -ENOMEM; +		goto fail; +	} + +	kref_init(&hdmi->refcount); + +	hdmi->dev = dev; +	hdmi->pdev = pdev; +	hdmi->config = config; +	hdmi->encoder = encoder; + +	hdmi_audio_infoframe_init(&hdmi->audio.infoframe); + +	/* not sure about which phy maps to which msm.. probably I miss some */ +	if (config->phy_init) +		hdmi->phy = config->phy_init(hdmi); +	else +		hdmi->phy = ERR_PTR(-ENXIO); + +	if (IS_ERR(hdmi->phy)) { +		ret = PTR_ERR(hdmi->phy); +		dev_err(dev->dev, "failed to load phy: %d\n", ret); +		hdmi->phy = NULL; +		goto fail; +	} + +	hdmi->mmio = msm_ioremap(pdev, config->mmio_name, "HDMI"); +	if (IS_ERR(hdmi->mmio)) { +		ret = PTR_ERR(hdmi->mmio); +		goto fail; +	} + +	BUG_ON(config->hpd_reg_cnt > ARRAY_SIZE(hdmi->hpd_regs)); +	for (i = 0; i < config->hpd_reg_cnt; i++) { +		struct regulator *reg; + +		reg = devm_regulator_get(&pdev->dev, config->hpd_reg_names[i]); +		if (IS_ERR(reg)) { +			ret = PTR_ERR(reg); +			dev_err(dev->dev, "failed to get hpd regulator: %s (%d)\n", +					config->hpd_reg_names[i], ret); +			goto fail; +		} + +		hdmi->hpd_regs[i] = reg; +	} + +	BUG_ON(config->pwr_reg_cnt > ARRAY_SIZE(hdmi->pwr_regs)); +	for (i = 0; i < config->pwr_reg_cnt; i++) { +		struct regulator *reg; + +		reg = devm_regulator_get(&pdev->dev, config->pwr_reg_names[i]); +		if (IS_ERR(reg)) { +			ret = PTR_ERR(reg); +			dev_err(dev->dev, "failed to get pwr regulator: %s (%d)\n", +					config->pwr_reg_names[i], ret); +			goto fail; +		} + +		hdmi->pwr_regs[i] = reg; +	} + +	BUG_ON(config->hpd_clk_cnt > ARRAY_SIZE(hdmi->hpd_clks)); +	for (i = 0; i < config->hpd_clk_cnt; i++) { +		struct clk *clk; + +		clk = devm_clk_get(&pdev->dev, config->hpd_clk_names[i]); +		if (IS_ERR(clk)) { +			ret = PTR_ERR(clk); +			dev_err(dev->dev, "failed to get hpd clk: %s (%d)\n", +					config->hpd_clk_names[i], ret); +			goto fail; +		} + +		hdmi->hpd_clks[i] = clk; +	} + +	BUG_ON(config->pwr_clk_cnt > ARRAY_SIZE(hdmi->pwr_clks)); +	for (i = 0; i < config->pwr_clk_cnt; i++) { +		struct clk *clk; + +		clk = devm_clk_get(&pdev->dev, config->pwr_clk_names[i]); +		if (IS_ERR(clk)) { +			ret = PTR_ERR(clk); +			dev_err(dev->dev, "failed to get pwr clk: %s (%d)\n", +					config->pwr_clk_names[i], ret); +			goto fail; +		} + +		hdmi->pwr_clks[i] = clk; +	} + +	hdmi->i2c = hdmi_i2c_init(hdmi); +	if (IS_ERR(hdmi->i2c)) { +		ret = PTR_ERR(hdmi->i2c); +		dev_err(dev->dev, "failed to get i2c: %d\n", ret); +		hdmi->i2c = NULL; +		goto fail; +	} + +	hdmi->bridge = hdmi_bridge_init(hdmi); +	if (IS_ERR(hdmi->bridge)) { +		ret = PTR_ERR(hdmi->bridge); +		dev_err(dev->dev, "failed to create HDMI bridge: %d\n", ret); +		hdmi->bridge = NULL; +		goto fail; +	} + +	hdmi->connector = hdmi_connector_init(hdmi); +	if (IS_ERR(hdmi->connector)) { +		ret = PTR_ERR(hdmi->connector); +		dev_err(dev->dev, "failed to create HDMI connector: %d\n", ret); +		hdmi->connector = NULL; +		goto fail; +	} + +	if (!config->shared_irq) { +		hdmi->irq = platform_get_irq(pdev, 0); +		if (hdmi->irq < 0) { +			ret = hdmi->irq; +			dev_err(dev->dev, "failed to get irq: %d\n", ret); +			goto fail; +		} + +		ret = devm_request_threaded_irq(&pdev->dev, hdmi->irq, +				NULL, hdmi_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, +				"hdmi_isr", hdmi); +		if (ret < 0) { +			dev_err(dev->dev, "failed to request IRQ%u: %d\n", +					hdmi->irq, ret); +			goto fail; +		} +	} + +	encoder->bridge = hdmi->bridge; + +	priv->bridges[priv->num_bridges++]       = hdmi->bridge; +	priv->connectors[priv->num_connectors++] = hdmi->connector; + +	platform_set_drvdata(pdev, hdmi); + +	return hdmi; + +fail: +	if (hdmi) { +		/* bridge/connector are normally destroyed by drm: */ +		if (hdmi->bridge) +			hdmi->bridge->funcs->destroy(hdmi->bridge); +		if (hdmi->connector) +			hdmi->connector->funcs->destroy(hdmi->connector); +		hdmi_destroy(&hdmi->refcount); +	} + +	return ERR_PTR(ret); +} + +/* + * The hdmi device: + */ + +#include <linux/of_gpio.h> + +static void set_hdmi_pdev(struct drm_device *dev, +		struct platform_device *pdev) +{ +	struct msm_drm_private *priv = dev->dev_private; +	priv->hdmi_pdev = pdev; +} + +static int hdmi_bind(struct device *dev, struct device *master, void *data) +{ +	static struct hdmi_platform_config config = {}; +#ifdef CONFIG_OF +	struct device_node *of_node = dev->of_node; + +	int get_gpio(const char *name) +	{ +		int gpio = of_get_named_gpio(of_node, name, 0); +		if (gpio < 0) { +			dev_err(dev, "failed to get gpio: %s (%d)\n", +					name, gpio); +			gpio = -1; +		} +		return gpio; +	} + +	/* TODO actually use DT.. */ +	static const char *hpd_reg_names[] = {"hpd-gdsc", "hpd-5v"}; +	static const char *pwr_reg_names[] = {"core-vdda", "core-vcc"}; +	static const char *hpd_clk_names[] = {"iface_clk", "core_clk", "mdp_core_clk"}; +	static unsigned long hpd_clk_freq[] = {0, 19200000, 0}; +	static const char *pwr_clk_names[] = {"extp_clk", "alt_iface_clk"}; + +	config.phy_init      = hdmi_phy_8x74_init; +	config.mmio_name     = "core_physical"; +	config.hpd_reg_names = hpd_reg_names; +	config.hpd_reg_cnt   = ARRAY_SIZE(hpd_reg_names); +	config.pwr_reg_names = pwr_reg_names; +	config.pwr_reg_cnt   = ARRAY_SIZE(pwr_reg_names); +	config.hpd_clk_names = hpd_clk_names; +	config.hpd_freq      = hpd_clk_freq; +	config.hpd_clk_cnt   = ARRAY_SIZE(hpd_clk_names); +	config.pwr_clk_names = pwr_clk_names; +	config.pwr_clk_cnt   = ARRAY_SIZE(pwr_clk_names); +	config.ddc_clk_gpio  = get_gpio("qcom,hdmi-tx-ddc-clk"); +	config.ddc_data_gpio = get_gpio("qcom,hdmi-tx-ddc-data"); +	config.hpd_gpio      = get_gpio("qcom,hdmi-tx-hpd"); +	config.mux_en_gpio   = get_gpio("qcom,hdmi-tx-mux-en"); +	config.mux_sel_gpio  = get_gpio("qcom,hdmi-tx-mux-sel"); +	config.shared_irq    = true; + +#else +	static const char *hpd_clk_names[] = { +			"core_clk", "master_iface_clk", "slave_iface_clk", +	}; +	if (cpu_is_apq8064()) { +		static const char *hpd_reg_names[] = {"8921_hdmi_mvs"}; +		config.phy_init      = hdmi_phy_8960_init; +		config.mmio_name     = "hdmi_msm_hdmi_addr"; +		config.hpd_reg_names = hpd_reg_names; +		config.hpd_reg_cnt   = ARRAY_SIZE(hpd_reg_names); +		config.hpd_clk_names = hpd_clk_names; +		config.hpd_clk_cnt   = ARRAY_SIZE(hpd_clk_names); +		config.ddc_clk_gpio  = 70; +		config.ddc_data_gpio = 71; +		config.hpd_gpio      = 72; +		config.mux_en_gpio   = -1; +		config.mux_sel_gpio  = -1; +	} else if (cpu_is_msm8960() || cpu_is_msm8960ab()) { +		static const char *hpd_reg_names[] = {"8921_hdmi_mvs"}; +		config.phy_init      = hdmi_phy_8960_init; +		config.mmio_name     = "hdmi_msm_hdmi_addr"; +		config.hpd_reg_names = hpd_reg_names; +		config.hpd_reg_cnt   = ARRAY_SIZE(hpd_reg_names); +		config.hpd_clk_names = hpd_clk_names; +		config.hpd_clk_cnt   = ARRAY_SIZE(hpd_clk_names); +		config.ddc_clk_gpio  = 100; +		config.ddc_data_gpio = 101; +		config.hpd_gpio      = 102; +		config.mux_en_gpio   = -1; +		config.mux_sel_gpio  = -1; +	} else if (cpu_is_msm8x60()) { +		static const char *hpd_reg_names[] = { +				"8901_hdmi_mvs", "8901_mpp0" +		}; +		config.phy_init      = hdmi_phy_8x60_init; +		config.mmio_name     = "hdmi_msm_hdmi_addr"; +		config.hpd_reg_names = hpd_reg_names; +		config.hpd_reg_cnt   = ARRAY_SIZE(hpd_reg_names); +		config.hpd_clk_names = hpd_clk_names; +		config.hpd_clk_cnt   = ARRAY_SIZE(hpd_clk_names); +		config.ddc_clk_gpio  = 170; +		config.ddc_data_gpio = 171; +		config.hpd_gpio      = 172; +		config.mux_en_gpio   = -1; +		config.mux_sel_gpio  = -1; +	} +#endif +	dev->platform_data = &config; +	set_hdmi_pdev(dev_get_drvdata(master), to_platform_device(dev)); +	return 0; +} + +static void hdmi_unbind(struct device *dev, struct device *master, +		void *data) +{ +	set_hdmi_pdev(dev_get_drvdata(master), NULL); +} + +static const struct component_ops hdmi_ops = { +		.bind   = hdmi_bind, +		.unbind = hdmi_unbind, +}; + +static int hdmi_dev_probe(struct platform_device *pdev) +{ +	return component_add(&pdev->dev, &hdmi_ops); +} + +static int hdmi_dev_remove(struct platform_device *pdev) +{ +	component_del(&pdev->dev, &hdmi_ops); +	return 0; +} + +static const struct of_device_id dt_match[] = { +	{ .compatible = "qcom,hdmi-tx" }, +	{} +}; + +static struct platform_driver hdmi_driver = { +	.probe = hdmi_dev_probe, +	.remove = hdmi_dev_remove, +	.driver = { +		.name = "hdmi_msm", +		.of_match_table = dt_match, +	}, +}; + +void __init hdmi_register(void) +{ +	platform_driver_register(&hdmi_driver); +} + +void __exit hdmi_unregister(void) +{ +	platform_driver_unregister(&hdmi_driver); +} diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h new file mode 100644 index 00000000000..9d7723c6528 --- /dev/null +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __HDMI_CONNECTOR_H__ +#define __HDMI_CONNECTOR_H__ + +#include <linux/i2c.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/hdmi.h> + +#include "msm_drv.h" +#include "hdmi.xml.h" + + +struct hdmi_phy; +struct hdmi_platform_config; + +struct hdmi_audio { +	bool enabled; +	struct hdmi_audio_infoframe infoframe; +	int rate; +}; + +struct hdmi { +	struct kref refcount; + +	struct drm_device *dev; +	struct platform_device *pdev; + +	const struct hdmi_platform_config *config; + +	/* audio state: */ +	struct hdmi_audio audio; + +	/* video state: */ +	bool power_on; +	unsigned long int pixclock; + +	void __iomem *mmio; + +	struct regulator *hpd_regs[2]; +	struct regulator *pwr_regs[2]; +	struct clk *hpd_clks[3]; +	struct clk *pwr_clks[2]; + +	struct hdmi_phy *phy; +	struct i2c_adapter *i2c; +	struct drm_connector *connector; +	struct drm_bridge *bridge; + +	/* the encoder we are hooked to (outside of hdmi block) */ +	struct drm_encoder *encoder; + +	bool hdmi_mode;               /* are we in hdmi mode? */ + +	int irq; +}; + +/* platform config data (ie. from DT, or pdata) */ +struct hdmi_platform_config { +	struct hdmi_phy *(*phy_init)(struct hdmi *hdmi); +	const char *mmio_name; + +	/* regulators that need to be on for hpd: */ +	const char **hpd_reg_names; +	int hpd_reg_cnt; + +	/* regulators that need to be on for screen pwr: */ +	const char **pwr_reg_names; +	int pwr_reg_cnt; + +	/* clks that need to be on for hpd: */ +	const char **hpd_clk_names; +	const long unsigned *hpd_freq; +	int hpd_clk_cnt; + +	/* clks that need to be on for screen pwr (ie pixel clk): */ +	const char **pwr_clk_names; +	int pwr_clk_cnt; + +	/* gpio's: */ +	int ddc_clk_gpio, ddc_data_gpio, hpd_gpio, mux_en_gpio, mux_sel_gpio; + +	/* older devices had their own irq, mdp5+ it is shared w/ mdp: */ +	bool shared_irq; +}; + +void hdmi_set_mode(struct hdmi *hdmi, bool power_on); +void hdmi_destroy(struct kref *kref); + +static inline void hdmi_write(struct hdmi *hdmi, u32 reg, u32 data) +{ +	msm_writel(data, hdmi->mmio + reg); +} + +static inline u32 hdmi_read(struct hdmi *hdmi, u32 reg) +{ +	return msm_readl(hdmi->mmio + reg); +} + +static inline struct hdmi * hdmi_reference(struct hdmi *hdmi) +{ +	kref_get(&hdmi->refcount); +	return hdmi; +} + +static inline void hdmi_unreference(struct hdmi *hdmi) +{ +	kref_put(&hdmi->refcount, hdmi_destroy); +} + +/* + * The phy appears to be different, for example between 8960 and 8x60, + * so split the phy related functions out and load the correct one at + * runtime: + */ + +struct hdmi_phy_funcs { +	void (*destroy)(struct hdmi_phy *phy); +	void (*reset)(struct hdmi_phy *phy); +	void (*powerup)(struct hdmi_phy *phy, unsigned long int pixclock); +	void (*powerdown)(struct hdmi_phy *phy); +}; + +struct hdmi_phy { +	const struct hdmi_phy_funcs *funcs; +}; + +struct hdmi_phy *hdmi_phy_8960_init(struct hdmi *hdmi); +struct hdmi_phy *hdmi_phy_8x60_init(struct hdmi *hdmi); +struct hdmi_phy *hdmi_phy_8x74_init(struct hdmi *hdmi); + +/* + * audio: + */ + +int hdmi_audio_update(struct hdmi *hdmi); +int hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled, +	uint32_t num_of_channels, uint32_t channel_allocation, +	uint32_t level_shift, bool down_mix); +void hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate); + + +/* + * hdmi bridge: + */ + +struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi); + +/* + * hdmi connector: + */ + +void hdmi_connector_irq(struct drm_connector *connector); +struct drm_connector *hdmi_connector_init(struct hdmi *hdmi); + +/* + * i2c adapter for ddc: + */ + +void hdmi_i2c_irq(struct i2c_adapter *i2c); +void hdmi_i2c_destroy(struct i2c_adapter *i2c); +struct i2c_adapter *hdmi_i2c_init(struct hdmi *hdmi); + +#endif /* __HDMI_CONNECTOR_H__ */ diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.xml.h b/drivers/gpu/drm/msm/hdmi/hdmi.xml.h new file mode 100644 index 00000000000..e2636582cfd --- /dev/null +++ b/drivers/gpu/drm/msm/hdmi/hdmi.xml.h @@ -0,0 +1,575 @@ +#ifndef HDMI_XML +#define HDMI_XML + +/* Autogenerated file, DO NOT EDIT manually! + +This file was generated by the rules-ng-ng headergen tool in this git repository: +http://github.com/freedreno/envytools/ +git clone https://github.com/freedreno/envytools.git + +The rules-ng-ng source files this header was generated from are: +- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    647 bytes, from 2013-11-30 14:45:35) +- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  17996 bytes, from 2013-12-01 19:10:31) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2013-11-30 15:00:52) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2013-12-03 20:59:13) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  20932 bytes, from 2013-12-01 15:13:04) + +Copyright (C) 2013 by the following authors: +- Rob Clark <robdclark@gmail.com> (robclark) + +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 THE COPYRIGHT OWNER(S) 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. +*/ + + +enum hdmi_hdcp_key_state { +	NO_KEYS = 0, +	NOT_CHECKED = 1, +	CHECKING = 2, +	KEYS_VALID = 3, +	AKSV_INVALID = 4, +	CHECKSUM_MISMATCH = 5, +}; + +enum hdmi_ddc_read_write { +	DDC_WRITE = 0, +	DDC_READ = 1, +}; + +enum hdmi_acr_cts { +	ACR_NONE = 0, +	ACR_32 = 1, +	ACR_44 = 2, +	ACR_48 = 3, +}; + +#define REG_HDMI_CTRL						0x00000000 +#define HDMI_CTRL_ENABLE					0x00000001 +#define HDMI_CTRL_HDMI						0x00000002 +#define HDMI_CTRL_ENCRYPTED					0x00000004 + +#define REG_HDMI_AUDIO_PKT_CTRL1				0x00000020 +#define HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND			0x00000001 + +#define REG_HDMI_ACR_PKT_CTRL					0x00000024 +#define HDMI_ACR_PKT_CTRL_CONT					0x00000001 +#define HDMI_ACR_PKT_CTRL_SEND					0x00000002 +#define HDMI_ACR_PKT_CTRL_SELECT__MASK				0x00000030 +#define HDMI_ACR_PKT_CTRL_SELECT__SHIFT				4 +static inline uint32_t HDMI_ACR_PKT_CTRL_SELECT(enum hdmi_acr_cts val) +{ +	return ((val) << HDMI_ACR_PKT_CTRL_SELECT__SHIFT) & HDMI_ACR_PKT_CTRL_SELECT__MASK; +} +#define HDMI_ACR_PKT_CTRL_SOURCE				0x00000100 +#define HDMI_ACR_PKT_CTRL_N_MULTIPLIER__MASK			0x00070000 +#define HDMI_ACR_PKT_CTRL_N_MULTIPLIER__SHIFT			16 +static inline uint32_t HDMI_ACR_PKT_CTRL_N_MULTIPLIER(uint32_t val) +{ +	return ((val) << HDMI_ACR_PKT_CTRL_N_MULTIPLIER__SHIFT) & HDMI_ACR_PKT_CTRL_N_MULTIPLIER__MASK; +} +#define HDMI_ACR_PKT_CTRL_AUDIO_PRIORITY			0x80000000 + +#define REG_HDMI_VBI_PKT_CTRL					0x00000028 +#define HDMI_VBI_PKT_CTRL_GC_ENABLE				0x00000010 +#define HDMI_VBI_PKT_CTRL_GC_EVERY_FRAME			0x00000020 +#define HDMI_VBI_PKT_CTRL_ISRC_SEND				0x00000100 +#define HDMI_VBI_PKT_CTRL_ISRC_CONTINUOUS			0x00000200 +#define HDMI_VBI_PKT_CTRL_ACP_SEND				0x00001000 +#define HDMI_VBI_PKT_CTRL_ACP_SRC_SW				0x00002000 + +#define REG_HDMI_INFOFRAME_CTRL0				0x0000002c +#define HDMI_INFOFRAME_CTRL0_AVI_SEND				0x00000001 +#define HDMI_INFOFRAME_CTRL0_AVI_CONT				0x00000002 +#define HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND			0x00000010 +#define HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT			0x00000020 +#define HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE			0x00000040 +#define HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE			0x00000080 + +#define REG_HDMI_GEN_PKT_CTRL					0x00000034 +#define HDMI_GEN_PKT_CTRL_GENERIC0_SEND				0x00000001 +#define HDMI_GEN_PKT_CTRL_GENERIC0_CONT				0x00000002 +#define HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE__MASK			0x0000000c +#define HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE__SHIFT		2 +static inline uint32_t HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE(uint32_t val) +{ +	return ((val) << HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE__SHIFT) & HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE__MASK; +} +#define HDMI_GEN_PKT_CTRL_GENERIC1_SEND				0x00000010 +#define HDMI_GEN_PKT_CTRL_GENERIC1_CONT				0x00000020 +#define HDMI_GEN_PKT_CTRL_GENERIC0_LINE__MASK			0x003f0000 +#define HDMI_GEN_PKT_CTRL_GENERIC0_LINE__SHIFT			16 +static inline uint32_t HDMI_GEN_PKT_CTRL_GENERIC0_LINE(uint32_t val) +{ +	return ((val) << HDMI_GEN_PKT_CTRL_GENERIC0_LINE__SHIFT) & HDMI_GEN_PKT_CTRL_GENERIC0_LINE__MASK; +} +#define HDMI_GEN_PKT_CTRL_GENERIC1_LINE__MASK			0x3f000000 +#define HDMI_GEN_PKT_CTRL_GENERIC1_LINE__SHIFT			24 +static inline uint32_t HDMI_GEN_PKT_CTRL_GENERIC1_LINE(uint32_t val) +{ +	return ((val) << HDMI_GEN_PKT_CTRL_GENERIC1_LINE__SHIFT) & HDMI_GEN_PKT_CTRL_GENERIC1_LINE__MASK; +} + +#define REG_HDMI_GC						0x00000040 +#define HDMI_GC_MUTE						0x00000001 + +#define REG_HDMI_AUDIO_PKT_CTRL2				0x00000044 +#define HDMI_AUDIO_PKT_CTRL2_OVERRIDE				0x00000001 +#define HDMI_AUDIO_PKT_CTRL2_LAYOUT				0x00000002 + +static inline uint32_t REG_HDMI_AVI_INFO(uint32_t i0) { return 0x0000006c + 0x4*i0; } + +#define REG_HDMI_GENERIC0_HDR					0x00000084 + +static inline uint32_t REG_HDMI_GENERIC0(uint32_t i0) { return 0x00000088 + 0x4*i0; } + +#define REG_HDMI_GENERIC1_HDR					0x000000a4 + +static inline uint32_t REG_HDMI_GENERIC1(uint32_t i0) { return 0x000000a8 + 0x4*i0; } + +static inline uint32_t REG_HDMI_ACR(uint32_t i0) { return 0x000000c4 + 0x8*i0; } + +static inline uint32_t REG_HDMI_ACR_0(uint32_t i0) { return 0x000000c4 + 0x8*i0; } +#define HDMI_ACR_0_CTS__MASK					0xfffff000 +#define HDMI_ACR_0_CTS__SHIFT					12 +static inline uint32_t HDMI_ACR_0_CTS(uint32_t val) +{ +	return ((val) << HDMI_ACR_0_CTS__SHIFT) & HDMI_ACR_0_CTS__MASK; +} + +static inline uint32_t REG_HDMI_ACR_1(uint32_t i0) { return 0x000000c8 + 0x8*i0; } +#define HDMI_ACR_1_N__MASK					0xffffffff +#define HDMI_ACR_1_N__SHIFT					0 +static inline uint32_t HDMI_ACR_1_N(uint32_t val) +{ +	return ((val) << HDMI_ACR_1_N__SHIFT) & HDMI_ACR_1_N__MASK; +} + +#define REG_HDMI_AUDIO_INFO0					0x000000e4 +#define HDMI_AUDIO_INFO0_CHECKSUM__MASK				0x000000ff +#define HDMI_AUDIO_INFO0_CHECKSUM__SHIFT			0 +static inline uint32_t HDMI_AUDIO_INFO0_CHECKSUM(uint32_t val) +{ +	return ((val) << HDMI_AUDIO_INFO0_CHECKSUM__SHIFT) & HDMI_AUDIO_INFO0_CHECKSUM__MASK; +} +#define HDMI_AUDIO_INFO0_CC__MASK				0x00000700 +#define HDMI_AUDIO_INFO0_CC__SHIFT				8 +static inline uint32_t HDMI_AUDIO_INFO0_CC(uint32_t val) +{ +	return ((val) << HDMI_AUDIO_INFO0_CC__SHIFT) & HDMI_AUDIO_INFO0_CC__MASK; +} + +#define REG_HDMI_AUDIO_INFO1					0x000000e8 +#define HDMI_AUDIO_INFO1_CA__MASK				0x000000ff +#define HDMI_AUDIO_INFO1_CA__SHIFT				0 +static inline uint32_t HDMI_AUDIO_INFO1_CA(uint32_t val) +{ +	return ((val) << HDMI_AUDIO_INFO1_CA__SHIFT) & HDMI_AUDIO_INFO1_CA__MASK; +} +#define HDMI_AUDIO_INFO1_LSV__MASK				0x00007800 +#define HDMI_AUDIO_INFO1_LSV__SHIFT				11 +static inline uint32_t HDMI_AUDIO_INFO1_LSV(uint32_t val) +{ +	return ((val) << HDMI_AUDIO_INFO1_LSV__SHIFT) & HDMI_AUDIO_INFO1_LSV__MASK; +} +#define HDMI_AUDIO_INFO1_DM_INH					0x00008000 + +#define REG_HDMI_HDCP_CTRL					0x00000110 +#define HDMI_HDCP_CTRL_ENABLE					0x00000001 +#define HDMI_HDCP_CTRL_ENCRYPTION_ENABLE			0x00000100 + +#define REG_HDMI_HDCP_INT_CTRL					0x00000118 + +#define REG_HDMI_HDCP_LINK0_STATUS				0x0000011c +#define HDMI_HDCP_LINK0_STATUS_AN_0_READY			0x00000100 +#define HDMI_HDCP_LINK0_STATUS_AN_1_READY			0x00000200 +#define HDMI_HDCP_LINK0_STATUS_KEY_STATE__MASK			0x70000000 +#define HDMI_HDCP_LINK0_STATUS_KEY_STATE__SHIFT			28 +static inline uint32_t HDMI_HDCP_LINK0_STATUS_KEY_STATE(enum hdmi_hdcp_key_state val) +{ +	return ((val) << HDMI_HDCP_LINK0_STATUS_KEY_STATE__SHIFT) & HDMI_HDCP_LINK0_STATUS_KEY_STATE__MASK; +} + +#define REG_HDMI_HDCP_RESET					0x00000130 +#define HDMI_HDCP_RESET_LINK0_DEAUTHENTICATE			0x00000001 + +#define REG_HDMI_VENSPEC_INFO0					0x0000016c + +#define REG_HDMI_VENSPEC_INFO1					0x00000170 + +#define REG_HDMI_VENSPEC_INFO2					0x00000174 + +#define REG_HDMI_VENSPEC_INFO3					0x00000178 + +#define REG_HDMI_VENSPEC_INFO4					0x0000017c + +#define REG_HDMI_VENSPEC_INFO5					0x00000180 + +#define REG_HDMI_VENSPEC_INFO6					0x00000184 + +#define REG_HDMI_AUDIO_CFG					0x000001d0 +#define HDMI_AUDIO_CFG_ENGINE_ENABLE				0x00000001 +#define HDMI_AUDIO_CFG_FIFO_WATERMARK__MASK			0x000000f0 +#define HDMI_AUDIO_CFG_FIFO_WATERMARK__SHIFT			4 +static inline uint32_t HDMI_AUDIO_CFG_FIFO_WATERMARK(uint32_t val) +{ +	return ((val) << HDMI_AUDIO_CFG_FIFO_WATERMARK__SHIFT) & HDMI_AUDIO_CFG_FIFO_WATERMARK__MASK; +} + +#define REG_HDMI_USEC_REFTIMER					0x00000208 + +#define REG_HDMI_DDC_CTRL					0x0000020c +#define HDMI_DDC_CTRL_GO					0x00000001 +#define HDMI_DDC_CTRL_SOFT_RESET				0x00000002 +#define HDMI_DDC_CTRL_SEND_RESET				0x00000004 +#define HDMI_DDC_CTRL_SW_STATUS_RESET				0x00000008 +#define HDMI_DDC_CTRL_TRANSACTION_CNT__MASK			0x00300000 +#define HDMI_DDC_CTRL_TRANSACTION_CNT__SHIFT			20 +static inline uint32_t HDMI_DDC_CTRL_TRANSACTION_CNT(uint32_t val) +{ +	return ((val) << HDMI_DDC_CTRL_TRANSACTION_CNT__SHIFT) & HDMI_DDC_CTRL_TRANSACTION_CNT__MASK; +} + +#define REG_HDMI_DDC_ARBITRATION				0x00000210 +#define HDMI_DDC_ARBITRATION_HW_ARBITRATION			0x00000010 + +#define REG_HDMI_DDC_INT_CTRL					0x00000214 +#define HDMI_DDC_INT_CTRL_SW_DONE_INT				0x00000001 +#define HDMI_DDC_INT_CTRL_SW_DONE_ACK				0x00000002 +#define HDMI_DDC_INT_CTRL_SW_DONE_MASK				0x00000004 + +#define REG_HDMI_DDC_SW_STATUS					0x00000218 +#define HDMI_DDC_SW_STATUS_NACK0				0x00001000 +#define HDMI_DDC_SW_STATUS_NACK1				0x00002000 +#define HDMI_DDC_SW_STATUS_NACK2				0x00004000 +#define HDMI_DDC_SW_STATUS_NACK3				0x00008000 + +#define REG_HDMI_DDC_HW_STATUS					0x0000021c + +#define REG_HDMI_DDC_SPEED					0x00000220 +#define HDMI_DDC_SPEED_THRESHOLD__MASK				0x00000003 +#define HDMI_DDC_SPEED_THRESHOLD__SHIFT				0 +static inline uint32_t HDMI_DDC_SPEED_THRESHOLD(uint32_t val) +{ +	return ((val) << HDMI_DDC_SPEED_THRESHOLD__SHIFT) & HDMI_DDC_SPEED_THRESHOLD__MASK; +} +#define HDMI_DDC_SPEED_PRESCALE__MASK				0xffff0000 +#define HDMI_DDC_SPEED_PRESCALE__SHIFT				16 +static inline uint32_t HDMI_DDC_SPEED_PRESCALE(uint32_t val) +{ +	return ((val) << HDMI_DDC_SPEED_PRESCALE__SHIFT) & HDMI_DDC_SPEED_PRESCALE__MASK; +} + +#define REG_HDMI_DDC_SETUP					0x00000224 +#define HDMI_DDC_SETUP_TIMEOUT__MASK				0xff000000 +#define HDMI_DDC_SETUP_TIMEOUT__SHIFT				24 +static inline uint32_t HDMI_DDC_SETUP_TIMEOUT(uint32_t val) +{ +	return ((val) << HDMI_DDC_SETUP_TIMEOUT__SHIFT) & HDMI_DDC_SETUP_TIMEOUT__MASK; +} + +static inline uint32_t REG_HDMI_I2C_TRANSACTION(uint32_t i0) { return 0x00000228 + 0x4*i0; } + +static inline uint32_t REG_HDMI_I2C_TRANSACTION_REG(uint32_t i0) { return 0x00000228 + 0x4*i0; } +#define HDMI_I2C_TRANSACTION_REG_RW__MASK			0x00000001 +#define HDMI_I2C_TRANSACTION_REG_RW__SHIFT			0 +static inline uint32_t HDMI_I2C_TRANSACTION_REG_RW(enum hdmi_ddc_read_write val) +{ +	return ((val) << HDMI_I2C_TRANSACTION_REG_RW__SHIFT) & HDMI_I2C_TRANSACTION_REG_RW__MASK; +} +#define HDMI_I2C_TRANSACTION_REG_STOP_ON_NACK			0x00000100 +#define HDMI_I2C_TRANSACTION_REG_START				0x00001000 +#define HDMI_I2C_TRANSACTION_REG_STOP				0x00002000 +#define HDMI_I2C_TRANSACTION_REG_CNT__MASK			0x00ff0000 +#define HDMI_I2C_TRANSACTION_REG_CNT__SHIFT			16 +static inline uint32_t HDMI_I2C_TRANSACTION_REG_CNT(uint32_t val) +{ +	return ((val) << HDMI_I2C_TRANSACTION_REG_CNT__SHIFT) & HDMI_I2C_TRANSACTION_REG_CNT__MASK; +} + +#define REG_HDMI_DDC_DATA					0x00000238 +#define HDMI_DDC_DATA_DATA_RW__MASK				0x00000001 +#define HDMI_DDC_DATA_DATA_RW__SHIFT				0 +static inline uint32_t HDMI_DDC_DATA_DATA_RW(enum hdmi_ddc_read_write val) +{ +	return ((val) << HDMI_DDC_DATA_DATA_RW__SHIFT) & HDMI_DDC_DATA_DATA_RW__MASK; +} +#define HDMI_DDC_DATA_DATA__MASK				0x0000ff00 +#define HDMI_DDC_DATA_DATA__SHIFT				8 +static inline uint32_t HDMI_DDC_DATA_DATA(uint32_t val) +{ +	return ((val) << HDMI_DDC_DATA_DATA__SHIFT) & HDMI_DDC_DATA_DATA__MASK; +} +#define HDMI_DDC_DATA_INDEX__MASK				0x00ff0000 +#define HDMI_DDC_DATA_INDEX__SHIFT				16 +static inline uint32_t HDMI_DDC_DATA_INDEX(uint32_t val) +{ +	return ((val) << HDMI_DDC_DATA_INDEX__SHIFT) & HDMI_DDC_DATA_INDEX__MASK; +} +#define HDMI_DDC_DATA_INDEX_WRITE				0x80000000 + +#define REG_HDMI_HPD_INT_STATUS					0x00000250 +#define HDMI_HPD_INT_STATUS_INT					0x00000001 +#define HDMI_HPD_INT_STATUS_CABLE_DETECTED			0x00000002 + +#define REG_HDMI_HPD_INT_CTRL					0x00000254 +#define HDMI_HPD_INT_CTRL_INT_ACK				0x00000001 +#define HDMI_HPD_INT_CTRL_INT_CONNECT				0x00000002 +#define HDMI_HPD_INT_CTRL_INT_EN				0x00000004 +#define HDMI_HPD_INT_CTRL_RX_INT_ACK				0x00000010 +#define HDMI_HPD_INT_CTRL_RX_INT_EN				0x00000020 +#define HDMI_HPD_INT_CTRL_RCV_PLUGIN_DET_MASK			0x00000200 + +#define REG_HDMI_HPD_CTRL					0x00000258 +#define HDMI_HPD_CTRL_TIMEOUT__MASK				0x00001fff +#define HDMI_HPD_CTRL_TIMEOUT__SHIFT				0 +static inline uint32_t HDMI_HPD_CTRL_TIMEOUT(uint32_t val) +{ +	return ((val) << HDMI_HPD_CTRL_TIMEOUT__SHIFT) & HDMI_HPD_CTRL_TIMEOUT__MASK; +} +#define HDMI_HPD_CTRL_ENABLE					0x10000000 + +#define REG_HDMI_DDC_REF					0x0000027c +#define HDMI_DDC_REF_REFTIMER_ENABLE				0x00010000 +#define HDMI_DDC_REF_REFTIMER__MASK				0x0000ffff +#define HDMI_DDC_REF_REFTIMER__SHIFT				0 +static inline uint32_t HDMI_DDC_REF_REFTIMER(uint32_t val) +{ +	return ((val) << HDMI_DDC_REF_REFTIMER__SHIFT) & HDMI_DDC_REF_REFTIMER__MASK; +} + +#define REG_HDMI_CEC_STATUS					0x00000298 + +#define REG_HDMI_CEC_INT					0x0000029c + +#define REG_HDMI_CEC_ADDR					0x000002a0 + +#define REG_HDMI_CEC_TIME					0x000002a4 + +#define REG_HDMI_CEC_REFTIMER					0x000002a8 + +#define REG_HDMI_CEC_RD_DATA					0x000002ac + +#define REG_HDMI_CEC_RD_FILTER					0x000002b0 + +#define REG_HDMI_ACTIVE_HSYNC					0x000002b4 +#define HDMI_ACTIVE_HSYNC_START__MASK				0x00000fff +#define HDMI_ACTIVE_HSYNC_START__SHIFT				0 +static inline uint32_t HDMI_ACTIVE_HSYNC_START(uint32_t val) +{ +	return ((val) << HDMI_ACTIVE_HSYNC_START__SHIFT) & HDMI_ACTIVE_HSYNC_START__MASK; +} +#define HDMI_ACTIVE_HSYNC_END__MASK				0x0fff0000 +#define HDMI_ACTIVE_HSYNC_END__SHIFT				16 +static inline uint32_t HDMI_ACTIVE_HSYNC_END(uint32_t val) +{ +	return ((val) << HDMI_ACTIVE_HSYNC_END__SHIFT) & HDMI_ACTIVE_HSYNC_END__MASK; +} + +#define REG_HDMI_ACTIVE_VSYNC					0x000002b8 +#define HDMI_ACTIVE_VSYNC_START__MASK				0x00000fff +#define HDMI_ACTIVE_VSYNC_START__SHIFT				0 +static inline uint32_t HDMI_ACTIVE_VSYNC_START(uint32_t val) +{ +	return ((val) << HDMI_ACTIVE_VSYNC_START__SHIFT) & HDMI_ACTIVE_VSYNC_START__MASK; +} +#define HDMI_ACTIVE_VSYNC_END__MASK				0x0fff0000 +#define HDMI_ACTIVE_VSYNC_END__SHIFT				16 +static inline uint32_t HDMI_ACTIVE_VSYNC_END(uint32_t val) +{ +	return ((val) << HDMI_ACTIVE_VSYNC_END__SHIFT) & HDMI_ACTIVE_VSYNC_END__MASK; +} + +#define REG_HDMI_VSYNC_ACTIVE_F2				0x000002bc +#define HDMI_VSYNC_ACTIVE_F2_START__MASK			0x00000fff +#define HDMI_VSYNC_ACTIVE_F2_START__SHIFT			0 +static inline uint32_t HDMI_VSYNC_ACTIVE_F2_START(uint32_t val) +{ +	return ((val) << HDMI_VSYNC_ACTIVE_F2_START__SHIFT) & HDMI_VSYNC_ACTIVE_F2_START__MASK; +} +#define HDMI_VSYNC_ACTIVE_F2_END__MASK				0x0fff0000 +#define HDMI_VSYNC_ACTIVE_F2_END__SHIFT				16 +static inline uint32_t HDMI_VSYNC_ACTIVE_F2_END(uint32_t val) +{ +	return ((val) << HDMI_VSYNC_ACTIVE_F2_END__SHIFT) & HDMI_VSYNC_ACTIVE_F2_END__MASK; +} + +#define REG_HDMI_TOTAL						0x000002c0 +#define HDMI_TOTAL_H_TOTAL__MASK				0x00000fff +#define HDMI_TOTAL_H_TOTAL__SHIFT				0 +static inline uint32_t HDMI_TOTAL_H_TOTAL(uint32_t val) +{ +	return ((val) << HDMI_TOTAL_H_TOTAL__SHIFT) & HDMI_TOTAL_H_TOTAL__MASK; +} +#define HDMI_TOTAL_V_TOTAL__MASK				0x0fff0000 +#define HDMI_TOTAL_V_TOTAL__SHIFT				16 +static inline uint32_t HDMI_TOTAL_V_TOTAL(uint32_t val) +{ +	return ((val) << HDMI_TOTAL_V_TOTAL__SHIFT) & HDMI_TOTAL_V_TOTAL__MASK; +} + +#define REG_HDMI_VSYNC_TOTAL_F2					0x000002c4 +#define HDMI_VSYNC_TOTAL_F2_V_TOTAL__MASK			0x00000fff +#define HDMI_VSYNC_TOTAL_F2_V_TOTAL__SHIFT			0 +static inline uint32_t HDMI_VSYNC_TOTAL_F2_V_TOTAL(uint32_t val) +{ +	return ((val) << HDMI_VSYNC_TOTAL_F2_V_TOTAL__SHIFT) & HDMI_VSYNC_TOTAL_F2_V_TOTAL__MASK; +} + +#define REG_HDMI_FRAME_CTRL					0x000002c8 +#define HDMI_FRAME_CTRL_RGB_MUX_SEL_BGR				0x00001000 +#define HDMI_FRAME_CTRL_VSYNC_LOW				0x10000000 +#define HDMI_FRAME_CTRL_HSYNC_LOW				0x20000000 +#define HDMI_FRAME_CTRL_INTERLACED_EN				0x80000000 + +#define REG_HDMI_AUD_INT					0x000002cc +#define HDMI_AUD_INT_AUD_FIFO_URUN_INT				0x00000001 +#define HDMI_AUD_INT_AUD_FIFO_URAN_MASK				0x00000002 +#define HDMI_AUD_INT_AUD_SAM_DROP_INT				0x00000004 +#define HDMI_AUD_INT_AUD_SAM_DROP_MASK				0x00000008 + +#define REG_HDMI_PHY_CTRL					0x000002d4 +#define HDMI_PHY_CTRL_SW_RESET_PLL				0x00000001 +#define HDMI_PHY_CTRL_SW_RESET_PLL_LOW				0x00000002 +#define HDMI_PHY_CTRL_SW_RESET					0x00000004 +#define HDMI_PHY_CTRL_SW_RESET_LOW				0x00000008 + +#define REG_HDMI_CEC_WR_RANGE					0x000002dc + +#define REG_HDMI_CEC_RD_RANGE					0x000002e0 + +#define REG_HDMI_VERSION					0x000002e4 + +#define REG_HDMI_CEC_COMPL_CTL					0x00000360 + +#define REG_HDMI_CEC_RD_START_RANGE				0x00000364 + +#define REG_HDMI_CEC_RD_TOTAL_RANGE				0x00000368 + +#define REG_HDMI_CEC_RD_ERR_RESP_LO				0x0000036c + +#define REG_HDMI_CEC_WR_CHECK_CONFIG				0x00000370 + +#define REG_HDMI_8x60_PHY_REG0					0x00000300 +#define HDMI_8x60_PHY_REG0_DESER_DEL_CTRL__MASK			0x0000001c +#define HDMI_8x60_PHY_REG0_DESER_DEL_CTRL__SHIFT		2 +static inline uint32_t HDMI_8x60_PHY_REG0_DESER_DEL_CTRL(uint32_t val) +{ +	return ((val) << HDMI_8x60_PHY_REG0_DESER_DEL_CTRL__SHIFT) & HDMI_8x60_PHY_REG0_DESER_DEL_CTRL__MASK; +} + +#define REG_HDMI_8x60_PHY_REG1					0x00000304 +#define HDMI_8x60_PHY_REG1_DTEST_MUX_SEL__MASK			0x000000f0 +#define HDMI_8x60_PHY_REG1_DTEST_MUX_SEL__SHIFT			4 +static inline uint32_t HDMI_8x60_PHY_REG1_DTEST_MUX_SEL(uint32_t val) +{ +	return ((val) << HDMI_8x60_PHY_REG1_DTEST_MUX_SEL__SHIFT) & HDMI_8x60_PHY_REG1_DTEST_MUX_SEL__MASK; +} +#define HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL__MASK		0x0000000f +#define HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL__SHIFT		0 +static inline uint32_t HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL(uint32_t val) +{ +	return ((val) << HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL__SHIFT) & HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL__MASK; +} + +#define REG_HDMI_8x60_PHY_REG2					0x00000308 +#define HDMI_8x60_PHY_REG2_PD_DESER				0x00000001 +#define HDMI_8x60_PHY_REG2_PD_DRIVE_1				0x00000002 +#define HDMI_8x60_PHY_REG2_PD_DRIVE_2				0x00000004 +#define HDMI_8x60_PHY_REG2_PD_DRIVE_3				0x00000008 +#define HDMI_8x60_PHY_REG2_PD_DRIVE_4				0x00000010 +#define HDMI_8x60_PHY_REG2_PD_PLL				0x00000020 +#define HDMI_8x60_PHY_REG2_PD_PWRGEN				0x00000040 +#define HDMI_8x60_PHY_REG2_RCV_SENSE_EN				0x00000080 + +#define REG_HDMI_8x60_PHY_REG3					0x0000030c +#define HDMI_8x60_PHY_REG3_PLL_ENABLE				0x00000001 + +#define REG_HDMI_8x60_PHY_REG4					0x00000310 + +#define REG_HDMI_8x60_PHY_REG5					0x00000314 + +#define REG_HDMI_8x60_PHY_REG6					0x00000318 + +#define REG_HDMI_8x60_PHY_REG7					0x0000031c + +#define REG_HDMI_8x60_PHY_REG8					0x00000320 + +#define REG_HDMI_8x60_PHY_REG9					0x00000324 + +#define REG_HDMI_8x60_PHY_REG10					0x00000328 + +#define REG_HDMI_8x60_PHY_REG11					0x0000032c + +#define REG_HDMI_8x60_PHY_REG12					0x00000330 +#define HDMI_8x60_PHY_REG12_RETIMING_EN				0x00000001 +#define HDMI_8x60_PHY_REG12_PLL_LOCK_DETECT_EN			0x00000002 +#define HDMI_8x60_PHY_REG12_FORCE_LOCK				0x00000010 + +#define REG_HDMI_8960_PHY_REG0					0x00000400 + +#define REG_HDMI_8960_PHY_REG1					0x00000404 + +#define REG_HDMI_8960_PHY_REG2					0x00000408 + +#define REG_HDMI_8960_PHY_REG3					0x0000040c + +#define REG_HDMI_8960_PHY_REG4					0x00000410 + +#define REG_HDMI_8960_PHY_REG5					0x00000414 + +#define REG_HDMI_8960_PHY_REG6					0x00000418 + +#define REG_HDMI_8960_PHY_REG7					0x0000041c + +#define REG_HDMI_8960_PHY_REG8					0x00000420 + +#define REG_HDMI_8960_PHY_REG9					0x00000424 + +#define REG_HDMI_8960_PHY_REG10					0x00000428 + +#define REG_HDMI_8960_PHY_REG11					0x0000042c + +#define REG_HDMI_8960_PHY_REG12					0x00000430 + +#define REG_HDMI_8x74_ANA_CFG0					0x00000000 + +#define REG_HDMI_8x74_ANA_CFG1					0x00000004 + +#define REG_HDMI_8x74_PD_CTRL0					0x00000010 + +#define REG_HDMI_8x74_PD_CTRL1					0x00000014 + +#define REG_HDMI_8x74_BIST_CFG0					0x00000034 + +#define REG_HDMI_8x74_BIST_PATN0				0x0000003c + +#define REG_HDMI_8x74_BIST_PATN1				0x00000040 + +#define REG_HDMI_8x74_BIST_PATN2				0x00000044 + +#define REG_HDMI_8x74_BIST_PATN3				0x00000048 + + +#endif /* HDMI_XML */ diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c new file mode 100644 index 00000000000..872485f6013 --- /dev/null +++ b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/hdmi.h> +#include "hdmi.h" + + +/* Supported HDMI Audio channels */ +#define MSM_HDMI_AUDIO_CHANNEL_2		0 +#define MSM_HDMI_AUDIO_CHANNEL_4		1 +#define MSM_HDMI_AUDIO_CHANNEL_6		2 +#define MSM_HDMI_AUDIO_CHANNEL_8		3 + +/* maps MSM_HDMI_AUDIO_CHANNEL_n consts used by audio driver to # of channels: */ +static int nchannels[] = { 2, 4, 6, 8 }; + +/* Supported HDMI Audio sample rates */ +#define MSM_HDMI_SAMPLE_RATE_32KHZ		0 +#define MSM_HDMI_SAMPLE_RATE_44_1KHZ		1 +#define MSM_HDMI_SAMPLE_RATE_48KHZ		2 +#define MSM_HDMI_SAMPLE_RATE_88_2KHZ		3 +#define MSM_HDMI_SAMPLE_RATE_96KHZ		4 +#define MSM_HDMI_SAMPLE_RATE_176_4KHZ		5 +#define MSM_HDMI_SAMPLE_RATE_192KHZ		6 +#define MSM_HDMI_SAMPLE_RATE_MAX		7 + + +struct hdmi_msm_audio_acr { +	uint32_t n;	/* N parameter for clock regeneration */ +	uint32_t cts;	/* CTS parameter for clock regeneration */ +}; + +struct hdmi_msm_audio_arcs { +	unsigned long int pixclock; +	struct hdmi_msm_audio_acr lut[MSM_HDMI_SAMPLE_RATE_MAX]; +}; + +#define HDMI_MSM_AUDIO_ARCS(pclk, ...) { (1000 * (pclk)), __VA_ARGS__ } + +/* Audio constants lookup table for hdmi_msm_audio_acr_setup */ +/* Valid Pixel-Clock rates: 25.2MHz, 27MHz, 27.03MHz, 74.25MHz, 148.5MHz */ +static const struct hdmi_msm_audio_arcs acr_lut[] = { +	/*  25.200MHz  */ +	HDMI_MSM_AUDIO_ARCS(25200, { +		{4096, 25200}, {6272, 28000}, {6144, 25200}, {12544, 28000}, +		{12288, 25200}, {25088, 28000}, {24576, 25200} }), +	/*  27.000MHz  */ +	HDMI_MSM_AUDIO_ARCS(27000, { +		{4096, 27000}, {6272, 30000}, {6144, 27000}, {12544, 30000}, +		{12288, 27000}, {25088, 30000}, {24576, 27000} }), +	/*  27.027MHz */ +	HDMI_MSM_AUDIO_ARCS(27030, { +		{4096, 27027}, {6272, 30030}, {6144, 27027}, {12544, 30030}, +		{12288, 27027}, {25088, 30030}, {24576, 27027} }), +	/*  74.250MHz */ +	HDMI_MSM_AUDIO_ARCS(74250, { +		{4096, 74250}, {6272, 82500}, {6144, 74250}, {12544, 82500}, +		{12288, 74250}, {25088, 82500}, {24576, 74250} }), +	/* 148.500MHz */ +	HDMI_MSM_AUDIO_ARCS(148500, { +		{4096, 148500}, {6272, 165000}, {6144, 148500}, {12544, 165000}, +		{12288, 148500}, {25088, 165000}, {24576, 148500} }), +}; + +static const struct hdmi_msm_audio_arcs *get_arcs(unsigned long int pixclock) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(acr_lut); i++) { +		const struct hdmi_msm_audio_arcs *arcs = &acr_lut[i]; +		if (arcs->pixclock == pixclock) +			return arcs; +	} + +	return NULL; +} + +int hdmi_audio_update(struct hdmi *hdmi) +{ +	struct hdmi_audio *audio = &hdmi->audio; +	struct hdmi_audio_infoframe *info = &audio->infoframe; +	const struct hdmi_msm_audio_arcs *arcs = NULL; +	bool enabled = audio->enabled; +	uint32_t acr_pkt_ctrl, vbi_pkt_ctrl, aud_pkt_ctrl; +	uint32_t infofrm_ctrl, audio_config; + +	DBG("audio: enabled=%d, channels=%d, channel_allocation=0x%x, " +		"level_shift_value=%d, downmix_inhibit=%d, rate=%d", +		audio->enabled, info->channels,  info->channel_allocation, +		info->level_shift_value, info->downmix_inhibit, audio->rate); +	DBG("video: power_on=%d, pixclock=%lu", hdmi->power_on, hdmi->pixclock); + +	if (enabled && !(hdmi->power_on && hdmi->pixclock)) { +		DBG("disabling audio: no video"); +		enabled = false; +	} + +	if (enabled) { +		arcs = get_arcs(hdmi->pixclock); +		if (!arcs) { +			DBG("disabling audio: unsupported pixclock: %lu", +					hdmi->pixclock); +			enabled = false; +		} +	} + +	/* Read first before writing */ +	acr_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_ACR_PKT_CTRL); +	vbi_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_VBI_PKT_CTRL); +	aud_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_AUDIO_PKT_CTRL1); +	infofrm_ctrl = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0); +	audio_config = hdmi_read(hdmi, REG_HDMI_AUDIO_CFG); + +	/* Clear N/CTS selection bits */ +	acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_SELECT__MASK; + +	if (enabled) { +		uint32_t n, cts, multiplier; +		enum hdmi_acr_cts select; +		uint8_t buf[14]; + +		n   = arcs->lut[audio->rate].n; +		cts = arcs->lut[audio->rate].cts; + +		if ((MSM_HDMI_SAMPLE_RATE_192KHZ == audio->rate) || +				(MSM_HDMI_SAMPLE_RATE_176_4KHZ == audio->rate)) { +			multiplier = 4; +			n >>= 2; /* divide N by 4 and use multiplier */ +		} else if ((MSM_HDMI_SAMPLE_RATE_96KHZ == audio->rate) || +				(MSM_HDMI_SAMPLE_RATE_88_2KHZ == audio->rate)) { +			multiplier = 2; +			n >>= 1; /* divide N by 2 and use multiplier */ +		} else { +			multiplier = 1; +		} + +		DBG("n=%u, cts=%u, multiplier=%u", n, cts, multiplier); + +		acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SOURCE; +		acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_AUDIO_PRIORITY; +		acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_N_MULTIPLIER(multiplier); + +		if ((MSM_HDMI_SAMPLE_RATE_48KHZ == audio->rate) || +				(MSM_HDMI_SAMPLE_RATE_96KHZ == audio->rate) || +				(MSM_HDMI_SAMPLE_RATE_192KHZ == audio->rate)) +			select = ACR_48; +		else if ((MSM_HDMI_SAMPLE_RATE_44_1KHZ == audio->rate) || +				(MSM_HDMI_SAMPLE_RATE_88_2KHZ == audio->rate) || +				(MSM_HDMI_SAMPLE_RATE_176_4KHZ == audio->rate)) +			select = ACR_44; +		else /* default to 32k */ +			select = ACR_32; + +		acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SELECT(select); + +		hdmi_write(hdmi, REG_HDMI_ACR_0(select - 1), +				HDMI_ACR_0_CTS(cts)); +		hdmi_write(hdmi, REG_HDMI_ACR_1(select - 1), +				HDMI_ACR_1_N(n)); + +		hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL2, +				COND(info->channels != 2, HDMI_AUDIO_PKT_CTRL2_LAYOUT) | +				HDMI_AUDIO_PKT_CTRL2_OVERRIDE); + +		acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_CONT; +		acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SEND; + +		/* configure infoframe: */ +		hdmi_audio_infoframe_pack(info, buf, sizeof(buf)); +		hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0, +				(buf[3] <<  0) || (buf[4] <<  8) || +				(buf[5] << 16) || (buf[6] << 24)); +		hdmi_write(hdmi, REG_HDMI_AUDIO_INFO1, +				(buf[7] <<  0) || (buf[8] << 8)); + +		hdmi_write(hdmi, REG_HDMI_GC, 0); + +		vbi_pkt_ctrl |= HDMI_VBI_PKT_CTRL_GC_ENABLE; +		vbi_pkt_ctrl |= HDMI_VBI_PKT_CTRL_GC_EVERY_FRAME; + +		aud_pkt_ctrl |= HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND; + +		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND; +		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT; +		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE; +		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE; + +		audio_config &= ~HDMI_AUDIO_CFG_FIFO_WATERMARK__MASK; +		audio_config |= HDMI_AUDIO_CFG_FIFO_WATERMARK(4); +		audio_config |= HDMI_AUDIO_CFG_ENGINE_ENABLE; +	} else { +		hdmi_write(hdmi, REG_HDMI_GC, HDMI_GC_MUTE); +		acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_CONT; +		acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_SEND; +		vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_ENABLE; +		vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_EVERY_FRAME; +		aud_pkt_ctrl &= ~HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND; +		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND; +		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT; +		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE; +		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE; +		audio_config &= ~HDMI_AUDIO_CFG_ENGINE_ENABLE; +	} + +	hdmi_write(hdmi, REG_HDMI_ACR_PKT_CTRL, acr_pkt_ctrl); +	hdmi_write(hdmi, REG_HDMI_VBI_PKT_CTRL, vbi_pkt_ctrl); +	hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL1, aud_pkt_ctrl); +	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, infofrm_ctrl); + +	hdmi_write(hdmi, REG_HDMI_AUD_INT, +			COND(enabled, HDMI_AUD_INT_AUD_FIFO_URUN_INT) | +			COND(enabled, HDMI_AUD_INT_AUD_SAM_DROP_INT)); + +	hdmi_write(hdmi, REG_HDMI_AUDIO_CFG, audio_config); + + +	DBG("audio %sabled", enabled ? "en" : "dis"); + +	return 0; +} + +int hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled, +	uint32_t num_of_channels, uint32_t channel_allocation, +	uint32_t level_shift, bool down_mix) +{ +	struct hdmi_audio *audio; + +	if (!hdmi) +		return -ENXIO; + +	audio = &hdmi->audio; + +	if (num_of_channels >= ARRAY_SIZE(nchannels)) +		return -EINVAL; + +	audio->enabled = enabled; +	audio->infoframe.channels = nchannels[num_of_channels]; +	audio->infoframe.channel_allocation = channel_allocation; +	audio->infoframe.level_shift_value = level_shift; +	audio->infoframe.downmix_inhibit = down_mix; + +	return hdmi_audio_update(hdmi); +} + +void hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate) +{ +	struct hdmi_audio *audio; + +	if (!hdmi) +		return; + +	audio = &hdmi->audio; + +	if ((rate < 0) || (rate >= MSM_HDMI_SAMPLE_RATE_MAX)) +		return; + +	audio->rate = rate; +	hdmi_audio_update(hdmi); +} diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c new file mode 100644 index 00000000000..f6cf745c249 --- /dev/null +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include "hdmi.h" + +struct hdmi_bridge { +	struct drm_bridge base; +	struct hdmi *hdmi; +}; +#define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base) + +static void hdmi_bridge_destroy(struct drm_bridge *bridge) +{ +	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); +	hdmi_unreference(hdmi_bridge->hdmi); +	drm_bridge_cleanup(bridge); +	kfree(hdmi_bridge); +} + +static void power_on(struct drm_bridge *bridge) +{ +	struct drm_device *dev = bridge->dev; +	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); +	struct hdmi *hdmi = hdmi_bridge->hdmi; +	const struct hdmi_platform_config *config = hdmi->config; +	int i, ret; + +	for (i = 0; i < config->pwr_reg_cnt; i++) { +		ret = regulator_enable(hdmi->pwr_regs[i]); +		if (ret) { +			dev_err(dev->dev, "failed to enable pwr regulator: %s (%d)\n", +					config->pwr_reg_names[i], ret); +		} +	} + +	if (config->pwr_clk_cnt > 0) { +		DBG("pixclock: %lu", hdmi->pixclock); +		ret = clk_set_rate(hdmi->pwr_clks[0], hdmi->pixclock); +		if (ret) { +			dev_err(dev->dev, "failed to set pixel clk: %s (%d)\n", +					config->pwr_clk_names[0], ret); +		} +	} + +	for (i = 0; i < config->pwr_clk_cnt; i++) { +		ret = clk_prepare_enable(hdmi->pwr_clks[i]); +		if (ret) { +			dev_err(dev->dev, "failed to enable pwr clk: %s (%d)\n", +					config->pwr_clk_names[i], ret); +		} +	} +} + +static void power_off(struct drm_bridge *bridge) +{ +	struct drm_device *dev = bridge->dev; +	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); +	struct hdmi *hdmi = hdmi_bridge->hdmi; +	const struct hdmi_platform_config *config = hdmi->config; +	int i, ret; + +	/* TODO do we need to wait for final vblank somewhere before +	 * cutting the clocks? +	 */ +	mdelay(16 + 4); + +	for (i = 0; i < config->pwr_clk_cnt; i++) +		clk_disable_unprepare(hdmi->pwr_clks[i]); + +	for (i = 0; i < config->pwr_reg_cnt; i++) { +		ret = regulator_disable(hdmi->pwr_regs[i]); +		if (ret) { +			dev_err(dev->dev, "failed to disable pwr regulator: %s (%d)\n", +					config->pwr_reg_names[i], ret); +		} +	} +} + +static void hdmi_bridge_pre_enable(struct drm_bridge *bridge) +{ +	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); +	struct hdmi *hdmi = hdmi_bridge->hdmi; +	struct hdmi_phy *phy = hdmi->phy; + +	DBG("power up"); + +	if (!hdmi->power_on) { +		power_on(bridge); +		hdmi->power_on = true; +		hdmi_audio_update(hdmi); +	} + +	phy->funcs->powerup(phy, hdmi->pixclock); +	hdmi_set_mode(hdmi, true); +} + +static void hdmi_bridge_enable(struct drm_bridge *bridge) +{ +} + +static void hdmi_bridge_disable(struct drm_bridge *bridge) +{ +} + +static void hdmi_bridge_post_disable(struct drm_bridge *bridge) +{ +	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); +	struct hdmi *hdmi = hdmi_bridge->hdmi; +	struct hdmi_phy *phy = hdmi->phy; + +	DBG("power down"); +	hdmi_set_mode(hdmi, false); +	phy->funcs->powerdown(phy); + +	if (hdmi->power_on) { +		power_off(bridge); +		hdmi->power_on = false; +		hdmi_audio_update(hdmi); +	} +} + +static void hdmi_bridge_mode_set(struct drm_bridge *bridge, +		 struct drm_display_mode *mode, +		 struct drm_display_mode *adjusted_mode) +{ +	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); +	struct hdmi *hdmi = hdmi_bridge->hdmi; +	int hstart, hend, vstart, vend; +	uint32_t frame_ctrl; + +	mode = adjusted_mode; + +	hdmi->pixclock = mode->clock * 1000; + +	hdmi->hdmi_mode = drm_match_cea_mode(mode) > 1; + +	hstart = mode->htotal - mode->hsync_start; +	hend   = mode->htotal - mode->hsync_start + mode->hdisplay; + +	vstart = mode->vtotal - mode->vsync_start - 1; +	vend   = mode->vtotal - mode->vsync_start + mode->vdisplay - 1; + +	DBG("htotal=%d, vtotal=%d, hstart=%d, hend=%d, vstart=%d, vend=%d", +			mode->htotal, mode->vtotal, hstart, hend, vstart, vend); + +	hdmi_write(hdmi, REG_HDMI_TOTAL, +			HDMI_TOTAL_H_TOTAL(mode->htotal - 1) | +			HDMI_TOTAL_V_TOTAL(mode->vtotal - 1)); + +	hdmi_write(hdmi, REG_HDMI_ACTIVE_HSYNC, +			HDMI_ACTIVE_HSYNC_START(hstart) | +			HDMI_ACTIVE_HSYNC_END(hend)); +	hdmi_write(hdmi, REG_HDMI_ACTIVE_VSYNC, +			HDMI_ACTIVE_VSYNC_START(vstart) | +			HDMI_ACTIVE_VSYNC_END(vend)); + +	if (mode->flags & DRM_MODE_FLAG_INTERLACE) { +		hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2, +				HDMI_VSYNC_TOTAL_F2_V_TOTAL(mode->vtotal)); +		hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2, +				HDMI_VSYNC_ACTIVE_F2_START(vstart + 1) | +				HDMI_VSYNC_ACTIVE_F2_END(vend + 1)); +	} else { +		hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2, +				HDMI_VSYNC_TOTAL_F2_V_TOTAL(0)); +		hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2, +				HDMI_VSYNC_ACTIVE_F2_START(0) | +				HDMI_VSYNC_ACTIVE_F2_END(0)); +	} + +	frame_ctrl = 0; +	if (mode->flags & DRM_MODE_FLAG_NHSYNC) +		frame_ctrl |= HDMI_FRAME_CTRL_HSYNC_LOW; +	if (mode->flags & DRM_MODE_FLAG_NVSYNC) +		frame_ctrl |= HDMI_FRAME_CTRL_VSYNC_LOW; +	if (mode->flags & DRM_MODE_FLAG_INTERLACE) +		frame_ctrl |= HDMI_FRAME_CTRL_INTERLACED_EN; +	DBG("frame_ctrl=%08x", frame_ctrl); +	hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl); + +	hdmi_audio_update(hdmi); +} + +static const struct drm_bridge_funcs hdmi_bridge_funcs = { +		.pre_enable = hdmi_bridge_pre_enable, +		.enable = hdmi_bridge_enable, +		.disable = hdmi_bridge_disable, +		.post_disable = hdmi_bridge_post_disable, +		.mode_set = hdmi_bridge_mode_set, +		.destroy = hdmi_bridge_destroy, +}; + + +/* initialize bridge */ +struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi) +{ +	struct drm_bridge *bridge = NULL; +	struct hdmi_bridge *hdmi_bridge; +	int ret; + +	hdmi_bridge = kzalloc(sizeof(*hdmi_bridge), GFP_KERNEL); +	if (!hdmi_bridge) { +		ret = -ENOMEM; +		goto fail; +	} + +	hdmi_bridge->hdmi = hdmi_reference(hdmi); + +	bridge = &hdmi_bridge->base; + +	drm_bridge_init(hdmi->dev, bridge, &hdmi_bridge_funcs); + +	return bridge; + +fail: +	if (bridge) +		hdmi_bridge_destroy(bridge); + +	return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c new file mode 100644 index 00000000000..28f7e3ec6c2 --- /dev/null +++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c @@ -0,0 +1,436 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/gpio.h> + +#include "msm_kms.h" +#include "hdmi.h" + +struct hdmi_connector { +	struct drm_connector base; +	struct hdmi *hdmi; +	struct work_struct hpd_work; +}; +#define to_hdmi_connector(x) container_of(x, struct hdmi_connector, base) + +static int gpio_config(struct hdmi *hdmi, bool on) +{ +	struct drm_device *dev = hdmi->dev; +	const struct hdmi_platform_config *config = hdmi->config; +	int ret; + +	if (on) { +		ret = gpio_request(config->ddc_clk_gpio, "HDMI_DDC_CLK"); +		if (ret) { +			dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n", +				"HDMI_DDC_CLK", config->ddc_clk_gpio, ret); +			goto error1; +		} +		gpio_set_value_cansleep(config->ddc_clk_gpio, 1); + +		ret = gpio_request(config->ddc_data_gpio, "HDMI_DDC_DATA"); +		if (ret) { +			dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n", +				"HDMI_DDC_DATA", config->ddc_data_gpio, ret); +			goto error2; +		} +		gpio_set_value_cansleep(config->ddc_data_gpio, 1); + +		ret = gpio_request(config->hpd_gpio, "HDMI_HPD"); +		if (ret) { +			dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n", +				"HDMI_HPD", config->hpd_gpio, ret); +			goto error3; +		} +		gpio_direction_input(config->hpd_gpio); +		gpio_set_value_cansleep(config->hpd_gpio, 1); + +		if (config->mux_en_gpio != -1) { +			ret = gpio_request(config->mux_en_gpio, "HDMI_MUX_EN"); +			if (ret) { +				dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n", +					"HDMI_MUX_SEL", config->mux_en_gpio, ret); +				goto error4; +			} +			gpio_set_value_cansleep(config->mux_en_gpio, 1); +		} + +		if (config->mux_sel_gpio != -1) { +			ret = gpio_request(config->mux_sel_gpio, "HDMI_MUX_SEL"); +			if (ret) { +				dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n", +					"HDMI_MUX_SEL", config->mux_sel_gpio, ret); +				goto error5; +			} +			gpio_set_value_cansleep(config->mux_sel_gpio, 0); +		} +		DBG("gpio on"); +	} else { +		gpio_free(config->ddc_clk_gpio); +		gpio_free(config->ddc_data_gpio); +		gpio_free(config->hpd_gpio); + +		if (config->mux_en_gpio != -1) { +			gpio_set_value_cansleep(config->mux_en_gpio, 0); +			gpio_free(config->mux_en_gpio); +		} + +		if (config->mux_sel_gpio != -1) { +			gpio_set_value_cansleep(config->mux_sel_gpio, 1); +			gpio_free(config->mux_sel_gpio); +		} +		DBG("gpio off"); +	} + +	return 0; + +error5: +	if (config->mux_en_gpio != -1) +		gpio_free(config->mux_en_gpio); +error4: +	gpio_free(config->hpd_gpio); +error3: +	gpio_free(config->ddc_data_gpio); +error2: +	gpio_free(config->ddc_clk_gpio); +error1: +	return ret; +} + +static int hpd_enable(struct hdmi_connector *hdmi_connector) +{ +	struct hdmi *hdmi = hdmi_connector->hdmi; +	const struct hdmi_platform_config *config = hdmi->config; +	struct drm_device *dev = hdmi_connector->base.dev; +	struct hdmi_phy *phy = hdmi->phy; +	uint32_t hpd_ctrl; +	int i, ret; + +	ret = gpio_config(hdmi, true); +	if (ret) { +		dev_err(dev->dev, "failed to configure GPIOs: %d\n", ret); +		goto fail; +	} + +	for (i = 0; i < config->hpd_clk_cnt; i++) { +		if (config->hpd_freq && config->hpd_freq[i]) { +			ret = clk_set_rate(hdmi->hpd_clks[i], +					config->hpd_freq[i]); +			if (ret) +				dev_warn(dev->dev, "failed to set clk %s (%d)\n", +						config->hpd_clk_names[i], ret); +		} + +		ret = clk_prepare_enable(hdmi->hpd_clks[i]); +		if (ret) { +			dev_err(dev->dev, "failed to enable hpd clk: %s (%d)\n", +					config->hpd_clk_names[i], ret); +			goto fail; +		} +	} + +	for (i = 0; i < config->hpd_reg_cnt; i++) { +		ret = regulator_enable(hdmi->hpd_regs[i]); +		if (ret) { +			dev_err(dev->dev, "failed to enable hpd regulator: %s (%d)\n", +					config->hpd_reg_names[i], ret); +			goto fail; +		} +	} + +	hdmi_set_mode(hdmi, false); +	phy->funcs->reset(phy); +	hdmi_set_mode(hdmi, true); + +	hdmi_write(hdmi, REG_HDMI_USEC_REFTIMER, 0x0001001b); + +	/* enable HPD events: */ +	hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, +			HDMI_HPD_INT_CTRL_INT_CONNECT | +			HDMI_HPD_INT_CTRL_INT_EN); + +	/* set timeout to 4.1ms (max) for hardware debounce */ +	hpd_ctrl = hdmi_read(hdmi, REG_HDMI_HPD_CTRL); +	hpd_ctrl |= HDMI_HPD_CTRL_TIMEOUT(0x1fff); + +	/* Toggle HPD circuit to trigger HPD sense */ +	hdmi_write(hdmi, REG_HDMI_HPD_CTRL, +			~HDMI_HPD_CTRL_ENABLE & hpd_ctrl); +	hdmi_write(hdmi, REG_HDMI_HPD_CTRL, +			HDMI_HPD_CTRL_ENABLE | hpd_ctrl); + +	return 0; + +fail: +	return ret; +} + +static int hdp_disable(struct hdmi_connector *hdmi_connector) +{ +	struct hdmi *hdmi = hdmi_connector->hdmi; +	const struct hdmi_platform_config *config = hdmi->config; +	struct drm_device *dev = hdmi_connector->base.dev; +	int i, ret = 0; + +	/* Disable HPD interrupt */ +	hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0); + +	hdmi_set_mode(hdmi, false); + +	for (i = 0; i < config->hpd_reg_cnt; i++) { +		ret = regulator_disable(hdmi->hpd_regs[i]); +		if (ret) { +			dev_err(dev->dev, "failed to disable hpd regulator: %s (%d)\n", +					config->hpd_reg_names[i], ret); +			goto fail; +		} +	} + +	for (i = 0; i < config->hpd_clk_cnt; i++) +		clk_disable_unprepare(hdmi->hpd_clks[i]); + +	ret = gpio_config(hdmi, false); +	if (ret) { +		dev_err(dev->dev, "failed to unconfigure GPIOs: %d\n", ret); +		goto fail; +	} + +	return 0; + +fail: +	return ret; +} + +static void +hotplug_work(struct work_struct *work) +{ +	struct hdmi_connector *hdmi_connector = +		container_of(work, struct hdmi_connector, hpd_work); +	struct drm_connector *connector = &hdmi_connector->base; +	drm_helper_hpd_irq_event(connector->dev); +} + +void hdmi_connector_irq(struct drm_connector *connector) +{ +	struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector); +	struct msm_drm_private *priv = connector->dev->dev_private; +	struct hdmi *hdmi = hdmi_connector->hdmi; +	uint32_t hpd_int_status, hpd_int_ctrl; + +	/* Process HPD: */ +	hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS); +	hpd_int_ctrl   = hdmi_read(hdmi, REG_HDMI_HPD_INT_CTRL); + +	if ((hpd_int_ctrl & HDMI_HPD_INT_CTRL_INT_EN) && +			(hpd_int_status & HDMI_HPD_INT_STATUS_INT)) { +		bool detected = !!(hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED); + +		DBG("status=%04x, ctrl=%04x", hpd_int_status, hpd_int_ctrl); + +		/* ack the irq: */ +		hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, +				hpd_int_ctrl | HDMI_HPD_INT_CTRL_INT_ACK); + +		/* detect disconnect if we are connected or visa versa: */ +		hpd_int_ctrl = HDMI_HPD_INT_CTRL_INT_EN; +		if (!detected) +			hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT; +		hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl); + +		queue_work(priv->wq, &hdmi_connector->hpd_work); +	} +} + +static enum drm_connector_status detect_reg(struct hdmi *hdmi) +{ +	uint32_t hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS); +	return (hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED) ? +			connector_status_connected : connector_status_disconnected; +} + +static enum drm_connector_status detect_gpio(struct hdmi *hdmi) +{ +	const struct hdmi_platform_config *config = hdmi->config; +	return gpio_get_value(config->hpd_gpio) ? +			connector_status_connected : +			connector_status_disconnected; +} + +static enum drm_connector_status hdmi_connector_detect( +		struct drm_connector *connector, bool force) +{ +	struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector); +	struct hdmi *hdmi = hdmi_connector->hdmi; +	enum drm_connector_status stat_gpio, stat_reg; +	int retry = 20; + +	do { +		stat_gpio = detect_gpio(hdmi); +		stat_reg  = detect_reg(hdmi); + +		if (stat_gpio == stat_reg) +			break; + +		mdelay(10); +	} while (--retry); + +	/* the status we get from reading gpio seems to be more reliable, +	 * so trust that one the most if we didn't manage to get hdmi and +	 * gpio status to agree: +	 */ +	if (stat_gpio != stat_reg) { +		DBG("HDMI_HPD_INT_STATUS tells us: %d", stat_reg); +		DBG("hpd gpio tells us: %d", stat_gpio); +	} + +	return stat_gpio; +} + +static void hdmi_connector_destroy(struct drm_connector *connector) +{ +	struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector); + +	hdp_disable(hdmi_connector); + +	drm_sysfs_connector_remove(connector); +	drm_connector_cleanup(connector); + +	hdmi_unreference(hdmi_connector->hdmi); + +	kfree(hdmi_connector); +} + +static int hdmi_connector_get_modes(struct drm_connector *connector) +{ +	struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector); +	struct hdmi *hdmi = hdmi_connector->hdmi; +	struct edid *edid; +	uint32_t hdmi_ctrl; +	int ret = 0; + +	hdmi_ctrl = hdmi_read(hdmi, REG_HDMI_CTRL); +	hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl | HDMI_CTRL_ENABLE); + +	edid = drm_get_edid(connector, hdmi->i2c); + +	hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl); + +	drm_mode_connector_update_edid_property(connector, edid); + +	if (edid) { +		ret = drm_add_edid_modes(connector, edid); +		kfree(edid); +	} + +	return ret; +} + +static int hdmi_connector_mode_valid(struct drm_connector *connector, +				 struct drm_display_mode *mode) +{ +	struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector); +	struct hdmi *hdmi = hdmi_connector->hdmi; +	const struct hdmi_platform_config *config = hdmi->config; +	struct msm_drm_private *priv = connector->dev->dev_private; +	struct msm_kms *kms = priv->kms; +	long actual, requested; + +	requested = 1000 * mode->clock; +	actual = kms->funcs->round_pixclk(kms, +			requested, hdmi_connector->hdmi->encoder); + +	/* for mdp5/apq8074, we manage our own pixel clk (as opposed to +	 * mdp4/dtv stuff where pixel clk is assigned to mdp/encoder +	 * instead): +	 */ +	if (config->pwr_clk_cnt > 0) +		actual = clk_round_rate(hdmi->pwr_clks[0], actual); + +	DBG("requested=%ld, actual=%ld", requested, actual); + +	if (actual != requested) +		return MODE_CLOCK_RANGE; + +	return 0; +} + +static struct drm_encoder * +hdmi_connector_best_encoder(struct drm_connector *connector) +{ +	struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector); +	return hdmi_connector->hdmi->encoder; +} + +static const struct drm_connector_funcs hdmi_connector_funcs = { +	.dpms = drm_helper_connector_dpms, +	.detect = hdmi_connector_detect, +	.fill_modes = drm_helper_probe_single_connector_modes, +	.destroy = hdmi_connector_destroy, +}; + +static const struct drm_connector_helper_funcs hdmi_connector_helper_funcs = { +	.get_modes = hdmi_connector_get_modes, +	.mode_valid = hdmi_connector_mode_valid, +	.best_encoder = hdmi_connector_best_encoder, +}; + +/* initialize connector */ +struct drm_connector *hdmi_connector_init(struct hdmi *hdmi) +{ +	struct drm_connector *connector = NULL; +	struct hdmi_connector *hdmi_connector; +	int ret; + +	hdmi_connector = kzalloc(sizeof(*hdmi_connector), GFP_KERNEL); +	if (!hdmi_connector) { +		ret = -ENOMEM; +		goto fail; +	} + +	hdmi_connector->hdmi = hdmi_reference(hdmi); +	INIT_WORK(&hdmi_connector->hpd_work, hotplug_work); + +	connector = &hdmi_connector->base; + +	drm_connector_init(hdmi->dev, connector, &hdmi_connector_funcs, +			DRM_MODE_CONNECTOR_HDMIA); +	drm_connector_helper_add(connector, &hdmi_connector_helper_funcs); + +	connector->polled = DRM_CONNECTOR_POLL_CONNECT | +			DRM_CONNECTOR_POLL_DISCONNECT; + +	connector->interlace_allowed = 1; +	connector->doublescan_allowed = 0; + +	drm_sysfs_connector_add(connector); + +	ret = hpd_enable(hdmi_connector); +	if (ret) { +		dev_err(hdmi->dev->dev, "failed to enable HPD: %d\n", ret); +		goto fail; +	} + +	drm_mode_connector_attach_encoder(connector, hdmi->encoder); + +	return connector; + +fail: +	if (connector) +		hdmi_connector_destroy(connector); + +	return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c b/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c new file mode 100644 index 00000000000..f4ab7f70fed --- /dev/null +++ b/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include "hdmi.h" + +struct hdmi_i2c_adapter { +	struct i2c_adapter base; +	struct hdmi *hdmi; +	bool sw_done; +	wait_queue_head_t ddc_event; +}; +#define to_hdmi_i2c_adapter(x) container_of(x, struct hdmi_i2c_adapter, base) + +static void init_ddc(struct hdmi_i2c_adapter *hdmi_i2c) +{ +	struct hdmi *hdmi = hdmi_i2c->hdmi; + +	hdmi_write(hdmi, REG_HDMI_DDC_CTRL, +			HDMI_DDC_CTRL_SW_STATUS_RESET); +	hdmi_write(hdmi, REG_HDMI_DDC_CTRL, +			HDMI_DDC_CTRL_SOFT_RESET); + +	hdmi_write(hdmi, REG_HDMI_DDC_SPEED, +			HDMI_DDC_SPEED_THRESHOLD(2) | +			HDMI_DDC_SPEED_PRESCALE(10)); + +	hdmi_write(hdmi, REG_HDMI_DDC_SETUP, +			HDMI_DDC_SETUP_TIMEOUT(0xff)); + +	/* enable reference timer for 27us */ +	hdmi_write(hdmi, REG_HDMI_DDC_REF, +			HDMI_DDC_REF_REFTIMER_ENABLE | +			HDMI_DDC_REF_REFTIMER(27)); +} + +static int ddc_clear_irq(struct hdmi_i2c_adapter *hdmi_i2c) +{ +	struct hdmi *hdmi = hdmi_i2c->hdmi; +	struct drm_device *dev = hdmi->dev; +	uint32_t retry = 0xffff; +	uint32_t ddc_int_ctrl; + +	do { +		--retry; + +		hdmi_write(hdmi, REG_HDMI_DDC_INT_CTRL, +				HDMI_DDC_INT_CTRL_SW_DONE_ACK | +				HDMI_DDC_INT_CTRL_SW_DONE_MASK); + +		ddc_int_ctrl = hdmi_read(hdmi, REG_HDMI_DDC_INT_CTRL); + +	} while ((ddc_int_ctrl & HDMI_DDC_INT_CTRL_SW_DONE_INT) && retry); + +	if (!retry) { +		dev_err(dev->dev, "timeout waiting for DDC\n"); +		return -ETIMEDOUT; +	} + +	hdmi_i2c->sw_done = false; + +	return 0; +} + +#define MAX_TRANSACTIONS 4 + +static bool sw_done(struct hdmi_i2c_adapter *hdmi_i2c) +{ +	struct hdmi *hdmi = hdmi_i2c->hdmi; + +	if (!hdmi_i2c->sw_done) { +		uint32_t ddc_int_ctrl; + +		ddc_int_ctrl = hdmi_read(hdmi, REG_HDMI_DDC_INT_CTRL); + +		if ((ddc_int_ctrl & HDMI_DDC_INT_CTRL_SW_DONE_MASK) && +				(ddc_int_ctrl & HDMI_DDC_INT_CTRL_SW_DONE_INT)) { +			hdmi_i2c->sw_done = true; +			hdmi_write(hdmi, REG_HDMI_DDC_INT_CTRL, +					HDMI_DDC_INT_CTRL_SW_DONE_ACK); +		} +	} + +	return hdmi_i2c->sw_done; +} + +static int hdmi_i2c_xfer(struct i2c_adapter *i2c, +		struct i2c_msg *msgs, int num) +{ +	struct hdmi_i2c_adapter *hdmi_i2c = to_hdmi_i2c_adapter(i2c); +	struct hdmi *hdmi = hdmi_i2c->hdmi; +	struct drm_device *dev = hdmi->dev; +	static const uint32_t nack[] = { +			HDMI_DDC_SW_STATUS_NACK0, HDMI_DDC_SW_STATUS_NACK1, +			HDMI_DDC_SW_STATUS_NACK2, HDMI_DDC_SW_STATUS_NACK3, +	}; +	int indices[MAX_TRANSACTIONS]; +	int ret, i, j, index = 0; +	uint32_t ddc_status, ddc_data, i2c_trans; + +	num = min(num, MAX_TRANSACTIONS); + +	WARN_ON(!(hdmi_read(hdmi, REG_HDMI_CTRL) & HDMI_CTRL_ENABLE)); + +	if (num == 0) +		return num; + +	init_ddc(hdmi_i2c); + +	ret = ddc_clear_irq(hdmi_i2c); +	if (ret) +		return ret; + +	for (i = 0; i < num; i++) { +		struct i2c_msg *p = &msgs[i]; +		uint32_t raw_addr = p->addr << 1; + +		if (p->flags & I2C_M_RD) +			raw_addr |= 1; + +		ddc_data = HDMI_DDC_DATA_DATA(raw_addr) | +				HDMI_DDC_DATA_DATA_RW(DDC_WRITE); + +		if (i == 0) { +			ddc_data |= HDMI_DDC_DATA_INDEX(0) | +					HDMI_DDC_DATA_INDEX_WRITE; +		} + +		hdmi_write(hdmi, REG_HDMI_DDC_DATA, ddc_data); +		index++; + +		indices[i] = index; + +		if (p->flags & I2C_M_RD) { +			index += p->len; +		} else { +			for (j = 0; j < p->len; j++) { +				ddc_data = HDMI_DDC_DATA_DATA(p->buf[j]) | +						HDMI_DDC_DATA_DATA_RW(DDC_WRITE); +				hdmi_write(hdmi, REG_HDMI_DDC_DATA, ddc_data); +				index++; +			} +		} + +		i2c_trans = HDMI_I2C_TRANSACTION_REG_CNT(p->len) | +				HDMI_I2C_TRANSACTION_REG_RW( +						(p->flags & I2C_M_RD) ? DDC_READ : DDC_WRITE) | +				HDMI_I2C_TRANSACTION_REG_START; + +		if (i == (num - 1)) +			i2c_trans |= HDMI_I2C_TRANSACTION_REG_STOP; + +		hdmi_write(hdmi, REG_HDMI_I2C_TRANSACTION(i), i2c_trans); +	} + +	/* trigger the transfer: */ +	hdmi_write(hdmi, REG_HDMI_DDC_CTRL, +			HDMI_DDC_CTRL_TRANSACTION_CNT(num - 1) | +			HDMI_DDC_CTRL_GO); + +	ret = wait_event_timeout(hdmi_i2c->ddc_event, sw_done(hdmi_i2c), HZ/4); +	if (ret <= 0) { +		if (ret == 0) +			ret = -ETIMEDOUT; +		dev_warn(dev->dev, "DDC timeout: %d\n", ret); +		DBG("sw_status=%08x, hw_status=%08x, int_ctrl=%08x", +				hdmi_read(hdmi, REG_HDMI_DDC_SW_STATUS), +				hdmi_read(hdmi, REG_HDMI_DDC_HW_STATUS), +				hdmi_read(hdmi, REG_HDMI_DDC_INT_CTRL)); +		return ret; +	} + +	ddc_status = hdmi_read(hdmi, REG_HDMI_DDC_SW_STATUS); + +	/* read back results of any read transactions: */ +	for (i = 0; i < num; i++) { +		struct i2c_msg *p = &msgs[i]; + +		if (!(p->flags & I2C_M_RD)) +			continue; + +		/* check for NACK: */ +		if (ddc_status & nack[i]) { +			DBG("ddc_status=%08x", ddc_status); +			break; +		} + +		ddc_data = HDMI_DDC_DATA_DATA_RW(DDC_READ) | +				HDMI_DDC_DATA_INDEX(indices[i]) | +				HDMI_DDC_DATA_INDEX_WRITE; + +		hdmi_write(hdmi, REG_HDMI_DDC_DATA, ddc_data); + +		/* discard first byte: */ +		hdmi_read(hdmi, REG_HDMI_DDC_DATA); + +		for (j = 0; j < p->len; j++) { +			ddc_data = hdmi_read(hdmi, REG_HDMI_DDC_DATA); +			p->buf[j] = FIELD(ddc_data, HDMI_DDC_DATA_DATA); +		} +	} + +	return i; +} + +static u32 hdmi_i2c_func(struct i2c_adapter *adapter) +{ +	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm hdmi_i2c_algorithm = { +	.master_xfer	= hdmi_i2c_xfer, +	.functionality	= hdmi_i2c_func, +}; + +void hdmi_i2c_irq(struct i2c_adapter *i2c) +{ +	struct hdmi_i2c_adapter *hdmi_i2c = to_hdmi_i2c_adapter(i2c); + +	if (sw_done(hdmi_i2c)) +		wake_up_all(&hdmi_i2c->ddc_event); +} + +void hdmi_i2c_destroy(struct i2c_adapter *i2c) +{ +	struct hdmi_i2c_adapter *hdmi_i2c = to_hdmi_i2c_adapter(i2c); +	i2c_del_adapter(i2c); +	kfree(hdmi_i2c); +} + +struct i2c_adapter *hdmi_i2c_init(struct hdmi *hdmi) +{ +	struct drm_device *dev = hdmi->dev; +	struct hdmi_i2c_adapter *hdmi_i2c; +	struct i2c_adapter *i2c = NULL; +	int ret; + +	hdmi_i2c = kzalloc(sizeof(*hdmi_i2c), GFP_KERNEL); +	if (!hdmi_i2c) { +		ret = -ENOMEM; +		goto fail; +	} + +	i2c = &hdmi_i2c->base; + +	hdmi_i2c->hdmi = hdmi; +	init_waitqueue_head(&hdmi_i2c->ddc_event); + + +	i2c->owner = THIS_MODULE; +	i2c->class = I2C_CLASS_DDC; +	snprintf(i2c->name, sizeof(i2c->name), "msm hdmi i2c"); +	i2c->dev.parent = &hdmi->pdev->dev; +	i2c->algo = &hdmi_i2c_algorithm; + +	ret = i2c_add_adapter(i2c); +	if (ret) { +		dev_err(dev->dev, "failed to register hdmi i2c: %d\n", ret); +		goto fail; +	} + +	return i2c; + +fail: +	if (i2c) +		hdmi_i2c_destroy(i2c); +	return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c new file mode 100644 index 00000000000..e5b7ed5b8f0 --- /dev/null +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include "hdmi.h" + +struct hdmi_phy_8960 { +	struct hdmi_phy base; +	struct hdmi *hdmi; +}; +#define to_hdmi_phy_8960(x) container_of(x, struct hdmi_phy_8960, base) + +static void hdmi_phy_8960_destroy(struct hdmi_phy *phy) +{ +	struct hdmi_phy_8960 *phy_8960 = to_hdmi_phy_8960(phy); +	kfree(phy_8960); +} + +static void hdmi_phy_8960_reset(struct hdmi_phy *phy) +{ +	struct hdmi_phy_8960 *phy_8960 = to_hdmi_phy_8960(phy); +	struct hdmi *hdmi = phy_8960->hdmi; +	unsigned int val; + +	val = hdmi_read(hdmi, REG_HDMI_PHY_CTRL); + +	if (val & HDMI_PHY_CTRL_SW_RESET_LOW) { +		/* pull low */ +		hdmi_write(hdmi, REG_HDMI_PHY_CTRL, +				val & ~HDMI_PHY_CTRL_SW_RESET); +	} else { +		/* pull high */ +		hdmi_write(hdmi, REG_HDMI_PHY_CTRL, +				val | HDMI_PHY_CTRL_SW_RESET); +	} + +	if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) { +		/* pull low */ +		hdmi_write(hdmi, REG_HDMI_PHY_CTRL, +				val & ~HDMI_PHY_CTRL_SW_RESET_PLL); +	} else { +		/* pull high */ +		hdmi_write(hdmi, REG_HDMI_PHY_CTRL, +				val | HDMI_PHY_CTRL_SW_RESET_PLL); +	} + +	msleep(100); + +	if (val & HDMI_PHY_CTRL_SW_RESET_LOW) { +		/* pull high */ +		hdmi_write(hdmi, REG_HDMI_PHY_CTRL, +				val | HDMI_PHY_CTRL_SW_RESET); +	} else { +		/* pull low */ +		hdmi_write(hdmi, REG_HDMI_PHY_CTRL, +				val & ~HDMI_PHY_CTRL_SW_RESET); +	} + +	if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) { +		/* pull high */ +		hdmi_write(hdmi, REG_HDMI_PHY_CTRL, +				val | HDMI_PHY_CTRL_SW_RESET_PLL); +	} else { +		/* pull low */ +		hdmi_write(hdmi, REG_HDMI_PHY_CTRL, +				val & ~HDMI_PHY_CTRL_SW_RESET_PLL); +	} +} + +static void hdmi_phy_8960_powerup(struct hdmi_phy *phy, +		unsigned long int pixclock) +{ +	struct hdmi_phy_8960 *phy_8960 = to_hdmi_phy_8960(phy); +	struct hdmi *hdmi = phy_8960->hdmi; + +	hdmi_write(hdmi, REG_HDMI_8960_PHY_REG0, 0x1b); +	hdmi_write(hdmi, REG_HDMI_8960_PHY_REG1, 0xf2); +	hdmi_write(hdmi, REG_HDMI_8960_PHY_REG4, 0x00); +	hdmi_write(hdmi, REG_HDMI_8960_PHY_REG5, 0x00); +	hdmi_write(hdmi, REG_HDMI_8960_PHY_REG6, 0x00); +	hdmi_write(hdmi, REG_HDMI_8960_PHY_REG7, 0x00); +	hdmi_write(hdmi, REG_HDMI_8960_PHY_REG8, 0x00); +	hdmi_write(hdmi, REG_HDMI_8960_PHY_REG9, 0x00); +	hdmi_write(hdmi, REG_HDMI_8960_PHY_REG10, 0x00); +	hdmi_write(hdmi, REG_HDMI_8960_PHY_REG11, 0x00); +	hdmi_write(hdmi, REG_HDMI_8960_PHY_REG3, 0x20); +} + +static void hdmi_phy_8960_powerdown(struct hdmi_phy *phy) +{ +	struct hdmi_phy_8960 *phy_8960 = to_hdmi_phy_8960(phy); +	struct hdmi *hdmi = phy_8960->hdmi; + +	hdmi_write(hdmi, REG_HDMI_8960_PHY_REG2, 0x7f); +} + +static const struct hdmi_phy_funcs hdmi_phy_8960_funcs = { +		.destroy = hdmi_phy_8960_destroy, +		.reset = hdmi_phy_8960_reset, +		.powerup = hdmi_phy_8960_powerup, +		.powerdown = hdmi_phy_8960_powerdown, +}; + +struct hdmi_phy *hdmi_phy_8960_init(struct hdmi *hdmi) +{ +	struct hdmi_phy_8960 *phy_8960; +	struct hdmi_phy *phy = NULL; +	int ret; + +	phy_8960 = kzalloc(sizeof(*phy_8960), GFP_KERNEL); +	if (!phy_8960) { +		ret = -ENOMEM; +		goto fail; +	} + +	phy = &phy_8960->base; + +	phy->funcs = &hdmi_phy_8960_funcs; + +	phy_8960->hdmi = hdmi; + +	return phy; + +fail: +	if (phy) +		hdmi_phy_8960_destroy(phy); +	return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c new file mode 100644 index 00000000000..391433c1af7 --- /dev/null +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include "hdmi.h" + +struct hdmi_phy_8x60 { +	struct hdmi_phy base; +	struct hdmi *hdmi; +}; +#define to_hdmi_phy_8x60(x) container_of(x, struct hdmi_phy_8x60, base) + +static void hdmi_phy_8x60_destroy(struct hdmi_phy *phy) +{ +	struct hdmi_phy_8x60 *phy_8x60 = to_hdmi_phy_8x60(phy); +	kfree(phy_8x60); +} + +static void hdmi_phy_8x60_reset(struct hdmi_phy *phy) +{ +	struct hdmi_phy_8x60 *phy_8x60 = to_hdmi_phy_8x60(phy); +	struct hdmi *hdmi = phy_8x60->hdmi; +	unsigned int val; + +	val = hdmi_read(hdmi, REG_HDMI_PHY_CTRL); + +	if (val & HDMI_PHY_CTRL_SW_RESET_LOW) { +		/* pull low */ +		hdmi_write(hdmi, REG_HDMI_PHY_CTRL, +				val & ~HDMI_PHY_CTRL_SW_RESET); +	} else { +		/* pull high */ +		hdmi_write(hdmi, REG_HDMI_PHY_CTRL, +				val | HDMI_PHY_CTRL_SW_RESET); +	} + +	msleep(100); + +	if (val & HDMI_PHY_CTRL_SW_RESET_LOW) { +		/* pull high */ +		hdmi_write(hdmi, REG_HDMI_PHY_CTRL, +				val | HDMI_PHY_CTRL_SW_RESET); +	} else { +		/* pull low */ +		hdmi_write(hdmi, REG_HDMI_PHY_CTRL, +				val & ~HDMI_PHY_CTRL_SW_RESET); +	} +} + +static void hdmi_phy_8x60_powerup(struct hdmi_phy *phy, +		unsigned long int pixclock) +{ +	struct hdmi_phy_8x60 *phy_8x60 = to_hdmi_phy_8x60(phy); +	struct hdmi *hdmi = phy_8x60->hdmi; + +	/* De-serializer delay D/C for non-lbk mode: */ +	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG0, +			HDMI_8x60_PHY_REG0_DESER_DEL_CTRL(3)); + +	if (pixclock == 27000000) { +		/* video_format == HDMI_VFRMT_720x480p60_16_9 */ +		hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG1, +				HDMI_8x60_PHY_REG1_DTEST_MUX_SEL(5) | +				HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL(3)); +	} else { +		hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG1, +				HDMI_8x60_PHY_REG1_DTEST_MUX_SEL(5) | +				HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL(4)); +	} + +	/* No matter what, start from the power down mode: */ +	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG2, +			HDMI_8x60_PHY_REG2_PD_PWRGEN | +			HDMI_8x60_PHY_REG2_PD_PLL | +			HDMI_8x60_PHY_REG2_PD_DRIVE_4 | +			HDMI_8x60_PHY_REG2_PD_DRIVE_3 | +			HDMI_8x60_PHY_REG2_PD_DRIVE_2 | +			HDMI_8x60_PHY_REG2_PD_DRIVE_1 | +			HDMI_8x60_PHY_REG2_PD_DESER); + +	/* Turn PowerGen on: */ +	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG2, +			HDMI_8x60_PHY_REG2_PD_PLL | +			HDMI_8x60_PHY_REG2_PD_DRIVE_4 | +			HDMI_8x60_PHY_REG2_PD_DRIVE_3 | +			HDMI_8x60_PHY_REG2_PD_DRIVE_2 | +			HDMI_8x60_PHY_REG2_PD_DRIVE_1 | +			HDMI_8x60_PHY_REG2_PD_DESER); + +	/* Turn PLL power on: */ +	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG2, +			HDMI_8x60_PHY_REG2_PD_DRIVE_4 | +			HDMI_8x60_PHY_REG2_PD_DRIVE_3 | +			HDMI_8x60_PHY_REG2_PD_DRIVE_2 | +			HDMI_8x60_PHY_REG2_PD_DRIVE_1 | +			HDMI_8x60_PHY_REG2_PD_DESER); + +	/* Write to HIGH after PLL power down de-assert: */ +	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG3, +			HDMI_8x60_PHY_REG3_PLL_ENABLE); + +	/* ASIC power on; PHY REG9 = 0 */ +	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG9, 0); + +	/* Enable PLL lock detect, PLL lock det will go high after lock +	 * Enable the re-time logic +	 */ +	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG12, +			HDMI_8x60_PHY_REG12_RETIMING_EN | +			HDMI_8x60_PHY_REG12_PLL_LOCK_DETECT_EN); + +	/* Drivers are on: */ +	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG2, +			HDMI_8x60_PHY_REG2_PD_DESER); + +	/* If the RX detector is needed: */ +	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG2, +			HDMI_8x60_PHY_REG2_RCV_SENSE_EN | +			HDMI_8x60_PHY_REG2_PD_DESER); + +	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG4, 0); +	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG5, 0); +	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG6, 0); +	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG7, 0); +	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG8, 0); +	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG9, 0); +	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG10, 0); +	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG11, 0); + +	/* If we want to use lock enable based on counting: */ +	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG12, +			HDMI_8x60_PHY_REG12_RETIMING_EN | +			HDMI_8x60_PHY_REG12_PLL_LOCK_DETECT_EN | +			HDMI_8x60_PHY_REG12_FORCE_LOCK); +} + +static void hdmi_phy_8x60_powerdown(struct hdmi_phy *phy) +{ +	struct hdmi_phy_8x60 *phy_8x60 = to_hdmi_phy_8x60(phy); +	struct hdmi *hdmi = phy_8x60->hdmi; + +	/* Assert RESET PHY from controller */ +	hdmi_write(hdmi, REG_HDMI_PHY_CTRL, +			HDMI_PHY_CTRL_SW_RESET); +	udelay(10); +	/* De-assert RESET PHY from controller */ +	hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 0); +	/* Turn off Driver */ +	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG2, +			HDMI_8x60_PHY_REG2_PD_DRIVE_4 | +			HDMI_8x60_PHY_REG2_PD_DRIVE_3 | +			HDMI_8x60_PHY_REG2_PD_DRIVE_2 | +			HDMI_8x60_PHY_REG2_PD_DRIVE_1 | +			HDMI_8x60_PHY_REG2_PD_DESER); +	udelay(10); +	/* Disable PLL */ +	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG3, 0); +	/* Power down PHY, but keep RX-sense: */ +	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG2, +			HDMI_8x60_PHY_REG2_RCV_SENSE_EN | +			HDMI_8x60_PHY_REG2_PD_PWRGEN | +			HDMI_8x60_PHY_REG2_PD_PLL | +			HDMI_8x60_PHY_REG2_PD_DRIVE_4 | +			HDMI_8x60_PHY_REG2_PD_DRIVE_3 | +			HDMI_8x60_PHY_REG2_PD_DRIVE_2 | +			HDMI_8x60_PHY_REG2_PD_DRIVE_1 | +			HDMI_8x60_PHY_REG2_PD_DESER); +} + +static const struct hdmi_phy_funcs hdmi_phy_8x60_funcs = { +		.destroy = hdmi_phy_8x60_destroy, +		.reset = hdmi_phy_8x60_reset, +		.powerup = hdmi_phy_8x60_powerup, +		.powerdown = hdmi_phy_8x60_powerdown, +}; + +struct hdmi_phy *hdmi_phy_8x60_init(struct hdmi *hdmi) +{ +	struct hdmi_phy_8x60 *phy_8x60; +	struct hdmi_phy *phy = NULL; +	int ret; + +	phy_8x60 = kzalloc(sizeof(*phy_8x60), GFP_KERNEL); +	if (!phy_8x60) { +		ret = -ENOMEM; +		goto fail; +	} + +	phy = &phy_8x60->base; + +	phy->funcs = &hdmi_phy_8x60_funcs; + +	phy_8x60->hdmi = hdmi; + +	return phy; + +fail: +	if (phy) +		hdmi_phy_8x60_destroy(phy); +	return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c new file mode 100644 index 00000000000..59fa6cdacb2 --- /dev/null +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include "hdmi.h" + +struct hdmi_phy_8x74 { +	struct hdmi_phy base; +	struct hdmi *hdmi; +	void __iomem *mmio; +}; +#define to_hdmi_phy_8x74(x) container_of(x, struct hdmi_phy_8x74, base) + + +static void phy_write(struct hdmi_phy_8x74 *phy, u32 reg, u32 data) +{ +	msm_writel(data, phy->mmio + reg); +} + +//static u32 phy_read(struct hdmi_phy_8x74 *phy, u32 reg) +//{ +//	return msm_readl(phy->mmio + reg); +//} + +static void hdmi_phy_8x74_destroy(struct hdmi_phy *phy) +{ +	struct hdmi_phy_8x74 *phy_8x74 = to_hdmi_phy_8x74(phy); +	kfree(phy_8x74); +} + +static void hdmi_phy_8x74_reset(struct hdmi_phy *phy) +{ +	struct hdmi_phy_8x74 *phy_8x74 = to_hdmi_phy_8x74(phy); +	struct hdmi *hdmi = phy_8x74->hdmi; +	unsigned int val; + +	/* NOTE that HDMI_PHY_CTL is in core mmio, not phy mmio: */ + +	val = hdmi_read(hdmi, REG_HDMI_PHY_CTRL); + +	if (val & HDMI_PHY_CTRL_SW_RESET_LOW) { +		/* pull low */ +		hdmi_write(hdmi, REG_HDMI_PHY_CTRL, +				val & ~HDMI_PHY_CTRL_SW_RESET); +	} else { +		/* pull high */ +		hdmi_write(hdmi, REG_HDMI_PHY_CTRL, +				val | HDMI_PHY_CTRL_SW_RESET); +	} + +	if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) { +		/* pull low */ +		hdmi_write(hdmi, REG_HDMI_PHY_CTRL, +				val & ~HDMI_PHY_CTRL_SW_RESET_PLL); +	} else { +		/* pull high */ +		hdmi_write(hdmi, REG_HDMI_PHY_CTRL, +				val | HDMI_PHY_CTRL_SW_RESET_PLL); +	} + +	msleep(100); + +	if (val & HDMI_PHY_CTRL_SW_RESET_LOW) { +		/* pull high */ +		hdmi_write(hdmi, REG_HDMI_PHY_CTRL, +				val | HDMI_PHY_CTRL_SW_RESET); +	} else { +		/* pull low */ +		hdmi_write(hdmi, REG_HDMI_PHY_CTRL, +				val & ~HDMI_PHY_CTRL_SW_RESET); +	} + +	if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) { +		/* pull high */ +		hdmi_write(hdmi, REG_HDMI_PHY_CTRL, +				val | HDMI_PHY_CTRL_SW_RESET_PLL); +	} else { +		/* pull low */ +		hdmi_write(hdmi, REG_HDMI_PHY_CTRL, +				val & ~HDMI_PHY_CTRL_SW_RESET_PLL); +	} +} + +static void hdmi_phy_8x74_powerup(struct hdmi_phy *phy, +		unsigned long int pixclock) +{ +	struct hdmi_phy_8x74 *phy_8x74 = to_hdmi_phy_8x74(phy); + +	phy_write(phy_8x74, REG_HDMI_8x74_ANA_CFG0,   0x1b); +	phy_write(phy_8x74, REG_HDMI_8x74_ANA_CFG1,   0xf2); +	phy_write(phy_8x74, REG_HDMI_8x74_BIST_CFG0,  0x0); +	phy_write(phy_8x74, REG_HDMI_8x74_BIST_PATN0, 0x0); +	phy_write(phy_8x74, REG_HDMI_8x74_BIST_PATN1, 0x0); +	phy_write(phy_8x74, REG_HDMI_8x74_BIST_PATN2, 0x0); +	phy_write(phy_8x74, REG_HDMI_8x74_BIST_PATN3, 0x0); +	phy_write(phy_8x74, REG_HDMI_8x74_PD_CTRL1,   0x20); +} + +static void hdmi_phy_8x74_powerdown(struct hdmi_phy *phy) +{ +	struct hdmi_phy_8x74 *phy_8x74 = to_hdmi_phy_8x74(phy); +	phy_write(phy_8x74, REG_HDMI_8x74_PD_CTRL0, 0x7f); +} + +static const struct hdmi_phy_funcs hdmi_phy_8x74_funcs = { +		.destroy = hdmi_phy_8x74_destroy, +		.reset = hdmi_phy_8x74_reset, +		.powerup = hdmi_phy_8x74_powerup, +		.powerdown = hdmi_phy_8x74_powerdown, +}; + +struct hdmi_phy *hdmi_phy_8x74_init(struct hdmi *hdmi) +{ +	struct hdmi_phy_8x74 *phy_8x74; +	struct hdmi_phy *phy = NULL; +	int ret; + +	phy_8x74 = kzalloc(sizeof(*phy_8x74), GFP_KERNEL); +	if (!phy_8x74) { +		ret = -ENOMEM; +		goto fail; +	} + +	phy = &phy_8x74->base; + +	phy->funcs = &hdmi_phy_8x74_funcs; + +	phy_8x74->hdmi = hdmi; + +	/* for 8x74, the phy mmio is mapped separately: */ +	phy_8x74->mmio = msm_ioremap(hdmi->pdev, +			"phy_physical", "HDMI_8x74"); +	if (IS_ERR(phy_8x74->mmio)) { +		ret = PTR_ERR(phy_8x74->mmio); +		goto fail; +	} + +	return phy; + +fail: +	if (phy) +		hdmi_phy_8x74_destroy(phy); +	return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/msm/hdmi/qfprom.xml.h b/drivers/gpu/drm/msm/hdmi/qfprom.xml.h new file mode 100644 index 00000000000..d591567173c --- /dev/null +++ b/drivers/gpu/drm/msm/hdmi/qfprom.xml.h @@ -0,0 +1,52 @@ +#ifndef QFPROM_XML +#define QFPROM_XML + +/* Autogenerated file, DO NOT EDIT manually! + +This file was generated by the rules-ng-ng headergen tool in this git repository: +http://github.com/freedreno/envytools/ +git clone https://github.com/freedreno/envytools.git + +The rules-ng-ng source files this header was generated from are: +- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    647 bytes, from 2013-11-30 14:45:35) +- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  17996 bytes, from 2013-12-01 19:10:31) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2013-11-30 15:00:52) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2013-12-03 20:59:13) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  20932 bytes, from 2013-12-01 15:13:04) + +Copyright (C) 2013 by the following authors: +- Rob Clark <robdclark@gmail.com> (robclark) + +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 THE COPYRIGHT OWNER(S) 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. +*/ + + +#define REG_QFPROM_CONFIG_ROW0_LSB				0x00000238 +#define QFPROM_CONFIG_ROW0_LSB_HDMI_DISABLE			0x00200000 +#define QFPROM_CONFIG_ROW0_LSB_HDCP_DISABLE			0x00400000 + + +#endif /* QFPROM_XML */ diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h new file mode 100644 index 00000000000..416a26e1e58 --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h @@ -0,0 +1,1033 @@ +#ifndef MDP4_XML +#define MDP4_XML + +/* Autogenerated file, DO NOT EDIT manually! + +This file was generated by the rules-ng-ng headergen tool in this git repository: +http://github.com/freedreno/envytools/ +git clone https://github.com/freedreno/envytools.git + +The rules-ng-ng source files this header was generated from are: +- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    647 bytes, from 2013-11-30 14:45:35) +- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  17996 bytes, from 2013-12-01 19:10:31) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2013-11-30 15:00:52) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2013-12-03 20:59:13) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  20932 bytes, from 2013-12-01 15:13:04) + +Copyright (C) 2013 by the following authors: +- Rob Clark <robdclark@gmail.com> (robclark) + +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 THE COPYRIGHT OWNER(S) 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. +*/ + + +enum mdp4_pipe { +	VG1 = 0, +	VG2 = 1, +	RGB1 = 2, +	RGB2 = 3, +	RGB3 = 4, +	VG3 = 5, +	VG4 = 6, +}; + +enum mdp4_mixer { +	MIXER0 = 0, +	MIXER1 = 1, +	MIXER2 = 2, +}; + +enum mdp4_intf { +	INTF_LCDC_DTV = 0, +	INTF_DSI_VIDEO = 1, +	INTF_DSI_CMD = 2, +	INTF_EBI2_TV = 3, +}; + +enum mdp4_cursor_format { +	CURSOR_ARGB = 1, +	CURSOR_XRGB = 2, +}; + +enum mdp4_dma { +	DMA_P = 0, +	DMA_S = 1, +	DMA_E = 2, +}; + +#define MDP4_IRQ_OVERLAY0_DONE					0x00000001 +#define MDP4_IRQ_OVERLAY1_DONE					0x00000002 +#define MDP4_IRQ_DMA_S_DONE					0x00000004 +#define MDP4_IRQ_DMA_E_DONE					0x00000008 +#define MDP4_IRQ_DMA_P_DONE					0x00000010 +#define MDP4_IRQ_VG1_HISTOGRAM					0x00000020 +#define MDP4_IRQ_VG2_HISTOGRAM					0x00000040 +#define MDP4_IRQ_PRIMARY_VSYNC					0x00000080 +#define MDP4_IRQ_PRIMARY_INTF_UDERRUN				0x00000100 +#define MDP4_IRQ_EXTERNAL_VSYNC					0x00000200 +#define MDP4_IRQ_EXTERNAL_INTF_UDERRUN				0x00000400 +#define MDP4_IRQ_PRIMARY_RDPTR					0x00000800 +#define MDP4_IRQ_DMA_P_HISTOGRAM				0x00020000 +#define MDP4_IRQ_DMA_S_HISTOGRAM				0x04000000 +#define MDP4_IRQ_OVERLAY2_DONE					0x40000000 +#define REG_MDP4_VERSION					0x00000000 +#define MDP4_VERSION_MINOR__MASK				0x00ff0000 +#define MDP4_VERSION_MINOR__SHIFT				16 +static inline uint32_t MDP4_VERSION_MINOR(uint32_t val) +{ +	return ((val) << MDP4_VERSION_MINOR__SHIFT) & MDP4_VERSION_MINOR__MASK; +} +#define MDP4_VERSION_MAJOR__MASK				0xff000000 +#define MDP4_VERSION_MAJOR__SHIFT				24 +static inline uint32_t MDP4_VERSION_MAJOR(uint32_t val) +{ +	return ((val) << MDP4_VERSION_MAJOR__SHIFT) & MDP4_VERSION_MAJOR__MASK; +} + +#define REG_MDP4_OVLP0_KICK					0x00000004 + +#define REG_MDP4_OVLP1_KICK					0x00000008 + +#define REG_MDP4_OVLP2_KICK					0x000000d0 + +#define REG_MDP4_DMA_P_KICK					0x0000000c + +#define REG_MDP4_DMA_S_KICK					0x00000010 + +#define REG_MDP4_DMA_E_KICK					0x00000014 + +#define REG_MDP4_DISP_STATUS					0x00000018 + +#define REG_MDP4_DISP_INTF_SEL					0x00000038 +#define MDP4_DISP_INTF_SEL_PRIM__MASK				0x00000003 +#define MDP4_DISP_INTF_SEL_PRIM__SHIFT				0 +static inline uint32_t MDP4_DISP_INTF_SEL_PRIM(enum mdp4_intf val) +{ +	return ((val) << MDP4_DISP_INTF_SEL_PRIM__SHIFT) & MDP4_DISP_INTF_SEL_PRIM__MASK; +} +#define MDP4_DISP_INTF_SEL_SEC__MASK				0x0000000c +#define MDP4_DISP_INTF_SEL_SEC__SHIFT				2 +static inline uint32_t MDP4_DISP_INTF_SEL_SEC(enum mdp4_intf val) +{ +	return ((val) << MDP4_DISP_INTF_SEL_SEC__SHIFT) & MDP4_DISP_INTF_SEL_SEC__MASK; +} +#define MDP4_DISP_INTF_SEL_EXT__MASK				0x00000030 +#define MDP4_DISP_INTF_SEL_EXT__SHIFT				4 +static inline uint32_t MDP4_DISP_INTF_SEL_EXT(enum mdp4_intf val) +{ +	return ((val) << MDP4_DISP_INTF_SEL_EXT__SHIFT) & MDP4_DISP_INTF_SEL_EXT__MASK; +} +#define MDP4_DISP_INTF_SEL_DSI_VIDEO				0x00000040 +#define MDP4_DISP_INTF_SEL_DSI_CMD				0x00000080 + +#define REG_MDP4_RESET_STATUS					0x0000003c + +#define REG_MDP4_READ_CNFG					0x0000004c + +#define REG_MDP4_INTR_ENABLE					0x00000050 + +#define REG_MDP4_INTR_STATUS					0x00000054 + +#define REG_MDP4_INTR_CLEAR					0x00000058 + +#define REG_MDP4_EBI2_LCD0					0x00000060 + +#define REG_MDP4_EBI2_LCD1					0x00000064 + +#define REG_MDP4_PORTMAP_MODE					0x00000070 + +#define REG_MDP4_CS_CONTROLLER0					0x000000c0 + +#define REG_MDP4_CS_CONTROLLER1					0x000000c4 + +#define REG_MDP4_LAYERMIXER2_IN_CFG				0x000100f0 +#define MDP4_LAYERMIXER2_IN_CFG_PIPE0__MASK			0x00000007 +#define MDP4_LAYERMIXER2_IN_CFG_PIPE0__SHIFT			0 +static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE0(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE0__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE0__MASK; +} +#define MDP4_LAYERMIXER2_IN_CFG_PIPE0_MIXER1			0x00000008 +#define MDP4_LAYERMIXER2_IN_CFG_PIPE1__MASK			0x00000070 +#define MDP4_LAYERMIXER2_IN_CFG_PIPE1__SHIFT			4 +static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE1(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE1__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE1__MASK; +} +#define MDP4_LAYERMIXER2_IN_CFG_PIPE1_MIXER1			0x00000080 +#define MDP4_LAYERMIXER2_IN_CFG_PIPE2__MASK			0x00000700 +#define MDP4_LAYERMIXER2_IN_CFG_PIPE2__SHIFT			8 +static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE2(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE2__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE2__MASK; +} +#define MDP4_LAYERMIXER2_IN_CFG_PIPE2_MIXER1			0x00000800 +#define MDP4_LAYERMIXER2_IN_CFG_PIPE3__MASK			0x00007000 +#define MDP4_LAYERMIXER2_IN_CFG_PIPE3__SHIFT			12 +static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE3(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE3__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE3__MASK; +} +#define MDP4_LAYERMIXER2_IN_CFG_PIPE3_MIXER1			0x00008000 +#define MDP4_LAYERMIXER2_IN_CFG_PIPE4__MASK			0x00070000 +#define MDP4_LAYERMIXER2_IN_CFG_PIPE4__SHIFT			16 +static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE4(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE4__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE4__MASK; +} +#define MDP4_LAYERMIXER2_IN_CFG_PIPE4_MIXER1			0x00080000 +#define MDP4_LAYERMIXER2_IN_CFG_PIPE5__MASK			0x00700000 +#define MDP4_LAYERMIXER2_IN_CFG_PIPE5__SHIFT			20 +static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE5(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE5__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE5__MASK; +} +#define MDP4_LAYERMIXER2_IN_CFG_PIPE5_MIXER1			0x00800000 +#define MDP4_LAYERMIXER2_IN_CFG_PIPE6__MASK			0x07000000 +#define MDP4_LAYERMIXER2_IN_CFG_PIPE6__SHIFT			24 +static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE6(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE6__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE6__MASK; +} +#define MDP4_LAYERMIXER2_IN_CFG_PIPE6_MIXER1			0x08000000 +#define MDP4_LAYERMIXER2_IN_CFG_PIPE7__MASK			0x70000000 +#define MDP4_LAYERMIXER2_IN_CFG_PIPE7__SHIFT			28 +static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE7(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE7__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE7__MASK; +} +#define MDP4_LAYERMIXER2_IN_CFG_PIPE7_MIXER1			0x80000000 + +#define REG_MDP4_LAYERMIXER_IN_CFG_UPDATE_METHOD		0x000100fc + +#define REG_MDP4_LAYERMIXER_IN_CFG				0x00010100 +#define MDP4_LAYERMIXER_IN_CFG_PIPE0__MASK			0x00000007 +#define MDP4_LAYERMIXER_IN_CFG_PIPE0__SHIFT			0 +static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE0(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE0__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE0__MASK; +} +#define MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1			0x00000008 +#define MDP4_LAYERMIXER_IN_CFG_PIPE1__MASK			0x00000070 +#define MDP4_LAYERMIXER_IN_CFG_PIPE1__SHIFT			4 +static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE1(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE1__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE1__MASK; +} +#define MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1			0x00000080 +#define MDP4_LAYERMIXER_IN_CFG_PIPE2__MASK			0x00000700 +#define MDP4_LAYERMIXER_IN_CFG_PIPE2__SHIFT			8 +static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE2(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE2__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE2__MASK; +} +#define MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1			0x00000800 +#define MDP4_LAYERMIXER_IN_CFG_PIPE3__MASK			0x00007000 +#define MDP4_LAYERMIXER_IN_CFG_PIPE3__SHIFT			12 +static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE3(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE3__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE3__MASK; +} +#define MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1			0x00008000 +#define MDP4_LAYERMIXER_IN_CFG_PIPE4__MASK			0x00070000 +#define MDP4_LAYERMIXER_IN_CFG_PIPE4__SHIFT			16 +static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE4(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE4__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE4__MASK; +} +#define MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1			0x00080000 +#define MDP4_LAYERMIXER_IN_CFG_PIPE5__MASK			0x00700000 +#define MDP4_LAYERMIXER_IN_CFG_PIPE5__SHIFT			20 +static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE5(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE5__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE5__MASK; +} +#define MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1			0x00800000 +#define MDP4_LAYERMIXER_IN_CFG_PIPE6__MASK			0x07000000 +#define MDP4_LAYERMIXER_IN_CFG_PIPE6__SHIFT			24 +static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE6(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE6__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE6__MASK; +} +#define MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1			0x08000000 +#define MDP4_LAYERMIXER_IN_CFG_PIPE7__MASK			0x70000000 +#define MDP4_LAYERMIXER_IN_CFG_PIPE7__SHIFT			28 +static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE7(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE7__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE7__MASK; +} +#define MDP4_LAYERMIXER_IN_CFG_PIPE7_MIXER1			0x80000000 + +#define REG_MDP4_VG2_SRC_FORMAT					0x00030050 + +#define REG_MDP4_VG2_CONST_COLOR				0x00031008 + +#define REG_MDP4_OVERLAY_FLUSH					0x00018000 +#define MDP4_OVERLAY_FLUSH_OVLP0				0x00000001 +#define MDP4_OVERLAY_FLUSH_OVLP1				0x00000002 +#define MDP4_OVERLAY_FLUSH_VG1					0x00000004 +#define MDP4_OVERLAY_FLUSH_VG2					0x00000008 +#define MDP4_OVERLAY_FLUSH_RGB1					0x00000010 +#define MDP4_OVERLAY_FLUSH_RGB2					0x00000020 + +static inline uint32_t __offset_OVLP(uint32_t idx) +{ +	switch (idx) { +		case 0: return 0x00010000; +		case 1: return 0x00018000; +		case 2: return 0x00088000; +		default: return INVALID_IDX(idx); +	} +} +static inline uint32_t REG_MDP4_OVLP(uint32_t i0) { return 0x00000000 + __offset_OVLP(i0); } + +static inline uint32_t REG_MDP4_OVLP_CFG(uint32_t i0) { return 0x00000004 + __offset_OVLP(i0); } + +static inline uint32_t REG_MDP4_OVLP_SIZE(uint32_t i0) { return 0x00000008 + __offset_OVLP(i0); } +#define MDP4_OVLP_SIZE_HEIGHT__MASK				0xffff0000 +#define MDP4_OVLP_SIZE_HEIGHT__SHIFT				16 +static inline uint32_t MDP4_OVLP_SIZE_HEIGHT(uint32_t val) +{ +	return ((val) << MDP4_OVLP_SIZE_HEIGHT__SHIFT) & MDP4_OVLP_SIZE_HEIGHT__MASK; +} +#define MDP4_OVLP_SIZE_WIDTH__MASK				0x0000ffff +#define MDP4_OVLP_SIZE_WIDTH__SHIFT				0 +static inline uint32_t MDP4_OVLP_SIZE_WIDTH(uint32_t val) +{ +	return ((val) << MDP4_OVLP_SIZE_WIDTH__SHIFT) & MDP4_OVLP_SIZE_WIDTH__MASK; +} + +static inline uint32_t REG_MDP4_OVLP_BASE(uint32_t i0) { return 0x0000000c + __offset_OVLP(i0); } + +static inline uint32_t REG_MDP4_OVLP_STRIDE(uint32_t i0) { return 0x00000010 + __offset_OVLP(i0); } + +static inline uint32_t REG_MDP4_OVLP_OPMODE(uint32_t i0) { return 0x00000014 + __offset_OVLP(i0); } + +static inline uint32_t __offset_STAGE(uint32_t idx) +{ +	switch (idx) { +		case 0: return 0x00000104; +		case 1: return 0x00000124; +		case 2: return 0x00000144; +		case 3: return 0x00000160; +		default: return INVALID_IDX(idx); +	} +} +static inline uint32_t REG_MDP4_OVLP_STAGE(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_OVLP(i0) + __offset_STAGE(i1); } + +static inline uint32_t REG_MDP4_OVLP_STAGE_OP(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_OVLP(i0) + __offset_STAGE(i1); } +#define MDP4_OVLP_STAGE_OP_FG_ALPHA__MASK			0x00000003 +#define MDP4_OVLP_STAGE_OP_FG_ALPHA__SHIFT			0 +static inline uint32_t MDP4_OVLP_STAGE_OP_FG_ALPHA(enum mdp_alpha_type val) +{ +	return ((val) << MDP4_OVLP_STAGE_OP_FG_ALPHA__SHIFT) & MDP4_OVLP_STAGE_OP_FG_ALPHA__MASK; +} +#define MDP4_OVLP_STAGE_OP_FG_INV_ALPHA				0x00000004 +#define MDP4_OVLP_STAGE_OP_FG_MOD_ALPHA				0x00000008 +#define MDP4_OVLP_STAGE_OP_BG_ALPHA__MASK			0x00000030 +#define MDP4_OVLP_STAGE_OP_BG_ALPHA__SHIFT			4 +static inline uint32_t MDP4_OVLP_STAGE_OP_BG_ALPHA(enum mdp_alpha_type val) +{ +	return ((val) << MDP4_OVLP_STAGE_OP_BG_ALPHA__SHIFT) & MDP4_OVLP_STAGE_OP_BG_ALPHA__MASK; +} +#define MDP4_OVLP_STAGE_OP_BG_INV_ALPHA				0x00000040 +#define MDP4_OVLP_STAGE_OP_BG_MOD_ALPHA				0x00000080 +#define MDP4_OVLP_STAGE_OP_FG_TRANSP				0x00000100 +#define MDP4_OVLP_STAGE_OP_BG_TRANSP				0x00000200 + +static inline uint32_t REG_MDP4_OVLP_STAGE_FG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00000004 + __offset_OVLP(i0) + __offset_STAGE(i1); } + +static inline uint32_t REG_MDP4_OVLP_STAGE_BG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00000008 + __offset_OVLP(i0) + __offset_STAGE(i1); } + +static inline uint32_t REG_MDP4_OVLP_STAGE_TRANSP_LOW0(uint32_t i0, uint32_t i1) { return 0x0000000c + __offset_OVLP(i0) + __offset_STAGE(i1); } + +static inline uint32_t REG_MDP4_OVLP_STAGE_TRANSP_LOW1(uint32_t i0, uint32_t i1) { return 0x00000010 + __offset_OVLP(i0) + __offset_STAGE(i1); } + +static inline uint32_t REG_MDP4_OVLP_STAGE_TRANSP_HIGH0(uint32_t i0, uint32_t i1) { return 0x00000014 + __offset_OVLP(i0) + __offset_STAGE(i1); } + +static inline uint32_t REG_MDP4_OVLP_STAGE_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00000018 + __offset_OVLP(i0) + __offset_STAGE(i1); } + +static inline uint32_t __offset_STAGE_CO3(uint32_t idx) +{ +	switch (idx) { +		case 0: return 0x00001004; +		case 1: return 0x00001404; +		case 2: return 0x00001804; +		case 3: return 0x00001b84; +		default: return INVALID_IDX(idx); +	} +} +static inline uint32_t REG_MDP4_OVLP_STAGE_CO3(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_OVLP(i0) + __offset_STAGE_CO3(i1); } + +static inline uint32_t REG_MDP4_OVLP_STAGE_CO3_SEL(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_OVLP(i0) + __offset_STAGE_CO3(i1); } +#define MDP4_OVLP_STAGE_CO3_SEL_FG_ALPHA			0x00000001 + +static inline uint32_t REG_MDP4_OVLP_TRANSP_LOW0(uint32_t i0) { return 0x00000180 + __offset_OVLP(i0); } + +static inline uint32_t REG_MDP4_OVLP_TRANSP_LOW1(uint32_t i0) { return 0x00000184 + __offset_OVLP(i0); } + +static inline uint32_t REG_MDP4_OVLP_TRANSP_HIGH0(uint32_t i0) { return 0x00000188 + __offset_OVLP(i0); } + +static inline uint32_t REG_MDP4_OVLP_TRANSP_HIGH1(uint32_t i0) { return 0x0000018c + __offset_OVLP(i0); } + +static inline uint32_t REG_MDP4_OVLP_CSC_CONFIG(uint32_t i0) { return 0x00000200 + __offset_OVLP(i0); } + +static inline uint32_t REG_MDP4_OVLP_CSC(uint32_t i0) { return 0x00002000 + __offset_OVLP(i0); } + + +static inline uint32_t REG_MDP4_OVLP_CSC_MV(uint32_t i0, uint32_t i1) { return 0x00002400 + __offset_OVLP(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP4_OVLP_CSC_MV_VAL(uint32_t i0, uint32_t i1) { return 0x00002400 + __offset_OVLP(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP4_OVLP_CSC_PRE_BV(uint32_t i0, uint32_t i1) { return 0x00002500 + __offset_OVLP(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP4_OVLP_CSC_PRE_BV_VAL(uint32_t i0, uint32_t i1) { return 0x00002500 + __offset_OVLP(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP4_OVLP_CSC_POST_BV(uint32_t i0, uint32_t i1) { return 0x00002580 + __offset_OVLP(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP4_OVLP_CSC_POST_BV_VAL(uint32_t i0, uint32_t i1) { return 0x00002580 + __offset_OVLP(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP4_OVLP_CSC_PRE_LV(uint32_t i0, uint32_t i1) { return 0x00002600 + __offset_OVLP(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP4_OVLP_CSC_PRE_LV_VAL(uint32_t i0, uint32_t i1) { return 0x00002600 + __offset_OVLP(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP4_OVLP_CSC_POST_LV(uint32_t i0, uint32_t i1) { return 0x00002680 + __offset_OVLP(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP4_OVLP_CSC_POST_LV_VAL(uint32_t i0, uint32_t i1) { return 0x00002680 + __offset_OVLP(i0) + 0x4*i1; } + +#define REG_MDP4_DMA_P_OP_MODE					0x00090070 + +static inline uint32_t REG_MDP4_LUTN(uint32_t i0) { return 0x00094800 + 0x400*i0; } + +static inline uint32_t REG_MDP4_LUTN_LUT(uint32_t i0, uint32_t i1) { return 0x00094800 + 0x400*i0 + 0x4*i1; } + +static inline uint32_t REG_MDP4_LUTN_LUT_VAL(uint32_t i0, uint32_t i1) { return 0x00094800 + 0x400*i0 + 0x4*i1; } + +#define REG_MDP4_DMA_S_OP_MODE					0x000a0028 + +static inline uint32_t REG_MDP4_DMA_E_QUANT(uint32_t i0) { return 0x000b0070 + 0x4*i0; } + +static inline uint32_t __offset_DMA(enum mdp4_dma idx) +{ +	switch (idx) { +		case DMA_P: return 0x00090000; +		case DMA_S: return 0x000a0000; +		case DMA_E: return 0x000b0000; +		default: return INVALID_IDX(idx); +	} +} +static inline uint32_t REG_MDP4_DMA(enum mdp4_dma i0) { return 0x00000000 + __offset_DMA(i0); } + +static inline uint32_t REG_MDP4_DMA_CONFIG(enum mdp4_dma i0) { return 0x00000000 + __offset_DMA(i0); } +#define MDP4_DMA_CONFIG_G_BPC__MASK				0x00000003 +#define MDP4_DMA_CONFIG_G_BPC__SHIFT				0 +static inline uint32_t MDP4_DMA_CONFIG_G_BPC(enum mdp_bpc val) +{ +	return ((val) << MDP4_DMA_CONFIG_G_BPC__SHIFT) & MDP4_DMA_CONFIG_G_BPC__MASK; +} +#define MDP4_DMA_CONFIG_B_BPC__MASK				0x0000000c +#define MDP4_DMA_CONFIG_B_BPC__SHIFT				2 +static inline uint32_t MDP4_DMA_CONFIG_B_BPC(enum mdp_bpc val) +{ +	return ((val) << MDP4_DMA_CONFIG_B_BPC__SHIFT) & MDP4_DMA_CONFIG_B_BPC__MASK; +} +#define MDP4_DMA_CONFIG_R_BPC__MASK				0x00000030 +#define MDP4_DMA_CONFIG_R_BPC__SHIFT				4 +static inline uint32_t MDP4_DMA_CONFIG_R_BPC(enum mdp_bpc val) +{ +	return ((val) << MDP4_DMA_CONFIG_R_BPC__SHIFT) & MDP4_DMA_CONFIG_R_BPC__MASK; +} +#define MDP4_DMA_CONFIG_PACK_ALIGN_MSB				0x00000080 +#define MDP4_DMA_CONFIG_PACK__MASK				0x0000ff00 +#define MDP4_DMA_CONFIG_PACK__SHIFT				8 +static inline uint32_t MDP4_DMA_CONFIG_PACK(uint32_t val) +{ +	return ((val) << MDP4_DMA_CONFIG_PACK__SHIFT) & MDP4_DMA_CONFIG_PACK__MASK; +} +#define MDP4_DMA_CONFIG_DEFLKR_EN				0x01000000 +#define MDP4_DMA_CONFIG_DITHER_EN				0x01000000 + +static inline uint32_t REG_MDP4_DMA_SRC_SIZE(enum mdp4_dma i0) { return 0x00000004 + __offset_DMA(i0); } +#define MDP4_DMA_SRC_SIZE_HEIGHT__MASK				0xffff0000 +#define MDP4_DMA_SRC_SIZE_HEIGHT__SHIFT				16 +static inline uint32_t MDP4_DMA_SRC_SIZE_HEIGHT(uint32_t val) +{ +	return ((val) << MDP4_DMA_SRC_SIZE_HEIGHT__SHIFT) & MDP4_DMA_SRC_SIZE_HEIGHT__MASK; +} +#define MDP4_DMA_SRC_SIZE_WIDTH__MASK				0x0000ffff +#define MDP4_DMA_SRC_SIZE_WIDTH__SHIFT				0 +static inline uint32_t MDP4_DMA_SRC_SIZE_WIDTH(uint32_t val) +{ +	return ((val) << MDP4_DMA_SRC_SIZE_WIDTH__SHIFT) & MDP4_DMA_SRC_SIZE_WIDTH__MASK; +} + +static inline uint32_t REG_MDP4_DMA_SRC_BASE(enum mdp4_dma i0) { return 0x00000008 + __offset_DMA(i0); } + +static inline uint32_t REG_MDP4_DMA_SRC_STRIDE(enum mdp4_dma i0) { return 0x0000000c + __offset_DMA(i0); } + +static inline uint32_t REG_MDP4_DMA_DST_SIZE(enum mdp4_dma i0) { return 0x00000010 + __offset_DMA(i0); } +#define MDP4_DMA_DST_SIZE_HEIGHT__MASK				0xffff0000 +#define MDP4_DMA_DST_SIZE_HEIGHT__SHIFT				16 +static inline uint32_t MDP4_DMA_DST_SIZE_HEIGHT(uint32_t val) +{ +	return ((val) << MDP4_DMA_DST_SIZE_HEIGHT__SHIFT) & MDP4_DMA_DST_SIZE_HEIGHT__MASK; +} +#define MDP4_DMA_DST_SIZE_WIDTH__MASK				0x0000ffff +#define MDP4_DMA_DST_SIZE_WIDTH__SHIFT				0 +static inline uint32_t MDP4_DMA_DST_SIZE_WIDTH(uint32_t val) +{ +	return ((val) << MDP4_DMA_DST_SIZE_WIDTH__SHIFT) & MDP4_DMA_DST_SIZE_WIDTH__MASK; +} + +static inline uint32_t REG_MDP4_DMA_CURSOR_SIZE(enum mdp4_dma i0) { return 0x00000044 + __offset_DMA(i0); } +#define MDP4_DMA_CURSOR_SIZE_WIDTH__MASK			0x0000007f +#define MDP4_DMA_CURSOR_SIZE_WIDTH__SHIFT			0 +static inline uint32_t MDP4_DMA_CURSOR_SIZE_WIDTH(uint32_t val) +{ +	return ((val) << MDP4_DMA_CURSOR_SIZE_WIDTH__SHIFT) & MDP4_DMA_CURSOR_SIZE_WIDTH__MASK; +} +#define MDP4_DMA_CURSOR_SIZE_HEIGHT__MASK			0x007f0000 +#define MDP4_DMA_CURSOR_SIZE_HEIGHT__SHIFT			16 +static inline uint32_t MDP4_DMA_CURSOR_SIZE_HEIGHT(uint32_t val) +{ +	return ((val) << MDP4_DMA_CURSOR_SIZE_HEIGHT__SHIFT) & MDP4_DMA_CURSOR_SIZE_HEIGHT__MASK; +} + +static inline uint32_t REG_MDP4_DMA_CURSOR_BASE(enum mdp4_dma i0) { return 0x00000048 + __offset_DMA(i0); } + +static inline uint32_t REG_MDP4_DMA_CURSOR_POS(enum mdp4_dma i0) { return 0x0000004c + __offset_DMA(i0); } +#define MDP4_DMA_CURSOR_POS_X__MASK				0x0000ffff +#define MDP4_DMA_CURSOR_POS_X__SHIFT				0 +static inline uint32_t MDP4_DMA_CURSOR_POS_X(uint32_t val) +{ +	return ((val) << MDP4_DMA_CURSOR_POS_X__SHIFT) & MDP4_DMA_CURSOR_POS_X__MASK; +} +#define MDP4_DMA_CURSOR_POS_Y__MASK				0xffff0000 +#define MDP4_DMA_CURSOR_POS_Y__SHIFT				16 +static inline uint32_t MDP4_DMA_CURSOR_POS_Y(uint32_t val) +{ +	return ((val) << MDP4_DMA_CURSOR_POS_Y__SHIFT) & MDP4_DMA_CURSOR_POS_Y__MASK; +} + +static inline uint32_t REG_MDP4_DMA_CURSOR_BLEND_CONFIG(enum mdp4_dma i0) { return 0x00000060 + __offset_DMA(i0); } +#define MDP4_DMA_CURSOR_BLEND_CONFIG_CURSOR_EN			0x00000001 +#define MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT__MASK		0x00000006 +#define MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT__SHIFT		1 +static inline uint32_t MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT(enum mdp4_cursor_format val) +{ +	return ((val) << MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT__SHIFT) & MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT__MASK; +} +#define MDP4_DMA_CURSOR_BLEND_CONFIG_TRANSP_EN			0x00000008 + +static inline uint32_t REG_MDP4_DMA_CURSOR_BLEND_PARAM(enum mdp4_dma i0) { return 0x00000064 + __offset_DMA(i0); } + +static inline uint32_t REG_MDP4_DMA_BLEND_TRANS_LOW(enum mdp4_dma i0) { return 0x00000068 + __offset_DMA(i0); } + +static inline uint32_t REG_MDP4_DMA_BLEND_TRANS_HIGH(enum mdp4_dma i0) { return 0x0000006c + __offset_DMA(i0); } + +static inline uint32_t REG_MDP4_DMA_FETCH_CONFIG(enum mdp4_dma i0) { return 0x00001004 + __offset_DMA(i0); } + +static inline uint32_t REG_MDP4_DMA_CSC(enum mdp4_dma i0) { return 0x00003000 + __offset_DMA(i0); } + + +static inline uint32_t REG_MDP4_DMA_CSC_MV(enum mdp4_dma i0, uint32_t i1) { return 0x00003400 + __offset_DMA(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP4_DMA_CSC_MV_VAL(enum mdp4_dma i0, uint32_t i1) { return 0x00003400 + __offset_DMA(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP4_DMA_CSC_PRE_BV(enum mdp4_dma i0, uint32_t i1) { return 0x00003500 + __offset_DMA(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP4_DMA_CSC_PRE_BV_VAL(enum mdp4_dma i0, uint32_t i1) { return 0x00003500 + __offset_DMA(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP4_DMA_CSC_POST_BV(enum mdp4_dma i0, uint32_t i1) { return 0x00003580 + __offset_DMA(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP4_DMA_CSC_POST_BV_VAL(enum mdp4_dma i0, uint32_t i1) { return 0x00003580 + __offset_DMA(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP4_DMA_CSC_PRE_LV(enum mdp4_dma i0, uint32_t i1) { return 0x00003600 + __offset_DMA(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP4_DMA_CSC_PRE_LV_VAL(enum mdp4_dma i0, uint32_t i1) { return 0x00003600 + __offset_DMA(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP4_DMA_CSC_POST_LV(enum mdp4_dma i0, uint32_t i1) { return 0x00003680 + __offset_DMA(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP4_DMA_CSC_POST_LV_VAL(enum mdp4_dma i0, uint32_t i1) { return 0x00003680 + __offset_DMA(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP4_PIPE(enum mdp4_pipe i0) { return 0x00020000 + 0x10000*i0; } + +static inline uint32_t REG_MDP4_PIPE_SRC_SIZE(enum mdp4_pipe i0) { return 0x00020000 + 0x10000*i0; } +#define MDP4_PIPE_SRC_SIZE_HEIGHT__MASK				0xffff0000 +#define MDP4_PIPE_SRC_SIZE_HEIGHT__SHIFT			16 +static inline uint32_t MDP4_PIPE_SRC_SIZE_HEIGHT(uint32_t val) +{ +	return ((val) << MDP4_PIPE_SRC_SIZE_HEIGHT__SHIFT) & MDP4_PIPE_SRC_SIZE_HEIGHT__MASK; +} +#define MDP4_PIPE_SRC_SIZE_WIDTH__MASK				0x0000ffff +#define MDP4_PIPE_SRC_SIZE_WIDTH__SHIFT				0 +static inline uint32_t MDP4_PIPE_SRC_SIZE_WIDTH(uint32_t val) +{ +	return ((val) << MDP4_PIPE_SRC_SIZE_WIDTH__SHIFT) & MDP4_PIPE_SRC_SIZE_WIDTH__MASK; +} + +static inline uint32_t REG_MDP4_PIPE_SRC_XY(enum mdp4_pipe i0) { return 0x00020004 + 0x10000*i0; } +#define MDP4_PIPE_SRC_XY_Y__MASK				0xffff0000 +#define MDP4_PIPE_SRC_XY_Y__SHIFT				16 +static inline uint32_t MDP4_PIPE_SRC_XY_Y(uint32_t val) +{ +	return ((val) << MDP4_PIPE_SRC_XY_Y__SHIFT) & MDP4_PIPE_SRC_XY_Y__MASK; +} +#define MDP4_PIPE_SRC_XY_X__MASK				0x0000ffff +#define MDP4_PIPE_SRC_XY_X__SHIFT				0 +static inline uint32_t MDP4_PIPE_SRC_XY_X(uint32_t val) +{ +	return ((val) << MDP4_PIPE_SRC_XY_X__SHIFT) & MDP4_PIPE_SRC_XY_X__MASK; +} + +static inline uint32_t REG_MDP4_PIPE_DST_SIZE(enum mdp4_pipe i0) { return 0x00020008 + 0x10000*i0; } +#define MDP4_PIPE_DST_SIZE_HEIGHT__MASK				0xffff0000 +#define MDP4_PIPE_DST_SIZE_HEIGHT__SHIFT			16 +static inline uint32_t MDP4_PIPE_DST_SIZE_HEIGHT(uint32_t val) +{ +	return ((val) << MDP4_PIPE_DST_SIZE_HEIGHT__SHIFT) & MDP4_PIPE_DST_SIZE_HEIGHT__MASK; +} +#define MDP4_PIPE_DST_SIZE_WIDTH__MASK				0x0000ffff +#define MDP4_PIPE_DST_SIZE_WIDTH__SHIFT				0 +static inline uint32_t MDP4_PIPE_DST_SIZE_WIDTH(uint32_t val) +{ +	return ((val) << MDP4_PIPE_DST_SIZE_WIDTH__SHIFT) & MDP4_PIPE_DST_SIZE_WIDTH__MASK; +} + +static inline uint32_t REG_MDP4_PIPE_DST_XY(enum mdp4_pipe i0) { return 0x0002000c + 0x10000*i0; } +#define MDP4_PIPE_DST_XY_Y__MASK				0xffff0000 +#define MDP4_PIPE_DST_XY_Y__SHIFT				16 +static inline uint32_t MDP4_PIPE_DST_XY_Y(uint32_t val) +{ +	return ((val) << MDP4_PIPE_DST_XY_Y__SHIFT) & MDP4_PIPE_DST_XY_Y__MASK; +} +#define MDP4_PIPE_DST_XY_X__MASK				0x0000ffff +#define MDP4_PIPE_DST_XY_X__SHIFT				0 +static inline uint32_t MDP4_PIPE_DST_XY_X(uint32_t val) +{ +	return ((val) << MDP4_PIPE_DST_XY_X__SHIFT) & MDP4_PIPE_DST_XY_X__MASK; +} + +static inline uint32_t REG_MDP4_PIPE_SRCP0_BASE(enum mdp4_pipe i0) { return 0x00020010 + 0x10000*i0; } + +static inline uint32_t REG_MDP4_PIPE_SRCP1_BASE(enum mdp4_pipe i0) { return 0x00020014 + 0x10000*i0; } + +static inline uint32_t REG_MDP4_PIPE_SRCP2_BASE(enum mdp4_pipe i0) { return 0x00020018 + 0x10000*i0; } + +static inline uint32_t REG_MDP4_PIPE_SRC_STRIDE_A(enum mdp4_pipe i0) { return 0x00020040 + 0x10000*i0; } +#define MDP4_PIPE_SRC_STRIDE_A_P0__MASK				0x0000ffff +#define MDP4_PIPE_SRC_STRIDE_A_P0__SHIFT			0 +static inline uint32_t MDP4_PIPE_SRC_STRIDE_A_P0(uint32_t val) +{ +	return ((val) << MDP4_PIPE_SRC_STRIDE_A_P0__SHIFT) & MDP4_PIPE_SRC_STRIDE_A_P0__MASK; +} +#define MDP4_PIPE_SRC_STRIDE_A_P1__MASK				0xffff0000 +#define MDP4_PIPE_SRC_STRIDE_A_P1__SHIFT			16 +static inline uint32_t MDP4_PIPE_SRC_STRIDE_A_P1(uint32_t val) +{ +	return ((val) << MDP4_PIPE_SRC_STRIDE_A_P1__SHIFT) & MDP4_PIPE_SRC_STRIDE_A_P1__MASK; +} + +static inline uint32_t REG_MDP4_PIPE_SRC_STRIDE_B(enum mdp4_pipe i0) { return 0x00020044 + 0x10000*i0; } +#define MDP4_PIPE_SRC_STRIDE_B_P2__MASK				0x0000ffff +#define MDP4_PIPE_SRC_STRIDE_B_P2__SHIFT			0 +static inline uint32_t MDP4_PIPE_SRC_STRIDE_B_P2(uint32_t val) +{ +	return ((val) << MDP4_PIPE_SRC_STRIDE_B_P2__SHIFT) & MDP4_PIPE_SRC_STRIDE_B_P2__MASK; +} +#define MDP4_PIPE_SRC_STRIDE_B_P3__MASK				0xffff0000 +#define MDP4_PIPE_SRC_STRIDE_B_P3__SHIFT			16 +static inline uint32_t MDP4_PIPE_SRC_STRIDE_B_P3(uint32_t val) +{ +	return ((val) << MDP4_PIPE_SRC_STRIDE_B_P3__SHIFT) & MDP4_PIPE_SRC_STRIDE_B_P3__MASK; +} + +static inline uint32_t REG_MDP4_PIPE_FRAME_SIZE(enum mdp4_pipe i0) { return 0x00020048 + 0x10000*i0; } +#define MDP4_PIPE_FRAME_SIZE_HEIGHT__MASK			0xffff0000 +#define MDP4_PIPE_FRAME_SIZE_HEIGHT__SHIFT			16 +static inline uint32_t MDP4_PIPE_FRAME_SIZE_HEIGHT(uint32_t val) +{ +	return ((val) << MDP4_PIPE_FRAME_SIZE_HEIGHT__SHIFT) & MDP4_PIPE_FRAME_SIZE_HEIGHT__MASK; +} +#define MDP4_PIPE_FRAME_SIZE_WIDTH__MASK			0x0000ffff +#define MDP4_PIPE_FRAME_SIZE_WIDTH__SHIFT			0 +static inline uint32_t MDP4_PIPE_FRAME_SIZE_WIDTH(uint32_t val) +{ +	return ((val) << MDP4_PIPE_FRAME_SIZE_WIDTH__SHIFT) & MDP4_PIPE_FRAME_SIZE_WIDTH__MASK; +} + +static inline uint32_t REG_MDP4_PIPE_SRC_FORMAT(enum mdp4_pipe i0) { return 0x00020050 + 0x10000*i0; } +#define MDP4_PIPE_SRC_FORMAT_G_BPC__MASK			0x00000003 +#define MDP4_PIPE_SRC_FORMAT_G_BPC__SHIFT			0 +static inline uint32_t MDP4_PIPE_SRC_FORMAT_G_BPC(enum mdp_bpc val) +{ +	return ((val) << MDP4_PIPE_SRC_FORMAT_G_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_G_BPC__MASK; +} +#define MDP4_PIPE_SRC_FORMAT_B_BPC__MASK			0x0000000c +#define MDP4_PIPE_SRC_FORMAT_B_BPC__SHIFT			2 +static inline uint32_t MDP4_PIPE_SRC_FORMAT_B_BPC(enum mdp_bpc val) +{ +	return ((val) << MDP4_PIPE_SRC_FORMAT_B_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_B_BPC__MASK; +} +#define MDP4_PIPE_SRC_FORMAT_R_BPC__MASK			0x00000030 +#define MDP4_PIPE_SRC_FORMAT_R_BPC__SHIFT			4 +static inline uint32_t MDP4_PIPE_SRC_FORMAT_R_BPC(enum mdp_bpc val) +{ +	return ((val) << MDP4_PIPE_SRC_FORMAT_R_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_R_BPC__MASK; +} +#define MDP4_PIPE_SRC_FORMAT_A_BPC__MASK			0x000000c0 +#define MDP4_PIPE_SRC_FORMAT_A_BPC__SHIFT			6 +static inline uint32_t MDP4_PIPE_SRC_FORMAT_A_BPC(enum mdp_bpc_alpha val) +{ +	return ((val) << MDP4_PIPE_SRC_FORMAT_A_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_A_BPC__MASK; +} +#define MDP4_PIPE_SRC_FORMAT_ALPHA_ENABLE			0x00000100 +#define MDP4_PIPE_SRC_FORMAT_CPP__MASK				0x00000600 +#define MDP4_PIPE_SRC_FORMAT_CPP__SHIFT				9 +static inline uint32_t MDP4_PIPE_SRC_FORMAT_CPP(uint32_t val) +{ +	return ((val) << MDP4_PIPE_SRC_FORMAT_CPP__SHIFT) & MDP4_PIPE_SRC_FORMAT_CPP__MASK; +} +#define MDP4_PIPE_SRC_FORMAT_ROTATED_90				0x00001000 +#define MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT__MASK			0x00006000 +#define MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT__SHIFT		13 +static inline uint32_t MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT(uint32_t val) +{ +	return ((val) << MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT__SHIFT) & MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT__MASK; +} +#define MDP4_PIPE_SRC_FORMAT_UNPACK_TIGHT			0x00020000 +#define MDP4_PIPE_SRC_FORMAT_UNPACK_ALIGN_MSB			0x00040000 +#define MDP4_PIPE_SRC_FORMAT_SOLID_FILL				0x00400000 + +static inline uint32_t REG_MDP4_PIPE_SRC_UNPACK(enum mdp4_pipe i0) { return 0x00020054 + 0x10000*i0; } +#define MDP4_PIPE_SRC_UNPACK_ELEM0__MASK			0x000000ff +#define MDP4_PIPE_SRC_UNPACK_ELEM0__SHIFT			0 +static inline uint32_t MDP4_PIPE_SRC_UNPACK_ELEM0(uint32_t val) +{ +	return ((val) << MDP4_PIPE_SRC_UNPACK_ELEM0__SHIFT) & MDP4_PIPE_SRC_UNPACK_ELEM0__MASK; +} +#define MDP4_PIPE_SRC_UNPACK_ELEM1__MASK			0x0000ff00 +#define MDP4_PIPE_SRC_UNPACK_ELEM1__SHIFT			8 +static inline uint32_t MDP4_PIPE_SRC_UNPACK_ELEM1(uint32_t val) +{ +	return ((val) << MDP4_PIPE_SRC_UNPACK_ELEM1__SHIFT) & MDP4_PIPE_SRC_UNPACK_ELEM1__MASK; +} +#define MDP4_PIPE_SRC_UNPACK_ELEM2__MASK			0x00ff0000 +#define MDP4_PIPE_SRC_UNPACK_ELEM2__SHIFT			16 +static inline uint32_t MDP4_PIPE_SRC_UNPACK_ELEM2(uint32_t val) +{ +	return ((val) << MDP4_PIPE_SRC_UNPACK_ELEM2__SHIFT) & MDP4_PIPE_SRC_UNPACK_ELEM2__MASK; +} +#define MDP4_PIPE_SRC_UNPACK_ELEM3__MASK			0xff000000 +#define MDP4_PIPE_SRC_UNPACK_ELEM3__SHIFT			24 +static inline uint32_t MDP4_PIPE_SRC_UNPACK_ELEM3(uint32_t val) +{ +	return ((val) << MDP4_PIPE_SRC_UNPACK_ELEM3__SHIFT) & MDP4_PIPE_SRC_UNPACK_ELEM3__MASK; +} + +static inline uint32_t REG_MDP4_PIPE_OP_MODE(enum mdp4_pipe i0) { return 0x00020058 + 0x10000*i0; } +#define MDP4_PIPE_OP_MODE_SCALEX_EN				0x00000001 +#define MDP4_PIPE_OP_MODE_SCALEY_EN				0x00000002 +#define MDP4_PIPE_OP_MODE_SRC_YCBCR				0x00000200 +#define MDP4_PIPE_OP_MODE_DST_YCBCR				0x00000400 +#define MDP4_PIPE_OP_MODE_CSC_EN				0x00000800 +#define MDP4_PIPE_OP_MODE_FLIP_LR				0x00002000 +#define MDP4_PIPE_OP_MODE_FLIP_UD				0x00004000 +#define MDP4_PIPE_OP_MODE_DITHER_EN				0x00008000 +#define MDP4_PIPE_OP_MODE_IGC_LUT_EN				0x00010000 +#define MDP4_PIPE_OP_MODE_DEINT_EN				0x00040000 +#define MDP4_PIPE_OP_MODE_DEINT_ODD_REF				0x00080000 + +static inline uint32_t REG_MDP4_PIPE_PHASEX_STEP(enum mdp4_pipe i0) { return 0x0002005c + 0x10000*i0; } + +static inline uint32_t REG_MDP4_PIPE_PHASEY_STEP(enum mdp4_pipe i0) { return 0x00020060 + 0x10000*i0; } + +static inline uint32_t REG_MDP4_PIPE_FETCH_CONFIG(enum mdp4_pipe i0) { return 0x00021004 + 0x10000*i0; } + +static inline uint32_t REG_MDP4_PIPE_SOLID_COLOR(enum mdp4_pipe i0) { return 0x00021008 + 0x10000*i0; } + +static inline uint32_t REG_MDP4_PIPE_CSC(enum mdp4_pipe i0) { return 0x00024000 + 0x10000*i0; } + + +static inline uint32_t REG_MDP4_PIPE_CSC_MV(enum mdp4_pipe i0, uint32_t i1) { return 0x00024400 + 0x10000*i0 + 0x4*i1; } + +static inline uint32_t REG_MDP4_PIPE_CSC_MV_VAL(enum mdp4_pipe i0, uint32_t i1) { return 0x00024400 + 0x10000*i0 + 0x4*i1; } + +static inline uint32_t REG_MDP4_PIPE_CSC_PRE_BV(enum mdp4_pipe i0, uint32_t i1) { return 0x00024500 + 0x10000*i0 + 0x4*i1; } + +static inline uint32_t REG_MDP4_PIPE_CSC_PRE_BV_VAL(enum mdp4_pipe i0, uint32_t i1) { return 0x00024500 + 0x10000*i0 + 0x4*i1; } + +static inline uint32_t REG_MDP4_PIPE_CSC_POST_BV(enum mdp4_pipe i0, uint32_t i1) { return 0x00024580 + 0x10000*i0 + 0x4*i1; } + +static inline uint32_t REG_MDP4_PIPE_CSC_POST_BV_VAL(enum mdp4_pipe i0, uint32_t i1) { return 0x00024580 + 0x10000*i0 + 0x4*i1; } + +static inline uint32_t REG_MDP4_PIPE_CSC_PRE_LV(enum mdp4_pipe i0, uint32_t i1) { return 0x00024600 + 0x10000*i0 + 0x4*i1; } + +static inline uint32_t REG_MDP4_PIPE_CSC_PRE_LV_VAL(enum mdp4_pipe i0, uint32_t i1) { return 0x00024600 + 0x10000*i0 + 0x4*i1; } + +static inline uint32_t REG_MDP4_PIPE_CSC_POST_LV(enum mdp4_pipe i0, uint32_t i1) { return 0x00024680 + 0x10000*i0 + 0x4*i1; } + +static inline uint32_t REG_MDP4_PIPE_CSC_POST_LV_VAL(enum mdp4_pipe i0, uint32_t i1) { return 0x00024680 + 0x10000*i0 + 0x4*i1; } + +#define REG_MDP4_LCDC						0x000c0000 + +#define REG_MDP4_LCDC_ENABLE					0x000c0000 + +#define REG_MDP4_LCDC_HSYNC_CTRL				0x000c0004 +#define MDP4_LCDC_HSYNC_CTRL_PULSEW__MASK			0x0000ffff +#define MDP4_LCDC_HSYNC_CTRL_PULSEW__SHIFT			0 +static inline uint32_t MDP4_LCDC_HSYNC_CTRL_PULSEW(uint32_t val) +{ +	return ((val) << MDP4_LCDC_HSYNC_CTRL_PULSEW__SHIFT) & MDP4_LCDC_HSYNC_CTRL_PULSEW__MASK; +} +#define MDP4_LCDC_HSYNC_CTRL_PERIOD__MASK			0xffff0000 +#define MDP4_LCDC_HSYNC_CTRL_PERIOD__SHIFT			16 +static inline uint32_t MDP4_LCDC_HSYNC_CTRL_PERIOD(uint32_t val) +{ +	return ((val) << MDP4_LCDC_HSYNC_CTRL_PERIOD__SHIFT) & MDP4_LCDC_HSYNC_CTRL_PERIOD__MASK; +} + +#define REG_MDP4_LCDC_VSYNC_PERIOD				0x000c0008 + +#define REG_MDP4_LCDC_VSYNC_LEN					0x000c000c + +#define REG_MDP4_LCDC_DISPLAY_HCTRL				0x000c0010 +#define MDP4_LCDC_DISPLAY_HCTRL_START__MASK			0x0000ffff +#define MDP4_LCDC_DISPLAY_HCTRL_START__SHIFT			0 +static inline uint32_t MDP4_LCDC_DISPLAY_HCTRL_START(uint32_t val) +{ +	return ((val) << MDP4_LCDC_DISPLAY_HCTRL_START__SHIFT) & MDP4_LCDC_DISPLAY_HCTRL_START__MASK; +} +#define MDP4_LCDC_DISPLAY_HCTRL_END__MASK			0xffff0000 +#define MDP4_LCDC_DISPLAY_HCTRL_END__SHIFT			16 +static inline uint32_t MDP4_LCDC_DISPLAY_HCTRL_END(uint32_t val) +{ +	return ((val) << MDP4_LCDC_DISPLAY_HCTRL_END__SHIFT) & MDP4_LCDC_DISPLAY_HCTRL_END__MASK; +} + +#define REG_MDP4_LCDC_DISPLAY_VSTART				0x000c0014 + +#define REG_MDP4_LCDC_DISPLAY_VEND				0x000c0018 + +#define REG_MDP4_LCDC_ACTIVE_HCTL				0x000c001c +#define MDP4_LCDC_ACTIVE_HCTL_START__MASK			0x00007fff +#define MDP4_LCDC_ACTIVE_HCTL_START__SHIFT			0 +static inline uint32_t MDP4_LCDC_ACTIVE_HCTL_START(uint32_t val) +{ +	return ((val) << MDP4_LCDC_ACTIVE_HCTL_START__SHIFT) & MDP4_LCDC_ACTIVE_HCTL_START__MASK; +} +#define MDP4_LCDC_ACTIVE_HCTL_END__MASK				0x7fff0000 +#define MDP4_LCDC_ACTIVE_HCTL_END__SHIFT			16 +static inline uint32_t MDP4_LCDC_ACTIVE_HCTL_END(uint32_t val) +{ +	return ((val) << MDP4_LCDC_ACTIVE_HCTL_END__SHIFT) & MDP4_LCDC_ACTIVE_HCTL_END__MASK; +} +#define MDP4_LCDC_ACTIVE_HCTL_ACTIVE_START_X			0x80000000 + +#define REG_MDP4_LCDC_ACTIVE_VSTART				0x000c0020 + +#define REG_MDP4_LCDC_ACTIVE_VEND				0x000c0024 + +#define REG_MDP4_LCDC_BORDER_CLR				0x000c0028 + +#define REG_MDP4_LCDC_UNDERFLOW_CLR				0x000c002c +#define MDP4_LCDC_UNDERFLOW_CLR_COLOR__MASK			0x00ffffff +#define MDP4_LCDC_UNDERFLOW_CLR_COLOR__SHIFT			0 +static inline uint32_t MDP4_LCDC_UNDERFLOW_CLR_COLOR(uint32_t val) +{ +	return ((val) << MDP4_LCDC_UNDERFLOW_CLR_COLOR__SHIFT) & MDP4_LCDC_UNDERFLOW_CLR_COLOR__MASK; +} +#define MDP4_LCDC_UNDERFLOW_CLR_ENABLE_RECOVERY			0x80000000 + +#define REG_MDP4_LCDC_HSYNC_SKEW				0x000c0030 + +#define REG_MDP4_LCDC_TEST_CNTL					0x000c0034 + +#define REG_MDP4_LCDC_CTRL_POLARITY				0x000c0038 +#define MDP4_LCDC_CTRL_POLARITY_HSYNC_LOW			0x00000001 +#define MDP4_LCDC_CTRL_POLARITY_VSYNC_LOW			0x00000002 +#define MDP4_LCDC_CTRL_POLARITY_DATA_EN_LOW			0x00000004 + +#define REG_MDP4_DTV						0x000d0000 + +#define REG_MDP4_DTV_ENABLE					0x000d0000 + +#define REG_MDP4_DTV_HSYNC_CTRL					0x000d0004 +#define MDP4_DTV_HSYNC_CTRL_PULSEW__MASK			0x0000ffff +#define MDP4_DTV_HSYNC_CTRL_PULSEW__SHIFT			0 +static inline uint32_t MDP4_DTV_HSYNC_CTRL_PULSEW(uint32_t val) +{ +	return ((val) << MDP4_DTV_HSYNC_CTRL_PULSEW__SHIFT) & MDP4_DTV_HSYNC_CTRL_PULSEW__MASK; +} +#define MDP4_DTV_HSYNC_CTRL_PERIOD__MASK			0xffff0000 +#define MDP4_DTV_HSYNC_CTRL_PERIOD__SHIFT			16 +static inline uint32_t MDP4_DTV_HSYNC_CTRL_PERIOD(uint32_t val) +{ +	return ((val) << MDP4_DTV_HSYNC_CTRL_PERIOD__SHIFT) & MDP4_DTV_HSYNC_CTRL_PERIOD__MASK; +} + +#define REG_MDP4_DTV_VSYNC_PERIOD				0x000d0008 + +#define REG_MDP4_DTV_VSYNC_LEN					0x000d000c + +#define REG_MDP4_DTV_DISPLAY_HCTRL				0x000d0018 +#define MDP4_DTV_DISPLAY_HCTRL_START__MASK			0x0000ffff +#define MDP4_DTV_DISPLAY_HCTRL_START__SHIFT			0 +static inline uint32_t MDP4_DTV_DISPLAY_HCTRL_START(uint32_t val) +{ +	return ((val) << MDP4_DTV_DISPLAY_HCTRL_START__SHIFT) & MDP4_DTV_DISPLAY_HCTRL_START__MASK; +} +#define MDP4_DTV_DISPLAY_HCTRL_END__MASK			0xffff0000 +#define MDP4_DTV_DISPLAY_HCTRL_END__SHIFT			16 +static inline uint32_t MDP4_DTV_DISPLAY_HCTRL_END(uint32_t val) +{ +	return ((val) << MDP4_DTV_DISPLAY_HCTRL_END__SHIFT) & MDP4_DTV_DISPLAY_HCTRL_END__MASK; +} + +#define REG_MDP4_DTV_DISPLAY_VSTART				0x000d001c + +#define REG_MDP4_DTV_DISPLAY_VEND				0x000d0020 + +#define REG_MDP4_DTV_ACTIVE_HCTL				0x000d002c +#define MDP4_DTV_ACTIVE_HCTL_START__MASK			0x00007fff +#define MDP4_DTV_ACTIVE_HCTL_START__SHIFT			0 +static inline uint32_t MDP4_DTV_ACTIVE_HCTL_START(uint32_t val) +{ +	return ((val) << MDP4_DTV_ACTIVE_HCTL_START__SHIFT) & MDP4_DTV_ACTIVE_HCTL_START__MASK; +} +#define MDP4_DTV_ACTIVE_HCTL_END__MASK				0x7fff0000 +#define MDP4_DTV_ACTIVE_HCTL_END__SHIFT				16 +static inline uint32_t MDP4_DTV_ACTIVE_HCTL_END(uint32_t val) +{ +	return ((val) << MDP4_DTV_ACTIVE_HCTL_END__SHIFT) & MDP4_DTV_ACTIVE_HCTL_END__MASK; +} +#define MDP4_DTV_ACTIVE_HCTL_ACTIVE_START_X			0x80000000 + +#define REG_MDP4_DTV_ACTIVE_VSTART				0x000d0030 + +#define REG_MDP4_DTV_ACTIVE_VEND				0x000d0038 + +#define REG_MDP4_DTV_BORDER_CLR					0x000d0040 + +#define REG_MDP4_DTV_UNDERFLOW_CLR				0x000d0044 +#define MDP4_DTV_UNDERFLOW_CLR_COLOR__MASK			0x00ffffff +#define MDP4_DTV_UNDERFLOW_CLR_COLOR__SHIFT			0 +static inline uint32_t MDP4_DTV_UNDERFLOW_CLR_COLOR(uint32_t val) +{ +	return ((val) << MDP4_DTV_UNDERFLOW_CLR_COLOR__SHIFT) & MDP4_DTV_UNDERFLOW_CLR_COLOR__MASK; +} +#define MDP4_DTV_UNDERFLOW_CLR_ENABLE_RECOVERY			0x80000000 + +#define REG_MDP4_DTV_HSYNC_SKEW					0x000d0048 + +#define REG_MDP4_DTV_TEST_CNTL					0x000d004c + +#define REG_MDP4_DTV_CTRL_POLARITY				0x000d0050 +#define MDP4_DTV_CTRL_POLARITY_HSYNC_LOW			0x00000001 +#define MDP4_DTV_CTRL_POLARITY_VSYNC_LOW			0x00000002 +#define MDP4_DTV_CTRL_POLARITY_DATA_EN_LOW			0x00000004 + +#define REG_MDP4_DSI						0x000e0000 + +#define REG_MDP4_DSI_ENABLE					0x000e0000 + +#define REG_MDP4_DSI_HSYNC_CTRL					0x000e0004 +#define MDP4_DSI_HSYNC_CTRL_PULSEW__MASK			0x0000ffff +#define MDP4_DSI_HSYNC_CTRL_PULSEW__SHIFT			0 +static inline uint32_t MDP4_DSI_HSYNC_CTRL_PULSEW(uint32_t val) +{ +	return ((val) << MDP4_DSI_HSYNC_CTRL_PULSEW__SHIFT) & MDP4_DSI_HSYNC_CTRL_PULSEW__MASK; +} +#define MDP4_DSI_HSYNC_CTRL_PERIOD__MASK			0xffff0000 +#define MDP4_DSI_HSYNC_CTRL_PERIOD__SHIFT			16 +static inline uint32_t MDP4_DSI_HSYNC_CTRL_PERIOD(uint32_t val) +{ +	return ((val) << MDP4_DSI_HSYNC_CTRL_PERIOD__SHIFT) & MDP4_DSI_HSYNC_CTRL_PERIOD__MASK; +} + +#define REG_MDP4_DSI_VSYNC_PERIOD				0x000e0008 + +#define REG_MDP4_DSI_VSYNC_LEN					0x000e000c + +#define REG_MDP4_DSI_DISPLAY_HCTRL				0x000e0010 +#define MDP4_DSI_DISPLAY_HCTRL_START__MASK			0x0000ffff +#define MDP4_DSI_DISPLAY_HCTRL_START__SHIFT			0 +static inline uint32_t MDP4_DSI_DISPLAY_HCTRL_START(uint32_t val) +{ +	return ((val) << MDP4_DSI_DISPLAY_HCTRL_START__SHIFT) & MDP4_DSI_DISPLAY_HCTRL_START__MASK; +} +#define MDP4_DSI_DISPLAY_HCTRL_END__MASK			0xffff0000 +#define MDP4_DSI_DISPLAY_HCTRL_END__SHIFT			16 +static inline uint32_t MDP4_DSI_DISPLAY_HCTRL_END(uint32_t val) +{ +	return ((val) << MDP4_DSI_DISPLAY_HCTRL_END__SHIFT) & MDP4_DSI_DISPLAY_HCTRL_END__MASK; +} + +#define REG_MDP4_DSI_DISPLAY_VSTART				0x000e0014 + +#define REG_MDP4_DSI_DISPLAY_VEND				0x000e0018 + +#define REG_MDP4_DSI_ACTIVE_HCTL				0x000e001c +#define MDP4_DSI_ACTIVE_HCTL_START__MASK			0x00007fff +#define MDP4_DSI_ACTIVE_HCTL_START__SHIFT			0 +static inline uint32_t MDP4_DSI_ACTIVE_HCTL_START(uint32_t val) +{ +	return ((val) << MDP4_DSI_ACTIVE_HCTL_START__SHIFT) & MDP4_DSI_ACTIVE_HCTL_START__MASK; +} +#define MDP4_DSI_ACTIVE_HCTL_END__MASK				0x7fff0000 +#define MDP4_DSI_ACTIVE_HCTL_END__SHIFT				16 +static inline uint32_t MDP4_DSI_ACTIVE_HCTL_END(uint32_t val) +{ +	return ((val) << MDP4_DSI_ACTIVE_HCTL_END__SHIFT) & MDP4_DSI_ACTIVE_HCTL_END__MASK; +} +#define MDP4_DSI_ACTIVE_HCTL_ACTIVE_START_X			0x80000000 + +#define REG_MDP4_DSI_ACTIVE_VSTART				0x000e0020 + +#define REG_MDP4_DSI_ACTIVE_VEND				0x000e0024 + +#define REG_MDP4_DSI_BORDER_CLR					0x000e0028 + +#define REG_MDP4_DSI_UNDERFLOW_CLR				0x000e002c +#define MDP4_DSI_UNDERFLOW_CLR_COLOR__MASK			0x00ffffff +#define MDP4_DSI_UNDERFLOW_CLR_COLOR__SHIFT			0 +static inline uint32_t MDP4_DSI_UNDERFLOW_CLR_COLOR(uint32_t val) +{ +	return ((val) << MDP4_DSI_UNDERFLOW_CLR_COLOR__SHIFT) & MDP4_DSI_UNDERFLOW_CLR_COLOR__MASK; +} +#define MDP4_DSI_UNDERFLOW_CLR_ENABLE_RECOVERY			0x80000000 + +#define REG_MDP4_DSI_HSYNC_SKEW					0x000e0030 + +#define REG_MDP4_DSI_TEST_CNTL					0x000e0034 + +#define REG_MDP4_DSI_CTRL_POLARITY				0x000e0038 +#define MDP4_DSI_CTRL_POLARITY_HSYNC_LOW			0x00000001 +#define MDP4_DSI_CTRL_POLARITY_VSYNC_LOW			0x00000002 +#define MDP4_DSI_CTRL_POLARITY_DATA_EN_LOW			0x00000004 + + +#endif /* MDP4_XML */ diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c new file mode 100644 index 00000000000..74cebb51e8c --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c @@ -0,0 +1,804 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include "mdp4_kms.h" + +#include <drm/drm_mode.h> +#include "drm_crtc.h" +#include "drm_crtc_helper.h" +#include "drm_flip_work.h" + +struct mdp4_crtc { +	struct drm_crtc base; +	char name[8]; +	struct drm_plane *plane; +	struct drm_plane *planes[8]; +	int id; +	int ovlp; +	enum mdp4_dma dma; +	bool enabled; + +	/* which mixer/encoder we route output to: */ +	int mixer; + +	struct { +		spinlock_t lock; +		bool stale; +		uint32_t width, height; +		uint32_t x, y; + +		/* next cursor to scan-out: */ +		uint32_t next_iova; +		struct drm_gem_object *next_bo; + +		/* current cursor being scanned out: */ +		struct drm_gem_object *scanout_bo; +	} cursor; + + +	/* if there is a pending flip, these will be non-null: */ +	struct drm_pending_vblank_event *event; +	struct msm_fence_cb pageflip_cb; + +#define PENDING_CURSOR 0x1 +#define PENDING_FLIP   0x2 +	atomic_t pending; + +	/* the fb that we logically (from PoV of KMS API) hold a ref +	 * to.  Which we may not yet be scanning out (we may still +	 * be scanning out previous in case of page_flip while waiting +	 * for gpu rendering to complete: +	 */ +	struct drm_framebuffer *fb; + +	/* the fb that we currently hold a scanout ref to: */ +	struct drm_framebuffer *scanout_fb; + +	/* for unref'ing framebuffers after scanout completes: */ +	struct drm_flip_work unref_fb_work; + +	/* for unref'ing cursor bo's after scanout completes: */ +	struct drm_flip_work unref_cursor_work; + +	struct mdp_irq vblank; +	struct mdp_irq err; +}; +#define to_mdp4_crtc(x) container_of(x, struct mdp4_crtc, base) + +static struct mdp4_kms *get_kms(struct drm_crtc *crtc) +{ +	struct msm_drm_private *priv = crtc->dev->dev_private; +	return to_mdp4_kms(to_mdp_kms(priv->kms)); +} + +static void request_pending(struct drm_crtc *crtc, uint32_t pending) +{ +	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); + +	atomic_or(pending, &mdp4_crtc->pending); +	mdp_irq_register(&get_kms(crtc)->base, &mdp4_crtc->vblank); +} + +static void crtc_flush(struct drm_crtc *crtc) +{ +	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); +	struct mdp4_kms *mdp4_kms = get_kms(crtc); +	uint32_t i, flush = 0; + +	for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) { +		struct drm_plane *plane = mdp4_crtc->planes[i]; +		if (plane) { +			enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane); +			flush |= pipe2flush(pipe_id); +		} +	} +	flush |= ovlp2flush(mdp4_crtc->ovlp); + +	DBG("%s: flush=%08x", mdp4_crtc->name, flush); + +	mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush); +} + +static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb) +{ +	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); +	struct drm_framebuffer *old_fb = mdp4_crtc->fb; + +	/* grab reference to incoming scanout fb: */ +	drm_framebuffer_reference(new_fb); +	mdp4_crtc->base.primary->fb = new_fb; +	mdp4_crtc->fb = new_fb; + +	if (old_fb) +		drm_flip_work_queue(&mdp4_crtc->unref_fb_work, old_fb); +} + +/* unlike update_fb(), take a ref to the new scanout fb *before* updating + * plane, then call this.  Needed to ensure we don't unref the buffer that + * is actually still being scanned out. + * + * Note that this whole thing goes away with atomic.. since we can defer + * calling into driver until rendering is done. + */ +static void update_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb) +{ +	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); + +	/* flush updates, to make sure hw is updated to new scanout fb, +	 * so that we can safely queue unref to current fb (ie. next +	 * vblank we know hw is done w/ previous scanout_fb). +	 */ +	crtc_flush(crtc); + +	if (mdp4_crtc->scanout_fb) +		drm_flip_work_queue(&mdp4_crtc->unref_fb_work, +				mdp4_crtc->scanout_fb); + +	mdp4_crtc->scanout_fb = fb; + +	/* enable vblank to complete flip: */ +	request_pending(crtc, PENDING_FLIP); +} + +/* if file!=NULL, this is preclose potential cancel-flip path */ +static void complete_flip(struct drm_crtc *crtc, struct drm_file *file) +{ +	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); +	struct drm_device *dev = crtc->dev; +	struct drm_pending_vblank_event *event; +	unsigned long flags; + +	spin_lock_irqsave(&dev->event_lock, flags); +	event = mdp4_crtc->event; +	if (event) { +		/* if regular vblank case (!file) or if cancel-flip from +		 * preclose on file that requested flip, then send the +		 * event: +		 */ +		if (!file || (event->base.file_priv == file)) { +			mdp4_crtc->event = NULL; +			drm_send_vblank_event(dev, mdp4_crtc->id, event); +		} +	} +	spin_unlock_irqrestore(&dev->event_lock, flags); +} + +static void pageflip_cb(struct msm_fence_cb *cb) +{ +	struct mdp4_crtc *mdp4_crtc = +		container_of(cb, struct mdp4_crtc, pageflip_cb); +	struct drm_crtc *crtc = &mdp4_crtc->base; +	struct drm_framebuffer *fb = crtc->primary->fb; + +	if (!fb) +		return; + +	drm_framebuffer_reference(fb); +	mdp4_plane_set_scanout(mdp4_crtc->plane, fb); +	update_scanout(crtc, fb); +} + +static void unref_fb_worker(struct drm_flip_work *work, void *val) +{ +	struct mdp4_crtc *mdp4_crtc = +		container_of(work, struct mdp4_crtc, unref_fb_work); +	struct drm_device *dev = mdp4_crtc->base.dev; + +	mutex_lock(&dev->mode_config.mutex); +	drm_framebuffer_unreference(val); +	mutex_unlock(&dev->mode_config.mutex); +} + +static void unref_cursor_worker(struct drm_flip_work *work, void *val) +{ +	struct mdp4_crtc *mdp4_crtc = +		container_of(work, struct mdp4_crtc, unref_cursor_work); +	struct mdp4_kms *mdp4_kms = get_kms(&mdp4_crtc->base); + +	msm_gem_put_iova(val, mdp4_kms->id); +	drm_gem_object_unreference_unlocked(val); +} + +static void mdp4_crtc_destroy(struct drm_crtc *crtc) +{ +	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); + +	drm_crtc_cleanup(crtc); +	drm_flip_work_cleanup(&mdp4_crtc->unref_fb_work); +	drm_flip_work_cleanup(&mdp4_crtc->unref_cursor_work); + +	kfree(mdp4_crtc); +} + +static void mdp4_crtc_dpms(struct drm_crtc *crtc, int mode) +{ +	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); +	struct mdp4_kms *mdp4_kms = get_kms(crtc); +	bool enabled = (mode == DRM_MODE_DPMS_ON); + +	DBG("%s: mode=%d", mdp4_crtc->name, mode); + +	if (enabled != mdp4_crtc->enabled) { +		if (enabled) { +			mdp4_enable(mdp4_kms); +			mdp_irq_register(&mdp4_kms->base, &mdp4_crtc->err); +		} else { +			mdp_irq_unregister(&mdp4_kms->base, &mdp4_crtc->err); +			mdp4_disable(mdp4_kms); +		} +		mdp4_crtc->enabled = enabled; +	} +} + +static bool mdp4_crtc_mode_fixup(struct drm_crtc *crtc, +		const struct drm_display_mode *mode, +		struct drm_display_mode *adjusted_mode) +{ +	return true; +} + +static void blend_setup(struct drm_crtc *crtc) +{ +	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); +	struct mdp4_kms *mdp4_kms = get_kms(crtc); +	int i, ovlp = mdp4_crtc->ovlp; +	uint32_t mixer_cfg = 0; +	static const enum mdp_mixer_stage_id stages[] = { +			STAGE_BASE, STAGE0, STAGE1, STAGE2, STAGE3, +	}; +	/* statically (for now) map planes to mixer stage (z-order): */ +	static const int idxs[] = { +			[VG1]  = 1, +			[VG2]  = 2, +			[RGB1] = 0, +			[RGB2] = 0, +			[RGB3] = 0, +			[VG3]  = 3, +			[VG4]  = 4, + +	}; +	bool alpha[4]= { false, false, false, false }; + +	mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW0(ovlp), 0); +	mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW1(ovlp), 0); +	mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH0(ovlp), 0); +	mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH1(ovlp), 0); + +	/* TODO single register for all CRTCs, so this won't work properly +	 * when multiple CRTCs are active.. +	 */ +	for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) { +		struct drm_plane *plane = mdp4_crtc->planes[i]; +		if (plane) { +			enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane); +			int idx = idxs[pipe_id]; +			if (idx > 0) { +				const struct mdp_format *format = +					to_mdp_format(msm_framebuffer_format(plane->fb)); +				alpha[idx-1] = format->alpha_enable; +			} +			mixer_cfg |= mixercfg(mdp4_crtc->mixer, pipe_id, stages[idx]); +		} +	} + +	/* this shouldn't happen.. and seems to cause underflow: */ +	WARN_ON(!mixer_cfg); + +	for (i = 0; i < 4; i++) { +		uint32_t op; + +		if (alpha[i]) { +			op = MDP4_OVLP_STAGE_OP_FG_ALPHA(FG_PIXEL) | +					MDP4_OVLP_STAGE_OP_BG_ALPHA(FG_PIXEL) | +					MDP4_OVLP_STAGE_OP_BG_INV_ALPHA; +		} else { +			op = MDP4_OVLP_STAGE_OP_FG_ALPHA(FG_CONST) | +					MDP4_OVLP_STAGE_OP_BG_ALPHA(BG_CONST); +		} + +		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_FG_ALPHA(ovlp, i), 0xff); +		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_BG_ALPHA(ovlp, i), 0x00); +		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_OP(ovlp, i), op); +		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_CO3(ovlp, i), 1); +		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_LOW0(ovlp, i), 0); +		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_LOW1(ovlp, i), 0); +		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH0(ovlp, i), 0); +		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH1(ovlp, i), 0); +	} + +	mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, mixer_cfg); +} + +static int mdp4_crtc_mode_set(struct drm_crtc *crtc, +		struct drm_display_mode *mode, +		struct drm_display_mode *adjusted_mode, +		int x, int y, +		struct drm_framebuffer *old_fb) +{ +	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); +	struct mdp4_kms *mdp4_kms = get_kms(crtc); +	enum mdp4_dma dma = mdp4_crtc->dma; +	int ret, ovlp = mdp4_crtc->ovlp; + +	mode = adjusted_mode; + +	DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", +			mdp4_crtc->name, mode->base.id, mode->name, +			mode->vrefresh, mode->clock, +			mode->hdisplay, mode->hsync_start, +			mode->hsync_end, mode->htotal, +			mode->vdisplay, mode->vsync_start, +			mode->vsync_end, mode->vtotal, +			mode->type, mode->flags); + +	/* grab extra ref for update_scanout() */ +	drm_framebuffer_reference(crtc->primary->fb); + +	ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->primary->fb, +			0, 0, mode->hdisplay, mode->vdisplay, +			x << 16, y << 16, +			mode->hdisplay << 16, mode->vdisplay << 16); +	if (ret) { +		drm_framebuffer_unreference(crtc->primary->fb); +		dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n", +				mdp4_crtc->name, ret); +		return ret; +	} + +	mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_SIZE(dma), +			MDP4_DMA_SRC_SIZE_WIDTH(mode->hdisplay) | +			MDP4_DMA_SRC_SIZE_HEIGHT(mode->vdisplay)); + +	/* take data from pipe: */ +	mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_BASE(dma), 0); +	mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_STRIDE(dma), +			crtc->primary->fb->pitches[0]); +	mdp4_write(mdp4_kms, REG_MDP4_DMA_DST_SIZE(dma), +			MDP4_DMA_DST_SIZE_WIDTH(0) | +			MDP4_DMA_DST_SIZE_HEIGHT(0)); + +	mdp4_write(mdp4_kms, REG_MDP4_OVLP_BASE(ovlp), 0); +	mdp4_write(mdp4_kms, REG_MDP4_OVLP_SIZE(ovlp), +			MDP4_OVLP_SIZE_WIDTH(mode->hdisplay) | +			MDP4_OVLP_SIZE_HEIGHT(mode->vdisplay)); +	mdp4_write(mdp4_kms, REG_MDP4_OVLP_STRIDE(ovlp), +			crtc->primary->fb->pitches[0]); + +	mdp4_write(mdp4_kms, REG_MDP4_OVLP_CFG(ovlp), 1); + +	if (dma == DMA_E) { +		mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(0), 0x00ff0000); +		mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(1), 0x00ff0000); +		mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(2), 0x00ff0000); +	} + +	update_fb(crtc, crtc->primary->fb); +	update_scanout(crtc, crtc->primary->fb); + +	return 0; +} + +static void mdp4_crtc_prepare(struct drm_crtc *crtc) +{ +	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); +	DBG("%s", mdp4_crtc->name); +	/* make sure we hold a ref to mdp clks while setting up mode: */ +	mdp4_enable(get_kms(crtc)); +	mdp4_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); +} + +static void mdp4_crtc_commit(struct drm_crtc *crtc) +{ +	mdp4_crtc_dpms(crtc, DRM_MODE_DPMS_ON); +	crtc_flush(crtc); +	/* drop the ref to mdp clk's that we got in prepare: */ +	mdp4_disable(get_kms(crtc)); +} + +static int mdp4_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, +		struct drm_framebuffer *old_fb) +{ +	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); +	struct drm_plane *plane = mdp4_crtc->plane; +	struct drm_display_mode *mode = &crtc->mode; +	int ret; + +	/* grab extra ref for update_scanout() */ +	drm_framebuffer_reference(crtc->primary->fb); + +	ret = mdp4_plane_mode_set(plane, crtc, crtc->primary->fb, +			0, 0, mode->hdisplay, mode->vdisplay, +			x << 16, y << 16, +			mode->hdisplay << 16, mode->vdisplay << 16); +	if (ret) { +		drm_framebuffer_unreference(crtc->primary->fb); +		return ret; +	} + +	update_fb(crtc, crtc->primary->fb); +	update_scanout(crtc, crtc->primary->fb); + +	return 0; +} + +static void mdp4_crtc_load_lut(struct drm_crtc *crtc) +{ +} + +static int mdp4_crtc_page_flip(struct drm_crtc *crtc, +		struct drm_framebuffer *new_fb, +		struct drm_pending_vblank_event *event, +		uint32_t page_flip_flags) +{ +	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); +	struct drm_device *dev = crtc->dev; +	struct drm_gem_object *obj; +	unsigned long flags; + +	if (mdp4_crtc->event) { +		dev_err(dev->dev, "already pending flip!\n"); +		return -EBUSY; +	} + +	obj = msm_framebuffer_bo(new_fb, 0); + +	spin_lock_irqsave(&dev->event_lock, flags); +	mdp4_crtc->event = event; +	spin_unlock_irqrestore(&dev->event_lock, flags); + +	update_fb(crtc, new_fb); + +	return msm_gem_queue_inactive_cb(obj, &mdp4_crtc->pageflip_cb); +} + +static int mdp4_crtc_set_property(struct drm_crtc *crtc, +		struct drm_property *property, uint64_t val) +{ +	// XXX +	return -EINVAL; +} + +#define CURSOR_WIDTH 64 +#define CURSOR_HEIGHT 64 + +/* called from IRQ to update cursor related registers (if needed).  The + * cursor registers, other than x/y position, appear not to be double + * buffered, and changing them other than from vblank seems to trigger + * underflow. + */ +static void update_cursor(struct drm_crtc *crtc) +{ +	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); +	struct mdp4_kms *mdp4_kms = get_kms(crtc); +	enum mdp4_dma dma = mdp4_crtc->dma; +	unsigned long flags; + +	spin_lock_irqsave(&mdp4_crtc->cursor.lock, flags); +	if (mdp4_crtc->cursor.stale) { +		struct drm_gem_object *next_bo = mdp4_crtc->cursor.next_bo; +		struct drm_gem_object *prev_bo = mdp4_crtc->cursor.scanout_bo; +		uint32_t iova = mdp4_crtc->cursor.next_iova; + +		if (next_bo) { +			/* take a obj ref + iova ref when we start scanning out: */ +			drm_gem_object_reference(next_bo); +			msm_gem_get_iova_locked(next_bo, mdp4_kms->id, &iova); + +			/* enable cursor: */ +			mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_SIZE(dma), +					MDP4_DMA_CURSOR_SIZE_WIDTH(mdp4_crtc->cursor.width) | +					MDP4_DMA_CURSOR_SIZE_HEIGHT(mdp4_crtc->cursor.height)); +			mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BASE(dma), iova); +			mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BLEND_CONFIG(dma), +					MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT(CURSOR_ARGB) | +					MDP4_DMA_CURSOR_BLEND_CONFIG_CURSOR_EN); +		} else { +			/* disable cursor: */ +			mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BASE(dma), +					mdp4_kms->blank_cursor_iova); +		} + +		/* and drop the iova ref + obj rev when done scanning out: */ +		if (prev_bo) +			drm_flip_work_queue(&mdp4_crtc->unref_cursor_work, prev_bo); + +		mdp4_crtc->cursor.scanout_bo = next_bo; +		mdp4_crtc->cursor.stale = false; +	} + +	mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_POS(dma), +			MDP4_DMA_CURSOR_POS_X(mdp4_crtc->cursor.x) | +			MDP4_DMA_CURSOR_POS_Y(mdp4_crtc->cursor.y)); + +	spin_unlock_irqrestore(&mdp4_crtc->cursor.lock, flags); +} + +static int mdp4_crtc_cursor_set(struct drm_crtc *crtc, +		struct drm_file *file_priv, uint32_t handle, +		uint32_t width, uint32_t height) +{ +	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); +	struct mdp4_kms *mdp4_kms = get_kms(crtc); +	struct drm_device *dev = crtc->dev; +	struct drm_gem_object *cursor_bo, *old_bo; +	unsigned long flags; +	uint32_t iova; +	int ret; + +	if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) { +		dev_err(dev->dev, "bad cursor size: %dx%d\n", width, height); +		return -EINVAL; +	} + +	if (handle) { +		cursor_bo = drm_gem_object_lookup(dev, file_priv, handle); +		if (!cursor_bo) +			return -ENOENT; +	} else { +		cursor_bo = NULL; +	} + +	if (cursor_bo) { +		ret = msm_gem_get_iova(cursor_bo, mdp4_kms->id, &iova); +		if (ret) +			goto fail; +	} else { +		iova = 0; +	} + +	spin_lock_irqsave(&mdp4_crtc->cursor.lock, flags); +	old_bo = mdp4_crtc->cursor.next_bo; +	mdp4_crtc->cursor.next_bo   = cursor_bo; +	mdp4_crtc->cursor.next_iova = iova; +	mdp4_crtc->cursor.width     = width; +	mdp4_crtc->cursor.height    = height; +	mdp4_crtc->cursor.stale     = true; +	spin_unlock_irqrestore(&mdp4_crtc->cursor.lock, flags); + +	if (old_bo) { +		/* drop our previous reference: */ +		drm_flip_work_queue(&mdp4_crtc->unref_cursor_work, old_bo); +	} + +	request_pending(crtc, PENDING_CURSOR); + +	return 0; + +fail: +	drm_gem_object_unreference_unlocked(cursor_bo); +	return ret; +} + +static int mdp4_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) +{ +	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); +	unsigned long flags; + +	spin_lock_irqsave(&mdp4_crtc->cursor.lock, flags); +	mdp4_crtc->cursor.x = x; +	mdp4_crtc->cursor.y = y; +	spin_unlock_irqrestore(&mdp4_crtc->cursor.lock, flags); + +	crtc_flush(crtc); +	request_pending(crtc, PENDING_CURSOR); + +	return 0; +} + +static const struct drm_crtc_funcs mdp4_crtc_funcs = { +	.set_config = drm_crtc_helper_set_config, +	.destroy = mdp4_crtc_destroy, +	.page_flip = mdp4_crtc_page_flip, +	.set_property = mdp4_crtc_set_property, +	.cursor_set = mdp4_crtc_cursor_set, +	.cursor_move = mdp4_crtc_cursor_move, +}; + +static const struct drm_crtc_helper_funcs mdp4_crtc_helper_funcs = { +	.dpms = mdp4_crtc_dpms, +	.mode_fixup = mdp4_crtc_mode_fixup, +	.mode_set = mdp4_crtc_mode_set, +	.prepare = mdp4_crtc_prepare, +	.commit = mdp4_crtc_commit, +	.mode_set_base = mdp4_crtc_mode_set_base, +	.load_lut = mdp4_crtc_load_lut, +}; + +static void mdp4_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus) +{ +	struct mdp4_crtc *mdp4_crtc = container_of(irq, struct mdp4_crtc, vblank); +	struct drm_crtc *crtc = &mdp4_crtc->base; +	struct msm_drm_private *priv = crtc->dev->dev_private; +	unsigned pending; + +	mdp_irq_unregister(&get_kms(crtc)->base, &mdp4_crtc->vblank); + +	pending = atomic_xchg(&mdp4_crtc->pending, 0); + +	if (pending & PENDING_FLIP) { +		complete_flip(crtc, NULL); +		drm_flip_work_commit(&mdp4_crtc->unref_fb_work, priv->wq); +	} + +	if (pending & PENDING_CURSOR) { +		update_cursor(crtc); +		drm_flip_work_commit(&mdp4_crtc->unref_cursor_work, priv->wq); +	} +} + +static void mdp4_crtc_err_irq(struct mdp_irq *irq, uint32_t irqstatus) +{ +	struct mdp4_crtc *mdp4_crtc = container_of(irq, struct mdp4_crtc, err); +	struct drm_crtc *crtc = &mdp4_crtc->base; +	DBG("%s: error: %08x", mdp4_crtc->name, irqstatus); +	crtc_flush(crtc); +} + +uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc) +{ +	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); +	return mdp4_crtc->vblank.irqmask; +} + +void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file) +{ +	DBG("cancel: %p", file); +	complete_flip(crtc, file); +} + +/* set dma config, ie. the format the encoder wants. */ +void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config) +{ +	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); +	struct mdp4_kms *mdp4_kms = get_kms(crtc); + +	mdp4_write(mdp4_kms, REG_MDP4_DMA_CONFIG(mdp4_crtc->dma), config); +} + +/* set interface for routing crtc->encoder: */ +void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf) +{ +	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); +	struct mdp4_kms *mdp4_kms = get_kms(crtc); +	uint32_t intf_sel; + +	intf_sel = mdp4_read(mdp4_kms, REG_MDP4_DISP_INTF_SEL); + +	switch (mdp4_crtc->dma) { +	case DMA_P: +		intf_sel &= ~MDP4_DISP_INTF_SEL_PRIM__MASK; +		intf_sel |= MDP4_DISP_INTF_SEL_PRIM(intf); +		break; +	case DMA_S: +		intf_sel &= ~MDP4_DISP_INTF_SEL_SEC__MASK; +		intf_sel |= MDP4_DISP_INTF_SEL_SEC(intf); +		break; +	case DMA_E: +		intf_sel &= ~MDP4_DISP_INTF_SEL_EXT__MASK; +		intf_sel |= MDP4_DISP_INTF_SEL_EXT(intf); +		break; +	} + +	if (intf == INTF_DSI_VIDEO) { +		intf_sel &= ~MDP4_DISP_INTF_SEL_DSI_CMD; +		intf_sel |= MDP4_DISP_INTF_SEL_DSI_VIDEO; +		mdp4_crtc->mixer = 0; +	} else if (intf == INTF_DSI_CMD) { +		intf_sel &= ~MDP4_DISP_INTF_SEL_DSI_VIDEO; +		intf_sel |= MDP4_DISP_INTF_SEL_DSI_CMD; +		mdp4_crtc->mixer = 0; +	} else if (intf == INTF_LCDC_DTV){ +		mdp4_crtc->mixer = 1; +	} + +	blend_setup(crtc); + +	DBG("%s: intf_sel=%08x", mdp4_crtc->name, intf_sel); + +	mdp4_write(mdp4_kms, REG_MDP4_DISP_INTF_SEL, intf_sel); +} + +static void set_attach(struct drm_crtc *crtc, enum mdp4_pipe pipe_id, +		struct drm_plane *plane) +{ +	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); + +	BUG_ON(pipe_id >= ARRAY_SIZE(mdp4_crtc->planes)); + +	if (mdp4_crtc->planes[pipe_id] == plane) +		return; + +	mdp4_crtc->planes[pipe_id] = plane; +	blend_setup(crtc); +	if (mdp4_crtc->enabled && (plane != mdp4_crtc->plane)) +		crtc_flush(crtc); +} + +void mdp4_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane) +{ +	set_attach(crtc, mdp4_plane_pipe(plane), plane); +} + +void mdp4_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane) +{ +	/* don't actually detatch our primary plane: */ +	if (to_mdp4_crtc(crtc)->plane == plane) +		return; +	set_attach(crtc, mdp4_plane_pipe(plane), NULL); +} + +static const char *dma_names[] = { +		"DMA_P", "DMA_S", "DMA_E", +}; + +/* initialize crtc */ +struct drm_crtc *mdp4_crtc_init(struct drm_device *dev, +		struct drm_plane *plane, int id, int ovlp_id, +		enum mdp4_dma dma_id) +{ +	struct drm_crtc *crtc = NULL; +	struct mdp4_crtc *mdp4_crtc; +	int ret; + +	mdp4_crtc = kzalloc(sizeof(*mdp4_crtc), GFP_KERNEL); +	if (!mdp4_crtc) { +		ret = -ENOMEM; +		goto fail; +	} + +	crtc = &mdp4_crtc->base; + +	mdp4_crtc->plane = plane; +	mdp4_crtc->id = id; + +	mdp4_crtc->ovlp = ovlp_id; +	mdp4_crtc->dma = dma_id; + +	mdp4_crtc->vblank.irqmask = dma2irq(mdp4_crtc->dma); +	mdp4_crtc->vblank.irq = mdp4_crtc_vblank_irq; + +	mdp4_crtc->err.irqmask = dma2err(mdp4_crtc->dma); +	mdp4_crtc->err.irq = mdp4_crtc_err_irq; + +	snprintf(mdp4_crtc->name, sizeof(mdp4_crtc->name), "%s:%d", +			dma_names[dma_id], ovlp_id); + +	spin_lock_init(&mdp4_crtc->cursor.lock); + +	ret = drm_flip_work_init(&mdp4_crtc->unref_fb_work, 16, +			"unref fb", unref_fb_worker); +	if (ret) +		goto fail; + +	ret = drm_flip_work_init(&mdp4_crtc->unref_cursor_work, 64, +			"unref cursor", unref_cursor_worker); + +	INIT_FENCE_CB(&mdp4_crtc->pageflip_cb, pageflip_cb); + +	drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp4_crtc_funcs); +	drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs); + +	mdp4_plane_install_properties(mdp4_crtc->plane, &crtc->base); + +	return crtc; + +fail: +	if (crtc) +		mdp4_crtc_destroy(crtc); + +	return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c new file mode 100644 index 00000000000..067ed03b35f --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include "mdp4_kms.h" + +#include "drm_crtc.h" +#include "drm_crtc_helper.h" + + +struct mdp4_dtv_encoder { +	struct drm_encoder base; +	struct clk *src_clk; +	struct clk *hdmi_clk; +	struct clk *mdp_clk; +	unsigned long int pixclock; +	bool enabled; +	uint32_t bsc; +}; +#define to_mdp4_dtv_encoder(x) container_of(x, struct mdp4_dtv_encoder, base) + +static struct mdp4_kms *get_kms(struct drm_encoder *encoder) +{ +	struct msm_drm_private *priv = encoder->dev->dev_private; +	return to_mdp4_kms(to_mdp_kms(priv->kms)); +} + +#ifdef CONFIG_MSM_BUS_SCALING +#include <mach/board.h> +/* not ironically named at all.. no, really.. */ +static void bs_init(struct mdp4_dtv_encoder *mdp4_dtv_encoder) +{ +	struct drm_device *dev = mdp4_dtv_encoder->base.dev; +	struct lcdc_platform_data *dtv_pdata = mdp4_find_pdata("dtv.0"); + +	if (!dtv_pdata) { +		dev_err(dev->dev, "could not find dtv pdata\n"); +		return; +	} + +	if (dtv_pdata->bus_scale_table) { +		mdp4_dtv_encoder->bsc = msm_bus_scale_register_client( +				dtv_pdata->bus_scale_table); +		DBG("bus scale client: %08x", mdp4_dtv_encoder->bsc); +		DBG("lcdc_power_save: %p", dtv_pdata->lcdc_power_save); +		if (dtv_pdata->lcdc_power_save) +			dtv_pdata->lcdc_power_save(1); +	} +} + +static void bs_fini(struct mdp4_dtv_encoder *mdp4_dtv_encoder) +{ +	if (mdp4_dtv_encoder->bsc) { +		msm_bus_scale_unregister_client(mdp4_dtv_encoder->bsc); +		mdp4_dtv_encoder->bsc = 0; +	} +} + +static void bs_set(struct mdp4_dtv_encoder *mdp4_dtv_encoder, int idx) +{ +	if (mdp4_dtv_encoder->bsc) { +		DBG("set bus scaling: %d", idx); +		msm_bus_scale_client_update_request(mdp4_dtv_encoder->bsc, idx); +	} +} +#else +static void bs_init(struct mdp4_dtv_encoder *mdp4_dtv_encoder) {} +static void bs_fini(struct mdp4_dtv_encoder *mdp4_dtv_encoder) {} +static void bs_set(struct mdp4_dtv_encoder *mdp4_dtv_encoder, int idx) {} +#endif + +static void mdp4_dtv_encoder_destroy(struct drm_encoder *encoder) +{ +	struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder); +	bs_fini(mdp4_dtv_encoder); +	drm_encoder_cleanup(encoder); +	kfree(mdp4_dtv_encoder); +} + +static const struct drm_encoder_funcs mdp4_dtv_encoder_funcs = { +	.destroy = mdp4_dtv_encoder_destroy, +}; + +static void mdp4_dtv_encoder_dpms(struct drm_encoder *encoder, int mode) +{ +	struct drm_device *dev = encoder->dev; +	struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder); +	struct mdp4_kms *mdp4_kms = get_kms(encoder); +	bool enabled = (mode == DRM_MODE_DPMS_ON); + +	DBG("mode=%d", mode); + +	if (enabled == mdp4_dtv_encoder->enabled) +		return; + +	if (enabled) { +		unsigned long pc = mdp4_dtv_encoder->pixclock; +		int ret; + +		bs_set(mdp4_dtv_encoder, 1); + +		DBG("setting src_clk=%lu", pc); + +		ret = clk_set_rate(mdp4_dtv_encoder->src_clk, pc); +		if (ret) +			dev_err(dev->dev, "failed to set src_clk to %lu: %d\n", pc, ret); +		clk_prepare_enable(mdp4_dtv_encoder->src_clk); +		ret = clk_prepare_enable(mdp4_dtv_encoder->hdmi_clk); +		if (ret) +			dev_err(dev->dev, "failed to enable hdmi_clk: %d\n", ret); +		ret = clk_prepare_enable(mdp4_dtv_encoder->mdp_clk); +		if (ret) +			dev_err(dev->dev, "failed to enabled mdp_clk: %d\n", ret); + +		mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 1); +	} else { +		mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 0); + +		/* +		 * Wait for a vsync so we know the ENABLE=0 latched before +		 * the (connector) source of the vsync's gets disabled, +		 * otherwise we end up in a funny state if we re-enable +		 * before the disable latches, which results that some of +		 * the settings changes for the new modeset (like new +		 * scanout buffer) don't latch properly.. +		 */ +		mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_EXTERNAL_VSYNC); + +		clk_disable_unprepare(mdp4_dtv_encoder->src_clk); +		clk_disable_unprepare(mdp4_dtv_encoder->hdmi_clk); +		clk_disable_unprepare(mdp4_dtv_encoder->mdp_clk); + +		bs_set(mdp4_dtv_encoder, 0); +	} + +	mdp4_dtv_encoder->enabled = enabled; +} + +static bool mdp4_dtv_encoder_mode_fixup(struct drm_encoder *encoder, +		const struct drm_display_mode *mode, +		struct drm_display_mode *adjusted_mode) +{ +	return true; +} + +static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder, +		struct drm_display_mode *mode, +		struct drm_display_mode *adjusted_mode) +{ +	struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder); +	struct mdp4_kms *mdp4_kms = get_kms(encoder); +	uint32_t dtv_hsync_skew, vsync_period, vsync_len, ctrl_pol; +	uint32_t display_v_start, display_v_end; +	uint32_t hsync_start_x, hsync_end_x; + +	mode = adjusted_mode; + +	DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", +			mode->base.id, mode->name, +			mode->vrefresh, mode->clock, +			mode->hdisplay, mode->hsync_start, +			mode->hsync_end, mode->htotal, +			mode->vdisplay, mode->vsync_start, +			mode->vsync_end, mode->vtotal, +			mode->type, mode->flags); + +	mdp4_dtv_encoder->pixclock = mode->clock * 1000; + +	DBG("pixclock=%lu", mdp4_dtv_encoder->pixclock); + +	ctrl_pol = 0; +	if (mode->flags & DRM_MODE_FLAG_NHSYNC) +		ctrl_pol |= MDP4_DTV_CTRL_POLARITY_HSYNC_LOW; +	if (mode->flags & DRM_MODE_FLAG_NVSYNC) +		ctrl_pol |= MDP4_DTV_CTRL_POLARITY_VSYNC_LOW; +	/* probably need to get DATA_EN polarity from panel.. */ + +	dtv_hsync_skew = 0;  /* get this from panel? */ + +	hsync_start_x = (mode->htotal - mode->hsync_start); +	hsync_end_x = mode->htotal - (mode->hsync_start - mode->hdisplay) - 1; + +	vsync_period = mode->vtotal * mode->htotal; +	vsync_len = (mode->vsync_end - mode->vsync_start) * mode->htotal; +	display_v_start = (mode->vtotal - mode->vsync_start) * mode->htotal + dtv_hsync_skew; +	display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + dtv_hsync_skew - 1; + +	mdp4_write(mdp4_kms, REG_MDP4_DTV_HSYNC_CTRL, +			MDP4_DTV_HSYNC_CTRL_PULSEW(mode->hsync_end - mode->hsync_start) | +			MDP4_DTV_HSYNC_CTRL_PERIOD(mode->htotal)); +	mdp4_write(mdp4_kms, REG_MDP4_DTV_VSYNC_PERIOD, vsync_period); +	mdp4_write(mdp4_kms, REG_MDP4_DTV_VSYNC_LEN, vsync_len); +	mdp4_write(mdp4_kms, REG_MDP4_DTV_DISPLAY_HCTRL, +			MDP4_DTV_DISPLAY_HCTRL_START(hsync_start_x) | +			MDP4_DTV_DISPLAY_HCTRL_END(hsync_end_x)); +	mdp4_write(mdp4_kms, REG_MDP4_DTV_DISPLAY_VSTART, display_v_start); +	mdp4_write(mdp4_kms, REG_MDP4_DTV_DISPLAY_VEND, display_v_end); +	mdp4_write(mdp4_kms, REG_MDP4_DTV_BORDER_CLR, 0); +	mdp4_write(mdp4_kms, REG_MDP4_DTV_UNDERFLOW_CLR, +			MDP4_DTV_UNDERFLOW_CLR_ENABLE_RECOVERY | +			MDP4_DTV_UNDERFLOW_CLR_COLOR(0xff)); +	mdp4_write(mdp4_kms, REG_MDP4_DTV_HSYNC_SKEW, dtv_hsync_skew); +	mdp4_write(mdp4_kms, REG_MDP4_DTV_CTRL_POLARITY, ctrl_pol); +	mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_HCTL, +			MDP4_DTV_ACTIVE_HCTL_START(0) | +			MDP4_DTV_ACTIVE_HCTL_END(0)); +	mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_VSTART, 0); +	mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_VEND, 0); +} + +static void mdp4_dtv_encoder_prepare(struct drm_encoder *encoder) +{ +	mdp4_dtv_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void mdp4_dtv_encoder_commit(struct drm_encoder *encoder) +{ +	mdp4_crtc_set_config(encoder->crtc, +			MDP4_DMA_CONFIG_R_BPC(BPC8) | +			MDP4_DMA_CONFIG_G_BPC(BPC8) | +			MDP4_DMA_CONFIG_B_BPC(BPC8) | +			MDP4_DMA_CONFIG_PACK(0x21)); +	mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV); +	mdp4_dtv_encoder_dpms(encoder, DRM_MODE_DPMS_ON); +} + +static const struct drm_encoder_helper_funcs mdp4_dtv_encoder_helper_funcs = { +	.dpms = mdp4_dtv_encoder_dpms, +	.mode_fixup = mdp4_dtv_encoder_mode_fixup, +	.mode_set = mdp4_dtv_encoder_mode_set, +	.prepare = mdp4_dtv_encoder_prepare, +	.commit = mdp4_dtv_encoder_commit, +}; + +long mdp4_dtv_round_pixclk(struct drm_encoder *encoder, unsigned long rate) +{ +	struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder); +	return clk_round_rate(mdp4_dtv_encoder->src_clk, rate); +} + +/* initialize encoder */ +struct drm_encoder *mdp4_dtv_encoder_init(struct drm_device *dev) +{ +	struct drm_encoder *encoder = NULL; +	struct mdp4_dtv_encoder *mdp4_dtv_encoder; +	int ret; + +	mdp4_dtv_encoder = kzalloc(sizeof(*mdp4_dtv_encoder), GFP_KERNEL); +	if (!mdp4_dtv_encoder) { +		ret = -ENOMEM; +		goto fail; +	} + +	encoder = &mdp4_dtv_encoder->base; + +	drm_encoder_init(dev, encoder, &mdp4_dtv_encoder_funcs, +			 DRM_MODE_ENCODER_TMDS); +	drm_encoder_helper_add(encoder, &mdp4_dtv_encoder_helper_funcs); + +	mdp4_dtv_encoder->src_clk = devm_clk_get(dev->dev, "src_clk"); +	if (IS_ERR(mdp4_dtv_encoder->src_clk)) { +		dev_err(dev->dev, "failed to get src_clk\n"); +		ret = PTR_ERR(mdp4_dtv_encoder->src_clk); +		goto fail; +	} + +	mdp4_dtv_encoder->hdmi_clk = devm_clk_get(dev->dev, "hdmi_clk"); +	if (IS_ERR(mdp4_dtv_encoder->hdmi_clk)) { +		dev_err(dev->dev, "failed to get hdmi_clk\n"); +		ret = PTR_ERR(mdp4_dtv_encoder->hdmi_clk); +		goto fail; +	} + +	mdp4_dtv_encoder->mdp_clk = devm_clk_get(dev->dev, "mdp_clk"); +	if (IS_ERR(mdp4_dtv_encoder->mdp_clk)) { +		dev_err(dev->dev, "failed to get mdp_clk\n"); +		ret = PTR_ERR(mdp4_dtv_encoder->mdp_clk); +		goto fail; +	} + +	bs_init(mdp4_dtv_encoder); + +	return encoder; + +fail: +	if (encoder) +		mdp4_dtv_encoder_destroy(encoder); + +	return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c new file mode 100644 index 00000000000..8edd531cb62 --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + + +#include "msm_drv.h" +#include "mdp4_kms.h" + +void mdp4_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask) +{ +	mdp4_write(to_mdp4_kms(mdp_kms), REG_MDP4_INTR_ENABLE, irqmask); +} + +static void mdp4_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus) +{ +	DRM_ERROR("errors: %08x\n", irqstatus); +} + +void mdp4_irq_preinstall(struct msm_kms *kms) +{ +	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); +	mdp4_write(mdp4_kms, REG_MDP4_INTR_CLEAR, 0xffffffff); +} + +int mdp4_irq_postinstall(struct msm_kms *kms) +{ +	struct mdp_kms *mdp_kms = to_mdp_kms(kms); +	struct mdp4_kms *mdp4_kms = to_mdp4_kms(mdp_kms); +	struct mdp_irq *error_handler = &mdp4_kms->error_handler; + +	error_handler->irq = mdp4_irq_error_handler; +	error_handler->irqmask = MDP4_IRQ_PRIMARY_INTF_UDERRUN | +			MDP4_IRQ_EXTERNAL_INTF_UDERRUN; + +	mdp_irq_register(mdp_kms, error_handler); + +	return 0; +} + +void mdp4_irq_uninstall(struct msm_kms *kms) +{ +	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); +	mdp4_write(mdp4_kms, REG_MDP4_INTR_ENABLE, 0x00000000); +} + +irqreturn_t mdp4_irq(struct msm_kms *kms) +{ +	struct mdp_kms *mdp_kms = to_mdp_kms(kms); +	struct mdp4_kms *mdp4_kms = to_mdp4_kms(mdp_kms); +	struct drm_device *dev = mdp4_kms->dev; +	struct msm_drm_private *priv = dev->dev_private; +	unsigned int id; +	uint32_t status; + +	status = mdp4_read(mdp4_kms, REG_MDP4_INTR_STATUS); +	mdp4_write(mdp4_kms, REG_MDP4_INTR_CLEAR, status); + +	VERB("status=%08x", status); + +	mdp_dispatch_irqs(mdp_kms, status); + +	for (id = 0; id < priv->num_crtcs; id++) +		if (status & mdp4_crtc_vblank(priv->crtcs[id])) +			drm_handle_vblank(dev, id); + +	return IRQ_HANDLED; +} + +int mdp4_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) +{ +	mdp_update_vblank_mask(to_mdp_kms(kms), +			mdp4_crtc_vblank(crtc), true); +	return 0; +} + +void mdp4_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) +{ +	mdp_update_vblank_mask(to_mdp_kms(kms), +			mdp4_crtc_vblank(crtc), false); +} diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c new file mode 100644 index 00000000000..0bb4faa1752 --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c @@ -0,0 +1,418 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + + +#include "msm_drv.h" +#include "msm_mmu.h" +#include "mdp4_kms.h" + +static struct mdp4_platform_config *mdp4_get_config(struct platform_device *dev); + +static int mdp4_hw_init(struct msm_kms *kms) +{ +	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); +	struct drm_device *dev = mdp4_kms->dev; +	uint32_t version, major, minor, dmap_cfg, vg_cfg; +	unsigned long clk; +	int ret = 0; + +	pm_runtime_get_sync(dev->dev); + +	mdp4_enable(mdp4_kms); +	version = mdp4_read(mdp4_kms, REG_MDP4_VERSION); +	mdp4_disable(mdp4_kms); + +	major = FIELD(version, MDP4_VERSION_MAJOR); +	minor = FIELD(version, MDP4_VERSION_MINOR); + +	DBG("found MDP4 version v%d.%d", major, minor); + +	if (major != 4) { +		dev_err(dev->dev, "unexpected MDP version: v%d.%d\n", +				major, minor); +		ret = -ENXIO; +		goto out; +	} + +	mdp4_kms->rev = minor; + +	if (mdp4_kms->dsi_pll_vdda) { +		if ((mdp4_kms->rev == 2) || (mdp4_kms->rev == 4)) { +			ret = regulator_set_voltage(mdp4_kms->dsi_pll_vdda, +					1200000, 1200000); +			if (ret) { +				dev_err(dev->dev, +					"failed to set dsi_pll_vdda voltage: %d\n", ret); +				goto out; +			} +		} +	} + +	if (mdp4_kms->dsi_pll_vddio) { +		if (mdp4_kms->rev == 2) { +			ret = regulator_set_voltage(mdp4_kms->dsi_pll_vddio, +					1800000, 1800000); +			if (ret) { +				dev_err(dev->dev, +					"failed to set dsi_pll_vddio voltage: %d\n", ret); +				goto out; +			} +		} +	} + +	if (mdp4_kms->rev > 1) { +		mdp4_write(mdp4_kms, REG_MDP4_CS_CONTROLLER0, 0x0707ffff); +		mdp4_write(mdp4_kms, REG_MDP4_CS_CONTROLLER1, 0x03073f3f); +	} + +	mdp4_write(mdp4_kms, REG_MDP4_PORTMAP_MODE, 0x3); + +	/* max read pending cmd config, 3 pending requests: */ +	mdp4_write(mdp4_kms, REG_MDP4_READ_CNFG, 0x02222); + +	clk = clk_get_rate(mdp4_kms->clk); + +	if ((mdp4_kms->rev >= 1) || (clk >= 90000000)) { +		dmap_cfg = 0x47;     /* 16 bytes-burst x 8 req */ +		vg_cfg = 0x47;       /* 16 bytes-burs x 8 req */ +	} else { +		dmap_cfg = 0x27;     /* 8 bytes-burst x 8 req */ +		vg_cfg = 0x43;       /* 16 bytes-burst x 4 req */ +	} + +	DBG("fetch config: dmap=%02x, vg=%02x", dmap_cfg, vg_cfg); + +	mdp4_write(mdp4_kms, REG_MDP4_DMA_FETCH_CONFIG(DMA_P), dmap_cfg); +	mdp4_write(mdp4_kms, REG_MDP4_DMA_FETCH_CONFIG(DMA_E), dmap_cfg); + +	mdp4_write(mdp4_kms, REG_MDP4_PIPE_FETCH_CONFIG(VG1), vg_cfg); +	mdp4_write(mdp4_kms, REG_MDP4_PIPE_FETCH_CONFIG(VG2), vg_cfg); +	mdp4_write(mdp4_kms, REG_MDP4_PIPE_FETCH_CONFIG(RGB1), vg_cfg); +	mdp4_write(mdp4_kms, REG_MDP4_PIPE_FETCH_CONFIG(RGB2), vg_cfg); + +	if (mdp4_kms->rev >= 2) +		mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG_UPDATE_METHOD, 1); + +	/* disable CSC matrix / YUV by default: */ +	mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(VG1), 0); +	mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(VG2), 0); +	mdp4_write(mdp4_kms, REG_MDP4_DMA_P_OP_MODE, 0); +	mdp4_write(mdp4_kms, REG_MDP4_DMA_S_OP_MODE, 0); +	mdp4_write(mdp4_kms, REG_MDP4_OVLP_CSC_CONFIG(1), 0); +	mdp4_write(mdp4_kms, REG_MDP4_OVLP_CSC_CONFIG(2), 0); + +	if (mdp4_kms->rev > 1) +		mdp4_write(mdp4_kms, REG_MDP4_RESET_STATUS, 1); + +out: +	pm_runtime_put_sync(dev->dev); + +	return ret; +} + +static long mdp4_round_pixclk(struct msm_kms *kms, unsigned long rate, +		struct drm_encoder *encoder) +{ +	/* if we had >1 encoder, we'd need something more clever: */ +	return mdp4_dtv_round_pixclk(encoder, rate); +} + +static void mdp4_preclose(struct msm_kms *kms, struct drm_file *file) +{ +	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); +	struct msm_drm_private *priv = mdp4_kms->dev->dev_private; +	unsigned i; + +	for (i = 0; i < priv->num_crtcs; i++) +		mdp4_crtc_cancel_pending_flip(priv->crtcs[i], file); +} + +static void mdp4_destroy(struct msm_kms *kms) +{ +	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); +	if (mdp4_kms->blank_cursor_iova) +		msm_gem_put_iova(mdp4_kms->blank_cursor_bo, mdp4_kms->id); +	if (mdp4_kms->blank_cursor_bo) +		drm_gem_object_unreference(mdp4_kms->blank_cursor_bo); +	kfree(mdp4_kms); +} + +static const struct mdp_kms_funcs kms_funcs = { +	.base = { +		.hw_init         = mdp4_hw_init, +		.irq_preinstall  = mdp4_irq_preinstall, +		.irq_postinstall = mdp4_irq_postinstall, +		.irq_uninstall   = mdp4_irq_uninstall, +		.irq             = mdp4_irq, +		.enable_vblank   = mdp4_enable_vblank, +		.disable_vblank  = mdp4_disable_vblank, +		.get_format      = mdp_get_format, +		.round_pixclk    = mdp4_round_pixclk, +		.preclose        = mdp4_preclose, +		.destroy         = mdp4_destroy, +	}, +	.set_irqmask         = mdp4_set_irqmask, +}; + +int mdp4_disable(struct mdp4_kms *mdp4_kms) +{ +	DBG(""); + +	clk_disable_unprepare(mdp4_kms->clk); +	if (mdp4_kms->pclk) +		clk_disable_unprepare(mdp4_kms->pclk); +	clk_disable_unprepare(mdp4_kms->lut_clk); + +	return 0; +} + +int mdp4_enable(struct mdp4_kms *mdp4_kms) +{ +	DBG(""); + +	clk_prepare_enable(mdp4_kms->clk); +	if (mdp4_kms->pclk) +		clk_prepare_enable(mdp4_kms->pclk); +	clk_prepare_enable(mdp4_kms->lut_clk); + +	return 0; +} + +static int modeset_init(struct mdp4_kms *mdp4_kms) +{ +	struct drm_device *dev = mdp4_kms->dev; +	struct msm_drm_private *priv = dev->dev_private; +	struct drm_plane *plane; +	struct drm_crtc *crtc; +	struct drm_encoder *encoder; +	struct hdmi *hdmi; +	int ret; + +	/* +	 *  NOTE: this is a bit simplistic until we add support +	 * for more than just RGB1->DMA_E->DTV->HDMI +	 */ + +	/* construct non-private planes: */ +	plane = mdp4_plane_init(dev, VG1, false); +	if (IS_ERR(plane)) { +		dev_err(dev->dev, "failed to construct plane for VG1\n"); +		ret = PTR_ERR(plane); +		goto fail; +	} +	priv->planes[priv->num_planes++] = plane; + +	plane = mdp4_plane_init(dev, VG2, false); +	if (IS_ERR(plane)) { +		dev_err(dev->dev, "failed to construct plane for VG2\n"); +		ret = PTR_ERR(plane); +		goto fail; +	} +	priv->planes[priv->num_planes++] = plane; + +	/* the CRTCs get constructed with a private plane: */ +	plane = mdp4_plane_init(dev, RGB1, true); +	if (IS_ERR(plane)) { +		dev_err(dev->dev, "failed to construct plane for RGB1\n"); +		ret = PTR_ERR(plane); +		goto fail; +	} + +	crtc  = mdp4_crtc_init(dev, plane, priv->num_crtcs, 1, DMA_E); +	if (IS_ERR(crtc)) { +		dev_err(dev->dev, "failed to construct crtc for DMA_E\n"); +		ret = PTR_ERR(crtc); +		goto fail; +	} +	priv->crtcs[priv->num_crtcs++] = crtc; + +	encoder = mdp4_dtv_encoder_init(dev); +	if (IS_ERR(encoder)) { +		dev_err(dev->dev, "failed to construct DTV encoder\n"); +		ret = PTR_ERR(encoder); +		goto fail; +	} +	encoder->possible_crtcs = 0x1;     /* DTV can be hooked to DMA_E */ +	priv->encoders[priv->num_encoders++] = encoder; + +	hdmi = hdmi_init(dev, encoder); +	if (IS_ERR(hdmi)) { +		ret = PTR_ERR(hdmi); +		dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret); +		goto fail; +	} + +	return 0; + +fail: +	return ret; +} + +static const char *iommu_ports[] = { +		"mdp_port0_cb0", "mdp_port1_cb0", +}; + +struct msm_kms *mdp4_kms_init(struct drm_device *dev) +{ +	struct platform_device *pdev = dev->platformdev; +	struct mdp4_platform_config *config = mdp4_get_config(pdev); +	struct mdp4_kms *mdp4_kms; +	struct msm_kms *kms = NULL; +	struct msm_mmu *mmu; +	int ret; + +	mdp4_kms = kzalloc(sizeof(*mdp4_kms), GFP_KERNEL); +	if (!mdp4_kms) { +		dev_err(dev->dev, "failed to allocate kms\n"); +		ret = -ENOMEM; +		goto fail; +	} + +	mdp_kms_init(&mdp4_kms->base, &kms_funcs); + +	kms = &mdp4_kms->base.base; + +	mdp4_kms->dev = dev; + +	mdp4_kms->mmio = msm_ioremap(pdev, NULL, "MDP4"); +	if (IS_ERR(mdp4_kms->mmio)) { +		ret = PTR_ERR(mdp4_kms->mmio); +		goto fail; +	} + +	mdp4_kms->dsi_pll_vdda = devm_regulator_get(&pdev->dev, "dsi_pll_vdda"); +	if (IS_ERR(mdp4_kms->dsi_pll_vdda)) +		mdp4_kms->dsi_pll_vdda = NULL; + +	mdp4_kms->dsi_pll_vddio = devm_regulator_get(&pdev->dev, "dsi_pll_vddio"); +	if (IS_ERR(mdp4_kms->dsi_pll_vddio)) +		mdp4_kms->dsi_pll_vddio = NULL; + +	mdp4_kms->vdd = devm_regulator_get(&pdev->dev, "vdd"); +	if (IS_ERR(mdp4_kms->vdd)) +		mdp4_kms->vdd = NULL; + +	if (mdp4_kms->vdd) { +		ret = regulator_enable(mdp4_kms->vdd); +		if (ret) { +			dev_err(dev->dev, "failed to enable regulator vdd: %d\n", ret); +			goto fail; +		} +	} + +	mdp4_kms->clk = devm_clk_get(&pdev->dev, "core_clk"); +	if (IS_ERR(mdp4_kms->clk)) { +		dev_err(dev->dev, "failed to get core_clk\n"); +		ret = PTR_ERR(mdp4_kms->clk); +		goto fail; +	} + +	mdp4_kms->pclk = devm_clk_get(&pdev->dev, "iface_clk"); +	if (IS_ERR(mdp4_kms->pclk)) +		mdp4_kms->pclk = NULL; + +	// XXX if (rev >= MDP_REV_42) { ??? +	mdp4_kms->lut_clk = devm_clk_get(&pdev->dev, "lut_clk"); +	if (IS_ERR(mdp4_kms->lut_clk)) { +		dev_err(dev->dev, "failed to get lut_clk\n"); +		ret = PTR_ERR(mdp4_kms->lut_clk); +		goto fail; +	} + +	clk_set_rate(mdp4_kms->clk, config->max_clk); +	clk_set_rate(mdp4_kms->lut_clk, config->max_clk); + +	/* make sure things are off before attaching iommu (bootloader could +	 * have left things on, in which case we'll start getting faults if +	 * we don't disable): +	 */ +	mdp4_enable(mdp4_kms); +	mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 0); +	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0); +	mdp4_write(mdp4_kms, REG_MDP4_DSI_ENABLE, 0); +	mdp4_disable(mdp4_kms); +	mdelay(16); + +	if (config->iommu) { +		mmu = msm_iommu_new(dev, config->iommu); +		if (IS_ERR(mmu)) { +			ret = PTR_ERR(mmu); +			goto fail; +		} +		ret = mmu->funcs->attach(mmu, iommu_ports, +				ARRAY_SIZE(iommu_ports)); +		if (ret) +			goto fail; +	} else { +		dev_info(dev->dev, "no iommu, fallback to phys " +				"contig buffers for scanout\n"); +		mmu = NULL; +	} + +	mdp4_kms->id = msm_register_mmu(dev, mmu); +	if (mdp4_kms->id < 0) { +		ret = mdp4_kms->id; +		dev_err(dev->dev, "failed to register mdp4 iommu: %d\n", ret); +		goto fail; +	} + +	ret = modeset_init(mdp4_kms); +	if (ret) { +		dev_err(dev->dev, "modeset_init failed: %d\n", ret); +		goto fail; +	} + +	mutex_lock(&dev->struct_mutex); +	mdp4_kms->blank_cursor_bo = msm_gem_new(dev, SZ_16K, MSM_BO_WC); +	mutex_unlock(&dev->struct_mutex); +	if (IS_ERR(mdp4_kms->blank_cursor_bo)) { +		ret = PTR_ERR(mdp4_kms->blank_cursor_bo); +		dev_err(dev->dev, "could not allocate blank-cursor bo: %d\n", ret); +		mdp4_kms->blank_cursor_bo = NULL; +		goto fail; +	} + +	ret = msm_gem_get_iova(mdp4_kms->blank_cursor_bo, mdp4_kms->id, +			&mdp4_kms->blank_cursor_iova); +	if (ret) { +		dev_err(dev->dev, "could not pin blank-cursor bo: %d\n", ret); +		goto fail; +	} + +	return kms; + +fail: +	if (kms) +		mdp4_destroy(kms); +	return ERR_PTR(ret); +} + +static struct mdp4_platform_config *mdp4_get_config(struct platform_device *dev) +{ +	static struct mdp4_platform_config config = {}; +#ifdef CONFIG_OF +	/* TODO */ +#else +	if (cpu_is_apq8064()) +		config.max_clk = 266667000; +	else +		config.max_clk = 200000000; + +	config.iommu = msm_get_iommu_domain(DISPLAY_READ_DOMAIN); +#endif +	return &config; +} diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h new file mode 100644 index 00000000000..715520c54cd --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __MDP4_KMS_H__ +#define __MDP4_KMS_H__ + +#include "msm_drv.h" +#include "msm_kms.h" +#include "mdp/mdp_kms.h" +#include "mdp4.xml.h" + +struct mdp4_kms { +	struct mdp_kms base; + +	struct drm_device *dev; + +	int rev; + +	/* mapper-id used to request GEM buffer mapped for scanout: */ +	int id; + +	void __iomem *mmio; + +	struct regulator *dsi_pll_vdda; +	struct regulator *dsi_pll_vddio; +	struct regulator *vdd; + +	struct clk *clk; +	struct clk *pclk; +	struct clk *lut_clk; + +	struct mdp_irq error_handler; + +	/* empty/blank cursor bo to use when cursor is "disabled" */ +	struct drm_gem_object *blank_cursor_bo; +	uint32_t blank_cursor_iova; +}; +#define to_mdp4_kms(x) container_of(x, struct mdp4_kms, base) + +/* platform config data (ie. from DT, or pdata) */ +struct mdp4_platform_config { +	struct iommu_domain *iommu; +	uint32_t max_clk; +}; + +static inline void mdp4_write(struct mdp4_kms *mdp4_kms, u32 reg, u32 data) +{ +	msm_writel(data, mdp4_kms->mmio + reg); +} + +static inline u32 mdp4_read(struct mdp4_kms *mdp4_kms, u32 reg) +{ +	return msm_readl(mdp4_kms->mmio + reg); +} + +static inline uint32_t pipe2flush(enum mdp4_pipe pipe) +{ +	switch (pipe) { +	case VG1:      return MDP4_OVERLAY_FLUSH_VG1; +	case VG2:      return MDP4_OVERLAY_FLUSH_VG2; +	case RGB1:     return MDP4_OVERLAY_FLUSH_RGB1; +	case RGB2:     return MDP4_OVERLAY_FLUSH_RGB1; +	default:       return 0; +	} +} + +static inline uint32_t ovlp2flush(int ovlp) +{ +	switch (ovlp) { +	case 0:        return MDP4_OVERLAY_FLUSH_OVLP0; +	case 1:        return MDP4_OVERLAY_FLUSH_OVLP1; +	default:       return 0; +	} +} + +static inline uint32_t dma2irq(enum mdp4_dma dma) +{ +	switch (dma) { +	case DMA_P:    return MDP4_IRQ_DMA_P_DONE; +	case DMA_S:    return MDP4_IRQ_DMA_S_DONE; +	case DMA_E:    return MDP4_IRQ_DMA_E_DONE; +	default:       return 0; +	} +} + +static inline uint32_t dma2err(enum mdp4_dma dma) +{ +	switch (dma) { +	case DMA_P:    return MDP4_IRQ_PRIMARY_INTF_UDERRUN; +	case DMA_S:    return 0;  // ??? +	case DMA_E:    return MDP4_IRQ_EXTERNAL_INTF_UDERRUN; +	default:       return 0; +	} +} + +static inline uint32_t mixercfg(int mixer, enum mdp4_pipe pipe, +		enum mdp_mixer_stage_id stage) +{ +	uint32_t mixer_cfg = 0; + +	switch (pipe) { +	case VG1: +		mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE0(stage) | +			COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1); +		break; +	case VG2: +		mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE1(stage) | +			COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1); +		break; +	case RGB1: +		mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE2(stage) | +			COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1); +		break; +	case RGB2: +		mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE3(stage) | +			COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1); +		break; +	case RGB3: +		mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE4(stage) | +			COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1); +		break; +	case VG3: +		mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE5(stage) | +			COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1); +		break; +	case VG4: +		mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE6(stage) | +			COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1); +		break; +	default: +		WARN_ON("invalid pipe"); +		break; +	} + +	return mixer_cfg; +} + +int mdp4_disable(struct mdp4_kms *mdp4_kms); +int mdp4_enable(struct mdp4_kms *mdp4_kms); + +void mdp4_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask); +void mdp4_irq_preinstall(struct msm_kms *kms); +int mdp4_irq_postinstall(struct msm_kms *kms); +void mdp4_irq_uninstall(struct msm_kms *kms); +irqreturn_t mdp4_irq(struct msm_kms *kms); +int mdp4_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); +void mdp4_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); + +static inline +uint32_t mdp4_get_formats(enum mdp4_pipe pipe_id, uint32_t *pixel_formats, +		uint32_t max_formats) +{ +	/* TODO when we have YUV, we need to filter supported formats +	 * based on pipe_id.. +	 */ +	return mdp_get_formats(pixel_formats, max_formats); +} + +void mdp4_plane_install_properties(struct drm_plane *plane, +		struct drm_mode_object *obj); +void mdp4_plane_set_scanout(struct drm_plane *plane, +		struct drm_framebuffer *fb); +int mdp4_plane_mode_set(struct drm_plane *plane, +		struct drm_crtc *crtc, struct drm_framebuffer *fb, +		int crtc_x, int crtc_y, +		unsigned int crtc_w, unsigned int crtc_h, +		uint32_t src_x, uint32_t src_y, +		uint32_t src_w, uint32_t src_h); +enum mdp4_pipe mdp4_plane_pipe(struct drm_plane *plane); +struct drm_plane *mdp4_plane_init(struct drm_device *dev, +		enum mdp4_pipe pipe_id, bool private_plane); + +uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc); +void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file); +void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config); +void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf); +void mdp4_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane); +void mdp4_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane); +struct drm_crtc *mdp4_crtc_init(struct drm_device *dev, +		struct drm_plane *plane, int id, int ovlp_id, +		enum mdp4_dma dma_id); + +long mdp4_dtv_round_pixclk(struct drm_encoder *encoder, unsigned long rate); +struct drm_encoder *mdp4_dtv_encoder_init(struct drm_device *dev); + +#ifdef CONFIG_MSM_BUS_SCALING +static inline int match_dev_name(struct device *dev, void *data) +{ +	return !strcmp(dev_name(dev), data); +} +/* bus scaling data is associated with extra pointless platform devices, + * "dtv", etc.. this is a bit of a hack, but we need a way for encoders + * to find their pdata to make the bus-scaling stuff work. + */ +static inline void *mdp4_find_pdata(const char *devname) +{ +	struct device *dev; +	dev = bus_find_device(&platform_bus_type, NULL, +			(void *)devname, match_dev_name); +	return dev ? dev->platform_data : NULL; +} +#endif + +#endif /* __MDP4_KMS_H__ */ diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c new file mode 100644 index 00000000000..66f33dba1eb --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include "mdp4_kms.h" + + +struct mdp4_plane { +	struct drm_plane base; +	const char *name; + +	enum mdp4_pipe pipe; + +	uint32_t nformats; +	uint32_t formats[32]; + +	bool enabled; +}; +#define to_mdp4_plane(x) container_of(x, struct mdp4_plane, base) + +static struct mdp4_kms *get_kms(struct drm_plane *plane) +{ +	struct msm_drm_private *priv = plane->dev->dev_private; +	return to_mdp4_kms(to_mdp_kms(priv->kms)); +} + +static int mdp4_plane_update(struct drm_plane *plane, +		struct drm_crtc *crtc, struct drm_framebuffer *fb, +		int crtc_x, int crtc_y, +		unsigned int crtc_w, unsigned int crtc_h, +		uint32_t src_x, uint32_t src_y, +		uint32_t src_w, uint32_t src_h) +{ +	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); + +	mdp4_plane->enabled = true; + +	if (plane->fb) +		drm_framebuffer_unreference(plane->fb); + +	drm_framebuffer_reference(fb); + +	return mdp4_plane_mode_set(plane, crtc, fb, +			crtc_x, crtc_y, crtc_w, crtc_h, +			src_x, src_y, src_w, src_h); +} + +static int mdp4_plane_disable(struct drm_plane *plane) +{ +	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); +	DBG("%s: disable", mdp4_plane->name); +	if (plane->crtc) +		mdp4_crtc_detach(plane->crtc, plane); +	return 0; +} + +static void mdp4_plane_destroy(struct drm_plane *plane) +{ +	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); + +	mdp4_plane_disable(plane); +	drm_plane_cleanup(plane); + +	kfree(mdp4_plane); +} + +/* helper to install properties which are common to planes and crtcs */ +void mdp4_plane_install_properties(struct drm_plane *plane, +		struct drm_mode_object *obj) +{ +	// XXX +} + +int mdp4_plane_set_property(struct drm_plane *plane, +		struct drm_property *property, uint64_t val) +{ +	// XXX +	return -EINVAL; +} + +static const struct drm_plane_funcs mdp4_plane_funcs = { +		.update_plane = mdp4_plane_update, +		.disable_plane = mdp4_plane_disable, +		.destroy = mdp4_plane_destroy, +		.set_property = mdp4_plane_set_property, +}; + +void mdp4_plane_set_scanout(struct drm_plane *plane, +		struct drm_framebuffer *fb) +{ +	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); +	struct mdp4_kms *mdp4_kms = get_kms(plane); +	enum mdp4_pipe pipe = mdp4_plane->pipe; +	uint32_t iova; + +	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_STRIDE_A(pipe), +			MDP4_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) | +			MDP4_PIPE_SRC_STRIDE_A_P1(fb->pitches[1])); + +	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_STRIDE_B(pipe), +			MDP4_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) | +			MDP4_PIPE_SRC_STRIDE_B_P3(fb->pitches[3])); + +	msm_gem_get_iova(msm_framebuffer_bo(fb, 0), mdp4_kms->id, &iova); +	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP0_BASE(pipe), iova); + +	plane->fb = fb; +} + +#define MDP4_VG_PHASE_STEP_DEFAULT	0x20000000 + +int mdp4_plane_mode_set(struct drm_plane *plane, +		struct drm_crtc *crtc, struct drm_framebuffer *fb, +		int crtc_x, int crtc_y, +		unsigned int crtc_w, unsigned int crtc_h, +		uint32_t src_x, uint32_t src_y, +		uint32_t src_w, uint32_t src_h) +{ +	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); +	struct mdp4_kms *mdp4_kms = get_kms(plane); +	enum mdp4_pipe pipe = mdp4_plane->pipe; +	const struct mdp_format *format; +	uint32_t op_mode = 0; +	uint32_t phasex_step = MDP4_VG_PHASE_STEP_DEFAULT; +	uint32_t phasey_step = MDP4_VG_PHASE_STEP_DEFAULT; + +	/* src values are in Q16 fixed point, convert to integer: */ +	src_x = src_x >> 16; +	src_y = src_y >> 16; +	src_w = src_w >> 16; +	src_h = src_h >> 16; + +	DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp4_plane->name, +			fb->base.id, src_x, src_y, src_w, src_h, +			crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h); + +	if (src_w != crtc_w) { +		op_mode |= MDP4_PIPE_OP_MODE_SCALEX_EN; +		/* TODO calc phasex_step */ +	} + +	if (src_h != crtc_h) { +		op_mode |= MDP4_PIPE_OP_MODE_SCALEY_EN; +		/* TODO calc phasey_step */ +	} + +	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_SIZE(pipe), +			MDP4_PIPE_SRC_SIZE_WIDTH(src_w) | +			MDP4_PIPE_SRC_SIZE_HEIGHT(src_h)); + +	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_XY(pipe), +			MDP4_PIPE_SRC_XY_X(src_x) | +			MDP4_PIPE_SRC_XY_Y(src_y)); + +	mdp4_write(mdp4_kms, REG_MDP4_PIPE_DST_SIZE(pipe), +			MDP4_PIPE_DST_SIZE_WIDTH(crtc_w) | +			MDP4_PIPE_DST_SIZE_HEIGHT(crtc_h)); + +	mdp4_write(mdp4_kms, REG_MDP4_PIPE_DST_XY(pipe), +			MDP4_PIPE_DST_XY_X(crtc_x) | +			MDP4_PIPE_DST_XY_Y(crtc_y)); + +	mdp4_plane_set_scanout(plane, fb); + +	format = to_mdp_format(msm_framebuffer_format(fb)); + +	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_FORMAT(pipe), +			MDP4_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) | +			MDP4_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) | +			MDP4_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) | +			MDP4_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) | +			COND(format->alpha_enable, MDP4_PIPE_SRC_FORMAT_ALPHA_ENABLE) | +			MDP4_PIPE_SRC_FORMAT_CPP(format->cpp - 1) | +			MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) | +			COND(format->unpack_tight, MDP4_PIPE_SRC_FORMAT_UNPACK_TIGHT)); + +	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_UNPACK(pipe), +			MDP4_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) | +			MDP4_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) | +			MDP4_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) | +			MDP4_PIPE_SRC_UNPACK_ELEM3(format->unpack[3])); + +	mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(pipe), op_mode); +	mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEX_STEP(pipe), phasex_step); +	mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEY_STEP(pipe), phasey_step); + +	/* TODO detach from old crtc (if we had more than one) */ +	mdp4_crtc_attach(crtc, plane); + +	return 0; +} + +static const char *pipe_names[] = { +		"VG1", "VG2", +		"RGB1", "RGB2", "RGB3", +		"VG3", "VG4", +}; + +enum mdp4_pipe mdp4_plane_pipe(struct drm_plane *plane) +{ +	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); +	return mdp4_plane->pipe; +} + +/* initialize plane */ +struct drm_plane *mdp4_plane_init(struct drm_device *dev, +		enum mdp4_pipe pipe_id, bool private_plane) +{ +	struct drm_plane *plane = NULL; +	struct mdp4_plane *mdp4_plane; +	int ret; +	enum drm_plane_type type; + +	mdp4_plane = kzalloc(sizeof(*mdp4_plane), GFP_KERNEL); +	if (!mdp4_plane) { +		ret = -ENOMEM; +		goto fail; +	} + +	plane = &mdp4_plane->base; + +	mdp4_plane->pipe = pipe_id; +	mdp4_plane->name = pipe_names[pipe_id]; + +	mdp4_plane->nformats = mdp4_get_formats(pipe_id, mdp4_plane->formats, +			ARRAY_SIZE(mdp4_plane->formats)); + +	type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; +	drm_universal_plane_init(dev, plane, 0xff, &mdp4_plane_funcs, +				 mdp4_plane->formats, mdp4_plane->nformats, +				 type); + +	mdp4_plane_install_properties(plane, &plane->base); + +	return plane; + +fail: +	if (plane) +		mdp4_plane_destroy(plane); + +	return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h new file mode 100644 index 00000000000..0aa51517f82 --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h @@ -0,0 +1,1036 @@ +#ifndef MDP5_XML +#define MDP5_XML + +/* Autogenerated file, DO NOT EDIT manually! + +This file was generated by the rules-ng-ng headergen tool in this git repository: +http://github.com/freedreno/envytools/ +git clone https://github.com/freedreno/envytools.git + +The rules-ng-ng source files this header was generated from are: +- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    647 bytes, from 2013-11-30 14:45:35) +- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  17996 bytes, from 2013-12-01 19:10:31) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2013-11-30 15:00:52) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2013-12-03 20:59:13) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  20932 bytes, from 2013-12-01 15:13:04) + +Copyright (C) 2013 by the following authors: +- Rob Clark <robdclark@gmail.com> (robclark) + +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 THE COPYRIGHT OWNER(S) 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. +*/ + + +enum mdp5_intf { +	INTF_DSI = 1, +	INTF_HDMI = 3, +	INTF_LCDC = 5, +	INTF_eDP = 9, +}; + +enum mdp5_intfnum { +	NO_INTF = 0, +	INTF0 = 1, +	INTF1 = 2, +	INTF2 = 3, +	INTF3 = 4, +}; + +enum mdp5_pipe { +	SSPP_VIG0 = 0, +	SSPP_VIG1 = 1, +	SSPP_VIG2 = 2, +	SSPP_RGB0 = 3, +	SSPP_RGB1 = 4, +	SSPP_RGB2 = 5, +	SSPP_DMA0 = 6, +	SSPP_DMA1 = 7, +}; + +enum mdp5_ctl_mode { +	MODE_NONE = 0, +	MODE_ROT0 = 1, +	MODE_ROT1 = 2, +	MODE_WB0 = 3, +	MODE_WB1 = 4, +	MODE_WFD = 5, +}; + +enum mdp5_pack_3d { +	PACK_3D_FRAME_INT = 0, +	PACK_3D_H_ROW_INT = 1, +	PACK_3D_V_ROW_INT = 2, +	PACK_3D_COL_INT = 3, +}; + +enum mdp5_chroma_samp_type { +	CHROMA_RGB = 0, +	CHROMA_H2V1 = 1, +	CHROMA_H1V2 = 2, +	CHROMA_420 = 3, +}; + +enum mdp5_scale_filter { +	SCALE_FILTER_NEAREST = 0, +	SCALE_FILTER_BIL = 1, +	SCALE_FILTER_PCMN = 2, +	SCALE_FILTER_CA = 3, +}; + +enum mdp5_pipe_bwc { +	BWC_LOSSLESS = 0, +	BWC_Q_HIGH = 1, +	BWC_Q_MED = 2, +}; + +enum mdp5_client_id { +	CID_UNUSED = 0, +	CID_VIG0_Y = 1, +	CID_VIG0_CR = 2, +	CID_VIG0_CB = 3, +	CID_VIG1_Y = 4, +	CID_VIG1_CR = 5, +	CID_VIG1_CB = 6, +	CID_VIG2_Y = 7, +	CID_VIG2_CR = 8, +	CID_VIG2_CB = 9, +	CID_DMA0_Y = 10, +	CID_DMA0_CR = 11, +	CID_DMA0_CB = 12, +	CID_DMA1_Y = 13, +	CID_DMA1_CR = 14, +	CID_DMA1_CB = 15, +	CID_RGB0 = 16, +	CID_RGB1 = 17, +	CID_RGB2 = 18, +	CID_MAX = 19, +}; + +enum mdp5_igc_type { +	IGC_VIG = 0, +	IGC_RGB = 1, +	IGC_DMA = 2, +	IGC_DSPP = 3, +}; + +#define MDP5_IRQ_INTF0_WB_ROT_COMP				0x00000001 +#define MDP5_IRQ_INTF1_WB_ROT_COMP				0x00000002 +#define MDP5_IRQ_INTF2_WB_ROT_COMP				0x00000004 +#define MDP5_IRQ_INTF3_WB_ROT_COMP				0x00000008 +#define MDP5_IRQ_INTF0_WB_WFD					0x00000010 +#define MDP5_IRQ_INTF1_WB_WFD					0x00000020 +#define MDP5_IRQ_INTF2_WB_WFD					0x00000040 +#define MDP5_IRQ_INTF3_WB_WFD					0x00000080 +#define MDP5_IRQ_INTF0_PING_PONG_COMP				0x00000100 +#define MDP5_IRQ_INTF1_PING_PONG_COMP				0x00000200 +#define MDP5_IRQ_INTF2_PING_PONG_COMP				0x00000400 +#define MDP5_IRQ_INTF3_PING_PONG_COMP				0x00000800 +#define MDP5_IRQ_INTF0_PING_PONG_RD_PTR				0x00001000 +#define MDP5_IRQ_INTF1_PING_PONG_RD_PTR				0x00002000 +#define MDP5_IRQ_INTF2_PING_PONG_RD_PTR				0x00004000 +#define MDP5_IRQ_INTF3_PING_PONG_RD_PTR				0x00008000 +#define MDP5_IRQ_INTF0_PING_PONG_WR_PTR				0x00010000 +#define MDP5_IRQ_INTF1_PING_PONG_WR_PTR				0x00020000 +#define MDP5_IRQ_INTF2_PING_PONG_WR_PTR				0x00040000 +#define MDP5_IRQ_INTF3_PING_PONG_WR_PTR				0x00080000 +#define MDP5_IRQ_INTF0_PING_PONG_AUTO_REF			0x00100000 +#define MDP5_IRQ_INTF1_PING_PONG_AUTO_REF			0x00200000 +#define MDP5_IRQ_INTF2_PING_PONG_AUTO_REF			0x00400000 +#define MDP5_IRQ_INTF3_PING_PONG_AUTO_REF			0x00800000 +#define MDP5_IRQ_INTF0_UNDER_RUN				0x01000000 +#define MDP5_IRQ_INTF0_VSYNC					0x02000000 +#define MDP5_IRQ_INTF1_UNDER_RUN				0x04000000 +#define MDP5_IRQ_INTF1_VSYNC					0x08000000 +#define MDP5_IRQ_INTF2_UNDER_RUN				0x10000000 +#define MDP5_IRQ_INTF2_VSYNC					0x20000000 +#define MDP5_IRQ_INTF3_UNDER_RUN				0x40000000 +#define MDP5_IRQ_INTF3_VSYNC					0x80000000 +#define REG_MDP5_HW_VERSION					0x00000000 + +#define REG_MDP5_HW_INTR_STATUS					0x00000010 +#define MDP5_HW_INTR_STATUS_INTR_MDP				0x00000001 +#define MDP5_HW_INTR_STATUS_INTR_DSI0				0x00000010 +#define MDP5_HW_INTR_STATUS_INTR_DSI1				0x00000020 +#define MDP5_HW_INTR_STATUS_INTR_HDMI				0x00000100 +#define MDP5_HW_INTR_STATUS_INTR_EDP				0x00001000 + +#define REG_MDP5_MDP_VERSION					0x00000100 +#define MDP5_MDP_VERSION_MINOR__MASK				0x00ff0000 +#define MDP5_MDP_VERSION_MINOR__SHIFT				16 +static inline uint32_t MDP5_MDP_VERSION_MINOR(uint32_t val) +{ +	return ((val) << MDP5_MDP_VERSION_MINOR__SHIFT) & MDP5_MDP_VERSION_MINOR__MASK; +} +#define MDP5_MDP_VERSION_MAJOR__MASK				0xf0000000 +#define MDP5_MDP_VERSION_MAJOR__SHIFT				28 +static inline uint32_t MDP5_MDP_VERSION_MAJOR(uint32_t val) +{ +	return ((val) << MDP5_MDP_VERSION_MAJOR__SHIFT) & MDP5_MDP_VERSION_MAJOR__MASK; +} + +#define REG_MDP5_DISP_INTF_SEL					0x00000104 +#define MDP5_DISP_INTF_SEL_INTF0__MASK				0x000000ff +#define MDP5_DISP_INTF_SEL_INTF0__SHIFT				0 +static inline uint32_t MDP5_DISP_INTF_SEL_INTF0(enum mdp5_intf val) +{ +	return ((val) << MDP5_DISP_INTF_SEL_INTF0__SHIFT) & MDP5_DISP_INTF_SEL_INTF0__MASK; +} +#define MDP5_DISP_INTF_SEL_INTF1__MASK				0x0000ff00 +#define MDP5_DISP_INTF_SEL_INTF1__SHIFT				8 +static inline uint32_t MDP5_DISP_INTF_SEL_INTF1(enum mdp5_intf val) +{ +	return ((val) << MDP5_DISP_INTF_SEL_INTF1__SHIFT) & MDP5_DISP_INTF_SEL_INTF1__MASK; +} +#define MDP5_DISP_INTF_SEL_INTF2__MASK				0x00ff0000 +#define MDP5_DISP_INTF_SEL_INTF2__SHIFT				16 +static inline uint32_t MDP5_DISP_INTF_SEL_INTF2(enum mdp5_intf val) +{ +	return ((val) << MDP5_DISP_INTF_SEL_INTF2__SHIFT) & MDP5_DISP_INTF_SEL_INTF2__MASK; +} +#define MDP5_DISP_INTF_SEL_INTF3__MASK				0xff000000 +#define MDP5_DISP_INTF_SEL_INTF3__SHIFT				24 +static inline uint32_t MDP5_DISP_INTF_SEL_INTF3(enum mdp5_intf val) +{ +	return ((val) << MDP5_DISP_INTF_SEL_INTF3__SHIFT) & MDP5_DISP_INTF_SEL_INTF3__MASK; +} + +#define REG_MDP5_INTR_EN					0x00000110 + +#define REG_MDP5_INTR_STATUS					0x00000114 + +#define REG_MDP5_INTR_CLEAR					0x00000118 + +#define REG_MDP5_HIST_INTR_EN					0x0000011c + +#define REG_MDP5_HIST_INTR_STATUS				0x00000120 + +#define REG_MDP5_HIST_INTR_CLEAR				0x00000124 + +static inline uint32_t REG_MDP5_SMP_ALLOC_W(uint32_t i0) { return 0x00000180 + 0x4*i0; } + +static inline uint32_t REG_MDP5_SMP_ALLOC_W_REG(uint32_t i0) { return 0x00000180 + 0x4*i0; } +#define MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK			0x000000ff +#define MDP5_SMP_ALLOC_W_REG_CLIENT0__SHIFT			0 +static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT0(enum mdp5_client_id val) +{ +	return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT0__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK; +} +#define MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK			0x0000ff00 +#define MDP5_SMP_ALLOC_W_REG_CLIENT1__SHIFT			8 +static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT1(enum mdp5_client_id val) +{ +	return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT1__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK; +} +#define MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK			0x00ff0000 +#define MDP5_SMP_ALLOC_W_REG_CLIENT2__SHIFT			16 +static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT2(enum mdp5_client_id val) +{ +	return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT2__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK; +} + +static inline uint32_t REG_MDP5_SMP_ALLOC_R(uint32_t i0) { return 0x00000230 + 0x4*i0; } + +static inline uint32_t REG_MDP5_SMP_ALLOC_R_REG(uint32_t i0) { return 0x00000230 + 0x4*i0; } +#define MDP5_SMP_ALLOC_R_REG_CLIENT0__MASK			0x000000ff +#define MDP5_SMP_ALLOC_R_REG_CLIENT0__SHIFT			0 +static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT0(enum mdp5_client_id val) +{ +	return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT0__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT0__MASK; +} +#define MDP5_SMP_ALLOC_R_REG_CLIENT1__MASK			0x0000ff00 +#define MDP5_SMP_ALLOC_R_REG_CLIENT1__SHIFT			8 +static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT1(enum mdp5_client_id val) +{ +	return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT1__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT1__MASK; +} +#define MDP5_SMP_ALLOC_R_REG_CLIENT2__MASK			0x00ff0000 +#define MDP5_SMP_ALLOC_R_REG_CLIENT2__SHIFT			16 +static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT2(enum mdp5_client_id val) +{ +	return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT2__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT2__MASK; +} + +static inline uint32_t __offset_IGC(enum mdp5_igc_type idx) +{ +	switch (idx) { +		case IGC_VIG: return 0x00000300; +		case IGC_RGB: return 0x00000310; +		case IGC_DMA: return 0x00000320; +		case IGC_DSPP: return 0x00000400; +		default: return INVALID_IDX(idx); +	} +} +static inline uint32_t REG_MDP5_IGC(enum mdp5_igc_type i0) { return 0x00000000 + __offset_IGC(i0); } + +static inline uint32_t REG_MDP5_IGC_LUT(enum mdp5_igc_type i0, uint32_t i1) { return 0x00000000 + __offset_IGC(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP5_IGC_LUT_REG(enum mdp5_igc_type i0, uint32_t i1) { return 0x00000000 + __offset_IGC(i0) + 0x4*i1; } +#define MDP5_IGC_LUT_REG_VAL__MASK				0x00000fff +#define MDP5_IGC_LUT_REG_VAL__SHIFT				0 +static inline uint32_t MDP5_IGC_LUT_REG_VAL(uint32_t val) +{ +	return ((val) << MDP5_IGC_LUT_REG_VAL__SHIFT) & MDP5_IGC_LUT_REG_VAL__MASK; +} +#define MDP5_IGC_LUT_REG_INDEX_UPDATE				0x02000000 +#define MDP5_IGC_LUT_REG_DISABLE_PIPE_0				0x10000000 +#define MDP5_IGC_LUT_REG_DISABLE_PIPE_1				0x20000000 +#define MDP5_IGC_LUT_REG_DISABLE_PIPE_2				0x40000000 + +static inline uint32_t REG_MDP5_CTL(uint32_t i0) { return 0x00000600 + 0x100*i0; } + +static inline uint32_t REG_MDP5_CTL_LAYER(uint32_t i0, uint32_t i1) { return 0x00000600 + 0x100*i0 + 0x4*i1; } + +static inline uint32_t REG_MDP5_CTL_LAYER_REG(uint32_t i0, uint32_t i1) { return 0x00000600 + 0x100*i0 + 0x4*i1; } +#define MDP5_CTL_LAYER_REG_VIG0__MASK				0x00000007 +#define MDP5_CTL_LAYER_REG_VIG0__SHIFT				0 +static inline uint32_t MDP5_CTL_LAYER_REG_VIG0(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP5_CTL_LAYER_REG_VIG0__SHIFT) & MDP5_CTL_LAYER_REG_VIG0__MASK; +} +#define MDP5_CTL_LAYER_REG_VIG1__MASK				0x00000038 +#define MDP5_CTL_LAYER_REG_VIG1__SHIFT				3 +static inline uint32_t MDP5_CTL_LAYER_REG_VIG1(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP5_CTL_LAYER_REG_VIG1__SHIFT) & MDP5_CTL_LAYER_REG_VIG1__MASK; +} +#define MDP5_CTL_LAYER_REG_VIG2__MASK				0x000001c0 +#define MDP5_CTL_LAYER_REG_VIG2__SHIFT				6 +static inline uint32_t MDP5_CTL_LAYER_REG_VIG2(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP5_CTL_LAYER_REG_VIG2__SHIFT) & MDP5_CTL_LAYER_REG_VIG2__MASK; +} +#define MDP5_CTL_LAYER_REG_RGB0__MASK				0x00000e00 +#define MDP5_CTL_LAYER_REG_RGB0__SHIFT				9 +static inline uint32_t MDP5_CTL_LAYER_REG_RGB0(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP5_CTL_LAYER_REG_RGB0__SHIFT) & MDP5_CTL_LAYER_REG_RGB0__MASK; +} +#define MDP5_CTL_LAYER_REG_RGB1__MASK				0x00007000 +#define MDP5_CTL_LAYER_REG_RGB1__SHIFT				12 +static inline uint32_t MDP5_CTL_LAYER_REG_RGB1(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP5_CTL_LAYER_REG_RGB1__SHIFT) & MDP5_CTL_LAYER_REG_RGB1__MASK; +} +#define MDP5_CTL_LAYER_REG_RGB2__MASK				0x00038000 +#define MDP5_CTL_LAYER_REG_RGB2__SHIFT				15 +static inline uint32_t MDP5_CTL_LAYER_REG_RGB2(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP5_CTL_LAYER_REG_RGB2__SHIFT) & MDP5_CTL_LAYER_REG_RGB2__MASK; +} +#define MDP5_CTL_LAYER_REG_DMA0__MASK				0x001c0000 +#define MDP5_CTL_LAYER_REG_DMA0__SHIFT				18 +static inline uint32_t MDP5_CTL_LAYER_REG_DMA0(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP5_CTL_LAYER_REG_DMA0__SHIFT) & MDP5_CTL_LAYER_REG_DMA0__MASK; +} +#define MDP5_CTL_LAYER_REG_DMA1__MASK				0x00e00000 +#define MDP5_CTL_LAYER_REG_DMA1__SHIFT				21 +static inline uint32_t MDP5_CTL_LAYER_REG_DMA1(enum mdp_mixer_stage_id val) +{ +	return ((val) << MDP5_CTL_LAYER_REG_DMA1__SHIFT) & MDP5_CTL_LAYER_REG_DMA1__MASK; +} +#define MDP5_CTL_LAYER_REG_BORDER_COLOR				0x01000000 +#define MDP5_CTL_LAYER_REG_CURSOR_OUT				0x02000000 + +static inline uint32_t REG_MDP5_CTL_OP(uint32_t i0) { return 0x00000614 + 0x100*i0; } +#define MDP5_CTL_OP_MODE__MASK					0x0000000f +#define MDP5_CTL_OP_MODE__SHIFT					0 +static inline uint32_t MDP5_CTL_OP_MODE(enum mdp5_ctl_mode val) +{ +	return ((val) << MDP5_CTL_OP_MODE__SHIFT) & MDP5_CTL_OP_MODE__MASK; +} +#define MDP5_CTL_OP_INTF_NUM__MASK				0x00000070 +#define MDP5_CTL_OP_INTF_NUM__SHIFT				4 +static inline uint32_t MDP5_CTL_OP_INTF_NUM(enum mdp5_intfnum val) +{ +	return ((val) << MDP5_CTL_OP_INTF_NUM__SHIFT) & MDP5_CTL_OP_INTF_NUM__MASK; +} +#define MDP5_CTL_OP_CMD_MODE					0x00020000 +#define MDP5_CTL_OP_PACK_3D_ENABLE				0x00080000 +#define MDP5_CTL_OP_PACK_3D__MASK				0x00300000 +#define MDP5_CTL_OP_PACK_3D__SHIFT				20 +static inline uint32_t MDP5_CTL_OP_PACK_3D(enum mdp5_pack_3d val) +{ +	return ((val) << MDP5_CTL_OP_PACK_3D__SHIFT) & MDP5_CTL_OP_PACK_3D__MASK; +} + +static inline uint32_t REG_MDP5_CTL_FLUSH(uint32_t i0) { return 0x00000618 + 0x100*i0; } +#define MDP5_CTL_FLUSH_VIG0					0x00000001 +#define MDP5_CTL_FLUSH_VIG1					0x00000002 +#define MDP5_CTL_FLUSH_VIG2					0x00000004 +#define MDP5_CTL_FLUSH_RGB0					0x00000008 +#define MDP5_CTL_FLUSH_RGB1					0x00000010 +#define MDP5_CTL_FLUSH_RGB2					0x00000020 +#define MDP5_CTL_FLUSH_LM0					0x00000040 +#define MDP5_CTL_FLUSH_LM1					0x00000080 +#define MDP5_CTL_FLUSH_LM2					0x00000100 +#define MDP5_CTL_FLUSH_DMA0					0x00000800 +#define MDP5_CTL_FLUSH_DMA1					0x00001000 +#define MDP5_CTL_FLUSH_DSPP0					0x00002000 +#define MDP5_CTL_FLUSH_DSPP1					0x00004000 +#define MDP5_CTL_FLUSH_DSPP2					0x00008000 +#define MDP5_CTL_FLUSH_CTL					0x00020000 + +static inline uint32_t REG_MDP5_CTL_START(uint32_t i0) { return 0x0000061c + 0x100*i0; } + +static inline uint32_t REG_MDP5_CTL_PACK_3D(uint32_t i0) { return 0x00000620 + 0x100*i0; } + +static inline uint32_t REG_MDP5_PIPE(enum mdp5_pipe i0) { return 0x00001200 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_HIST_CTL_BASE(enum mdp5_pipe i0) { return 0x000014c4 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_HIST_LUT_BASE(enum mdp5_pipe i0) { return 0x000014f0 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_HIST_LUT_SWAP(enum mdp5_pipe i0) { return 0x00001500 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_SRC_SIZE(enum mdp5_pipe i0) { return 0x00001200 + 0x400*i0; } +#define MDP5_PIPE_SRC_SIZE_HEIGHT__MASK				0xffff0000 +#define MDP5_PIPE_SRC_SIZE_HEIGHT__SHIFT			16 +static inline uint32_t MDP5_PIPE_SRC_SIZE_HEIGHT(uint32_t val) +{ +	return ((val) << MDP5_PIPE_SRC_SIZE_HEIGHT__SHIFT) & MDP5_PIPE_SRC_SIZE_HEIGHT__MASK; +} +#define MDP5_PIPE_SRC_SIZE_WIDTH__MASK				0x0000ffff +#define MDP5_PIPE_SRC_SIZE_WIDTH__SHIFT				0 +static inline uint32_t MDP5_PIPE_SRC_SIZE_WIDTH(uint32_t val) +{ +	return ((val) << MDP5_PIPE_SRC_SIZE_WIDTH__SHIFT) & MDP5_PIPE_SRC_SIZE_WIDTH__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_SRC_IMG_SIZE(enum mdp5_pipe i0) { return 0x00001204 + 0x400*i0; } +#define MDP5_PIPE_SRC_IMG_SIZE_HEIGHT__MASK			0xffff0000 +#define MDP5_PIPE_SRC_IMG_SIZE_HEIGHT__SHIFT			16 +static inline uint32_t MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(uint32_t val) +{ +	return ((val) << MDP5_PIPE_SRC_IMG_SIZE_HEIGHT__SHIFT) & MDP5_PIPE_SRC_IMG_SIZE_HEIGHT__MASK; +} +#define MDP5_PIPE_SRC_IMG_SIZE_WIDTH__MASK			0x0000ffff +#define MDP5_PIPE_SRC_IMG_SIZE_WIDTH__SHIFT			0 +static inline uint32_t MDP5_PIPE_SRC_IMG_SIZE_WIDTH(uint32_t val) +{ +	return ((val) << MDP5_PIPE_SRC_IMG_SIZE_WIDTH__SHIFT) & MDP5_PIPE_SRC_IMG_SIZE_WIDTH__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_SRC_XY(enum mdp5_pipe i0) { return 0x00001208 + 0x400*i0; } +#define MDP5_PIPE_SRC_XY_Y__MASK				0xffff0000 +#define MDP5_PIPE_SRC_XY_Y__SHIFT				16 +static inline uint32_t MDP5_PIPE_SRC_XY_Y(uint32_t val) +{ +	return ((val) << MDP5_PIPE_SRC_XY_Y__SHIFT) & MDP5_PIPE_SRC_XY_Y__MASK; +} +#define MDP5_PIPE_SRC_XY_X__MASK				0x0000ffff +#define MDP5_PIPE_SRC_XY_X__SHIFT				0 +static inline uint32_t MDP5_PIPE_SRC_XY_X(uint32_t val) +{ +	return ((val) << MDP5_PIPE_SRC_XY_X__SHIFT) & MDP5_PIPE_SRC_XY_X__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_OUT_SIZE(enum mdp5_pipe i0) { return 0x0000120c + 0x400*i0; } +#define MDP5_PIPE_OUT_SIZE_HEIGHT__MASK				0xffff0000 +#define MDP5_PIPE_OUT_SIZE_HEIGHT__SHIFT			16 +static inline uint32_t MDP5_PIPE_OUT_SIZE_HEIGHT(uint32_t val) +{ +	return ((val) << MDP5_PIPE_OUT_SIZE_HEIGHT__SHIFT) & MDP5_PIPE_OUT_SIZE_HEIGHT__MASK; +} +#define MDP5_PIPE_OUT_SIZE_WIDTH__MASK				0x0000ffff +#define MDP5_PIPE_OUT_SIZE_WIDTH__SHIFT				0 +static inline uint32_t MDP5_PIPE_OUT_SIZE_WIDTH(uint32_t val) +{ +	return ((val) << MDP5_PIPE_OUT_SIZE_WIDTH__SHIFT) & MDP5_PIPE_OUT_SIZE_WIDTH__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_OUT_XY(enum mdp5_pipe i0) { return 0x00001210 + 0x400*i0; } +#define MDP5_PIPE_OUT_XY_Y__MASK				0xffff0000 +#define MDP5_PIPE_OUT_XY_Y__SHIFT				16 +static inline uint32_t MDP5_PIPE_OUT_XY_Y(uint32_t val) +{ +	return ((val) << MDP5_PIPE_OUT_XY_Y__SHIFT) & MDP5_PIPE_OUT_XY_Y__MASK; +} +#define MDP5_PIPE_OUT_XY_X__MASK				0x0000ffff +#define MDP5_PIPE_OUT_XY_X__SHIFT				0 +static inline uint32_t MDP5_PIPE_OUT_XY_X(uint32_t val) +{ +	return ((val) << MDP5_PIPE_OUT_XY_X__SHIFT) & MDP5_PIPE_OUT_XY_X__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_SRC0_ADDR(enum mdp5_pipe i0) { return 0x00001214 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_SRC1_ADDR(enum mdp5_pipe i0) { return 0x00001218 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_SRC2_ADDR(enum mdp5_pipe i0) { return 0x0000121c + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_SRC3_ADDR(enum mdp5_pipe i0) { return 0x00001220 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_SRC_STRIDE_A(enum mdp5_pipe i0) { return 0x00001224 + 0x400*i0; } +#define MDP5_PIPE_SRC_STRIDE_A_P0__MASK				0x0000ffff +#define MDP5_PIPE_SRC_STRIDE_A_P0__SHIFT			0 +static inline uint32_t MDP5_PIPE_SRC_STRIDE_A_P0(uint32_t val) +{ +	return ((val) << MDP5_PIPE_SRC_STRIDE_A_P0__SHIFT) & MDP5_PIPE_SRC_STRIDE_A_P0__MASK; +} +#define MDP5_PIPE_SRC_STRIDE_A_P1__MASK				0xffff0000 +#define MDP5_PIPE_SRC_STRIDE_A_P1__SHIFT			16 +static inline uint32_t MDP5_PIPE_SRC_STRIDE_A_P1(uint32_t val) +{ +	return ((val) << MDP5_PIPE_SRC_STRIDE_A_P1__SHIFT) & MDP5_PIPE_SRC_STRIDE_A_P1__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_SRC_STRIDE_B(enum mdp5_pipe i0) { return 0x00001228 + 0x400*i0; } +#define MDP5_PIPE_SRC_STRIDE_B_P2__MASK				0x0000ffff +#define MDP5_PIPE_SRC_STRIDE_B_P2__SHIFT			0 +static inline uint32_t MDP5_PIPE_SRC_STRIDE_B_P2(uint32_t val) +{ +	return ((val) << MDP5_PIPE_SRC_STRIDE_B_P2__SHIFT) & MDP5_PIPE_SRC_STRIDE_B_P2__MASK; +} +#define MDP5_PIPE_SRC_STRIDE_B_P3__MASK				0xffff0000 +#define MDP5_PIPE_SRC_STRIDE_B_P3__SHIFT			16 +static inline uint32_t MDP5_PIPE_SRC_STRIDE_B_P3(uint32_t val) +{ +	return ((val) << MDP5_PIPE_SRC_STRIDE_B_P3__SHIFT) & MDP5_PIPE_SRC_STRIDE_B_P3__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_STILE_FRAME_SIZE(enum mdp5_pipe i0) { return 0x0000122c + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_SRC_FORMAT(enum mdp5_pipe i0) { return 0x00001230 + 0x400*i0; } +#define MDP5_PIPE_SRC_FORMAT_G_BPC__MASK			0x00000003 +#define MDP5_PIPE_SRC_FORMAT_G_BPC__SHIFT			0 +static inline uint32_t MDP5_PIPE_SRC_FORMAT_G_BPC(enum mdp_bpc val) +{ +	return ((val) << MDP5_PIPE_SRC_FORMAT_G_BPC__SHIFT) & MDP5_PIPE_SRC_FORMAT_G_BPC__MASK; +} +#define MDP5_PIPE_SRC_FORMAT_B_BPC__MASK			0x0000000c +#define MDP5_PIPE_SRC_FORMAT_B_BPC__SHIFT			2 +static inline uint32_t MDP5_PIPE_SRC_FORMAT_B_BPC(enum mdp_bpc val) +{ +	return ((val) << MDP5_PIPE_SRC_FORMAT_B_BPC__SHIFT) & MDP5_PIPE_SRC_FORMAT_B_BPC__MASK; +} +#define MDP5_PIPE_SRC_FORMAT_R_BPC__MASK			0x00000030 +#define MDP5_PIPE_SRC_FORMAT_R_BPC__SHIFT			4 +static inline uint32_t MDP5_PIPE_SRC_FORMAT_R_BPC(enum mdp_bpc val) +{ +	return ((val) << MDP5_PIPE_SRC_FORMAT_R_BPC__SHIFT) & MDP5_PIPE_SRC_FORMAT_R_BPC__MASK; +} +#define MDP5_PIPE_SRC_FORMAT_A_BPC__MASK			0x000000c0 +#define MDP5_PIPE_SRC_FORMAT_A_BPC__SHIFT			6 +static inline uint32_t MDP5_PIPE_SRC_FORMAT_A_BPC(enum mdp_bpc_alpha val) +{ +	return ((val) << MDP5_PIPE_SRC_FORMAT_A_BPC__SHIFT) & MDP5_PIPE_SRC_FORMAT_A_BPC__MASK; +} +#define MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE			0x00000100 +#define MDP5_PIPE_SRC_FORMAT_CPP__MASK				0x00000600 +#define MDP5_PIPE_SRC_FORMAT_CPP__SHIFT				9 +static inline uint32_t MDP5_PIPE_SRC_FORMAT_CPP(uint32_t val) +{ +	return ((val) << MDP5_PIPE_SRC_FORMAT_CPP__SHIFT) & MDP5_PIPE_SRC_FORMAT_CPP__MASK; +} +#define MDP5_PIPE_SRC_FORMAT_ROT90				0x00000800 +#define MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT__MASK			0x00003000 +#define MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT__SHIFT		12 +static inline uint32_t MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(uint32_t val) +{ +	return ((val) << MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT__SHIFT) & MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT__MASK; +} +#define MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT			0x00020000 +#define MDP5_PIPE_SRC_FORMAT_UNPACK_ALIGN_MSB			0x00040000 +#define MDP5_PIPE_SRC_FORMAT_NUM_PLANES__MASK			0x00780000 +#define MDP5_PIPE_SRC_FORMAT_NUM_PLANES__SHIFT			19 +static inline uint32_t MDP5_PIPE_SRC_FORMAT_NUM_PLANES(uint32_t val) +{ +	return ((val) << MDP5_PIPE_SRC_FORMAT_NUM_PLANES__SHIFT) & MDP5_PIPE_SRC_FORMAT_NUM_PLANES__MASK; +} +#define MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK			0x01800000 +#define MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT			23 +static inline uint32_t MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(enum mdp5_chroma_samp_type val) +{ +	return ((val) << MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT) & MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_SRC_UNPACK(enum mdp5_pipe i0) { return 0x00001234 + 0x400*i0; } +#define MDP5_PIPE_SRC_UNPACK_ELEM0__MASK			0x000000ff +#define MDP5_PIPE_SRC_UNPACK_ELEM0__SHIFT			0 +static inline uint32_t MDP5_PIPE_SRC_UNPACK_ELEM0(uint32_t val) +{ +	return ((val) << MDP5_PIPE_SRC_UNPACK_ELEM0__SHIFT) & MDP5_PIPE_SRC_UNPACK_ELEM0__MASK; +} +#define MDP5_PIPE_SRC_UNPACK_ELEM1__MASK			0x0000ff00 +#define MDP5_PIPE_SRC_UNPACK_ELEM1__SHIFT			8 +static inline uint32_t MDP5_PIPE_SRC_UNPACK_ELEM1(uint32_t val) +{ +	return ((val) << MDP5_PIPE_SRC_UNPACK_ELEM1__SHIFT) & MDP5_PIPE_SRC_UNPACK_ELEM1__MASK; +} +#define MDP5_PIPE_SRC_UNPACK_ELEM2__MASK			0x00ff0000 +#define MDP5_PIPE_SRC_UNPACK_ELEM2__SHIFT			16 +static inline uint32_t MDP5_PIPE_SRC_UNPACK_ELEM2(uint32_t val) +{ +	return ((val) << MDP5_PIPE_SRC_UNPACK_ELEM2__SHIFT) & MDP5_PIPE_SRC_UNPACK_ELEM2__MASK; +} +#define MDP5_PIPE_SRC_UNPACK_ELEM3__MASK			0xff000000 +#define MDP5_PIPE_SRC_UNPACK_ELEM3__SHIFT			24 +static inline uint32_t MDP5_PIPE_SRC_UNPACK_ELEM3(uint32_t val) +{ +	return ((val) << MDP5_PIPE_SRC_UNPACK_ELEM3__SHIFT) & MDP5_PIPE_SRC_UNPACK_ELEM3__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_SRC_OP_MODE(enum mdp5_pipe i0) { return 0x00001238 + 0x400*i0; } +#define MDP5_PIPE_SRC_OP_MODE_BWC_EN				0x00000001 +#define MDP5_PIPE_SRC_OP_MODE_BWC__MASK				0x00000006 +#define MDP5_PIPE_SRC_OP_MODE_BWC__SHIFT			1 +static inline uint32_t MDP5_PIPE_SRC_OP_MODE_BWC(enum mdp5_pipe_bwc val) +{ +	return ((val) << MDP5_PIPE_SRC_OP_MODE_BWC__SHIFT) & MDP5_PIPE_SRC_OP_MODE_BWC__MASK; +} +#define MDP5_PIPE_SRC_OP_MODE_FLIP_LR				0x00002000 +#define MDP5_PIPE_SRC_OP_MODE_FLIP_UD				0x00004000 +#define MDP5_PIPE_SRC_OP_MODE_IGC_EN				0x00010000 +#define MDP5_PIPE_SRC_OP_MODE_IGC_ROM_0				0x00020000 +#define MDP5_PIPE_SRC_OP_MODE_IGC_ROM_1				0x00040000 +#define MDP5_PIPE_SRC_OP_MODE_DEINTERLACE			0x00400000 +#define MDP5_PIPE_SRC_OP_MODE_DEINTERLACE_ODD			0x00800000 + +static inline uint32_t REG_MDP5_PIPE_SRC_CONSTANT_COLOR(enum mdp5_pipe i0) { return 0x0000123c + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_FETCH_CONFIG(enum mdp5_pipe i0) { return 0x00001248 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_VC1_RANGE(enum mdp5_pipe i0) { return 0x0000124c + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_REQPRIO_FIFO_WM_0(enum mdp5_pipe i0) { return 0x00001250 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_REQPRIO_FIFO_WM_1(enum mdp5_pipe i0) { return 0x00001254 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_REQPRIO_FIFO_WM_2(enum mdp5_pipe i0) { return 0x00001258 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(enum mdp5_pipe i0) { return 0x00001270 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_CURRENT_SRC0_ADDR(enum mdp5_pipe i0) { return 0x000012a4 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_CURRENT_SRC1_ADDR(enum mdp5_pipe i0) { return 0x000012a8 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_CURRENT_SRC2_ADDR(enum mdp5_pipe i0) { return 0x000012ac + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_CURRENT_SRC3_ADDR(enum mdp5_pipe i0) { return 0x000012b0 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_DECIMATION(enum mdp5_pipe i0) { return 0x000012b4 + 0x400*i0; } +#define MDP5_PIPE_DECIMATION_VERT__MASK				0x000000ff +#define MDP5_PIPE_DECIMATION_VERT__SHIFT			0 +static inline uint32_t MDP5_PIPE_DECIMATION_VERT(uint32_t val) +{ +	return ((val) << MDP5_PIPE_DECIMATION_VERT__SHIFT) & MDP5_PIPE_DECIMATION_VERT__MASK; +} +#define MDP5_PIPE_DECIMATION_HORZ__MASK				0x0000ff00 +#define MDP5_PIPE_DECIMATION_HORZ__SHIFT			8 +static inline uint32_t MDP5_PIPE_DECIMATION_HORZ(uint32_t val) +{ +	return ((val) << MDP5_PIPE_DECIMATION_HORZ__SHIFT) & MDP5_PIPE_DECIMATION_HORZ__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_SCALE_CONFIG(enum mdp5_pipe i0) { return 0x00001404 + 0x400*i0; } +#define MDP5_PIPE_SCALE_CONFIG_SCALEX_EN			0x00000001 +#define MDP5_PIPE_SCALE_CONFIG_SCALEY_EN			0x00000002 +#define MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER__MASK		0x00000300 +#define MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER__SHIFT		8 +static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(enum mdp5_scale_filter val) +{ +	return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER__MASK; +} +#define MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER__MASK		0x00000c00 +#define MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER__SHIFT		10 +static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(enum mdp5_scale_filter val) +{ +	return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER__MASK; +} +#define MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER__MASK		0x00003000 +#define MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER__SHIFT		12 +static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(enum mdp5_scale_filter val) +{ +	return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER__MASK; +} +#define MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER__MASK		0x0000c000 +#define MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER__SHIFT		14 +static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(enum mdp5_scale_filter val) +{ +	return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER__MASK; +} +#define MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER__MASK		0x00030000 +#define MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER__SHIFT		16 +static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(enum mdp5_scale_filter val) +{ +	return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER__MASK; +} +#define MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER__MASK		0x000c0000 +#define MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER__SHIFT		18 +static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(enum mdp5_scale_filter val) +{ +	return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_SCALE_PHASE_STEP_X(enum mdp5_pipe i0) { return 0x00001410 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(enum mdp5_pipe i0) { return 0x00001414 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_SCALE_INIT_PHASE_X(enum mdp5_pipe i0) { return 0x00001420 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_SCALE_INIT_PHASE_Y(enum mdp5_pipe i0) { return 0x00001424 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM(uint32_t i0) { return 0x00003200 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_BLEND_COLOR_OUT(uint32_t i0) { return 0x00003200 + 0x400*i0; } +#define MDP5_LM_BLEND_COLOR_OUT_STAGE0_FG_ALPHA			0x00000002 +#define MDP5_LM_BLEND_COLOR_OUT_STAGE1_FG_ALPHA			0x00000004 +#define MDP5_LM_BLEND_COLOR_OUT_STAGE2_FG_ALPHA			0x00000008 +#define MDP5_LM_BLEND_COLOR_OUT_STAGE3_FG_ALPHA			0x00000010 + +static inline uint32_t REG_MDP5_LM_OUT_SIZE(uint32_t i0) { return 0x00003204 + 0x400*i0; } +#define MDP5_LM_OUT_SIZE_HEIGHT__MASK				0xffff0000 +#define MDP5_LM_OUT_SIZE_HEIGHT__SHIFT				16 +static inline uint32_t MDP5_LM_OUT_SIZE_HEIGHT(uint32_t val) +{ +	return ((val) << MDP5_LM_OUT_SIZE_HEIGHT__SHIFT) & MDP5_LM_OUT_SIZE_HEIGHT__MASK; +} +#define MDP5_LM_OUT_SIZE_WIDTH__MASK				0x0000ffff +#define MDP5_LM_OUT_SIZE_WIDTH__SHIFT				0 +static inline uint32_t MDP5_LM_OUT_SIZE_WIDTH(uint32_t val) +{ +	return ((val) << MDP5_LM_OUT_SIZE_WIDTH__SHIFT) & MDP5_LM_OUT_SIZE_WIDTH__MASK; +} + +static inline uint32_t REG_MDP5_LM_BORDER_COLOR_0(uint32_t i0) { return 0x00003208 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_BORDER_COLOR_1(uint32_t i0) { return 0x00003210 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_BLEND(uint32_t i0, uint32_t i1) { return 0x00003220 + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_BLEND_OP_MODE(uint32_t i0, uint32_t i1) { return 0x00003220 + 0x400*i0 + 0x30*i1; } +#define MDP5_LM_BLEND_OP_MODE_FG_ALPHA__MASK			0x00000003 +#define MDP5_LM_BLEND_OP_MODE_FG_ALPHA__SHIFT			0 +static inline uint32_t MDP5_LM_BLEND_OP_MODE_FG_ALPHA(enum mdp_alpha_type val) +{ +	return ((val) << MDP5_LM_BLEND_OP_MODE_FG_ALPHA__SHIFT) & MDP5_LM_BLEND_OP_MODE_FG_ALPHA__MASK; +} +#define MDP5_LM_BLEND_OP_MODE_FG_INV_ALPHA			0x00000004 +#define MDP5_LM_BLEND_OP_MODE_FG_MOD_ALPHA			0x00000008 +#define MDP5_LM_BLEND_OP_MODE_FG_INV_MOD_ALPHA			0x00000010 +#define MDP5_LM_BLEND_OP_MODE_FG_TRANSP_EN			0x00000020 +#define MDP5_LM_BLEND_OP_MODE_BG_ALPHA__MASK			0x00000300 +#define MDP5_LM_BLEND_OP_MODE_BG_ALPHA__SHIFT			8 +static inline uint32_t MDP5_LM_BLEND_OP_MODE_BG_ALPHA(enum mdp_alpha_type val) +{ +	return ((val) << MDP5_LM_BLEND_OP_MODE_BG_ALPHA__SHIFT) & MDP5_LM_BLEND_OP_MODE_BG_ALPHA__MASK; +} +#define MDP5_LM_BLEND_OP_MODE_BG_INV_ALPHA			0x00000400 +#define MDP5_LM_BLEND_OP_MODE_BG_MOD_ALPHA			0x00000800 +#define MDP5_LM_BLEND_OP_MODE_BG_INV_MOD_ALPHA			0x00001000 +#define MDP5_LM_BLEND_OP_MODE_BG_TRANSP_EN			0x00002000 + +static inline uint32_t REG_MDP5_LM_BLEND_FG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00003224 + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_BLEND_BG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00003228 + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_LOW0(uint32_t i0, uint32_t i1) { return 0x0000322c + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_LOW1(uint32_t i0, uint32_t i1) { return 0x00003230 + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_HIGH0(uint32_t i0, uint32_t i1) { return 0x00003234 + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00003238 + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_LOW0(uint32_t i0, uint32_t i1) { return 0x0000323c + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_LOW1(uint32_t i0, uint32_t i1) { return 0x00003240 + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH0(uint32_t i0, uint32_t i1) { return 0x00003244 + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00003248 + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_CURSOR_IMG_SIZE(uint32_t i0) { return 0x000032e0 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_SIZE(uint32_t i0) { return 0x000032e4 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_XY(uint32_t i0) { return 0x000032e8 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_STRIDE(uint32_t i0) { return 0x000032dc + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_FORMAT(uint32_t i0) { return 0x000032ec + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_BASE_ADDR(uint32_t i0) { return 0x000032f0 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_START_XY(uint32_t i0) { return 0x000032f4 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_CONFIG(uint32_t i0) { return 0x000032f8 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_PARAM(uint32_t i0) { return 0x000032fc + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_TRANSP_LOW0(uint32_t i0) { return 0x00003300 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_TRANSP_LOW1(uint32_t i0) { return 0x00003304 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_TRANSP_HIGH0(uint32_t i0) { return 0x00003308 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_TRANSP_HIGH1(uint32_t i0) { return 0x0000330c + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_GC_LUT_BASE(uint32_t i0) { return 0x00003310 + 0x400*i0; } + +static inline uint32_t REG_MDP5_DSPP(uint32_t i0) { return 0x00004600 + 0x400*i0; } + +static inline uint32_t REG_MDP5_DSPP_OP_MODE(uint32_t i0) { return 0x00004600 + 0x400*i0; } +#define MDP5_DSPP_OP_MODE_IGC_LUT_EN				0x00000001 +#define MDP5_DSPP_OP_MODE_IGC_TBL_IDX__MASK			0x0000000e +#define MDP5_DSPP_OP_MODE_IGC_TBL_IDX__SHIFT			1 +static inline uint32_t MDP5_DSPP_OP_MODE_IGC_TBL_IDX(uint32_t val) +{ +	return ((val) << MDP5_DSPP_OP_MODE_IGC_TBL_IDX__SHIFT) & MDP5_DSPP_OP_MODE_IGC_TBL_IDX__MASK; +} +#define MDP5_DSPP_OP_MODE_PCC_EN				0x00000010 +#define MDP5_DSPP_OP_MODE_DITHER_EN				0x00000100 +#define MDP5_DSPP_OP_MODE_HIST_EN				0x00010000 +#define MDP5_DSPP_OP_MODE_AUTO_CLEAR				0x00020000 +#define MDP5_DSPP_OP_MODE_HIST_LUT_EN				0x00080000 +#define MDP5_DSPP_OP_MODE_PA_EN					0x00100000 +#define MDP5_DSPP_OP_MODE_GAMUT_EN				0x00800000 +#define MDP5_DSPP_OP_MODE_GAMUT_ORDER				0x01000000 + +static inline uint32_t REG_MDP5_DSPP_PCC_BASE(uint32_t i0) { return 0x00004630 + 0x400*i0; } + +static inline uint32_t REG_MDP5_DSPP_DITHER_DEPTH(uint32_t i0) { return 0x00004750 + 0x400*i0; } + +static inline uint32_t REG_MDP5_DSPP_HIST_CTL_BASE(uint32_t i0) { return 0x00004810 + 0x400*i0; } + +static inline uint32_t REG_MDP5_DSPP_HIST_LUT_BASE(uint32_t i0) { return 0x00004830 + 0x400*i0; } + +static inline uint32_t REG_MDP5_DSPP_HIST_LUT_SWAP(uint32_t i0) { return 0x00004834 + 0x400*i0; } + +static inline uint32_t REG_MDP5_DSPP_PA_BASE(uint32_t i0) { return 0x00004838 + 0x400*i0; } + +static inline uint32_t REG_MDP5_DSPP_GAMUT_BASE(uint32_t i0) { return 0x000048dc + 0x400*i0; } + +static inline uint32_t REG_MDP5_DSPP_GC_BASE(uint32_t i0) { return 0x000048b0 + 0x400*i0; } + +static inline uint32_t REG_MDP5_INTF(uint32_t i0) { return 0x00012500 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TIMING_ENGINE_EN(uint32_t i0) { return 0x00012500 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_CONFIG(uint32_t i0) { return 0x00012504 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_HSYNC_CTL(uint32_t i0) { return 0x00012508 + 0x200*i0; } +#define MDP5_INTF_HSYNC_CTL_PULSEW__MASK			0x0000ffff +#define MDP5_INTF_HSYNC_CTL_PULSEW__SHIFT			0 +static inline uint32_t MDP5_INTF_HSYNC_CTL_PULSEW(uint32_t val) +{ +	return ((val) << MDP5_INTF_HSYNC_CTL_PULSEW__SHIFT) & MDP5_INTF_HSYNC_CTL_PULSEW__MASK; +} +#define MDP5_INTF_HSYNC_CTL_PERIOD__MASK			0xffff0000 +#define MDP5_INTF_HSYNC_CTL_PERIOD__SHIFT			16 +static inline uint32_t MDP5_INTF_HSYNC_CTL_PERIOD(uint32_t val) +{ +	return ((val) << MDP5_INTF_HSYNC_CTL_PERIOD__SHIFT) & MDP5_INTF_HSYNC_CTL_PERIOD__MASK; +} + +static inline uint32_t REG_MDP5_INTF_VSYNC_PERIOD_F0(uint32_t i0) { return 0x0001250c + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_VSYNC_PERIOD_F1(uint32_t i0) { return 0x00012510 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_VSYNC_LEN_F0(uint32_t i0) { return 0x00012514 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_VSYNC_LEN_F1(uint32_t i0) { return 0x00012518 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_DISPLAY_VSTART_F0(uint32_t i0) { return 0x0001251c + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_DISPLAY_VSTART_F1(uint32_t i0) { return 0x00012520 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_DISPLAY_VEND_F0(uint32_t i0) { return 0x00012524 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_DISPLAY_VEND_F1(uint32_t i0) { return 0x00012528 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_ACTIVE_VSTART_F0(uint32_t i0) { return 0x0001252c + 0x200*i0; } +#define MDP5_INTF_ACTIVE_VSTART_F0_VAL__MASK			0x7fffffff +#define MDP5_INTF_ACTIVE_VSTART_F0_VAL__SHIFT			0 +static inline uint32_t MDP5_INTF_ACTIVE_VSTART_F0_VAL(uint32_t val) +{ +	return ((val) << MDP5_INTF_ACTIVE_VSTART_F0_VAL__SHIFT) & MDP5_INTF_ACTIVE_VSTART_F0_VAL__MASK; +} +#define MDP5_INTF_ACTIVE_VSTART_F0_ACTIVE_V_ENABLE		0x80000000 + +static inline uint32_t REG_MDP5_INTF_ACTIVE_VSTART_F1(uint32_t i0) { return 0x00012530 + 0x200*i0; } +#define MDP5_INTF_ACTIVE_VSTART_F1_VAL__MASK			0x7fffffff +#define MDP5_INTF_ACTIVE_VSTART_F1_VAL__SHIFT			0 +static inline uint32_t MDP5_INTF_ACTIVE_VSTART_F1_VAL(uint32_t val) +{ +	return ((val) << MDP5_INTF_ACTIVE_VSTART_F1_VAL__SHIFT) & MDP5_INTF_ACTIVE_VSTART_F1_VAL__MASK; +} + +static inline uint32_t REG_MDP5_INTF_ACTIVE_VEND_F0(uint32_t i0) { return 0x00012534 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_ACTIVE_VEND_F1(uint32_t i0) { return 0x00012538 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_DISPLAY_HCTL(uint32_t i0) { return 0x0001253c + 0x200*i0; } +#define MDP5_INTF_DISPLAY_HCTL_START__MASK			0x0000ffff +#define MDP5_INTF_DISPLAY_HCTL_START__SHIFT			0 +static inline uint32_t MDP5_INTF_DISPLAY_HCTL_START(uint32_t val) +{ +	return ((val) << MDP5_INTF_DISPLAY_HCTL_START__SHIFT) & MDP5_INTF_DISPLAY_HCTL_START__MASK; +} +#define MDP5_INTF_DISPLAY_HCTL_END__MASK			0xffff0000 +#define MDP5_INTF_DISPLAY_HCTL_END__SHIFT			16 +static inline uint32_t MDP5_INTF_DISPLAY_HCTL_END(uint32_t val) +{ +	return ((val) << MDP5_INTF_DISPLAY_HCTL_END__SHIFT) & MDP5_INTF_DISPLAY_HCTL_END__MASK; +} + +static inline uint32_t REG_MDP5_INTF_ACTIVE_HCTL(uint32_t i0) { return 0x00012540 + 0x200*i0; } +#define MDP5_INTF_ACTIVE_HCTL_START__MASK			0x00007fff +#define MDP5_INTF_ACTIVE_HCTL_START__SHIFT			0 +static inline uint32_t MDP5_INTF_ACTIVE_HCTL_START(uint32_t val) +{ +	return ((val) << MDP5_INTF_ACTIVE_HCTL_START__SHIFT) & MDP5_INTF_ACTIVE_HCTL_START__MASK; +} +#define MDP5_INTF_ACTIVE_HCTL_END__MASK				0x7fff0000 +#define MDP5_INTF_ACTIVE_HCTL_END__SHIFT			16 +static inline uint32_t MDP5_INTF_ACTIVE_HCTL_END(uint32_t val) +{ +	return ((val) << MDP5_INTF_ACTIVE_HCTL_END__SHIFT) & MDP5_INTF_ACTIVE_HCTL_END__MASK; +} +#define MDP5_INTF_ACTIVE_HCTL_ACTIVE_H_ENABLE			0x80000000 + +static inline uint32_t REG_MDP5_INTF_BORDER_COLOR(uint32_t i0) { return 0x00012544 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_UNDERFLOW_COLOR(uint32_t i0) { return 0x00012548 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_HSYNC_SKEW(uint32_t i0) { return 0x0001254c + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_POLARITY_CTL(uint32_t i0) { return 0x00012550 + 0x200*i0; } +#define MDP5_INTF_POLARITY_CTL_HSYNC_LOW			0x00000001 +#define MDP5_INTF_POLARITY_CTL_VSYNC_LOW			0x00000002 +#define MDP5_INTF_POLARITY_CTL_DATA_EN_LOW			0x00000004 + +static inline uint32_t REG_MDP5_INTF_TEST_CTL(uint32_t i0) { return 0x00012554 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TP_COLOR0(uint32_t i0) { return 0x00012558 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TP_COLOR1(uint32_t i0) { return 0x0001255c + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_DSI_CMD_MODE_TRIGGER_EN(uint32_t i0) { return 0x00012584 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_PANEL_FORMAT(uint32_t i0) { return 0x00012590 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_FRAME_LINE_COUNT_EN(uint32_t i0) { return 0x000125a8 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_FRAME_COUNT(uint32_t i0) { return 0x000125ac + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_LINE_COUNT(uint32_t i0) { return 0x000125b0 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_DEFLICKER_CONFIG(uint32_t i0) { return 0x000125f0 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_DEFLICKER_STRNG_COEFF(uint32_t i0) { return 0x000125f4 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_DEFLICKER_WEAK_COEFF(uint32_t i0) { return 0x000125f8 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TPG_ENABLE(uint32_t i0) { return 0x00012600 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TPG_MAIN_CONTROL(uint32_t i0) { return 0x00012604 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TPG_VIDEO_CONFIG(uint32_t i0) { return 0x00012608 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TPG_COMPONENT_LIMITS(uint32_t i0) { return 0x0001260c + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TPG_RECTANGLE(uint32_t i0) { return 0x00012610 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TPG_INITIAL_VALUE(uint32_t i0) { return 0x00012614 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TPG_BLK_WHITE_PATTERN_FRAME(uint32_t i0) { return 0x00012618 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TPG_RGB_MAPPING(uint32_t i0) { return 0x0001261c + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD(uint32_t i0) { return 0x00013100 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_BYPASS(uint32_t i0) { return 0x00013100 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_CTRL_0(uint32_t i0) { return 0x00013104 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_CTRL_1(uint32_t i0) { return 0x00013108 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_FRAME_SIZE(uint32_t i0) { return 0x0001310c + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_CON_CTRL_0(uint32_t i0) { return 0x00013110 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_CON_CTRL_1(uint32_t i0) { return 0x00013114 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_STR_MAN(uint32_t i0) { return 0x00013118 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_VAR(uint32_t i0) { return 0x0001311c + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_DITH(uint32_t i0) { return 0x00013120 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_DITH_CTRL(uint32_t i0) { return 0x00013124 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_AMP_LIM(uint32_t i0) { return 0x00013128 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_SLOPE(uint32_t i0) { return 0x0001312c + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_BW_LVL(uint32_t i0) { return 0x00013130 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_LOGO_POS(uint32_t i0) { return 0x00013134 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_LUT_FI(uint32_t i0) { return 0x00013138 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_LUT_CC(uint32_t i0) { return 0x0001317c + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_STR_LIM(uint32_t i0) { return 0x000131c8 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_CALIB_AB(uint32_t i0) { return 0x000131cc + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_CALIB_CD(uint32_t i0) { return 0x000131d0 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_MODE_SEL(uint32_t i0) { return 0x000131d4 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_TFILT_CTRL(uint32_t i0) { return 0x000131d8 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_BL_MINMAX(uint32_t i0) { return 0x000131dc + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_BL(uint32_t i0) { return 0x000131e0 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_BL_MAX(uint32_t i0) { return 0x000131e8 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_AL(uint32_t i0) { return 0x000131ec + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_AL_MIN(uint32_t i0) { return 0x000131f0 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_AL_FILT(uint32_t i0) { return 0x000131f4 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_CFG_BUF(uint32_t i0) { return 0x000131f8 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_LUT_AL(uint32_t i0) { return 0x00013200 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_TARG_STR(uint32_t i0) { return 0x00013244 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_START_CALC(uint32_t i0) { return 0x00013248 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_STR_OUT(uint32_t i0) { return 0x0001324c + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_BL_OUT(uint32_t i0) { return 0x00013254 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_CALC_DONE(uint32_t i0) { return 0x00013258 + 0x200*i0; } + + +#endif /* MDP5_XML */ diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c new file mode 100644 index 00000000000..ebe2e60f3ab --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -0,0 +1,575 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include "mdp5_kms.h" + +#include <drm/drm_mode.h> +#include "drm_crtc.h" +#include "drm_crtc_helper.h" +#include "drm_flip_work.h" + +struct mdp5_crtc { +	struct drm_crtc base; +	char name[8]; +	struct drm_plane *plane; +	struct drm_plane *planes[8]; +	int id; +	bool enabled; + +	/* which mixer/encoder we route output to: */ +	int mixer; + +	/* if there is a pending flip, these will be non-null: */ +	struct drm_pending_vblank_event *event; +	struct msm_fence_cb pageflip_cb; + +#define PENDING_CURSOR 0x1 +#define PENDING_FLIP   0x2 +	atomic_t pending; + +	/* the fb that we logically (from PoV of KMS API) hold a ref +	 * to.  Which we may not yet be scanning out (we may still +	 * be scanning out previous in case of page_flip while waiting +	 * for gpu rendering to complete: +	 */ +	struct drm_framebuffer *fb; + +	/* the fb that we currently hold a scanout ref to: */ +	struct drm_framebuffer *scanout_fb; + +	/* for unref'ing framebuffers after scanout completes: */ +	struct drm_flip_work unref_fb_work; + +	struct mdp_irq vblank; +	struct mdp_irq err; +}; +#define to_mdp5_crtc(x) container_of(x, struct mdp5_crtc, base) + +static struct mdp5_kms *get_kms(struct drm_crtc *crtc) +{ +	struct msm_drm_private *priv = crtc->dev->dev_private; +	return to_mdp5_kms(to_mdp_kms(priv->kms)); +} + +static void request_pending(struct drm_crtc *crtc, uint32_t pending) +{ +	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + +	atomic_or(pending, &mdp5_crtc->pending); +	mdp_irq_register(&get_kms(crtc)->base, &mdp5_crtc->vblank); +} + +static void crtc_flush(struct drm_crtc *crtc) +{ +	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); +	struct mdp5_kms *mdp5_kms = get_kms(crtc); +	int id = mdp5_crtc->id; +	uint32_t i, flush = 0; + +	for (i = 0; i < ARRAY_SIZE(mdp5_crtc->planes); i++) { +		struct drm_plane *plane = mdp5_crtc->planes[i]; +		if (plane) { +			enum mdp5_pipe pipe = mdp5_plane_pipe(plane); +			flush |= pipe2flush(pipe); +		} +	} +	flush |= mixer2flush(mdp5_crtc->id); +	flush |= MDP5_CTL_FLUSH_CTL; + +	DBG("%s: flush=%08x", mdp5_crtc->name, flush); + +	mdp5_write(mdp5_kms, REG_MDP5_CTL_FLUSH(id), flush); +} + +static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb) +{ +	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); +	struct drm_framebuffer *old_fb = mdp5_crtc->fb; + +	/* grab reference to incoming scanout fb: */ +	drm_framebuffer_reference(new_fb); +	mdp5_crtc->base.primary->fb = new_fb; +	mdp5_crtc->fb = new_fb; + +	if (old_fb) +		drm_flip_work_queue(&mdp5_crtc->unref_fb_work, old_fb); +} + +/* unlike update_fb(), take a ref to the new scanout fb *before* updating + * plane, then call this.  Needed to ensure we don't unref the buffer that + * is actually still being scanned out. + * + * Note that this whole thing goes away with atomic.. since we can defer + * calling into driver until rendering is done. + */ +static void update_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb) +{ +	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + +	/* flush updates, to make sure hw is updated to new scanout fb, +	 * so that we can safely queue unref to current fb (ie. next +	 * vblank we know hw is done w/ previous scanout_fb). +	 */ +	crtc_flush(crtc); + +	if (mdp5_crtc->scanout_fb) +		drm_flip_work_queue(&mdp5_crtc->unref_fb_work, +				mdp5_crtc->scanout_fb); + +	mdp5_crtc->scanout_fb = fb; + +	/* enable vblank to complete flip: */ +	request_pending(crtc, PENDING_FLIP); +} + +/* if file!=NULL, this is preclose potential cancel-flip path */ +static void complete_flip(struct drm_crtc *crtc, struct drm_file *file) +{ +	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); +	struct drm_device *dev = crtc->dev; +	struct drm_pending_vblank_event *event; +	unsigned long flags, i; + +	spin_lock_irqsave(&dev->event_lock, flags); +	event = mdp5_crtc->event; +	if (event) { +		/* if regular vblank case (!file) or if cancel-flip from +		 * preclose on file that requested flip, then send the +		 * event: +		 */ +		if (!file || (event->base.file_priv == file)) { +			mdp5_crtc->event = NULL; +			drm_send_vblank_event(dev, mdp5_crtc->id, event); +		} +	} +	spin_unlock_irqrestore(&dev->event_lock, flags); + +	for (i = 0; i < ARRAY_SIZE(mdp5_crtc->planes); i++) { +		struct drm_plane *plane = mdp5_crtc->planes[i]; +		if (plane) +			mdp5_plane_complete_flip(plane); +	} +} + +static void pageflip_cb(struct msm_fence_cb *cb) +{ +	struct mdp5_crtc *mdp5_crtc = +		container_of(cb, struct mdp5_crtc, pageflip_cb); +	struct drm_crtc *crtc = &mdp5_crtc->base; +	struct drm_framebuffer *fb = mdp5_crtc->fb; + +	if (!fb) +		return; + +	drm_framebuffer_reference(fb); +	mdp5_plane_set_scanout(mdp5_crtc->plane, fb); +	update_scanout(crtc, fb); +} + +static void unref_fb_worker(struct drm_flip_work *work, void *val) +{ +	struct mdp5_crtc *mdp5_crtc = +		container_of(work, struct mdp5_crtc, unref_fb_work); +	struct drm_device *dev = mdp5_crtc->base.dev; + +	mutex_lock(&dev->mode_config.mutex); +	drm_framebuffer_unreference(val); +	mutex_unlock(&dev->mode_config.mutex); +} + +static void mdp5_crtc_destroy(struct drm_crtc *crtc) +{ +	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + +	drm_crtc_cleanup(crtc); +	drm_flip_work_cleanup(&mdp5_crtc->unref_fb_work); + +	kfree(mdp5_crtc); +} + +static void mdp5_crtc_dpms(struct drm_crtc *crtc, int mode) +{ +	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); +	struct mdp5_kms *mdp5_kms = get_kms(crtc); +	bool enabled = (mode == DRM_MODE_DPMS_ON); + +	DBG("%s: mode=%d", mdp5_crtc->name, mode); + +	if (enabled != mdp5_crtc->enabled) { +		if (enabled) { +			mdp5_enable(mdp5_kms); +			mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err); +		} else { +			mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->err); +			mdp5_disable(mdp5_kms); +		} +		mdp5_crtc->enabled = enabled; +	} +} + +static bool mdp5_crtc_mode_fixup(struct drm_crtc *crtc, +		const struct drm_display_mode *mode, +		struct drm_display_mode *adjusted_mode) +{ +	return true; +} + +static void blend_setup(struct drm_crtc *crtc) +{ +	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); +	struct mdp5_kms *mdp5_kms = get_kms(crtc); +	int id = mdp5_crtc->id; + +	/* +	 * Hard-coded setup for now until I figure out how the +	 * layer-mixer works +	 */ + +	/* LM[id]: */ +	mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(id), +			MDP5_LM_BLEND_COLOR_OUT_STAGE0_FG_ALPHA); +	mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_OP_MODE(id, 0), +			MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_CONST) | +			MDP5_LM_BLEND_OP_MODE_BG_ALPHA(FG_PIXEL) | +			MDP5_LM_BLEND_OP_MODE_BG_INV_ALPHA); +	mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_FG_ALPHA(id, 0), 0xff); +	mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(id, 0), 0x00); + +	/* NOTE: seems that LM[n] and CTL[m], we do not need n==m.. but +	 * we want to be setting CTL[m].LAYER[n].  Not sure what the +	 * point of having CTL[m].LAYER[o] (for o!=n).. maybe that is +	 * used when chaining up mixers for high resolution displays? +	 */ + +	/* CTL[id]: */ +	mdp5_write(mdp5_kms, REG_MDP5_CTL_LAYER_REG(id, 0), +			MDP5_CTL_LAYER_REG_RGB0(STAGE0) | +			MDP5_CTL_LAYER_REG_BORDER_COLOR); +	mdp5_write(mdp5_kms, REG_MDP5_CTL_LAYER_REG(id, 1), 0); +	mdp5_write(mdp5_kms, REG_MDP5_CTL_LAYER_REG(id, 2), 0); +	mdp5_write(mdp5_kms, REG_MDP5_CTL_LAYER_REG(id, 3), 0); +	mdp5_write(mdp5_kms, REG_MDP5_CTL_LAYER_REG(id, 4), 0); +} + +static int mdp5_crtc_mode_set(struct drm_crtc *crtc, +		struct drm_display_mode *mode, +		struct drm_display_mode *adjusted_mode, +		int x, int y, +		struct drm_framebuffer *old_fb) +{ +	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); +	struct mdp5_kms *mdp5_kms = get_kms(crtc); +	int ret; + +	mode = adjusted_mode; + +	DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", +			mdp5_crtc->name, mode->base.id, mode->name, +			mode->vrefresh, mode->clock, +			mode->hdisplay, mode->hsync_start, +			mode->hsync_end, mode->htotal, +			mode->vdisplay, mode->vsync_start, +			mode->vsync_end, mode->vtotal, +			mode->type, mode->flags); + +	/* grab extra ref for update_scanout() */ +	drm_framebuffer_reference(crtc->primary->fb); + +	ret = mdp5_plane_mode_set(mdp5_crtc->plane, crtc, crtc->primary->fb, +			0, 0, mode->hdisplay, mode->vdisplay, +			x << 16, y << 16, +			mode->hdisplay << 16, mode->vdisplay << 16); +	if (ret) { +		drm_framebuffer_unreference(crtc->primary->fb); +		dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n", +				mdp5_crtc->name, ret); +		return ret; +	} + +	mdp5_write(mdp5_kms, REG_MDP5_LM_OUT_SIZE(mdp5_crtc->id), +			MDP5_LM_OUT_SIZE_WIDTH(mode->hdisplay) | +			MDP5_LM_OUT_SIZE_HEIGHT(mode->vdisplay)); + +	update_fb(crtc, crtc->primary->fb); +	update_scanout(crtc, crtc->primary->fb); + +	return 0; +} + +static void mdp5_crtc_prepare(struct drm_crtc *crtc) +{ +	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); +	DBG("%s", mdp5_crtc->name); +	/* make sure we hold a ref to mdp clks while setting up mode: */ +	mdp5_enable(get_kms(crtc)); +	mdp5_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); +} + +static void mdp5_crtc_commit(struct drm_crtc *crtc) +{ +	mdp5_crtc_dpms(crtc, DRM_MODE_DPMS_ON); +	crtc_flush(crtc); +	/* drop the ref to mdp clk's that we got in prepare: */ +	mdp5_disable(get_kms(crtc)); +} + +static int mdp5_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, +		struct drm_framebuffer *old_fb) +{ +	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); +	struct drm_plane *plane = mdp5_crtc->plane; +	struct drm_display_mode *mode = &crtc->mode; +	int ret; + +	/* grab extra ref for update_scanout() */ +	drm_framebuffer_reference(crtc->primary->fb); + +	ret = mdp5_plane_mode_set(plane, crtc, crtc->primary->fb, +			0, 0, mode->hdisplay, mode->vdisplay, +			x << 16, y << 16, +			mode->hdisplay << 16, mode->vdisplay << 16); +	if (ret) { +		drm_framebuffer_unreference(crtc->primary->fb); +		return ret; +	} + +	update_fb(crtc, crtc->primary->fb); +	update_scanout(crtc, crtc->primary->fb); + +	return 0; +} + +static void mdp5_crtc_load_lut(struct drm_crtc *crtc) +{ +} + +static int mdp5_crtc_page_flip(struct drm_crtc *crtc, +		struct drm_framebuffer *new_fb, +		struct drm_pending_vblank_event *event, +		uint32_t page_flip_flags) +{ +	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); +	struct drm_device *dev = crtc->dev; +	struct drm_gem_object *obj; +	unsigned long flags; + +	if (mdp5_crtc->event) { +		dev_err(dev->dev, "already pending flip!\n"); +		return -EBUSY; +	} + +	obj = msm_framebuffer_bo(new_fb, 0); + +	spin_lock_irqsave(&dev->event_lock, flags); +	mdp5_crtc->event = event; +	spin_unlock_irqrestore(&dev->event_lock, flags); + +	update_fb(crtc, new_fb); + +	return msm_gem_queue_inactive_cb(obj, &mdp5_crtc->pageflip_cb); +} + +static int mdp5_crtc_set_property(struct drm_crtc *crtc, +		struct drm_property *property, uint64_t val) +{ +	// XXX +	return -EINVAL; +} + +static const struct drm_crtc_funcs mdp5_crtc_funcs = { +	.set_config = drm_crtc_helper_set_config, +	.destroy = mdp5_crtc_destroy, +	.page_flip = mdp5_crtc_page_flip, +	.set_property = mdp5_crtc_set_property, +}; + +static const struct drm_crtc_helper_funcs mdp5_crtc_helper_funcs = { +	.dpms = mdp5_crtc_dpms, +	.mode_fixup = mdp5_crtc_mode_fixup, +	.mode_set = mdp5_crtc_mode_set, +	.prepare = mdp5_crtc_prepare, +	.commit = mdp5_crtc_commit, +	.mode_set_base = mdp5_crtc_mode_set_base, +	.load_lut = mdp5_crtc_load_lut, +}; + +static void mdp5_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus) +{ +	struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc, vblank); +	struct drm_crtc *crtc = &mdp5_crtc->base; +	struct msm_drm_private *priv = crtc->dev->dev_private; +	unsigned pending; + +	mdp_irq_unregister(&get_kms(crtc)->base, &mdp5_crtc->vblank); + +	pending = atomic_xchg(&mdp5_crtc->pending, 0); + +	if (pending & PENDING_FLIP) { +		complete_flip(crtc, NULL); +		drm_flip_work_commit(&mdp5_crtc->unref_fb_work, priv->wq); +	} +} + +static void mdp5_crtc_err_irq(struct mdp_irq *irq, uint32_t irqstatus) +{ +	struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc, err); +	struct drm_crtc *crtc = &mdp5_crtc->base; +	DBG("%s: error: %08x", mdp5_crtc->name, irqstatus); +	crtc_flush(crtc); +} + +uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc) +{ +	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); +	return mdp5_crtc->vblank.irqmask; +} + +void mdp5_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file) +{ +	DBG("cancel: %p", file); +	complete_flip(crtc, file); +} + +/* set interface for routing crtc->encoder: */ +void mdp5_crtc_set_intf(struct drm_crtc *crtc, int intf, +		enum mdp5_intf intf_id) +{ +	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); +	struct mdp5_kms *mdp5_kms = get_kms(crtc); +	static const enum mdp5_intfnum intfnum[] = { +			INTF0, INTF1, INTF2, INTF3, +	}; +	uint32_t intf_sel; + +	/* now that we know what irq's we want: */ +	mdp5_crtc->err.irqmask = intf2err(intf); +	mdp5_crtc->vblank.irqmask = intf2vblank(intf); + +	/* when called from modeset_init(), skip the rest until later: */ +	if (!mdp5_kms) +		return; + +	intf_sel = mdp5_read(mdp5_kms, REG_MDP5_DISP_INTF_SEL); + +	switch (intf) { +	case 0: +		intf_sel &= ~MDP5_DISP_INTF_SEL_INTF0__MASK; +		intf_sel |= MDP5_DISP_INTF_SEL_INTF0(intf_id); +		break; +	case 1: +		intf_sel &= ~MDP5_DISP_INTF_SEL_INTF1__MASK; +		intf_sel |= MDP5_DISP_INTF_SEL_INTF1(intf_id); +		break; +	case 2: +		intf_sel &= ~MDP5_DISP_INTF_SEL_INTF2__MASK; +		intf_sel |= MDP5_DISP_INTF_SEL_INTF2(intf_id); +		break; +	case 3: +		intf_sel &= ~MDP5_DISP_INTF_SEL_INTF3__MASK; +		intf_sel |= MDP5_DISP_INTF_SEL_INTF3(intf_id); +		break; +	default: +		BUG(); +		break; +	} + +	blend_setup(crtc); + +	DBG("%s: intf_sel=%08x", mdp5_crtc->name, intf_sel); + +	mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, intf_sel); +	mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(mdp5_crtc->id), +			MDP5_CTL_OP_MODE(MODE_NONE) | +			MDP5_CTL_OP_INTF_NUM(intfnum[intf])); + +	crtc_flush(crtc); +} + +static void set_attach(struct drm_crtc *crtc, enum mdp5_pipe pipe_id, +		struct drm_plane *plane) +{ +	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + +	BUG_ON(pipe_id >= ARRAY_SIZE(mdp5_crtc->planes)); + +	if (mdp5_crtc->planes[pipe_id] == plane) +		return; + +	mdp5_crtc->planes[pipe_id] = plane; +	blend_setup(crtc); +	if (mdp5_crtc->enabled && (plane != mdp5_crtc->plane)) +		crtc_flush(crtc); +} + +void mdp5_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane) +{ +	set_attach(crtc, mdp5_plane_pipe(plane), plane); +} + +void mdp5_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane) +{ +	/* don't actually detatch our primary plane: */ +	if (to_mdp5_crtc(crtc)->plane == plane) +		return; +	set_attach(crtc, mdp5_plane_pipe(plane), NULL); +} + +/* initialize crtc */ +struct drm_crtc *mdp5_crtc_init(struct drm_device *dev, +		struct drm_plane *plane, int id) +{ +	struct drm_crtc *crtc = NULL; +	struct mdp5_crtc *mdp5_crtc; +	int ret; + +	mdp5_crtc = kzalloc(sizeof(*mdp5_crtc), GFP_KERNEL); +	if (!mdp5_crtc) { +		ret = -ENOMEM; +		goto fail; +	} + +	crtc = &mdp5_crtc->base; + +	mdp5_crtc->plane = plane; +	mdp5_crtc->id = id; + +	mdp5_crtc->vblank.irq = mdp5_crtc_vblank_irq; +	mdp5_crtc->err.irq = mdp5_crtc_err_irq; + +	snprintf(mdp5_crtc->name, sizeof(mdp5_crtc->name), "%s:%d", +			pipe2name(mdp5_plane_pipe(plane)), id); + +	ret = drm_flip_work_init(&mdp5_crtc->unref_fb_work, 16, +			"unref fb", unref_fb_worker); +	if (ret) +		goto fail; + +	INIT_FENCE_CB(&mdp5_crtc->pageflip_cb, pageflip_cb); + +	drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp5_crtc_funcs); +	drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs); + +	mdp5_plane_install_properties(mdp5_crtc->plane, &crtc->base); + +	return crtc; + +fail: +	if (crtc) +		mdp5_crtc_destroy(crtc); + +	return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c new file mode 100644 index 00000000000..edec7bfaa95 --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include "mdp5_kms.h" + +#include "drm_crtc.h" +#include "drm_crtc_helper.h" + +struct mdp5_encoder { +	struct drm_encoder base; +	int intf; +	enum mdp5_intf intf_id; +	bool enabled; +	uint32_t bsc; +}; +#define to_mdp5_encoder(x) container_of(x, struct mdp5_encoder, base) + +static struct mdp5_kms *get_kms(struct drm_encoder *encoder) +{ +	struct msm_drm_private *priv = encoder->dev->dev_private; +	return to_mdp5_kms(to_mdp_kms(priv->kms)); +} + +#ifdef CONFIG_MSM_BUS_SCALING +#include <mach/board.h> +#include <mach/msm_bus.h> +#include <mach/msm_bus_board.h> +#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val)		\ +	{						\ +		.src = MSM_BUS_MASTER_MDP_PORT0,	\ +		.dst = MSM_BUS_SLAVE_EBI_CH0,		\ +		.ab = (ab_val),				\ +		.ib = (ib_val),				\ +	} + +static struct msm_bus_vectors mdp_bus_vectors[] = { +	MDP_BUS_VECTOR_ENTRY(0, 0), +	MDP_BUS_VECTOR_ENTRY(2000000000, 2000000000), +}; +static struct msm_bus_paths mdp_bus_usecases[] = { { +		.num_paths = 1, +		.vectors = &mdp_bus_vectors[0], +}, { +		.num_paths = 1, +		.vectors = &mdp_bus_vectors[1], +} }; +static struct msm_bus_scale_pdata mdp_bus_scale_table = { +	.usecase = mdp_bus_usecases, +	.num_usecases = ARRAY_SIZE(mdp_bus_usecases), +	.name = "mdss_mdp", +}; + +static void bs_init(struct mdp5_encoder *mdp5_encoder) +{ +	mdp5_encoder->bsc = msm_bus_scale_register_client( +			&mdp_bus_scale_table); +	DBG("bus scale client: %08x", mdp5_encoder->bsc); +} + +static void bs_fini(struct mdp5_encoder *mdp5_encoder) +{ +	if (mdp5_encoder->bsc) { +		msm_bus_scale_unregister_client(mdp5_encoder->bsc); +		mdp5_encoder->bsc = 0; +	} +} + +static void bs_set(struct mdp5_encoder *mdp5_encoder, int idx) +{ +	if (mdp5_encoder->bsc) { +		DBG("set bus scaling: %d", idx); +		/* HACK: scaling down, and then immediately back up +		 * seems to leave things broken (underflow).. so +		 * never disable: +		 */ +		idx = 1; +		msm_bus_scale_client_update_request(mdp5_encoder->bsc, idx); +	} +} +#else +static void bs_init(struct mdp5_encoder *mdp5_encoder) {} +static void bs_fini(struct mdp5_encoder *mdp5_encoder) {} +static void bs_set(struct mdp5_encoder *mdp5_encoder, int idx) {} +#endif + +static void mdp5_encoder_destroy(struct drm_encoder *encoder) +{ +	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder); +	bs_fini(mdp5_encoder); +	drm_encoder_cleanup(encoder); +	kfree(mdp5_encoder); +} + +static const struct drm_encoder_funcs mdp5_encoder_funcs = { +	.destroy = mdp5_encoder_destroy, +}; + +static void mdp5_encoder_dpms(struct drm_encoder *encoder, int mode) +{ +	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder); +	struct mdp5_kms *mdp5_kms = get_kms(encoder); +	int intf = mdp5_encoder->intf; +	bool enabled = (mode == DRM_MODE_DPMS_ON); + +	DBG("mode=%d", mode); + +	if (enabled == mdp5_encoder->enabled) +		return; + +	if (enabled) { +		bs_set(mdp5_encoder, 1); +		mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 1); +	} else { +		mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 0); +		bs_set(mdp5_encoder, 0); +	} + +	mdp5_encoder->enabled = enabled; +} + +static bool mdp5_encoder_mode_fixup(struct drm_encoder *encoder, +		const struct drm_display_mode *mode, +		struct drm_display_mode *adjusted_mode) +{ +	return true; +} + +static void mdp5_encoder_mode_set(struct drm_encoder *encoder, +		struct drm_display_mode *mode, +		struct drm_display_mode *adjusted_mode) +{ +	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder); +	struct mdp5_kms *mdp5_kms = get_kms(encoder); +	int intf = mdp5_encoder->intf; +	uint32_t dtv_hsync_skew, vsync_period, vsync_len, ctrl_pol; +	uint32_t display_v_start, display_v_end; +	uint32_t hsync_start_x, hsync_end_x; +	uint32_t format; + +	mode = adjusted_mode; + +	DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", +			mode->base.id, mode->name, +			mode->vrefresh, mode->clock, +			mode->hdisplay, mode->hsync_start, +			mode->hsync_end, mode->htotal, +			mode->vdisplay, mode->vsync_start, +			mode->vsync_end, mode->vtotal, +			mode->type, mode->flags); + +	ctrl_pol = 0; +	if (mode->flags & DRM_MODE_FLAG_NHSYNC) +		ctrl_pol |= MDP5_INTF_POLARITY_CTL_HSYNC_LOW; +	if (mode->flags & DRM_MODE_FLAG_NVSYNC) +		ctrl_pol |= MDP5_INTF_POLARITY_CTL_VSYNC_LOW; +	/* probably need to get DATA_EN polarity from panel.. */ + +	dtv_hsync_skew = 0;  /* get this from panel? */ +	format = 0x213f;     /* get this from panel? */ + +	hsync_start_x = (mode->htotal - mode->hsync_start); +	hsync_end_x = mode->htotal - (mode->hsync_start - mode->hdisplay) - 1; + +	vsync_period = mode->vtotal * mode->htotal; +	vsync_len = (mode->vsync_end - mode->vsync_start) * mode->htotal; +	display_v_start = (mode->vtotal - mode->vsync_start) * mode->htotal + dtv_hsync_skew; +	display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + dtv_hsync_skew - 1; + +	mdp5_write(mdp5_kms, REG_MDP5_INTF_HSYNC_CTL(intf), +			MDP5_INTF_HSYNC_CTL_PULSEW(mode->hsync_end - mode->hsync_start) | +			MDP5_INTF_HSYNC_CTL_PERIOD(mode->htotal)); +	mdp5_write(mdp5_kms, REG_MDP5_INTF_VSYNC_PERIOD_F0(intf), vsync_period); +	mdp5_write(mdp5_kms, REG_MDP5_INTF_VSYNC_LEN_F0(intf), vsync_len); +	mdp5_write(mdp5_kms, REG_MDP5_INTF_DISPLAY_HCTL(intf), +			MDP5_INTF_DISPLAY_HCTL_START(hsync_start_x) | +			MDP5_INTF_DISPLAY_HCTL_END(hsync_end_x)); +	mdp5_write(mdp5_kms, REG_MDP5_INTF_DISPLAY_VSTART_F0(intf), display_v_start); +	mdp5_write(mdp5_kms, REG_MDP5_INTF_DISPLAY_VEND_F0(intf), display_v_end); +	mdp5_write(mdp5_kms, REG_MDP5_INTF_BORDER_COLOR(intf), 0); +	mdp5_write(mdp5_kms, REG_MDP5_INTF_UNDERFLOW_COLOR(intf), 0xff); +	mdp5_write(mdp5_kms, REG_MDP5_INTF_HSYNC_SKEW(intf), dtv_hsync_skew); +	mdp5_write(mdp5_kms, REG_MDP5_INTF_POLARITY_CTL(intf), ctrl_pol); +	mdp5_write(mdp5_kms, REG_MDP5_INTF_ACTIVE_HCTL(intf), +			MDP5_INTF_ACTIVE_HCTL_START(0) | +			MDP5_INTF_ACTIVE_HCTL_END(0)); +	mdp5_write(mdp5_kms, REG_MDP5_INTF_ACTIVE_VSTART_F0(intf), 0); +	mdp5_write(mdp5_kms, REG_MDP5_INTF_ACTIVE_VEND_F0(intf), 0); +	mdp5_write(mdp5_kms, REG_MDP5_INTF_PANEL_FORMAT(intf), format); +	mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(intf), 0x3);  /* frame+line? */ +} + +static void mdp5_encoder_prepare(struct drm_encoder *encoder) +{ +	mdp5_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void mdp5_encoder_commit(struct drm_encoder *encoder) +{ +	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder); +	mdp5_crtc_set_intf(encoder->crtc, mdp5_encoder->intf, +			mdp5_encoder->intf_id); +	mdp5_encoder_dpms(encoder, DRM_MODE_DPMS_ON); +} + +static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = { +	.dpms = mdp5_encoder_dpms, +	.mode_fixup = mdp5_encoder_mode_fixup, +	.mode_set = mdp5_encoder_mode_set, +	.prepare = mdp5_encoder_prepare, +	.commit = mdp5_encoder_commit, +}; + +/* initialize encoder */ +struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, int intf, +		enum mdp5_intf intf_id) +{ +	struct drm_encoder *encoder = NULL; +	struct mdp5_encoder *mdp5_encoder; +	int ret; + +	mdp5_encoder = kzalloc(sizeof(*mdp5_encoder), GFP_KERNEL); +	if (!mdp5_encoder) { +		ret = -ENOMEM; +		goto fail; +	} + +	mdp5_encoder->intf = intf; +	mdp5_encoder->intf_id = intf_id; +	encoder = &mdp5_encoder->base; + +	drm_encoder_init(dev, encoder, &mdp5_encoder_funcs, +			 DRM_MODE_ENCODER_TMDS); +	drm_encoder_helper_add(encoder, &mdp5_encoder_helper_funcs); + +	bs_init(mdp5_encoder); + +	return encoder; + +fail: +	if (encoder) +		mdp5_encoder_destroy(encoder); + +	return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c new file mode 100644 index 00000000000..f2b985bc2ad --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + + +#include "msm_drv.h" +#include "mdp5_kms.h" + +void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask) +{ +	mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_INTR_EN, irqmask); +} + +static void mdp5_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus) +{ +	DRM_ERROR("errors: %08x\n", irqstatus); +} + +void mdp5_irq_preinstall(struct msm_kms *kms) +{ +	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); +	mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, 0xffffffff); +} + +int mdp5_irq_postinstall(struct msm_kms *kms) +{ +	struct mdp_kms *mdp_kms = to_mdp_kms(kms); +	struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms); +	struct mdp_irq *error_handler = &mdp5_kms->error_handler; + +	error_handler->irq = mdp5_irq_error_handler; +	error_handler->irqmask = MDP5_IRQ_INTF0_UNDER_RUN | +			MDP5_IRQ_INTF1_UNDER_RUN | +			MDP5_IRQ_INTF2_UNDER_RUN | +			MDP5_IRQ_INTF3_UNDER_RUN; + +	mdp_irq_register(mdp_kms, error_handler); + +	return 0; +} + +void mdp5_irq_uninstall(struct msm_kms *kms) +{ +	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); +	mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000); +} + +static void mdp5_irq_mdp(struct mdp_kms *mdp_kms) +{ +	struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms); +	struct drm_device *dev = mdp5_kms->dev; +	struct msm_drm_private *priv = dev->dev_private; +	unsigned int id; +	uint32_t status; + +	status = mdp5_read(mdp5_kms, REG_MDP5_INTR_STATUS); +	mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, status); + +	VERB("status=%08x", status); + +	mdp_dispatch_irqs(mdp_kms, status); + +	for (id = 0; id < priv->num_crtcs; id++) +		if (status & mdp5_crtc_vblank(priv->crtcs[id])) +			drm_handle_vblank(dev, id); +} + +irqreturn_t mdp5_irq(struct msm_kms *kms) +{ +	struct mdp_kms *mdp_kms = to_mdp_kms(kms); +	struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms); +	uint32_t intr; + +	intr = mdp5_read(mdp5_kms, REG_MDP5_HW_INTR_STATUS); + +	VERB("intr=%08x", intr); + +	if (intr & MDP5_HW_INTR_STATUS_INTR_MDP) +		mdp5_irq_mdp(mdp_kms); + +	if (intr & MDP5_HW_INTR_STATUS_INTR_HDMI) +		hdmi_irq(0, mdp5_kms->hdmi); + +	return IRQ_HANDLED; +} + +int mdp5_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) +{ +	mdp_update_vblank_mask(to_mdp_kms(kms), +			mdp5_crtc_vblank(crtc), true); +	return 0; +} + +void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) +{ +	mdp_update_vblank_mask(to_mdp_kms(kms), +			mdp5_crtc_vblank(crtc), false); +} diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c new file mode 100644 index 00000000000..71510ee26e9 --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -0,0 +1,372 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + + +#include "msm_drv.h" +#include "msm_mmu.h" +#include "mdp5_kms.h" + +static const char *iommu_ports[] = { +		"mdp_0", +}; + +static struct mdp5_platform_config *mdp5_get_config(struct platform_device *dev); + +static int mdp5_hw_init(struct msm_kms *kms) +{ +	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); +	struct drm_device *dev = mdp5_kms->dev; +	uint32_t version, major, minor; +	int ret = 0; + +	pm_runtime_get_sync(dev->dev); + +	mdp5_enable(mdp5_kms); +	version = mdp5_read(mdp5_kms, REG_MDP5_MDP_VERSION); +	mdp5_disable(mdp5_kms); + +	major = FIELD(version, MDP5_MDP_VERSION_MAJOR); +	minor = FIELD(version, MDP5_MDP_VERSION_MINOR); + +	DBG("found MDP5 version v%d.%d", major, minor); + +	if ((major != 1) || ((minor != 0) && (minor != 2))) { +		dev_err(dev->dev, "unexpected MDP version: v%d.%d\n", +				major, minor); +		ret = -ENXIO; +		goto out; +	} + +	mdp5_kms->rev = minor; + +	/* Magic unknown register writes: +	 * +	 *    W VBIF:0x004 00000001      (mdss_mdp.c:839) +	 *    W MDP5:0x2e0 0xe9          (mdss_mdp.c:839) +	 *    W MDP5:0x2e4 0x55          (mdss_mdp.c:839) +	 *    W MDP5:0x3ac 0xc0000ccc    (mdss_mdp.c:839) +	 *    W MDP5:0x3b4 0xc0000ccc    (mdss_mdp.c:839) +	 *    W MDP5:0x3bc 0xcccccc      (mdss_mdp.c:839) +	 *    W MDP5:0x4a8 0xcccc0c0     (mdss_mdp.c:839) +	 *    W MDP5:0x4b0 0xccccc0c0    (mdss_mdp.c:839) +	 *    W MDP5:0x4b8 0xccccc000    (mdss_mdp.c:839) +	 * +	 * Downstream fbdev driver gets these register offsets/values +	 * from DT.. not really sure what these registers are or if +	 * different values for different boards/SoC's, etc.  I guess +	 * they are the golden registers. +	 * +	 * Not setting these does not seem to cause any problem.  But +	 * we may be getting lucky with the bootloader initializing +	 * them for us.  OTOH, if we can always count on the bootloader +	 * setting the golden registers, then perhaps we don't need to +	 * care. +	 */ + +	mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, 0); +	mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(0), 0); +	mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(1), 0); +	mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(2), 0); +	mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(3), 0); + +out: +	pm_runtime_put_sync(dev->dev); + +	return ret; +} + +static long mdp5_round_pixclk(struct msm_kms *kms, unsigned long rate, +		struct drm_encoder *encoder) +{ +	return rate; +} + +static void mdp5_preclose(struct msm_kms *kms, struct drm_file *file) +{ +	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); +	struct msm_drm_private *priv = mdp5_kms->dev->dev_private; +	unsigned i; + +	for (i = 0; i < priv->num_crtcs; i++) +		mdp5_crtc_cancel_pending_flip(priv->crtcs[i], file); +} + +static void mdp5_destroy(struct msm_kms *kms) +{ +	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); +	struct msm_mmu *mmu = mdp5_kms->mmu; + +	if (mmu) { +		mmu->funcs->detach(mmu, iommu_ports, ARRAY_SIZE(iommu_ports)); +		mmu->funcs->destroy(mmu); +	} +	kfree(mdp5_kms); +} + +static const struct mdp_kms_funcs kms_funcs = { +	.base = { +		.hw_init         = mdp5_hw_init, +		.irq_preinstall  = mdp5_irq_preinstall, +		.irq_postinstall = mdp5_irq_postinstall, +		.irq_uninstall   = mdp5_irq_uninstall, +		.irq             = mdp5_irq, +		.enable_vblank   = mdp5_enable_vblank, +		.disable_vblank  = mdp5_disable_vblank, +		.get_format      = mdp_get_format, +		.round_pixclk    = mdp5_round_pixclk, +		.preclose        = mdp5_preclose, +		.destroy         = mdp5_destroy, +	}, +	.set_irqmask         = mdp5_set_irqmask, +}; + +int mdp5_disable(struct mdp5_kms *mdp5_kms) +{ +	DBG(""); + +	clk_disable_unprepare(mdp5_kms->ahb_clk); +	clk_disable_unprepare(mdp5_kms->axi_clk); +	clk_disable_unprepare(mdp5_kms->core_clk); +	clk_disable_unprepare(mdp5_kms->lut_clk); + +	return 0; +} + +int mdp5_enable(struct mdp5_kms *mdp5_kms) +{ +	DBG(""); + +	clk_prepare_enable(mdp5_kms->ahb_clk); +	clk_prepare_enable(mdp5_kms->axi_clk); +	clk_prepare_enable(mdp5_kms->core_clk); +	clk_prepare_enable(mdp5_kms->lut_clk); + +	return 0; +} + +static int modeset_init(struct mdp5_kms *mdp5_kms) +{ +	static const enum mdp5_pipe crtcs[] = { +			SSPP_RGB0, SSPP_RGB1, SSPP_RGB2, +	}; +	struct drm_device *dev = mdp5_kms->dev; +	struct msm_drm_private *priv = dev->dev_private; +	struct drm_encoder *encoder; +	int i, ret; + +	/* construct CRTCs: */ +	for (i = 0; i < ARRAY_SIZE(crtcs); i++) { +		struct drm_plane *plane; +		struct drm_crtc *crtc; + +		plane = mdp5_plane_init(dev, crtcs[i], true); +		if (IS_ERR(plane)) { +			ret = PTR_ERR(plane); +			dev_err(dev->dev, "failed to construct plane for %s (%d)\n", +					pipe2name(crtcs[i]), ret); +			goto fail; +		} + +		crtc  = mdp5_crtc_init(dev, plane, i); +		if (IS_ERR(crtc)) { +			ret = PTR_ERR(crtc); +			dev_err(dev->dev, "failed to construct crtc for %s (%d)\n", +					pipe2name(crtcs[i]), ret); +			goto fail; +		} +		priv->crtcs[priv->num_crtcs++] = crtc; +	} + +	/* Construct encoder for HDMI: */ +	encoder = mdp5_encoder_init(dev, 3, INTF_HDMI); +	if (IS_ERR(encoder)) { +		dev_err(dev->dev, "failed to construct encoder\n"); +		ret = PTR_ERR(encoder); +		goto fail; +	} + +	/* NOTE: the vsync and error irq's are actually associated with +	 * the INTF/encoder.. the easiest way to deal with this (ie. what +	 * we do now) is assume a fixed relationship between crtc's and +	 * encoders.  I'm not sure if there is ever a need to more freely +	 * assign crtcs to encoders, but if there is then we need to take +	 * care of error and vblank irq's that the crtc has registered, +	 * and also update user-requested vblank_mask. +	 */ +	encoder->possible_crtcs = BIT(0); +	mdp5_crtc_set_intf(priv->crtcs[0], 3, INTF_HDMI); + +	priv->encoders[priv->num_encoders++] = encoder; + +	/* Construct bridge/connector for HDMI: */ +	mdp5_kms->hdmi = hdmi_init(dev, encoder); +	if (IS_ERR(mdp5_kms->hdmi)) { +		ret = PTR_ERR(mdp5_kms->hdmi); +		dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret); +		goto fail; +	} + +	return 0; + +fail: +	return ret; +} + +static int get_clk(struct platform_device *pdev, struct clk **clkp, +		const char *name) +{ +	struct device *dev = &pdev->dev; +	struct clk *clk = devm_clk_get(dev, name); +	if (IS_ERR(clk)) { +		dev_err(dev, "failed to get %s (%ld)\n", name, PTR_ERR(clk)); +		return PTR_ERR(clk); +	} +	*clkp = clk; +	return 0; +} + +struct msm_kms *mdp5_kms_init(struct drm_device *dev) +{ +	struct platform_device *pdev = dev->platformdev; +	struct mdp5_platform_config *config = mdp5_get_config(pdev); +	struct mdp5_kms *mdp5_kms; +	struct msm_kms *kms = NULL; +	struct msm_mmu *mmu; +	int ret; + +	mdp5_kms = kzalloc(sizeof(*mdp5_kms), GFP_KERNEL); +	if (!mdp5_kms) { +		dev_err(dev->dev, "failed to allocate kms\n"); +		ret = -ENOMEM; +		goto fail; +	} + +	mdp_kms_init(&mdp5_kms->base, &kms_funcs); + +	kms = &mdp5_kms->base.base; + +	mdp5_kms->dev = dev; +	mdp5_kms->smp_blk_cnt = config->smp_blk_cnt; + +	mdp5_kms->mmio = msm_ioremap(pdev, "mdp_phys", "MDP5"); +	if (IS_ERR(mdp5_kms->mmio)) { +		ret = PTR_ERR(mdp5_kms->mmio); +		goto fail; +	} + +	mdp5_kms->vbif = msm_ioremap(pdev, "vbif_phys", "VBIF"); +	if (IS_ERR(mdp5_kms->vbif)) { +		ret = PTR_ERR(mdp5_kms->vbif); +		goto fail; +	} + +	mdp5_kms->vdd = devm_regulator_get(&pdev->dev, "vdd"); +	if (IS_ERR(mdp5_kms->vdd)) { +		ret = PTR_ERR(mdp5_kms->vdd); +		goto fail; +	} + +	ret = regulator_enable(mdp5_kms->vdd); +	if (ret) { +		dev_err(dev->dev, "failed to enable regulator vdd: %d\n", ret); +		goto fail; +	} + +	ret = get_clk(pdev, &mdp5_kms->axi_clk, "bus_clk"); +	if (ret) +		goto fail; +	ret = get_clk(pdev, &mdp5_kms->ahb_clk, "iface_clk"); +	if (ret) +		goto fail; +	ret = get_clk(pdev, &mdp5_kms->src_clk, "core_clk_src"); +	if (ret) +		goto fail; +	ret = get_clk(pdev, &mdp5_kms->core_clk, "core_clk"); +	if (ret) +		goto fail; +	ret = get_clk(pdev, &mdp5_kms->lut_clk, "lut_clk"); +	if (ret) +		goto fail; +	ret = get_clk(pdev, &mdp5_kms->vsync_clk, "vsync_clk"); +	if (ret) +		goto fail; + +	ret = clk_set_rate(mdp5_kms->src_clk, config->max_clk); + +	/* make sure things are off before attaching iommu (bootloader could +	 * have left things on, in which case we'll start getting faults if +	 * we don't disable): +	 */ +	mdp5_enable(mdp5_kms); +	mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(0), 0); +	mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(1), 0); +	mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(2), 0); +	mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(3), 0); +	mdp5_disable(mdp5_kms); +	mdelay(16); + +	if (config->iommu) { +		mmu = msm_iommu_new(dev, config->iommu); +		if (IS_ERR(mmu)) { +			ret = PTR_ERR(mmu); +			dev_err(dev->dev, "failed to init iommu: %d\n", ret); +			goto fail; +		} + +		ret = mmu->funcs->attach(mmu, iommu_ports, +				ARRAY_SIZE(iommu_ports)); +		if (ret) { +			dev_err(dev->dev, "failed to attach iommu: %d\n", ret); +			mmu->funcs->destroy(mmu); +			goto fail; +		} +	} else { +		dev_info(dev->dev, "no iommu, fallback to phys " +				"contig buffers for scanout\n"); +		mmu = NULL; +	} +	mdp5_kms->mmu = mmu; + +	mdp5_kms->id = msm_register_mmu(dev, mmu); +	if (mdp5_kms->id < 0) { +		ret = mdp5_kms->id; +		dev_err(dev->dev, "failed to register mdp5 iommu: %d\n", ret); +		goto fail; +	} + +	ret = modeset_init(mdp5_kms); +	if (ret) { +		dev_err(dev->dev, "modeset_init failed: %d\n", ret); +		goto fail; +	} + +	return kms; + +fail: +	if (kms) +		mdp5_destroy(kms); +	return ERR_PTR(ret); +} + +static struct mdp5_platform_config *mdp5_get_config(struct platform_device *dev) +{ +	static struct mdp5_platform_config config = {}; +#ifdef CONFIG_OF +	/* TODO */ +#endif +	return &config; +} diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h new file mode 100644 index 00000000000..6e981b692d1 --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __MDP5_KMS_H__ +#define __MDP5_KMS_H__ + +#include "msm_drv.h" +#include "msm_kms.h" +#include "mdp/mdp_kms.h" +#include "mdp5.xml.h" +#include "mdp5_smp.h" + +struct mdp5_kms { +	struct mdp_kms base; + +	struct drm_device *dev; + +	int rev; + +	/* mapper-id used to request GEM buffer mapped for scanout: */ +	int id; +	struct msm_mmu *mmu; + +	/* for tracking smp allocation amongst pipes: */ +	mdp5_smp_state_t smp_state; +	struct mdp5_client_smp_state smp_client_state[CID_MAX]; +	int smp_blk_cnt; + +	/* io/register spaces: */ +	void __iomem *mmio, *vbif; + +	struct regulator *vdd; + +	struct clk *axi_clk; +	struct clk *ahb_clk; +	struct clk *src_clk; +	struct clk *core_clk; +	struct clk *lut_clk; +	struct clk *vsync_clk; + +	struct hdmi *hdmi; + +	struct mdp_irq error_handler; +}; +#define to_mdp5_kms(x) container_of(x, struct mdp5_kms, base) + +/* platform config data (ie. from DT, or pdata) */ +struct mdp5_platform_config { +	struct iommu_domain *iommu; +	uint32_t max_clk; +	int smp_blk_cnt; +}; + +static inline void mdp5_write(struct mdp5_kms *mdp5_kms, u32 reg, u32 data) +{ +	msm_writel(data, mdp5_kms->mmio + reg); +} + +static inline u32 mdp5_read(struct mdp5_kms *mdp5_kms, u32 reg) +{ +	return msm_readl(mdp5_kms->mmio + reg); +} + +static inline const char *pipe2name(enum mdp5_pipe pipe) +{ +	static const char *names[] = { +#define NAME(n) [SSPP_ ## n] = #n +		NAME(VIG0), NAME(VIG1), NAME(VIG2), +		NAME(RGB0), NAME(RGB1), NAME(RGB2), +		NAME(DMA0), NAME(DMA1), +#undef NAME +	}; +	return names[pipe]; +} + +static inline uint32_t pipe2flush(enum mdp5_pipe pipe) +{ +	switch (pipe) { +	case SSPP_VIG0: return MDP5_CTL_FLUSH_VIG0; +	case SSPP_VIG1: return MDP5_CTL_FLUSH_VIG1; +	case SSPP_VIG2: return MDP5_CTL_FLUSH_VIG2; +	case SSPP_RGB0: return MDP5_CTL_FLUSH_RGB0; +	case SSPP_RGB1: return MDP5_CTL_FLUSH_RGB1; +	case SSPP_RGB2: return MDP5_CTL_FLUSH_RGB2; +	case SSPP_DMA0: return MDP5_CTL_FLUSH_DMA0; +	case SSPP_DMA1: return MDP5_CTL_FLUSH_DMA1; +	default:        return 0; +	} +} + +static inline int pipe2nclients(enum mdp5_pipe pipe) +{ +	switch (pipe) { +	case SSPP_RGB0: +	case SSPP_RGB1: +	case SSPP_RGB2: +		return 1; +	default: +		return 3; +	} +} + +static inline enum mdp5_client_id pipe2client(enum mdp5_pipe pipe, int plane) +{ +	WARN_ON(plane >= pipe2nclients(pipe)); +	switch (pipe) { +	case SSPP_VIG0: return CID_VIG0_Y + plane; +	case SSPP_VIG1: return CID_VIG1_Y + plane; +	case SSPP_VIG2: return CID_VIG2_Y + plane; +	case SSPP_RGB0: return CID_RGB0; +	case SSPP_RGB1: return CID_RGB1; +	case SSPP_RGB2: return CID_RGB2; +	case SSPP_DMA0: return CID_DMA0_Y + plane; +	case SSPP_DMA1: return CID_DMA1_Y + plane; +	default:        return CID_UNUSED; +	} +} + +static inline uint32_t mixer2flush(int lm) +{ +	switch (lm) { +	case 0:  return MDP5_CTL_FLUSH_LM0; +	case 1:  return MDP5_CTL_FLUSH_LM1; +	case 2:  return MDP5_CTL_FLUSH_LM2; +	default: return 0; +	} +} + +static inline uint32_t intf2err(int intf) +{ +	switch (intf) { +	case 0:  return MDP5_IRQ_INTF0_UNDER_RUN; +	case 1:  return MDP5_IRQ_INTF1_UNDER_RUN; +	case 2:  return MDP5_IRQ_INTF2_UNDER_RUN; +	case 3:  return MDP5_IRQ_INTF3_UNDER_RUN; +	default: return 0; +	} +} + +static inline uint32_t intf2vblank(int intf) +{ +	switch (intf) { +	case 0:  return MDP5_IRQ_INTF0_VSYNC; +	case 1:  return MDP5_IRQ_INTF1_VSYNC; +	case 2:  return MDP5_IRQ_INTF2_VSYNC; +	case 3:  return MDP5_IRQ_INTF3_VSYNC; +	default: return 0; +	} +} + +int mdp5_disable(struct mdp5_kms *mdp5_kms); +int mdp5_enable(struct mdp5_kms *mdp5_kms); + +void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask); +void mdp5_irq_preinstall(struct msm_kms *kms); +int mdp5_irq_postinstall(struct msm_kms *kms); +void mdp5_irq_uninstall(struct msm_kms *kms); +irqreturn_t mdp5_irq(struct msm_kms *kms); +int mdp5_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); +void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); + +static inline +uint32_t mdp5_get_formats(enum mdp5_pipe pipe, uint32_t *pixel_formats, +		uint32_t max_formats) +{ +	/* TODO when we have YUV, we need to filter supported formats +	 * based on pipe id.. +	 */ +	return mdp_get_formats(pixel_formats, max_formats); +} + +void mdp5_plane_install_properties(struct drm_plane *plane, +		struct drm_mode_object *obj); +void mdp5_plane_set_scanout(struct drm_plane *plane, +		struct drm_framebuffer *fb); +int mdp5_plane_mode_set(struct drm_plane *plane, +		struct drm_crtc *crtc, struct drm_framebuffer *fb, +		int crtc_x, int crtc_y, +		unsigned int crtc_w, unsigned int crtc_h, +		uint32_t src_x, uint32_t src_y, +		uint32_t src_w, uint32_t src_h); +void mdp5_plane_complete_flip(struct drm_plane *plane); +enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane); +struct drm_plane *mdp5_plane_init(struct drm_device *dev, +		enum mdp5_pipe pipe, bool private_plane); + +uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc); + +void mdp5_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file); +void mdp5_crtc_set_intf(struct drm_crtc *crtc, int intf, +		enum mdp5_intf intf_id); +void mdp5_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane); +void mdp5_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane); +struct drm_crtc *mdp5_crtc_init(struct drm_device *dev, +		struct drm_plane *plane, int id); + +struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, int intf, +		enum mdp5_intf intf_id); + +#endif /* __MDP5_KMS_H__ */ diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c new file mode 100644 index 00000000000..f3daec4412a --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -0,0 +1,394 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include "mdp5_kms.h" + + +struct mdp5_plane { +	struct drm_plane base; +	const char *name; + +	enum mdp5_pipe pipe; + +	uint32_t nformats; +	uint32_t formats[32]; + +	bool enabled; +}; +#define to_mdp5_plane(x) container_of(x, struct mdp5_plane, base) + +static struct mdp5_kms *get_kms(struct drm_plane *plane) +{ +	struct msm_drm_private *priv = plane->dev->dev_private; +	return to_mdp5_kms(to_mdp_kms(priv->kms)); +} + +static int mdp5_plane_update(struct drm_plane *plane, +		struct drm_crtc *crtc, struct drm_framebuffer *fb, +		int crtc_x, int crtc_y, +		unsigned int crtc_w, unsigned int crtc_h, +		uint32_t src_x, uint32_t src_y, +		uint32_t src_w, uint32_t src_h) +{ +	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); + +	mdp5_plane->enabled = true; + +	if (plane->fb) +		drm_framebuffer_unreference(plane->fb); + +	drm_framebuffer_reference(fb); + +	return mdp5_plane_mode_set(plane, crtc, fb, +			crtc_x, crtc_y, crtc_w, crtc_h, +			src_x, src_y, src_w, src_h); +} + +static int mdp5_plane_disable(struct drm_plane *plane) +{ +	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); +	struct mdp5_kms *mdp5_kms = get_kms(plane); +	enum mdp5_pipe pipe = mdp5_plane->pipe; +	int i; + +	DBG("%s: disable", mdp5_plane->name); + +	/* update our SMP request to zero (release all our blks): */ +	for (i = 0; i < pipe2nclients(pipe); i++) +		mdp5_smp_request(mdp5_kms, pipe2client(pipe, i), 0); + +	/* TODO detaching now will cause us not to get the last +	 * vblank and mdp5_smp_commit().. so other planes will +	 * still see smp blocks previously allocated to us as +	 * in-use.. +	 */ +	if (plane->crtc) +		mdp5_crtc_detach(plane->crtc, plane); + +	return 0; +} + +static void mdp5_plane_destroy(struct drm_plane *plane) +{ +	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); +	struct msm_drm_private *priv = plane->dev->dev_private; + +	if (priv->kms) +		mdp5_plane_disable(plane); + +	drm_plane_cleanup(plane); + +	kfree(mdp5_plane); +} + +/* helper to install properties which are common to planes and crtcs */ +void mdp5_plane_install_properties(struct drm_plane *plane, +		struct drm_mode_object *obj) +{ +	// XXX +} + +int mdp5_plane_set_property(struct drm_plane *plane, +		struct drm_property *property, uint64_t val) +{ +	// XXX +	return -EINVAL; +} + +static const struct drm_plane_funcs mdp5_plane_funcs = { +		.update_plane = mdp5_plane_update, +		.disable_plane = mdp5_plane_disable, +		.destroy = mdp5_plane_destroy, +		.set_property = mdp5_plane_set_property, +}; + +void mdp5_plane_set_scanout(struct drm_plane *plane, +		struct drm_framebuffer *fb) +{ +	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); +	struct mdp5_kms *mdp5_kms = get_kms(plane); +	enum mdp5_pipe pipe = mdp5_plane->pipe; +	uint32_t nplanes = drm_format_num_planes(fb->pixel_format); +	uint32_t iova[4]; +	int i; + +	for (i = 0; i < nplanes; i++) { +		struct drm_gem_object *bo = msm_framebuffer_bo(fb, i); +		msm_gem_get_iova(bo, mdp5_kms->id, &iova[i]); +	} +	for (; i < 4; i++) +		iova[i] = 0; + +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_A(pipe), +			MDP5_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) | +			MDP5_PIPE_SRC_STRIDE_A_P1(fb->pitches[1])); + +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_B(pipe), +			MDP5_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) | +			MDP5_PIPE_SRC_STRIDE_B_P3(fb->pitches[3])); + +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC0_ADDR(pipe), iova[0]); +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC1_ADDR(pipe), iova[1]); +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC2_ADDR(pipe), iova[2]); +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC3_ADDR(pipe), iova[3]); + +	plane->fb = fb; +} + +/* NOTE: looks like if horizontal decimation is used (if we supported that) + * then the width used to calculate SMP block requirements is the post- + * decimated width.  Ie. SMP buffering sits downstream of decimation (which + * presumably happens during the dma from scanout buffer). + */ +static int request_smp_blocks(struct drm_plane *plane, uint32_t format, +		uint32_t nplanes, uint32_t width) +{ +	struct drm_device *dev = plane->dev; +	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); +	struct mdp5_kms *mdp5_kms = get_kms(plane); +	enum mdp5_pipe pipe = mdp5_plane->pipe; +	int i, hsub, nlines, nblks, ret; + +	hsub = drm_format_horz_chroma_subsampling(format); + +	/* different if BWC (compressed framebuffer?) enabled: */ +	nlines = 2; + +	for (i = 0, nblks = 0; i < nplanes; i++) { +		int n, fetch_stride, cpp; + +		cpp = drm_format_plane_cpp(format, i); +		fetch_stride = width * cpp / (i ? hsub : 1); + +		n = DIV_ROUND_UP(fetch_stride * nlines, SMP_BLK_SIZE); + +		/* for hw rev v1.00 */ +		if (mdp5_kms->rev == 0) +			n = roundup_pow_of_two(n); + +		DBG("%s[%d]: request %d SMP blocks", mdp5_plane->name, i, n); +		ret = mdp5_smp_request(mdp5_kms, pipe2client(pipe, i), n); +		if (ret) { +			dev_err(dev->dev, "Could not allocate %d SMP blocks: %d\n", +					n, ret); +			return ret; +		} + +		nblks += n; +	} + +	/* in success case, return total # of blocks allocated: */ +	return nblks; +} + +static void set_fifo_thresholds(struct drm_plane *plane, int nblks) +{ +	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); +	struct mdp5_kms *mdp5_kms = get_kms(plane); +	enum mdp5_pipe pipe = mdp5_plane->pipe; +	uint32_t val; + +	/* 1/4 of SMP pool that is being fetched */ +	val = (nblks * SMP_ENTRIES_PER_BLK) / 4; + +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_0(pipe), val * 1); +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_1(pipe), val * 2); +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_2(pipe), val * 3); + +} + +int mdp5_plane_mode_set(struct drm_plane *plane, +		struct drm_crtc *crtc, struct drm_framebuffer *fb, +		int crtc_x, int crtc_y, +		unsigned int crtc_w, unsigned int crtc_h, +		uint32_t src_x, uint32_t src_y, +		uint32_t src_w, uint32_t src_h) +{ +	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); +	struct mdp5_kms *mdp5_kms = get_kms(plane); +	enum mdp5_pipe pipe = mdp5_plane->pipe; +	const struct mdp_format *format; +	uint32_t nplanes, config = 0; +	uint32_t phasex_step = 0, phasey_step = 0; +	uint32_t hdecm = 0, vdecm = 0; +	int i, nblks; + +	nplanes = drm_format_num_planes(fb->pixel_format); + +	/* bad formats should already be rejected: */ +	if (WARN_ON(nplanes > pipe2nclients(pipe))) +		return -EINVAL; + +	/* src values are in Q16 fixed point, convert to integer: */ +	src_x = src_x >> 16; +	src_y = src_y >> 16; +	src_w = src_w >> 16; +	src_h = src_h >> 16; + +	DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp5_plane->name, +			fb->base.id, src_x, src_y, src_w, src_h, +			crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h); + +	/* +	 * Calculate and request required # of smp blocks: +	 */ +	nblks = request_smp_blocks(plane, fb->pixel_format, nplanes, src_w); +	if (nblks < 0) +		return nblks; + +	/* +	 * Currently we update the hw for allocations/requests immediately, +	 * but once atomic modeset/pageflip is in place, the allocation +	 * would move into atomic->check_plane_state(), while updating the +	 * hw would remain here: +	 */ +	for (i = 0; i < pipe2nclients(pipe); i++) +		mdp5_smp_configure(mdp5_kms, pipe2client(pipe, i)); + +	if (src_w != crtc_w) { +		config |= MDP5_PIPE_SCALE_CONFIG_SCALEX_EN; +		/* TODO calc phasex_step, hdecm */ +	} + +	if (src_h != crtc_h) { +		config |= MDP5_PIPE_SCALE_CONFIG_SCALEY_EN; +		/* TODO calc phasey_step, vdecm */ +	} + +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe), +			MDP5_PIPE_SRC_IMG_SIZE_WIDTH(src_w) | +			MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(src_h)); + +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_SIZE(pipe), +			MDP5_PIPE_SRC_SIZE_WIDTH(src_w) | +			MDP5_PIPE_SRC_SIZE_HEIGHT(src_h)); + +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_XY(pipe), +			MDP5_PIPE_SRC_XY_X(src_x) | +			MDP5_PIPE_SRC_XY_Y(src_y)); + +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_SIZE(pipe), +			MDP5_PIPE_OUT_SIZE_WIDTH(crtc_w) | +			MDP5_PIPE_OUT_SIZE_HEIGHT(crtc_h)); + +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_XY(pipe), +			MDP5_PIPE_OUT_XY_X(crtc_x) | +			MDP5_PIPE_OUT_XY_Y(crtc_y)); + +	mdp5_plane_set_scanout(plane, fb); + +	format = to_mdp_format(msm_framebuffer_format(fb)); + +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_FORMAT(pipe), +			MDP5_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) | +			MDP5_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) | +			MDP5_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) | +			MDP5_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) | +			COND(format->alpha_enable, MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE) | +			MDP5_PIPE_SRC_FORMAT_CPP(format->cpp - 1) | +			MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) | +			COND(format->unpack_tight, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT) | +			MDP5_PIPE_SRC_FORMAT_NUM_PLANES(nplanes - 1) | +			MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(CHROMA_RGB)); + +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe), +			MDP5_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) | +			MDP5_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) | +			MDP5_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) | +			MDP5_PIPE_SRC_UNPACK_ELEM3(format->unpack[3])); + +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_OP_MODE(pipe), +			MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS)); + +	/* not using secure mode: */ +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0); + +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe), phasex_step); +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe), phasey_step); +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe), +			MDP5_PIPE_DECIMATION_VERT(vdecm) | +			MDP5_PIPE_DECIMATION_HORZ(hdecm)); +	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe), +			MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(SCALE_FILTER_NEAREST) | +			MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(SCALE_FILTER_NEAREST) | +			MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(SCALE_FILTER_NEAREST) | +			MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(SCALE_FILTER_NEAREST) | +			MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(SCALE_FILTER_NEAREST) | +			MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(SCALE_FILTER_NEAREST)); + +	set_fifo_thresholds(plane, nblks); + +	/* TODO detach from old crtc (if we had more than one) */ +	mdp5_crtc_attach(crtc, plane); + +	return 0; +} + +void mdp5_plane_complete_flip(struct drm_plane *plane) +{ +	struct mdp5_kms *mdp5_kms = get_kms(plane); +	enum mdp5_pipe pipe = to_mdp5_plane(plane)->pipe; +	int i; + +	for (i = 0; i < pipe2nclients(pipe); i++) +		mdp5_smp_commit(mdp5_kms, pipe2client(pipe, i)); +} + +enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane) +{ +	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); +	return mdp5_plane->pipe; +} + +/* initialize plane */ +struct drm_plane *mdp5_plane_init(struct drm_device *dev, +		enum mdp5_pipe pipe, bool private_plane) +{ +	struct drm_plane *plane = NULL; +	struct mdp5_plane *mdp5_plane; +	int ret; +	enum drm_plane_type type; + +	mdp5_plane = kzalloc(sizeof(*mdp5_plane), GFP_KERNEL); +	if (!mdp5_plane) { +		ret = -ENOMEM; +		goto fail; +	} + +	plane = &mdp5_plane->base; + +	mdp5_plane->pipe = pipe; +	mdp5_plane->name = pipe2name(pipe); + +	mdp5_plane->nformats = mdp5_get_formats(pipe, mdp5_plane->formats, +			ARRAY_SIZE(mdp5_plane->formats)); + +	type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; +	drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs, +				 mdp5_plane->formats, mdp5_plane->nformats, +				 type); + +	mdp5_plane_install_properties(plane, &plane->base); + +	return plane; + +fail: +	if (plane) +		mdp5_plane_destroy(plane); + +	return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c new file mode 100644 index 00000000000..2d0236b963a --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + + +#include "mdp5_kms.h" +#include "mdp5_smp.h" + + +/* SMP - Shared Memory Pool + * + * These are shared between all the clients, where each plane in a + * scanout buffer is a SMP client.  Ie. scanout of 3 plane I420 on + * pipe VIG0 => 3 clients: VIG0_Y, VIG0_CB, VIG0_CR. + * + * Based on the size of the attached scanout buffer, a certain # of + * blocks must be allocated to that client out of the shared pool. + * + * For each block, it can be either free, or pending/in-use by a + * client.  The updates happen in three steps: + * + *  1) mdp5_smp_request(): + *     When plane scanout is setup, calculate required number of + *     blocks needed per client, and request.  Blocks not inuse or + *     pending by any other client are added to client's pending + *     set. + * + *  2) mdp5_smp_configure(): + *     As hw is programmed, before FLUSH, MDP5_SMP_ALLOC registers + *     are configured for the union(pending, inuse) + * + *  3) mdp5_smp_commit(): + *     After next vblank, copy pending -> inuse.  Optionally update + *     MDP5_SMP_ALLOC registers if there are newly unused blocks + * + * On the next vblank after changes have been committed to hw, the + * client's pending blocks become it's in-use blocks (and no-longer + * in-use blocks become available to other clients). + * + * btw, hurray for confusing overloaded acronyms!  :-/ + * + * NOTE: for atomic modeset/pageflip NONBLOCK operations, step #1 + * should happen at (or before)? atomic->check().  And we'd need + * an API to discard previous requests if update is aborted or + * (test-only). + * + * TODO would perhaps be nice to have debugfs to dump out kernel + * inuse and pending state of all clients.. + */ + +static DEFINE_SPINLOCK(smp_lock); + + +/* step #1: update # of blocks pending for the client: */ +int mdp5_smp_request(struct mdp5_kms *mdp5_kms, +		enum mdp5_client_id cid, int nblks) +{ +	struct mdp5_client_smp_state *ps = &mdp5_kms->smp_client_state[cid]; +	int i, ret, avail, cur_nblks, cnt = mdp5_kms->smp_blk_cnt; +	unsigned long flags; + +	spin_lock_irqsave(&smp_lock, flags); + +	avail = cnt - bitmap_weight(mdp5_kms->smp_state, cnt); +	if (nblks > avail) { +		ret = -ENOSPC; +		goto fail; +	} + +	cur_nblks = bitmap_weight(ps->pending, cnt); +	if (nblks > cur_nblks) { +		/* grow the existing pending reservation: */ +		for (i = cur_nblks; i < nblks; i++) { +			int blk = find_first_zero_bit(mdp5_kms->smp_state, cnt); +			set_bit(blk, ps->pending); +			set_bit(blk, mdp5_kms->smp_state); +		} +	} else { +		/* shrink the existing pending reservation: */ +		for (i = cur_nblks; i > nblks; i--) { +			int blk = find_first_bit(ps->pending, cnt); +			clear_bit(blk, ps->pending); +			/* don't clear in global smp_state until _commit() */ +		} +	} + +fail: +	spin_unlock_irqrestore(&smp_lock, flags); +	return 0; +} + +static void update_smp_state(struct mdp5_kms *mdp5_kms, +		enum mdp5_client_id cid, mdp5_smp_state_t *assigned) +{ +	int cnt = mdp5_kms->smp_blk_cnt; +	uint32_t blk, val; + +	for_each_set_bit(blk, *assigned, cnt) { +		int idx = blk / 3; +		int fld = blk % 3; + +		val = mdp5_read(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(idx)); + +		switch (fld) { +		case 0: +			val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK; +			val |= MDP5_SMP_ALLOC_W_REG_CLIENT0(cid); +			break; +		case 1: +			val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK; +			val |= MDP5_SMP_ALLOC_W_REG_CLIENT1(cid); +			break; +		case 2: +			val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK; +			val |= MDP5_SMP_ALLOC_W_REG_CLIENT2(cid); +			break; +		} + +		mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(idx), val); +		mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_R_REG(idx), val); +	} +} + +/* step #2: configure hw for union(pending, inuse): */ +void mdp5_smp_configure(struct mdp5_kms *mdp5_kms, enum mdp5_client_id cid) +{ +	struct mdp5_client_smp_state *ps = &mdp5_kms->smp_client_state[cid]; +	int cnt = mdp5_kms->smp_blk_cnt; +	mdp5_smp_state_t assigned; + +	bitmap_or(assigned, ps->inuse, ps->pending, cnt); +	update_smp_state(mdp5_kms, cid, &assigned); +} + +/* step #3: after vblank, copy pending -> inuse: */ +void mdp5_smp_commit(struct mdp5_kms *mdp5_kms, enum mdp5_client_id cid) +{ +	struct mdp5_client_smp_state *ps = &mdp5_kms->smp_client_state[cid]; +	int cnt = mdp5_kms->smp_blk_cnt; +	mdp5_smp_state_t released; + +	/* +	 * Figure out if there are any blocks we where previously +	 * using, which can be released and made available to other +	 * clients: +	 */ +	if (bitmap_andnot(released, ps->inuse, ps->pending, cnt)) { +		unsigned long flags; + +		spin_lock_irqsave(&smp_lock, flags); +		/* clear released blocks: */ +		bitmap_andnot(mdp5_kms->smp_state, mdp5_kms->smp_state, +				released, cnt); +		spin_unlock_irqrestore(&smp_lock, flags); + +		update_smp_state(mdp5_kms, CID_UNUSED, &released); +	} + +	bitmap_copy(ps->inuse, ps->pending, cnt); +} diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.h new file mode 100644 index 00000000000..0ab739e1a1d --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __MDP5_SMP_H__ +#define __MDP5_SMP_H__ + +#include "msm_drv.h" + +#define MAX_SMP_BLOCKS  22 +#define SMP_BLK_SIZE    4096 +#define SMP_ENTRIES_PER_BLK (SMP_BLK_SIZE / 16) + +typedef DECLARE_BITMAP(mdp5_smp_state_t, MAX_SMP_BLOCKS); + +struct mdp5_client_smp_state { +	mdp5_smp_state_t inuse; +	mdp5_smp_state_t pending; +}; + +struct mdp5_kms; + +int mdp5_smp_request(struct mdp5_kms *mdp5_kms, enum mdp5_client_id cid, int nblks); +void mdp5_smp_configure(struct mdp5_kms *mdp5_kms, enum mdp5_client_id cid); +void mdp5_smp_commit(struct mdp5_kms *mdp5_kms, enum mdp5_client_id cid); + + +#endif /* __MDP5_SMP_H__ */ diff --git a/drivers/gpu/drm/msm/mdp/mdp_common.xml.h b/drivers/gpu/drm/msm/mdp/mdp_common.xml.h new file mode 100644 index 00000000000..a9629b85b98 --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp_common.xml.h @@ -0,0 +1,78 @@ +#ifndef MDP_COMMON_XML +#define MDP_COMMON_XML + +/* Autogenerated file, DO NOT EDIT manually! + +This file was generated by the rules-ng-ng headergen tool in this git repository: +http://github.com/freedreno/envytools/ +git clone https://github.com/freedreno/envytools.git + +The rules-ng-ng source files this header was generated from are: +- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    647 bytes, from 2013-11-30 14:45:35) +- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  17996 bytes, from 2013-12-01 19:10:31) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2013-11-30 15:00:52) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2013-12-03 20:59:13) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  20932 bytes, from 2013-12-01 15:13:04) + +Copyright (C) 2013 by the following authors: +- Rob Clark <robdclark@gmail.com> (robclark) + +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 THE COPYRIGHT OWNER(S) 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. +*/ + + +enum mdp_mixer_stage_id { +	STAGE_UNUSED = 0, +	STAGE_BASE = 1, +	STAGE0 = 2, +	STAGE1 = 3, +	STAGE2 = 4, +	STAGE3 = 5, +}; + +enum mdp_alpha_type { +	FG_CONST = 0, +	BG_CONST = 1, +	FG_PIXEL = 2, +	BG_PIXEL = 3, +}; + +enum mdp_bpc { +	BPC1 = 0, +	BPC5 = 1, +	BPC6 = 2, +	BPC8 = 3, +}; + +enum mdp_bpc_alpha { +	BPC1A = 0, +	BPC4A = 1, +	BPC6A = 2, +	BPC8A = 3, +}; + + +#endif /* MDP_COMMON_XML */ diff --git a/drivers/gpu/drm/msm/mdp/mdp_format.c b/drivers/gpu/drm/msm/mdp/mdp_format.c new file mode 100644 index 00000000000..e0a6ffbe6ab --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp_format.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + + +#include "msm_drv.h" +#include "mdp_kms.h" + +#define FMT(name, a, r, g, b, e0, e1, e2, e3, alpha, tight, c, cnt) { \ +		.base = { .pixel_format = DRM_FORMAT_ ## name }, \ +		.bpc_a = BPC ## a ## A,                          \ +		.bpc_r = BPC ## r,                               \ +		.bpc_g = BPC ## g,                               \ +		.bpc_b = BPC ## b,                               \ +		.unpack = { e0, e1, e2, e3 },                    \ +		.alpha_enable = alpha,                           \ +		.unpack_tight = tight,                           \ +		.cpp = c,                                        \ +		.unpack_count = cnt,                             \ +	} + +#define BPC0A 0 + +static const struct mdp_format formats[] = { +	/*  name      a  r  g  b   e0 e1 e2 e3  alpha   tight  cpp cnt */ +	FMT(ARGB8888, 8, 8, 8, 8,  1, 0, 2, 3,  true,   true,  4,  4), +	FMT(XRGB8888, 8, 8, 8, 8,  1, 0, 2, 3,  false,  true,  4,  4), +	FMT(RGB888,   0, 8, 8, 8,  1, 0, 2, 0,  false,  true,  3,  3), +	FMT(BGR888,   0, 8, 8, 8,  2, 0, 1, 0,  false,  true,  3,  3), +	FMT(RGB565,   0, 5, 6, 5,  1, 0, 2, 0,  false,  true,  2,  3), +	FMT(BGR565,   0, 5, 6, 5,  2, 0, 1, 0,  false,  true,  2,  3), +}; + +uint32_t mdp_get_formats(uint32_t *pixel_formats, uint32_t max_formats) +{ +	uint32_t i; +	for (i = 0; i < ARRAY_SIZE(formats); i++) { +		const struct mdp_format *f = &formats[i]; + +		if (i == max_formats) +			break; + +		pixel_formats[i] = f->base.pixel_format; +	} + +	return i; +} + +const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format) +{ +	int i; +	for (i = 0; i < ARRAY_SIZE(formats); i++) { +		const struct mdp_format *f = &formats[i]; +		if (f->base.pixel_format == format) +			return &f->base; +	} +	return NULL; +} diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.c b/drivers/gpu/drm/msm/mdp/mdp_kms.c new file mode 100644 index 00000000000..03455b64a24 --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp_kms.c @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + + +#include "msm_drv.h" +#include "mdp_kms.h" + + +struct mdp_irq_wait { +	struct mdp_irq irq; +	int count; +}; + +static DECLARE_WAIT_QUEUE_HEAD(wait_event); + +static DEFINE_SPINLOCK(list_lock); + +static void update_irq(struct mdp_kms *mdp_kms) +{ +	struct mdp_irq *irq; +	uint32_t irqmask = mdp_kms->vblank_mask; + +	BUG_ON(!spin_is_locked(&list_lock)); + +	list_for_each_entry(irq, &mdp_kms->irq_list, node) +		irqmask |= irq->irqmask; + +	mdp_kms->funcs->set_irqmask(mdp_kms, irqmask); +} + +static void update_irq_unlocked(struct mdp_kms *mdp_kms) +{ +	unsigned long flags; +	spin_lock_irqsave(&list_lock, flags); +	update_irq(mdp_kms); +	spin_unlock_irqrestore(&list_lock, flags); +} + +void mdp_dispatch_irqs(struct mdp_kms *mdp_kms, uint32_t status) +{ +	struct mdp_irq *handler, *n; +	unsigned long flags; + +	spin_lock_irqsave(&list_lock, flags); +	mdp_kms->in_irq = true; +	list_for_each_entry_safe(handler, n, &mdp_kms->irq_list, node) { +		if (handler->irqmask & status) { +			spin_unlock_irqrestore(&list_lock, flags); +			handler->irq(handler, handler->irqmask & status); +			spin_lock_irqsave(&list_lock, flags); +		} +	} +	mdp_kms->in_irq = false; +	update_irq(mdp_kms); +	spin_unlock_irqrestore(&list_lock, flags); + +} + +void mdp_update_vblank_mask(struct mdp_kms *mdp_kms, uint32_t mask, bool enable) +{ +	unsigned long flags; + +	spin_lock_irqsave(&list_lock, flags); +	if (enable) +		mdp_kms->vblank_mask |= mask; +	else +		mdp_kms->vblank_mask &= ~mask; +	update_irq(mdp_kms); +	spin_unlock_irqrestore(&list_lock, flags); +} + +static void wait_irq(struct mdp_irq *irq, uint32_t irqstatus) +{ +	struct mdp_irq_wait *wait = +			container_of(irq, struct mdp_irq_wait, irq); +	wait->count--; +	wake_up_all(&wait_event); +} + +void mdp_irq_wait(struct mdp_kms *mdp_kms, uint32_t irqmask) +{ +	struct mdp_irq_wait wait = { +		.irq = { +			.irq = wait_irq, +			.irqmask = irqmask, +		}, +		.count = 1, +	}; +	mdp_irq_register(mdp_kms, &wait.irq); +	wait_event_timeout(wait_event, (wait.count <= 0), +			msecs_to_jiffies(100)); +	mdp_irq_unregister(mdp_kms, &wait.irq); +} + +void mdp_irq_register(struct mdp_kms *mdp_kms, struct mdp_irq *irq) +{ +	unsigned long flags; +	bool needs_update = false; + +	spin_lock_irqsave(&list_lock, flags); + +	if (!irq->registered) { +		irq->registered = true; +		list_add(&irq->node, &mdp_kms->irq_list); +		needs_update = !mdp_kms->in_irq; +	} + +	spin_unlock_irqrestore(&list_lock, flags); + +	if (needs_update) +		update_irq_unlocked(mdp_kms); +} + +void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq) +{ +	unsigned long flags; +	bool needs_update = false; + +	spin_lock_irqsave(&list_lock, flags); + +	if (irq->registered) { +		irq->registered = false; +		list_del(&irq->node); +		needs_update = !mdp_kms->in_irq; +	} + +	spin_unlock_irqrestore(&list_lock, flags); + +	if (needs_update) +		update_irq_unlocked(mdp_kms); +} diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.h b/drivers/gpu/drm/msm/mdp/mdp_kms.h new file mode 100644 index 00000000000..99557b5ad4f --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp_kms.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __MDP_KMS_H__ +#define __MDP_KMS_H__ + +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> + +#include "msm_drv.h" +#include "msm_kms.h" +#include "mdp_common.xml.h" + +struct mdp_kms; + +struct mdp_kms_funcs { +	struct msm_kms_funcs base; +	void (*set_irqmask)(struct mdp_kms *mdp_kms, uint32_t irqmask); +}; + +struct mdp_kms { +	struct msm_kms base; + +	const struct mdp_kms_funcs *funcs; + +	/* irq handling: */ +	bool in_irq; +	struct list_head irq_list;    /* list of mdp4_irq */ +	uint32_t vblank_mask;         /* irq bits set for userspace vblank */ +}; +#define to_mdp_kms(x) container_of(x, struct mdp_kms, base) + +static inline void mdp_kms_init(struct mdp_kms *mdp_kms, +		const struct mdp_kms_funcs *funcs) +{ +	mdp_kms->funcs = funcs; +	INIT_LIST_HEAD(&mdp_kms->irq_list); +	msm_kms_init(&mdp_kms->base, &funcs->base); +} + +/* + * irq helpers: + */ + +/* For transiently registering for different MDP irqs that various parts + * of the KMS code need during setup/configuration.  These are not + * necessarily the same as what drm_vblank_get/put() are requesting, and + * the hysteresis in drm_vblank_put() is not necessarily desirable for + * internal housekeeping related irq usage. + */ +struct mdp_irq { +	struct list_head node; +	uint32_t irqmask; +	bool registered; +	void (*irq)(struct mdp_irq *irq, uint32_t irqstatus); +}; + +void mdp_dispatch_irqs(struct mdp_kms *mdp_kms, uint32_t status); +void mdp_update_vblank_mask(struct mdp_kms *mdp_kms, uint32_t mask, bool enable); +void mdp_irq_wait(struct mdp_kms *mdp_kms, uint32_t irqmask); +void mdp_irq_register(struct mdp_kms *mdp_kms, struct mdp_irq *irq); +void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq); + + +/* + * pixel format helpers: + */ + +struct mdp_format { +	struct msm_format base; +	enum mdp_bpc bpc_r, bpc_g, bpc_b; +	enum mdp_bpc_alpha bpc_a; +	uint8_t unpack[4]; +	bool alpha_enable, unpack_tight; +	uint8_t cpp, unpack_count; +}; +#define to_mdp_format(x) container_of(x, struct mdp_format, base) + +uint32_t mdp_get_formats(uint32_t *formats, uint32_t max_formats); +const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format); + +#endif /* __MDP_KMS_H__ */ diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c new file mode 100644 index 00000000000..9a5d87db5c2 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -0,0 +1,1049 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include "msm_drv.h" +#include "msm_gpu.h" +#include "msm_kms.h" + +static void msm_fb_output_poll_changed(struct drm_device *dev) +{ +	struct msm_drm_private *priv = dev->dev_private; +	if (priv->fbdev) +		drm_fb_helper_hotplug_event(priv->fbdev); +} + +static const struct drm_mode_config_funcs mode_config_funcs = { +	.fb_create = msm_framebuffer_create, +	.output_poll_changed = msm_fb_output_poll_changed, +}; + +int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu) +{ +	struct msm_drm_private *priv = dev->dev_private; +	int idx = priv->num_mmus++; + +	if (WARN_ON(idx >= ARRAY_SIZE(priv->mmus))) +		return -EINVAL; + +	priv->mmus[idx] = mmu; + +	return idx; +} + +#ifdef CONFIG_DRM_MSM_REGISTER_LOGGING +static bool reglog = false; +MODULE_PARM_DESC(reglog, "Enable register read/write logging"); +module_param(reglog, bool, 0600); +#else +#define reglog 0 +#endif + +static char *vram; +MODULE_PARM_DESC(vram, "Configure VRAM size (for devices without IOMMU/GPUMMU"); +module_param(vram, charp, 0); + +/* + * Util/helpers: + */ + +void __iomem *msm_ioremap(struct platform_device *pdev, const char *name, +		const char *dbgname) +{ +	struct resource *res; +	unsigned long size; +	void __iomem *ptr; + +	if (name) +		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); +	else +		res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + +	if (!res) { +		dev_err(&pdev->dev, "failed to get memory resource: %s\n", name); +		return ERR_PTR(-EINVAL); +	} + +	size = resource_size(res); + +	ptr = devm_ioremap_nocache(&pdev->dev, res->start, size); +	if (!ptr) { +		dev_err(&pdev->dev, "failed to ioremap: %s\n", name); +		return ERR_PTR(-ENOMEM); +	} + +	if (reglog) +		printk(KERN_DEBUG "IO:region %s %08x %08lx\n", dbgname, (u32)ptr, size); + +	return ptr; +} + +void msm_writel(u32 data, void __iomem *addr) +{ +	if (reglog) +		printk(KERN_DEBUG "IO:W %08x %08x\n", (u32)addr, data); +	writel(data, addr); +} + +u32 msm_readl(const void __iomem *addr) +{ +	u32 val = readl(addr); +	if (reglog) +		printk(KERN_ERR "IO:R %08x %08x\n", (u32)addr, val); +	return val; +} + +/* + * DRM operations: + */ + +static int msm_unload(struct drm_device *dev) +{ +	struct msm_drm_private *priv = dev->dev_private; +	struct msm_kms *kms = priv->kms; +	struct msm_gpu *gpu = priv->gpu; + +	drm_kms_helper_poll_fini(dev); +	drm_mode_config_cleanup(dev); +	drm_vblank_cleanup(dev); + +	pm_runtime_get_sync(dev->dev); +	drm_irq_uninstall(dev); +	pm_runtime_put_sync(dev->dev); + +	flush_workqueue(priv->wq); +	destroy_workqueue(priv->wq); + +	if (kms) { +		pm_runtime_disable(dev->dev); +		kms->funcs->destroy(kms); +	} + +	if (gpu) { +		mutex_lock(&dev->struct_mutex); +		gpu->funcs->pm_suspend(gpu); +		gpu->funcs->destroy(gpu); +		mutex_unlock(&dev->struct_mutex); +	} + +	if (priv->vram.paddr) { +		DEFINE_DMA_ATTRS(attrs); +		dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs); +		drm_mm_takedown(&priv->vram.mm); +		dma_free_attrs(dev->dev, priv->vram.size, NULL, +				priv->vram.paddr, &attrs); +	} + +	component_unbind_all(dev->dev, dev); + +	dev->dev_private = NULL; + +	kfree(priv); + +	return 0; +} + +static int get_mdp_ver(struct platform_device *pdev) +{ +#ifdef CONFIG_OF +	static const struct of_device_id match_types[] = { { +		.compatible = "qcom,mdss_mdp", +		.data	= (void	*)5, +	}, { +		/* end node */ +	} }; +	struct device *dev = &pdev->dev; +	const struct of_device_id *match; +	match = of_match_node(match_types, dev->of_node); +	if (match) +		return (int)match->data; +#endif +	return 4; +} + +static int msm_load(struct drm_device *dev, unsigned long flags) +{ +	struct platform_device *pdev = dev->platformdev; +	struct msm_drm_private *priv; +	struct msm_kms *kms; +	int ret; + + +	priv = kzalloc(sizeof(*priv), GFP_KERNEL); +	if (!priv) { +		dev_err(dev->dev, "failed to allocate private data\n"); +		return -ENOMEM; +	} + +	dev->dev_private = priv; + +	priv->wq = alloc_ordered_workqueue("msm", 0); +	init_waitqueue_head(&priv->fence_event); + +	INIT_LIST_HEAD(&priv->inactive_list); +	INIT_LIST_HEAD(&priv->fence_cbs); + +	drm_mode_config_init(dev); + +	/* if we have no IOMMU, then we need to use carveout allocator. +	 * Grab the entire CMA chunk carved out in early startup in +	 * mach-msm: +	 */ +	if (!iommu_present(&platform_bus_type)) { +		DEFINE_DMA_ATTRS(attrs); +		unsigned long size; +		void *p; + +		DBG("using %s VRAM carveout", vram); +		size = memparse(vram, NULL); +		priv->vram.size = size; + +		drm_mm_init(&priv->vram.mm, 0, (size >> PAGE_SHIFT) - 1); + +		dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs); +		dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); + +		/* note that for no-kernel-mapping, the vaddr returned +		 * is bogus, but non-null if allocation succeeded: +		 */ +		p = dma_alloc_attrs(dev->dev, size, +				&priv->vram.paddr, GFP_KERNEL, &attrs); +		if (!p) { +			dev_err(dev->dev, "failed to allocate VRAM\n"); +			priv->vram.paddr = 0; +			ret = -ENOMEM; +			goto fail; +		} + +		dev_info(dev->dev, "VRAM: %08x->%08x\n", +				(uint32_t)priv->vram.paddr, +				(uint32_t)(priv->vram.paddr + size)); +	} + +	platform_set_drvdata(pdev, dev); + +	/* Bind all our sub-components: */ +	ret = component_bind_all(dev->dev, dev); +	if (ret) +		return ret; + +	switch (get_mdp_ver(pdev)) { +	case 4: +		kms = mdp4_kms_init(dev); +		break; +	case 5: +		kms = mdp5_kms_init(dev); +		break; +	default: +		kms = ERR_PTR(-ENODEV); +		break; +	} + +	if (IS_ERR(kms)) { +		/* +		 * NOTE: once we have GPU support, having no kms should not +		 * be considered fatal.. ideally we would still support gpu +		 * and (for example) use dmabuf/prime to share buffers with +		 * imx drm driver on iMX5 +		 */ +		dev_err(dev->dev, "failed to load kms\n"); +		ret = PTR_ERR(kms); +		goto fail; +	} + +	priv->kms = kms; + +	if (kms) { +		pm_runtime_enable(dev->dev); +		ret = kms->funcs->hw_init(kms); +		if (ret) { +			dev_err(dev->dev, "kms hw init failed: %d\n", ret); +			goto fail; +		} +	} + +	dev->mode_config.min_width = 0; +	dev->mode_config.min_height = 0; +	dev->mode_config.max_width = 2048; +	dev->mode_config.max_height = 2048; +	dev->mode_config.funcs = &mode_config_funcs; + +	ret = drm_vblank_init(dev, 1); +	if (ret < 0) { +		dev_err(dev->dev, "failed to initialize vblank\n"); +		goto fail; +	} + +	pm_runtime_get_sync(dev->dev); +	ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0)); +	pm_runtime_put_sync(dev->dev); +	if (ret < 0) { +		dev_err(dev->dev, "failed to install IRQ handler\n"); +		goto fail; +	} + +#ifdef CONFIG_DRM_MSM_FBDEV +	priv->fbdev = msm_fbdev_init(dev); +#endif + +	ret = msm_debugfs_late_init(dev); +	if (ret) +		goto fail; + +	drm_kms_helper_poll_init(dev); + +	return 0; + +fail: +	msm_unload(dev); +	return ret; +} + +static void load_gpu(struct drm_device *dev) +{ +	struct msm_drm_private *priv = dev->dev_private; +	struct msm_gpu *gpu; + +	if (priv->gpu) +		return; + +	mutex_lock(&dev->struct_mutex); +	gpu = a3xx_gpu_init(dev); +	if (IS_ERR(gpu)) { +		dev_warn(dev->dev, "failed to load a3xx gpu\n"); +		gpu = NULL; +		/* not fatal */ +	} + +	if (gpu) { +		int ret; +		gpu->funcs->pm_resume(gpu); +		ret = gpu->funcs->hw_init(gpu); +		if (ret) { +			dev_err(dev->dev, "gpu hw init failed: %d\n", ret); +			gpu->funcs->destroy(gpu); +			gpu = NULL; +		} else { +			/* give inactive pm a chance to kick in: */ +			msm_gpu_retire(gpu); +		} + +	} + +	priv->gpu = gpu; + +	mutex_unlock(&dev->struct_mutex); +} + +static int msm_open(struct drm_device *dev, struct drm_file *file) +{ +	struct msm_file_private *ctx; + +	/* For now, load gpu on open.. to avoid the requirement of having +	 * firmware in the initrd. +	 */ +	load_gpu(dev); + +	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); +	if (!ctx) +		return -ENOMEM; + +	file->driver_priv = ctx; + +	return 0; +} + +static void msm_preclose(struct drm_device *dev, struct drm_file *file) +{ +	struct msm_drm_private *priv = dev->dev_private; +	struct msm_file_private *ctx = file->driver_priv; +	struct msm_kms *kms = priv->kms; + +	if (kms) +		kms->funcs->preclose(kms, file); + +	mutex_lock(&dev->struct_mutex); +	if (ctx == priv->lastctx) +		priv->lastctx = NULL; +	mutex_unlock(&dev->struct_mutex); + +	kfree(ctx); +} + +static void msm_lastclose(struct drm_device *dev) +{ +	struct msm_drm_private *priv = dev->dev_private; +	if (priv->fbdev) +		drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev); +} + +static irqreturn_t msm_irq(int irq, void *arg) +{ +	struct drm_device *dev = arg; +	struct msm_drm_private *priv = dev->dev_private; +	struct msm_kms *kms = priv->kms; +	BUG_ON(!kms); +	return kms->funcs->irq(kms); +} + +static void msm_irq_preinstall(struct drm_device *dev) +{ +	struct msm_drm_private *priv = dev->dev_private; +	struct msm_kms *kms = priv->kms; +	BUG_ON(!kms); +	kms->funcs->irq_preinstall(kms); +} + +static int msm_irq_postinstall(struct drm_device *dev) +{ +	struct msm_drm_private *priv = dev->dev_private; +	struct msm_kms *kms = priv->kms; +	BUG_ON(!kms); +	return kms->funcs->irq_postinstall(kms); +} + +static void msm_irq_uninstall(struct drm_device *dev) +{ +	struct msm_drm_private *priv = dev->dev_private; +	struct msm_kms *kms = priv->kms; +	BUG_ON(!kms); +	kms->funcs->irq_uninstall(kms); +} + +static int msm_enable_vblank(struct drm_device *dev, int crtc_id) +{ +	struct msm_drm_private *priv = dev->dev_private; +	struct msm_kms *kms = priv->kms; +	if (!kms) +		return -ENXIO; +	DBG("dev=%p, crtc=%d", dev, crtc_id); +	return kms->funcs->enable_vblank(kms, priv->crtcs[crtc_id]); +} + +static void msm_disable_vblank(struct drm_device *dev, int crtc_id) +{ +	struct msm_drm_private *priv = dev->dev_private; +	struct msm_kms *kms = priv->kms; +	if (!kms) +		return; +	DBG("dev=%p, crtc=%d", dev, crtc_id); +	kms->funcs->disable_vblank(kms, priv->crtcs[crtc_id]); +} + +/* + * DRM debugfs: + */ + +#ifdef CONFIG_DEBUG_FS +static int msm_gpu_show(struct drm_device *dev, struct seq_file *m) +{ +	struct msm_drm_private *priv = dev->dev_private; +	struct msm_gpu *gpu = priv->gpu; + +	if (gpu) { +		seq_printf(m, "%s Status:\n", gpu->name); +		gpu->funcs->show(gpu, m); +	} + +	return 0; +} + +static int msm_gem_show(struct drm_device *dev, struct seq_file *m) +{ +	struct msm_drm_private *priv = dev->dev_private; +	struct msm_gpu *gpu = priv->gpu; + +	if (gpu) { +		seq_printf(m, "Active Objects (%s):\n", gpu->name); +		msm_gem_describe_objects(&gpu->active_list, m); +	} + +	seq_printf(m, "Inactive Objects:\n"); +	msm_gem_describe_objects(&priv->inactive_list, m); + +	return 0; +} + +static int msm_mm_show(struct drm_device *dev, struct seq_file *m) +{ +	return drm_mm_dump_table(m, &dev->vma_offset_manager->vm_addr_space_mm); +} + +static int msm_fb_show(struct drm_device *dev, struct seq_file *m) +{ +	struct msm_drm_private *priv = dev->dev_private; +	struct drm_framebuffer *fb, *fbdev_fb = NULL; + +	if (priv->fbdev) { +		seq_printf(m, "fbcon "); +		fbdev_fb = priv->fbdev->fb; +		msm_framebuffer_describe(fbdev_fb, m); +	} + +	mutex_lock(&dev->mode_config.fb_lock); +	list_for_each_entry(fb, &dev->mode_config.fb_list, head) { +		if (fb == fbdev_fb) +			continue; + +		seq_printf(m, "user "); +		msm_framebuffer_describe(fb, m); +	} +	mutex_unlock(&dev->mode_config.fb_lock); + +	return 0; +} + +static int show_locked(struct seq_file *m, void *arg) +{ +	struct drm_info_node *node = (struct drm_info_node *) m->private; +	struct drm_device *dev = node->minor->dev; +	int (*show)(struct drm_device *dev, struct seq_file *m) = +			node->info_ent->data; +	int ret; + +	ret = mutex_lock_interruptible(&dev->struct_mutex); +	if (ret) +		return ret; + +	ret = show(dev, m); + +	mutex_unlock(&dev->struct_mutex); + +	return ret; +} + +static struct drm_info_list msm_debugfs_list[] = { +		{"gpu", show_locked, 0, msm_gpu_show}, +		{"gem", show_locked, 0, msm_gem_show}, +		{ "mm", show_locked, 0, msm_mm_show }, +		{ "fb", show_locked, 0, msm_fb_show }, +}; + +static int late_init_minor(struct drm_minor *minor) +{ +	int ret; + +	if (!minor) +		return 0; + +	ret = msm_rd_debugfs_init(minor); +	if (ret) { +		dev_err(minor->dev->dev, "could not install rd debugfs\n"); +		return ret; +	} + +	ret = msm_perf_debugfs_init(minor); +	if (ret) { +		dev_err(minor->dev->dev, "could not install perf debugfs\n"); +		return ret; +	} + +	return 0; +} + +int msm_debugfs_late_init(struct drm_device *dev) +{ +	int ret; +	ret = late_init_minor(dev->primary); +	if (ret) +		return ret; +	ret = late_init_minor(dev->render); +	if (ret) +		return ret; +	ret = late_init_minor(dev->control); +	return ret; +} + +static int msm_debugfs_init(struct drm_minor *minor) +{ +	struct drm_device *dev = minor->dev; +	int ret; + +	ret = drm_debugfs_create_files(msm_debugfs_list, +			ARRAY_SIZE(msm_debugfs_list), +			minor->debugfs_root, minor); + +	if (ret) { +		dev_err(dev->dev, "could not install msm_debugfs_list\n"); +		return ret; +	} + +	return 0; +} + +static void msm_debugfs_cleanup(struct drm_minor *minor) +{ +	drm_debugfs_remove_files(msm_debugfs_list, +			ARRAY_SIZE(msm_debugfs_list), minor); +	if (!minor->dev->dev_private) +		return; +	msm_rd_debugfs_cleanup(minor); +	msm_perf_debugfs_cleanup(minor); +} +#endif + +/* + * Fences: + */ + +int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence, +		struct timespec *timeout) +{ +	struct msm_drm_private *priv = dev->dev_private; +	int ret; + +	if (!priv->gpu) +		return 0; + +	if (fence > priv->gpu->submitted_fence) { +		DRM_ERROR("waiting on invalid fence: %u (of %u)\n", +				fence, priv->gpu->submitted_fence); +		return -EINVAL; +	} + +	if (!timeout) { +		/* no-wait: */ +		ret = fence_completed(dev, fence) ? 0 : -EBUSY; +	} else { +		unsigned long timeout_jiffies = timespec_to_jiffies(timeout); +		unsigned long start_jiffies = jiffies; +		unsigned long remaining_jiffies; + +		if (time_after(start_jiffies, timeout_jiffies)) +			remaining_jiffies = 0; +		else +			remaining_jiffies = timeout_jiffies - start_jiffies; + +		ret = wait_event_interruptible_timeout(priv->fence_event, +				fence_completed(dev, fence), +				remaining_jiffies); + +		if (ret == 0) { +			DBG("timeout waiting for fence: %u (completed: %u)", +					fence, priv->completed_fence); +			ret = -ETIMEDOUT; +		} else if (ret != -ERESTARTSYS) { +			ret = 0; +		} +	} + +	return ret; +} + +/* called from workqueue */ +void msm_update_fence(struct drm_device *dev, uint32_t fence) +{ +	struct msm_drm_private *priv = dev->dev_private; + +	mutex_lock(&dev->struct_mutex); +	priv->completed_fence = max(fence, priv->completed_fence); + +	while (!list_empty(&priv->fence_cbs)) { +		struct msm_fence_cb *cb; + +		cb = list_first_entry(&priv->fence_cbs, +				struct msm_fence_cb, work.entry); + +		if (cb->fence > priv->completed_fence) +			break; + +		list_del_init(&cb->work.entry); +		queue_work(priv->wq, &cb->work); +	} + +	mutex_unlock(&dev->struct_mutex); + +	wake_up_all(&priv->fence_event); +} + +void __msm_fence_worker(struct work_struct *work) +{ +	struct msm_fence_cb *cb = container_of(work, struct msm_fence_cb, work); +	cb->func(cb); +} + +/* + * DRM ioctls: + */ + +static int msm_ioctl_get_param(struct drm_device *dev, void *data, +		struct drm_file *file) +{ +	struct msm_drm_private *priv = dev->dev_private; +	struct drm_msm_param *args = data; +	struct msm_gpu *gpu; + +	/* for now, we just have 3d pipe.. eventually this would need to +	 * be more clever to dispatch to appropriate gpu module: +	 */ +	if (args->pipe != MSM_PIPE_3D0) +		return -EINVAL; + +	gpu = priv->gpu; + +	if (!gpu) +		return -ENXIO; + +	return gpu->funcs->get_param(gpu, args->param, &args->value); +} + +static int msm_ioctl_gem_new(struct drm_device *dev, void *data, +		struct drm_file *file) +{ +	struct drm_msm_gem_new *args = data; + +	if (args->flags & ~MSM_BO_FLAGS) { +		DRM_ERROR("invalid flags: %08x\n", args->flags); +		return -EINVAL; +	} + +	return msm_gem_new_handle(dev, file, args->size, +			args->flags, &args->handle); +} + +#define TS(t) ((struct timespec){ .tv_sec = (t).tv_sec, .tv_nsec = (t).tv_nsec }) + +static int msm_ioctl_gem_cpu_prep(struct drm_device *dev, void *data, +		struct drm_file *file) +{ +	struct drm_msm_gem_cpu_prep *args = data; +	struct drm_gem_object *obj; +	int ret; + +	if (args->op & ~MSM_PREP_FLAGS) { +		DRM_ERROR("invalid op: %08x\n", args->op); +		return -EINVAL; +	} + +	obj = drm_gem_object_lookup(dev, file, args->handle); +	if (!obj) +		return -ENOENT; + +	ret = msm_gem_cpu_prep(obj, args->op, &TS(args->timeout)); + +	drm_gem_object_unreference_unlocked(obj); + +	return ret; +} + +static int msm_ioctl_gem_cpu_fini(struct drm_device *dev, void *data, +		struct drm_file *file) +{ +	struct drm_msm_gem_cpu_fini *args = data; +	struct drm_gem_object *obj; +	int ret; + +	obj = drm_gem_object_lookup(dev, file, args->handle); +	if (!obj) +		return -ENOENT; + +	ret = msm_gem_cpu_fini(obj); + +	drm_gem_object_unreference_unlocked(obj); + +	return ret; +} + +static int msm_ioctl_gem_info(struct drm_device *dev, void *data, +		struct drm_file *file) +{ +	struct drm_msm_gem_info *args = data; +	struct drm_gem_object *obj; +	int ret = 0; + +	if (args->pad) +		return -EINVAL; + +	obj = drm_gem_object_lookup(dev, file, args->handle); +	if (!obj) +		return -ENOENT; + +	args->offset = msm_gem_mmap_offset(obj); + +	drm_gem_object_unreference_unlocked(obj); + +	return ret; +} + +static int msm_ioctl_wait_fence(struct drm_device *dev, void *data, +		struct drm_file *file) +{ +	struct drm_msm_wait_fence *args = data; + +	if (args->pad) { +		DRM_ERROR("invalid pad: %08x\n", args->pad); +		return -EINVAL; +	} + +	return msm_wait_fence_interruptable(dev, args->fence, +			&TS(args->timeout)); +} + +static const struct drm_ioctl_desc msm_ioctls[] = { +	DRM_IOCTL_DEF_DRV(MSM_GET_PARAM,    msm_ioctl_get_param,    DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), +	DRM_IOCTL_DEF_DRV(MSM_GEM_NEW,      msm_ioctl_gem_new,      DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), +	DRM_IOCTL_DEF_DRV(MSM_GEM_INFO,     msm_ioctl_gem_info,     DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), +	DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_PREP, msm_ioctl_gem_cpu_prep, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), +	DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_FINI, msm_ioctl_gem_cpu_fini, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), +	DRM_IOCTL_DEF_DRV(MSM_GEM_SUBMIT,   msm_ioctl_gem_submit,   DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), +	DRM_IOCTL_DEF_DRV(MSM_WAIT_FENCE,   msm_ioctl_wait_fence,   DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), +}; + +static const struct vm_operations_struct vm_ops = { +	.fault = msm_gem_fault, +	.open = drm_gem_vm_open, +	.close = drm_gem_vm_close, +}; + +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             = no_llseek, +	.mmap               = msm_gem_mmap, +}; + +static struct drm_driver msm_driver = { +	.driver_features    = DRIVER_HAVE_IRQ | +				DRIVER_GEM | +				DRIVER_PRIME | +				DRIVER_RENDER | +				DRIVER_MODESET, +	.load               = msm_load, +	.unload             = msm_unload, +	.open               = msm_open, +	.preclose           = msm_preclose, +	.lastclose          = msm_lastclose, +	.irq_handler        = msm_irq, +	.irq_preinstall     = msm_irq_preinstall, +	.irq_postinstall    = msm_irq_postinstall, +	.irq_uninstall      = msm_irq_uninstall, +	.get_vblank_counter = drm_vblank_count, +	.enable_vblank      = msm_enable_vblank, +	.disable_vblank     = msm_disable_vblank, +	.gem_free_object    = msm_gem_free_object, +	.gem_vm_ops         = &vm_ops, +	.dumb_create        = msm_gem_dumb_create, +	.dumb_map_offset    = msm_gem_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_pin      = msm_gem_prime_pin, +	.gem_prime_unpin    = msm_gem_prime_unpin, +	.gem_prime_get_sg_table = msm_gem_prime_get_sg_table, +	.gem_prime_import_sg_table = msm_gem_prime_import_sg_table, +	.gem_prime_vmap     = msm_gem_prime_vmap, +	.gem_prime_vunmap   = msm_gem_prime_vunmap, +#ifdef CONFIG_DEBUG_FS +	.debugfs_init       = msm_debugfs_init, +	.debugfs_cleanup    = msm_debugfs_cleanup, +#endif +	.ioctls             = msm_ioctls, +	.num_ioctls         = DRM_MSM_NUM_IOCTLS, +	.fops               = &fops, +	.name               = "msm", +	.desc               = "MSM Snapdragon DRM", +	.date               = "20130625", +	.major              = 1, +	.minor              = 0, +}; + +#ifdef CONFIG_PM_SLEEP +static int msm_pm_suspend(struct device *dev) +{ +	struct drm_device *ddev = dev_get_drvdata(dev); + +	drm_kms_helper_poll_disable(ddev); + +	return 0; +} + +static int msm_pm_resume(struct device *dev) +{ +	struct drm_device *ddev = dev_get_drvdata(dev); + +	drm_kms_helper_poll_enable(ddev); + +	return 0; +} +#endif + +static const struct dev_pm_ops msm_pm_ops = { +	SET_SYSTEM_SLEEP_PM_OPS(msm_pm_suspend, msm_pm_resume) +}; + +/* + * Componentized driver support: + */ + +#ifdef CONFIG_OF +/* NOTE: the CONFIG_OF case duplicates the same code as exynos or imx + * (or probably any other).. so probably some room for some helpers + */ +static int compare_of(struct device *dev, void *data) +{ +	return dev->of_node == data; +} + +static int msm_drm_add_components(struct device *master, struct master *m) +{ +	struct device_node *np = master->of_node; +	unsigned i; +	int ret; + +	for (i = 0; ; i++) { +		struct device_node *node; + +		node = of_parse_phandle(np, "connectors", i); +		if (!node) +			break; + +		ret = component_master_add_child(m, compare_of, node); +		of_node_put(node); + +		if (ret) +			return ret; +	} +	return 0; +} +#else +static int compare_dev(struct device *dev, void *data) +{ +	return dev == data; +} + +static int msm_drm_add_components(struct device *master, struct master *m) +{ +	/* For non-DT case, it kinda sucks.  We don't actually have a way +	 * to know whether or not we are waiting for certain devices (or if +	 * they are simply not present).  But for non-DT we only need to +	 * care about apq8064/apq8060/etc (all mdp4/a3xx): +	 */ +	static const char *devnames[] = { +			"hdmi_msm.0", "kgsl-3d0.0", +	}; +	int i; + +	DBG("Adding components.."); + +	for (i = 0; i < ARRAY_SIZE(devnames); i++) { +		struct device *dev; +		int ret; + +		dev = bus_find_device_by_name(&platform_bus_type, +				NULL, devnames[i]); +		if (!dev) { +			dev_info(master, "still waiting for %s\n", devnames[i]); +			return -EPROBE_DEFER; +		} + +		ret = component_master_add_child(m, compare_dev, dev); +		if (ret) { +			DBG("could not add child: %d", ret); +			return ret; +		} +	} + +	return 0; +} +#endif + +static int msm_drm_bind(struct device *dev) +{ +	return drm_platform_init(&msm_driver, to_platform_device(dev)); +} + +static void msm_drm_unbind(struct device *dev) +{ +	drm_put_dev(platform_get_drvdata(to_platform_device(dev))); +} + +static const struct component_master_ops msm_drm_ops = { +		.add_components = msm_drm_add_components, +		.bind = msm_drm_bind, +		.unbind = msm_drm_unbind, +}; + +/* + * Platform driver: + */ + +static int msm_pdev_probe(struct platform_device *pdev) +{ +	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); +	return component_master_add(&pdev->dev, &msm_drm_ops); +} + +static int msm_pdev_remove(struct platform_device *pdev) +{ +	component_master_del(&pdev->dev, &msm_drm_ops); + +	return 0; +} + +static const struct platform_device_id msm_id[] = { +	{ "mdp", 0 }, +	{ } +}; + +static const struct of_device_id dt_match[] = { +	{ .compatible = "qcom,mdss_mdp" }, +	{} +}; +MODULE_DEVICE_TABLE(of, dt_match); + +static struct platform_driver msm_platform_driver = { +	.probe      = msm_pdev_probe, +	.remove     = msm_pdev_remove, +	.driver     = { +		.owner  = THIS_MODULE, +		.name   = "msm", +		.of_match_table = dt_match, +		.pm     = &msm_pm_ops, +	}, +	.id_table   = msm_id, +}; + +static int __init msm_drm_register(void) +{ +	DBG("init"); +	hdmi_register(); +	a3xx_register(); +	return platform_driver_register(&msm_platform_driver); +} + +static void __exit msm_drm_unregister(void) +{ +	DBG("fini"); +	platform_driver_unregister(&msm_platform_driver); +	hdmi_unregister(); +	a3xx_unregister(); +} + +module_init(msm_drm_register); +module_exit(msm_drm_unregister); + +MODULE_AUTHOR("Rob Clark <robdclark@gmail.com"); +MODULE_DESCRIPTION("MSM DRM Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h new file mode 100644 index 00000000000..8a2c5fd0893 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __MSM_DRV_H__ +#define __MSM_DRV_H__ + +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/cpufreq.h> +#include <linux/module.h> +#include <linux/component.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/slab.h> +#include <linux/list.h> +#include <linux/iommu.h> +#include <linux/types.h> +#include <asm/sizes.h> + + +#if defined(CONFIG_COMPILE_TEST) && !defined(CONFIG_ARCH_QCOM) +/* stubs we need for compile-test: */ +static inline struct device *msm_iommu_get_ctx(const char *ctx_name) +{ +	return NULL; +} +#endif + +#ifndef CONFIG_OF +#include <mach/board.h> +#include <mach/socinfo.h> +#include <mach/iommu_domains.h> +#endif + +#include <drm/drmP.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_helper.h> +#include <drm/msm_drm.h> + +struct msm_kms; +struct msm_gpu; +struct msm_mmu; +struct msm_rd_state; +struct msm_perf_state; +struct msm_gem_submit; + +#define NUM_DOMAINS 2    /* one for KMS, then one per gpu core (?) */ + +struct msm_file_private { +	/* currently we don't do anything useful with this.. but when +	 * per-context address spaces are supported we'd keep track of +	 * the context's page-tables here. +	 */ +	int dummy; +}; + +struct msm_drm_private { + +	struct msm_kms *kms; + +	/* subordinate devices, if present: */ +	struct platform_device *hdmi_pdev, *gpu_pdev; + +	/* when we have more than one 'msm_gpu' these need to be an array: */ +	struct msm_gpu *gpu; +	struct msm_file_private *lastctx; + +	struct drm_fb_helper *fbdev; + +	uint32_t next_fence, completed_fence; +	wait_queue_head_t fence_event; + +	struct msm_rd_state *rd; +	struct msm_perf_state *perf; + +	/* list of GEM objects: */ +	struct list_head inactive_list; + +	struct workqueue_struct *wq; + +	/* callbacks deferred until bo is inactive: */ +	struct list_head fence_cbs; + +	/* registered MMUs: */ +	unsigned int num_mmus; +	struct msm_mmu *mmus[NUM_DOMAINS]; + +	unsigned int num_planes; +	struct drm_plane *planes[8]; + +	unsigned int num_crtcs; +	struct drm_crtc *crtcs[8]; + +	unsigned int num_encoders; +	struct drm_encoder *encoders[8]; + +	unsigned int num_bridges; +	struct drm_bridge *bridges[8]; + +	unsigned int num_connectors; +	struct drm_connector *connectors[8]; + +	/* VRAM carveout, used when no IOMMU: */ +	struct { +		unsigned long size; +		dma_addr_t paddr; +		/* NOTE: mm managed at the page level, size is in # of pages +		 * and position mm_node->start is in # of pages: +		 */ +		struct drm_mm mm; +	} vram; +}; + +struct msm_format { +	uint32_t pixel_format; +}; + +/* callback from wq once fence has passed: */ +struct msm_fence_cb { +	struct work_struct work; +	uint32_t fence; +	void (*func)(struct msm_fence_cb *cb); +}; + +void __msm_fence_worker(struct work_struct *work); + +#define INIT_FENCE_CB(_cb, _func)  do {                     \ +		INIT_WORK(&(_cb)->work, __msm_fence_worker); \ +		(_cb)->func = _func;                         \ +	} while (0) + +int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu); + +int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence, +		struct timespec *timeout); +void msm_update_fence(struct drm_device *dev, uint32_t fence); + +int msm_ioctl_gem_submit(struct drm_device *dev, void *data, +		struct drm_file *file); + +int msm_gem_mmap(struct file *filp, struct vm_area_struct *vma); +int msm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); +uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj); +int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id, +		uint32_t *iova); +int msm_gem_get_iova(struct drm_gem_object *obj, int id, uint32_t *iova); +struct page **msm_gem_get_pages(struct drm_gem_object *obj); +void msm_gem_put_pages(struct drm_gem_object *obj); +void msm_gem_put_iova(struct drm_gem_object *obj, int id); +int msm_gem_dumb_create(struct drm_file *file, struct drm_device *dev, +		struct drm_mode_create_dumb *args); +int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, +		uint32_t handle, uint64_t *offset); +struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj); +void *msm_gem_prime_vmap(struct drm_gem_object *obj); +void msm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); +struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev, +		size_t size, struct sg_table *sg); +int msm_gem_prime_pin(struct drm_gem_object *obj); +void msm_gem_prime_unpin(struct drm_gem_object *obj); +void *msm_gem_vaddr_locked(struct drm_gem_object *obj); +void *msm_gem_vaddr(struct drm_gem_object *obj); +int msm_gem_queue_inactive_cb(struct drm_gem_object *obj, +		struct msm_fence_cb *cb); +void msm_gem_move_to_active(struct drm_gem_object *obj, +		struct msm_gpu *gpu, bool write, uint32_t fence); +void msm_gem_move_to_inactive(struct drm_gem_object *obj); +int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, +		struct timespec *timeout); +int msm_gem_cpu_fini(struct drm_gem_object *obj); +void msm_gem_free_object(struct drm_gem_object *obj); +int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file, +		uint32_t size, uint32_t flags, uint32_t *handle); +struct drm_gem_object *msm_gem_new(struct drm_device *dev, +		uint32_t size, uint32_t flags); +struct drm_gem_object *msm_gem_import(struct drm_device *dev, +		uint32_t size, struct sg_table *sgt); + +struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane); +const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb); +struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, +		struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos); +struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev, +		struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd); + +struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev); + +struct hdmi; +struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder); +irqreturn_t hdmi_irq(int irq, void *dev_id); +void __init hdmi_register(void); +void __exit hdmi_unregister(void); + +#ifdef CONFIG_DEBUG_FS +void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m); +void msm_gem_describe_objects(struct list_head *list, struct seq_file *m); +void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m); +int msm_debugfs_late_init(struct drm_device *dev); +int msm_rd_debugfs_init(struct drm_minor *minor); +void msm_rd_debugfs_cleanup(struct drm_minor *minor); +void msm_rd_dump_submit(struct msm_gem_submit *submit); +int msm_perf_debugfs_init(struct drm_minor *minor); +void msm_perf_debugfs_cleanup(struct drm_minor *minor); +#else +static inline int msm_debugfs_late_init(struct drm_device *dev) { return 0; } +static inline void msm_rd_dump_submit(struct msm_gem_submit *submit) {} +#endif + +void __iomem *msm_ioremap(struct platform_device *pdev, const char *name, +		const char *dbgname); +void msm_writel(u32 data, void __iomem *addr); +u32 msm_readl(const void __iomem *addr); + +#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) +#define VERB(fmt, ...) if (0) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) + +static inline bool fence_completed(struct drm_device *dev, uint32_t fence) +{ +	struct msm_drm_private *priv = dev->dev_private; +	return priv->completed_fence >= fence; +} + +static inline int align_pitch(int width, int bpp) +{ +	int bytespp = (bpp + 7) / 8; +	/* adreno needs pitch aligned to 32 pixels: */ +	return bytespp * ALIGN(width, 32); +} + +/* for the generated headers: */ +#define INVALID_IDX(idx) ({BUG(); 0;}) +#define fui(x)                ({BUG(); 0;}) +#define util_float_to_half(x) ({BUG(); 0;}) + + +#define FIELD(val, name) (((val) & name ## __MASK) >> name ## __SHIFT) + +/* for conditionally setting boolean flag(s): */ +#define COND(bool, val) ((bool) ? (val) : 0) + + +#endif /* __MSM_DRV_H__ */ diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c new file mode 100644 index 00000000000..81bafdf19ab --- /dev/null +++ b/drivers/gpu/drm/msm/msm_fb.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include "msm_drv.h" +#include "msm_kms.h" + +#include "drm_crtc.h" +#include "drm_crtc_helper.h" + +struct msm_framebuffer { +	struct drm_framebuffer base; +	const struct msm_format *format; +	struct drm_gem_object *planes[2]; +}; +#define to_msm_framebuffer(x) container_of(x, struct msm_framebuffer, base) + + +static int msm_framebuffer_create_handle(struct drm_framebuffer *fb, +		struct drm_file *file_priv, +		unsigned int *handle) +{ +	struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); +	return drm_gem_handle_create(file_priv, +			msm_fb->planes[0], handle); +} + +static void msm_framebuffer_destroy(struct drm_framebuffer *fb) +{ +	struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); +	int i, n = drm_format_num_planes(fb->pixel_format); + +	DBG("destroy: FB ID: %d (%p)", fb->base.id, fb); + +	drm_framebuffer_cleanup(fb); + +	for (i = 0; i < n; i++) { +		struct drm_gem_object *bo = msm_fb->planes[i]; +		if (bo) +			drm_gem_object_unreference_unlocked(bo); +	} + +	kfree(msm_fb); +} + +static int msm_framebuffer_dirty(struct drm_framebuffer *fb, +		struct drm_file *file_priv, unsigned flags, unsigned color, +		struct drm_clip_rect *clips, unsigned num_clips) +{ +	return 0; +} + +static const struct drm_framebuffer_funcs msm_framebuffer_funcs = { +	.create_handle = msm_framebuffer_create_handle, +	.destroy = msm_framebuffer_destroy, +	.dirty = msm_framebuffer_dirty, +}; + +#ifdef CONFIG_DEBUG_FS +void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m) +{ +	struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); +	int i, n = drm_format_num_planes(fb->pixel_format); + +	seq_printf(m, "fb: %dx%d@%4.4s (%2d, ID:%d)\n", +			fb->width, fb->height, (char *)&fb->pixel_format, +			fb->refcount.refcount.counter, fb->base.id); + +	for (i = 0; i < n; i++) { +		seq_printf(m, "   %d: offset=%d pitch=%d, obj: ", +				i, fb->offsets[i], fb->pitches[i]); +		msm_gem_describe(msm_fb->planes[i], m); +	} +} +#endif + +struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane) +{ +	struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); +	return msm_fb->planes[plane]; +} + +const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb) +{ +	struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); +	return msm_fb->format; +} + +struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev, +		struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd) +{ +	struct drm_gem_object *bos[4] = {0}; +	struct drm_framebuffer *fb; +	int ret, i, n = drm_format_num_planes(mode_cmd->pixel_format); + +	for (i = 0; i < n; i++) { +		bos[i] = drm_gem_object_lookup(dev, file, +				mode_cmd->handles[i]); +		if (!bos[i]) { +			ret = -ENXIO; +			goto out_unref; +		} +	} + +	fb = msm_framebuffer_init(dev, mode_cmd, bos); +	if (IS_ERR(fb)) { +		ret = PTR_ERR(fb); +		goto out_unref; +	} + +	return fb; + +out_unref: +	for (i = 0; i < n; i++) +		drm_gem_object_unreference_unlocked(bos[i]); +	return ERR_PTR(ret); +} + +struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, +		struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos) +{ +	struct msm_drm_private *priv = dev->dev_private; +	struct msm_kms *kms = priv->kms; +	struct msm_framebuffer *msm_fb; +	struct drm_framebuffer *fb = NULL; +	const struct msm_format *format; +	int ret, i, n; +	unsigned int hsub, vsub; + +	DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)", +			dev, mode_cmd, mode_cmd->width, mode_cmd->height, +			(char *)&mode_cmd->pixel_format); + +	n = drm_format_num_planes(mode_cmd->pixel_format); +	hsub = drm_format_horz_chroma_subsampling(mode_cmd->pixel_format); +	vsub = drm_format_vert_chroma_subsampling(mode_cmd->pixel_format); + +	format = kms->funcs->get_format(kms, mode_cmd->pixel_format); +	if (!format) { +		dev_err(dev->dev, "unsupported pixel format: %4.4s\n", +				(char *)&mode_cmd->pixel_format); +		ret = -EINVAL; +		goto fail; +	} + +	msm_fb = kzalloc(sizeof(*msm_fb), GFP_KERNEL); +	if (!msm_fb) { +		ret = -ENOMEM; +		goto fail; +	} + +	fb = &msm_fb->base; + +	msm_fb->format = format; + +	for (i = 0; i < n; i++) { +		unsigned int width = mode_cmd->width / (i ? hsub : 1); +		unsigned int height = mode_cmd->height / (i ? vsub : 1); +		unsigned int min_size; + +		min_size = (height - 1) * mode_cmd->pitches[i] +			 + width * drm_format_plane_cpp(mode_cmd->pixel_format, i) +			 + mode_cmd->offsets[i]; + +		if (bos[i]->size < min_size) { +			ret = -EINVAL; +			goto fail; +		} + +		msm_fb->planes[i] = bos[i]; +	} + +	drm_helper_mode_fill_fb_struct(fb, mode_cmd); + +	ret = drm_framebuffer_init(dev, fb, &msm_framebuffer_funcs); +	if (ret) { +		dev_err(dev->dev, "framebuffer init failed: %d\n", ret); +		goto fail; +	} + +	DBG("create: FB ID: %d (%p)", fb->base.id, fb); + +	return fb; + +fail: +	if (fb) +		msm_framebuffer_destroy(fb); + +	return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c new file mode 100644 index 00000000000..5107fc4826b --- /dev/null +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include "msm_drv.h" + +#include "drm_crtc.h" +#include "drm_fb_helper.h" + +/* + * fbdev funcs, to implement legacy fbdev interface on top of drm driver + */ + +#define to_msm_fbdev(x) container_of(x, struct msm_fbdev, base) + +struct msm_fbdev { +	struct drm_fb_helper base; +	struct drm_framebuffer *fb; +	struct drm_gem_object *bo; +}; + +static struct fb_ops msm_fb_ops = { +	.owner = THIS_MODULE, + +	/* Note: to properly handle manual update displays, we wrap the +	 * basic fbdev ops which write to the framebuffer +	 */ +	.fb_read = fb_sys_read, +	.fb_write = fb_sys_write, +	.fb_fillrect = sys_fillrect, +	.fb_copyarea = sys_copyarea, +	.fb_imageblit = sys_imageblit, + +	.fb_check_var = drm_fb_helper_check_var, +	.fb_set_par = drm_fb_helper_set_par, +	.fb_pan_display = drm_fb_helper_pan_display, +	.fb_blank = drm_fb_helper_blank, +	.fb_setcmap = drm_fb_helper_setcmap, +}; + +static int msm_fbdev_create(struct drm_fb_helper *helper, +		struct drm_fb_helper_surface_size *sizes) +{ +	struct msm_fbdev *fbdev = to_msm_fbdev(helper); +	struct drm_device *dev = helper->dev; +	struct drm_framebuffer *fb = NULL; +	struct fb_info *fbi = NULL; +	struct drm_mode_fb_cmd2 mode_cmd = {0}; +	uint32_t paddr; +	int ret, size; + +	sizes->surface_bpp = 32; +	sizes->surface_depth = 24; + +	DBG("create fbdev: %dx%d@%d (%dx%d)", sizes->surface_width, +			sizes->surface_height, sizes->surface_bpp, +			sizes->fb_width, sizes->fb_height); + +	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, +			sizes->surface_depth); + +	mode_cmd.width = sizes->surface_width; +	mode_cmd.height = sizes->surface_height; + +	mode_cmd.pitches[0] = align_pitch( +			mode_cmd.width, sizes->surface_bpp); + +	/* allocate backing bo */ +	size = mode_cmd.pitches[0] * mode_cmd.height; +	DBG("allocating %d bytes for fb %d", size, dev->primary->index); +	mutex_lock(&dev->struct_mutex); +	fbdev->bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC); +	mutex_unlock(&dev->struct_mutex); +	if (IS_ERR(fbdev->bo)) { +		ret = PTR_ERR(fbdev->bo); +		fbdev->bo = NULL; +		dev_err(dev->dev, "failed to allocate buffer object: %d\n", ret); +		goto fail; +	} + +	fb = msm_framebuffer_init(dev, &mode_cmd, &fbdev->bo); +	if (IS_ERR(fb)) { +		dev_err(dev->dev, "failed to allocate fb\n"); +		/* note: if fb creation failed, we can't rely on fb destroy +		 * to unref the bo: +		 */ +		drm_gem_object_unreference(fbdev->bo); +		ret = PTR_ERR(fb); +		goto fail; +	} + +	mutex_lock(&dev->struct_mutex); + +	/* TODO implement our own fb_mmap so we don't need this: */ +	msm_gem_get_iova_locked(fbdev->bo, 0, &paddr); + +	fbi = framebuffer_alloc(0, dev->dev); +	if (!fbi) { +		dev_err(dev->dev, "failed to allocate fb info\n"); +		ret = -ENOMEM; +		goto fail_unlock; +	} + +	DBG("fbi=%p, dev=%p", fbi, dev); + +	fbdev->fb = fb; +	helper->fb = fb; +	helper->fbdev = fbi; + +	fbi->par = helper; +	fbi->flags = FBINFO_DEFAULT; +	fbi->fbops = &msm_fb_ops; + +	strcpy(fbi->fix.id, "msm"); + +	ret = fb_alloc_cmap(&fbi->cmap, 256, 0); +	if (ret) { +		ret = -ENOMEM; +		goto fail_unlock; +	} + +	drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth); +	drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height); + +	dev->mode_config.fb_base = paddr; + +	fbi->screen_base = msm_gem_vaddr_locked(fbdev->bo); +	fbi->screen_size = fbdev->bo->size; +	fbi->fix.smem_start = paddr; +	fbi->fix.smem_len = fbdev->bo->size; + +	DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres); +	DBG("allocated %dx%d fb", fbdev->fb->width, fbdev->fb->height); + +	mutex_unlock(&dev->struct_mutex); + +	return 0; + +fail_unlock: +	mutex_unlock(&dev->struct_mutex); +fail: + +	if (ret) { +		if (fbi) +			framebuffer_release(fbi); +		if (fb) { +			drm_framebuffer_unregister_private(fb); +			drm_framebuffer_remove(fb); +		} +	} + +	return ret; +} + +static void msm_crtc_fb_gamma_set(struct drm_crtc *crtc, +		u16 red, u16 green, u16 blue, int regno) +{ +	DBG("fbdev: set gamma"); +} + +static void msm_crtc_fb_gamma_get(struct drm_crtc *crtc, +		u16 *red, u16 *green, u16 *blue, int regno) +{ +	DBG("fbdev: get gamma"); +} + +static struct drm_fb_helper_funcs msm_fb_helper_funcs = { +	.gamma_set = msm_crtc_fb_gamma_set, +	.gamma_get = msm_crtc_fb_gamma_get, +	.fb_probe = msm_fbdev_create, +}; + +/* initialize fbdev helper */ +struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev) +{ +	struct msm_drm_private *priv = dev->dev_private; +	struct msm_fbdev *fbdev = NULL; +	struct drm_fb_helper *helper; +	int ret = 0; + +	fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); +	if (!fbdev) +		goto fail; + +	helper = &fbdev->base; + +	helper->funcs = &msm_fb_helper_funcs; + +	ret = drm_fb_helper_init(dev, helper, +			priv->num_crtcs, priv->num_connectors); +	if (ret) { +		dev_err(dev->dev, "could not init fbdev: ret=%d\n", ret); +		goto fail; +	} + +	drm_fb_helper_single_add_all_connectors(helper); + +	/* disable all the possible outputs/crtcs before entering KMS mode */ +	drm_helper_disable_unused_functions(dev); + +	drm_fb_helper_initial_config(helper, 32); + +	priv->fbdev = helper; + +	return helper; + +fail: +	kfree(fbdev); +	return NULL; +} + +void msm_fbdev_free(struct drm_device *dev) +{ +	struct msm_drm_private *priv = dev->dev_private; +	struct drm_fb_helper *helper = priv->fbdev; +	struct msm_fbdev *fbdev; +	struct fb_info *fbi; + +	DBG(); + +	fbi = helper->fbdev; + +	/* only cleanup framebuffer if it is present */ +	if (fbi) { +		unregister_framebuffer(fbi); +		framebuffer_release(fbi); +	} + +	drm_fb_helper_fini(helper); + +	fbdev = to_msm_fbdev(priv->fbdev); + +	/* this will free the backing object */ +	if (fbdev->fb) { +		drm_framebuffer_unregister_private(fbdev->fb); +		drm_framebuffer_remove(fbdev->fb); +	} + +	kfree(fbdev); + +	priv->fbdev = NULL; +} diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c new file mode 100644 index 00000000000..690d7e7b6d1 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -0,0 +1,702 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/spinlock.h> +#include <linux/shmem_fs.h> +#include <linux/dma-buf.h> + +#include "msm_drv.h" +#include "msm_gem.h" +#include "msm_gpu.h" +#include "msm_mmu.h" + +static dma_addr_t physaddr(struct drm_gem_object *obj) +{ +	struct msm_gem_object *msm_obj = to_msm_bo(obj); +	struct msm_drm_private *priv = obj->dev->dev_private; +	return (((dma_addr_t)msm_obj->vram_node->start) << PAGE_SHIFT) + +			priv->vram.paddr; +} + +/* allocate pages from VRAM carveout, used when no IOMMU: */ +static struct page **get_pages_vram(struct drm_gem_object *obj, +		int npages) +{ +	struct msm_gem_object *msm_obj = to_msm_bo(obj); +	struct msm_drm_private *priv = obj->dev->dev_private; +	dma_addr_t paddr; +	struct page **p; +	int ret, i; + +	p = drm_malloc_ab(npages, sizeof(struct page *)); +	if (!p) +		return ERR_PTR(-ENOMEM); + +	ret = drm_mm_insert_node(&priv->vram.mm, msm_obj->vram_node, +			npages, 0, DRM_MM_SEARCH_DEFAULT); +	if (ret) { +		drm_free_large(p); +		return ERR_PTR(ret); +	} + +	paddr = physaddr(obj); +	for (i = 0; i < npages; i++) { +		p[i] = phys_to_page(paddr); +		paddr += PAGE_SIZE; +	} + +	return p; +} + +/* called with dev->struct_mutex held */ +static struct page **get_pages(struct drm_gem_object *obj) +{ +	struct msm_gem_object *msm_obj = to_msm_bo(obj); + +	if (!msm_obj->pages) { +		struct drm_device *dev = obj->dev; +		struct page **p; +		int npages = obj->size >> PAGE_SHIFT; + +		if (iommu_present(&platform_bus_type)) +			p = drm_gem_get_pages(obj, 0); +		else +			p = get_pages_vram(obj, npages); + +		if (IS_ERR(p)) { +			dev_err(dev->dev, "could not get pages: %ld\n", +					PTR_ERR(p)); +			return p; +		} + +		msm_obj->sgt = drm_prime_pages_to_sg(p, npages); +		if (IS_ERR(msm_obj->sgt)) { +			dev_err(dev->dev, "failed to allocate sgt\n"); +			return ERR_CAST(msm_obj->sgt); +		} + +		msm_obj->pages = p; + +		/* For non-cached buffers, ensure the new pages are clean +		 * because display controller, GPU, etc. are not coherent: +		 */ +		if (msm_obj->flags & (MSM_BO_WC|MSM_BO_UNCACHED)) +			dma_map_sg(dev->dev, msm_obj->sgt->sgl, +					msm_obj->sgt->nents, DMA_BIDIRECTIONAL); +	} + +	return msm_obj->pages; +} + +static void put_pages(struct drm_gem_object *obj) +{ +	struct msm_gem_object *msm_obj = to_msm_bo(obj); + +	if (msm_obj->pages) { +		/* For non-cached buffers, ensure the new pages are clean +		 * because display controller, GPU, etc. are not coherent: +		 */ +		if (msm_obj->flags & (MSM_BO_WC|MSM_BO_UNCACHED)) +			dma_unmap_sg(obj->dev->dev, msm_obj->sgt->sgl, +					msm_obj->sgt->nents, DMA_BIDIRECTIONAL); +		sg_free_table(msm_obj->sgt); +		kfree(msm_obj->sgt); + +		if (iommu_present(&platform_bus_type)) +			drm_gem_put_pages(obj, msm_obj->pages, true, false); +		else { +			drm_mm_remove_node(msm_obj->vram_node); +			drm_free_large(msm_obj->pages); +		} + +		msm_obj->pages = NULL; +	} +} + +struct page **msm_gem_get_pages(struct drm_gem_object *obj) +{ +	struct drm_device *dev = obj->dev; +	struct page **p; +	mutex_lock(&dev->struct_mutex); +	p = get_pages(obj); +	mutex_unlock(&dev->struct_mutex); +	return p; +} + +void msm_gem_put_pages(struct drm_gem_object *obj) +{ +	/* when we start tracking the pin count, then do something here */ +} + +int msm_gem_mmap_obj(struct drm_gem_object *obj, +		struct vm_area_struct *vma) +{ +	struct msm_gem_object *msm_obj = to_msm_bo(obj); + +	vma->vm_flags &= ~VM_PFNMAP; +	vma->vm_flags |= VM_MIXEDMAP; + +	if (msm_obj->flags & MSM_BO_WC) { +		vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); +	} else if (msm_obj->flags & MSM_BO_UNCACHED) { +		vma->vm_page_prot = pgprot_noncached(vm_get_page_prot(vma->vm_flags)); +	} else { +		/* +		 * Shunt off cached objs to shmem file so they have their own +		 * address_space (so unmap_mapping_range does what we want, +		 * in particular in the case of mmap'd dmabufs) +		 */ +		fput(vma->vm_file); +		get_file(obj->filp); +		vma->vm_pgoff = 0; +		vma->vm_file  = obj->filp; + +		vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); +	} + +	return 0; +} + +int msm_gem_mmap(struct file *filp, struct vm_area_struct *vma) +{ +	int ret; + +	ret = drm_gem_mmap(filp, vma); +	if (ret) { +		DBG("mmap failed: %d", ret); +		return ret; +	} + +	return msm_gem_mmap_obj(vma->vm_private_data, vma); +} + +int msm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ +	struct drm_gem_object *obj = vma->vm_private_data; +	struct drm_device *dev = obj->dev; +	struct page **pages; +	unsigned long pfn; +	pgoff_t pgoff; +	int ret; + +	/* Make sure we don't parallel update on a fault, nor move or remove +	 * something from beneath our feet +	 */ +	ret = mutex_lock_interruptible(&dev->struct_mutex); +	if (ret) +		goto out; + +	/* make sure we have pages attached now */ +	pages = get_pages(obj); +	if (IS_ERR(pages)) { +		ret = PTR_ERR(pages); +		goto out_unlock; +	} + +	/* We don't use vmf->pgoff since that has the fake offset: */ +	pgoff = ((unsigned long)vmf->virtual_address - +			vma->vm_start) >> PAGE_SHIFT; + +	pfn = page_to_pfn(pages[pgoff]); + +	VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address, +			pfn, pfn << PAGE_SHIFT); + +	ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn); + +out_unlock: +	mutex_unlock(&dev->struct_mutex); +out: +	switch (ret) { +	case -EAGAIN: +	case 0: +	case -ERESTARTSYS: +	case -EINTR: +	case -EBUSY: +		/* +		 * EBUSY is ok: this just means that another thread +		 * already did the job. +		 */ +		return VM_FAULT_NOPAGE; +	case -ENOMEM: +		return VM_FAULT_OOM; +	default: +		return VM_FAULT_SIGBUS; +	} +} + +/** get mmap offset */ +static uint64_t mmap_offset(struct drm_gem_object *obj) +{ +	struct drm_device *dev = obj->dev; +	int ret; + +	WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + +	/* Make it mmapable */ +	ret = drm_gem_create_mmap_offset(obj); + +	if (ret) { +		dev_err(dev->dev, "could not allocate mmap offset\n"); +		return 0; +	} + +	return drm_vma_node_offset_addr(&obj->vma_node); +} + +uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj) +{ +	uint64_t offset; +	mutex_lock(&obj->dev->struct_mutex); +	offset = mmap_offset(obj); +	mutex_unlock(&obj->dev->struct_mutex); +	return offset; +} + +/* should be called under struct_mutex.. although it can be called + * from atomic context without struct_mutex to acquire an extra + * iova ref if you know one is already held. + * + * That means when I do eventually need to add support for unpinning + * the refcnt counter needs to be atomic_t. + */ +int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id, +		uint32_t *iova) +{ +	struct msm_gem_object *msm_obj = to_msm_bo(obj); +	struct drm_device *dev = obj->dev; +	int ret = 0; + +	if (!msm_obj->domain[id].iova) { +		struct msm_drm_private *priv = obj->dev->dev_private; +		struct msm_mmu *mmu = priv->mmus[id]; +		struct page **pages = get_pages(obj); + +		if (!mmu) { +			dev_err(dev->dev, "null MMU pointer\n"); +			return -EINVAL; +		} + +		if (IS_ERR(pages)) +			return PTR_ERR(pages); + +		if (iommu_present(&platform_bus_type)) { +			uint32_t offset = (uint32_t)mmap_offset(obj); +			ret = mmu->funcs->map(mmu, offset, msm_obj->sgt, +					obj->size, IOMMU_READ | IOMMU_WRITE); +			msm_obj->domain[id].iova = offset; +		} else { +			msm_obj->domain[id].iova = physaddr(obj); +		} +	} + +	if (!ret) +		*iova = msm_obj->domain[id].iova; + +	return ret; +} + +int msm_gem_get_iova(struct drm_gem_object *obj, int id, uint32_t *iova) +{ +	struct msm_gem_object *msm_obj = to_msm_bo(obj); +	int ret; + +	/* this is safe right now because we don't unmap until the +	 * bo is deleted: +	 */ +	if (msm_obj->domain[id].iova) { +		*iova = msm_obj->domain[id].iova; +		return 0; +	} + +	mutex_lock(&obj->dev->struct_mutex); +	ret = msm_gem_get_iova_locked(obj, id, iova); +	mutex_unlock(&obj->dev->struct_mutex); +	return ret; +} + +void msm_gem_put_iova(struct drm_gem_object *obj, int id) +{ +	// XXX TODO .. +	// NOTE: probably don't need a _locked() version.. we wouldn't +	// normally unmap here, but instead just mark that it could be +	// unmapped (if the iova refcnt drops to zero), but then later +	// if another _get_iova_locked() fails we can start unmapping +	// things that are no longer needed.. +} + +int msm_gem_dumb_create(struct drm_file *file, struct drm_device *dev, +		struct drm_mode_create_dumb *args) +{ +	args->pitch = align_pitch(args->width, args->bpp); +	args->size  = PAGE_ALIGN(args->pitch * args->height); +	return msm_gem_new_handle(dev, file, args->size, +			MSM_BO_SCANOUT | MSM_BO_WC, &args->handle); +} + +int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, +		uint32_t handle, uint64_t *offset) +{ +	struct drm_gem_object *obj; +	int ret = 0; + +	/* GEM does all our handle to object mapping */ +	obj = drm_gem_object_lookup(dev, file, handle); +	if (obj == NULL) { +		ret = -ENOENT; +		goto fail; +	} + +	*offset = msm_gem_mmap_offset(obj); + +	drm_gem_object_unreference_unlocked(obj); + +fail: +	return ret; +} + +void *msm_gem_vaddr_locked(struct drm_gem_object *obj) +{ +	struct msm_gem_object *msm_obj = to_msm_bo(obj); +	WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); +	if (!msm_obj->vaddr) { +		struct page **pages = get_pages(obj); +		if (IS_ERR(pages)) +			return ERR_CAST(pages); +		msm_obj->vaddr = vmap(pages, obj->size >> PAGE_SHIFT, +				VM_MAP, pgprot_writecombine(PAGE_KERNEL)); +	} +	return msm_obj->vaddr; +} + +void *msm_gem_vaddr(struct drm_gem_object *obj) +{ +	void *ret; +	mutex_lock(&obj->dev->struct_mutex); +	ret = msm_gem_vaddr_locked(obj); +	mutex_unlock(&obj->dev->struct_mutex); +	return ret; +} + +/* setup callback for when bo is no longer busy.. + * TODO probably want to differentiate read vs write.. + */ +int msm_gem_queue_inactive_cb(struct drm_gem_object *obj, +		struct msm_fence_cb *cb) +{ +	struct drm_device *dev = obj->dev; +	struct msm_drm_private *priv = dev->dev_private; +	struct msm_gem_object *msm_obj = to_msm_bo(obj); +	int ret = 0; + +	mutex_lock(&dev->struct_mutex); +	if (!list_empty(&cb->work.entry)) { +		ret = -EINVAL; +	} else if (is_active(msm_obj)) { +		cb->fence = max(msm_obj->read_fence, msm_obj->write_fence); +		list_add_tail(&cb->work.entry, &priv->fence_cbs); +	} else { +		queue_work(priv->wq, &cb->work); +	} +	mutex_unlock(&dev->struct_mutex); + +	return ret; +} + +void msm_gem_move_to_active(struct drm_gem_object *obj, +		struct msm_gpu *gpu, bool write, uint32_t fence) +{ +	struct msm_gem_object *msm_obj = to_msm_bo(obj); +	msm_obj->gpu = gpu; +	if (write) +		msm_obj->write_fence = fence; +	else +		msm_obj->read_fence = fence; +	list_del_init(&msm_obj->mm_list); +	list_add_tail(&msm_obj->mm_list, &gpu->active_list); +} + +void msm_gem_move_to_inactive(struct drm_gem_object *obj) +{ +	struct drm_device *dev = obj->dev; +	struct msm_drm_private *priv = dev->dev_private; +	struct msm_gem_object *msm_obj = to_msm_bo(obj); + +	WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + +	msm_obj->gpu = NULL; +	msm_obj->read_fence = 0; +	msm_obj->write_fence = 0; +	list_del_init(&msm_obj->mm_list); +	list_add_tail(&msm_obj->mm_list, &priv->inactive_list); +} + +int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, +		struct timespec *timeout) +{ +	struct drm_device *dev = obj->dev; +	struct msm_gem_object *msm_obj = to_msm_bo(obj); +	int ret = 0; + +	if (is_active(msm_obj)) { +		uint32_t fence = 0; + +		if (op & MSM_PREP_READ) +			fence = msm_obj->write_fence; +		if (op & MSM_PREP_WRITE) +			fence = max(fence, msm_obj->read_fence); +		if (op & MSM_PREP_NOSYNC) +			timeout = NULL; + +		ret = msm_wait_fence_interruptable(dev, fence, timeout); +	} + +	/* TODO cache maintenance */ + +	return ret; +} + +int msm_gem_cpu_fini(struct drm_gem_object *obj) +{ +	/* TODO cache maintenance */ +	return 0; +} + +#ifdef CONFIG_DEBUG_FS +void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m) +{ +	struct drm_device *dev = obj->dev; +	struct msm_gem_object *msm_obj = to_msm_bo(obj); +	uint64_t off = drm_vma_node_start(&obj->vma_node); + +	WARN_ON(!mutex_is_locked(&dev->struct_mutex)); +	seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08llx %p %d\n", +			msm_obj->flags, is_active(msm_obj) ? 'A' : 'I', +			msm_obj->read_fence, msm_obj->write_fence, +			obj->name, obj->refcount.refcount.counter, +			off, msm_obj->vaddr, obj->size); +} + +void msm_gem_describe_objects(struct list_head *list, struct seq_file *m) +{ +	struct msm_gem_object *msm_obj; +	int count = 0; +	size_t size = 0; + +	list_for_each_entry(msm_obj, list, mm_list) { +		struct drm_gem_object *obj = &msm_obj->base; +		seq_printf(m, "   "); +		msm_gem_describe(obj, m); +		count++; +		size += obj->size; +	} + +	seq_printf(m, "Total %d objects, %zu bytes\n", count, size); +} +#endif + +void msm_gem_free_object(struct drm_gem_object *obj) +{ +	struct drm_device *dev = obj->dev; +	struct msm_drm_private *priv = obj->dev->dev_private; +	struct msm_gem_object *msm_obj = to_msm_bo(obj); +	int id; + +	WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + +	/* object should not be on active list: */ +	WARN_ON(is_active(msm_obj)); + +	list_del(&msm_obj->mm_list); + +	for (id = 0; id < ARRAY_SIZE(msm_obj->domain); id++) { +		struct msm_mmu *mmu = priv->mmus[id]; +		if (mmu && msm_obj->domain[id].iova) { +			uint32_t offset = (uint32_t)mmap_offset(obj); +			mmu->funcs->unmap(mmu, offset, msm_obj->sgt, obj->size); +		} +	} + +	drm_gem_free_mmap_offset(obj); + +	if (obj->import_attach) { +		if (msm_obj->vaddr) +			dma_buf_vunmap(obj->import_attach->dmabuf, msm_obj->vaddr); + +		/* Don't drop the pages for imported dmabuf, as they are not +		 * ours, just free the array we allocated: +		 */ +		if (msm_obj->pages) +			drm_free_large(msm_obj->pages); + +	} else { +		if (msm_obj->vaddr) +			vunmap(msm_obj->vaddr); +		put_pages(obj); +	} + +	if (msm_obj->resv == &msm_obj->_resv) +		reservation_object_fini(msm_obj->resv); + +	drm_gem_object_release(obj); + +	kfree(msm_obj); +} + +/* convenience method to construct a GEM buffer object, and userspace handle */ +int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file, +		uint32_t size, uint32_t flags, uint32_t *handle) +{ +	struct drm_gem_object *obj; +	int ret; + +	ret = mutex_lock_interruptible(&dev->struct_mutex); +	if (ret) +		return ret; + +	obj = msm_gem_new(dev, size, flags); + +	mutex_unlock(&dev->struct_mutex); + +	if (IS_ERR(obj)) +		return PTR_ERR(obj); + +	ret = drm_gem_handle_create(file, obj, handle); + +	/* drop reference from allocate - handle holds it now */ +	drm_gem_object_unreference_unlocked(obj); + +	return ret; +} + +static int msm_gem_new_impl(struct drm_device *dev, +		uint32_t size, uint32_t flags, +		struct drm_gem_object **obj) +{ +	struct msm_drm_private *priv = dev->dev_private; +	struct msm_gem_object *msm_obj; +	unsigned sz; + +	switch (flags & MSM_BO_CACHE_MASK) { +	case MSM_BO_UNCACHED: +	case MSM_BO_CACHED: +	case MSM_BO_WC: +		break; +	default: +		dev_err(dev->dev, "invalid cache flag: %x\n", +				(flags & MSM_BO_CACHE_MASK)); +		return -EINVAL; +	} + +	sz = sizeof(*msm_obj); +	if (!iommu_present(&platform_bus_type)) +		sz += sizeof(struct drm_mm_node); + +	msm_obj = kzalloc(sz, GFP_KERNEL); +	if (!msm_obj) +		return -ENOMEM; + +	if (!iommu_present(&platform_bus_type)) +		msm_obj->vram_node = (void *)&msm_obj[1]; + +	msm_obj->flags = flags; + +	msm_obj->resv = &msm_obj->_resv; +	reservation_object_init(msm_obj->resv); + +	INIT_LIST_HEAD(&msm_obj->submit_entry); +	list_add_tail(&msm_obj->mm_list, &priv->inactive_list); + +	*obj = &msm_obj->base; + +	return 0; +} + +struct drm_gem_object *msm_gem_new(struct drm_device *dev, +		uint32_t size, uint32_t flags) +{ +	struct drm_gem_object *obj = NULL; +	int ret; + +	WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + +	size = PAGE_ALIGN(size); + +	ret = msm_gem_new_impl(dev, size, flags, &obj); +	if (ret) +		goto fail; + +	if (iommu_present(&platform_bus_type)) { +		ret = drm_gem_object_init(dev, obj, size); +		if (ret) +			goto fail; +	} else { +		drm_gem_private_object_init(dev, obj, size); +	} + +	return obj; + +fail: +	if (obj) +		drm_gem_object_unreference(obj); + +	return ERR_PTR(ret); +} + +struct drm_gem_object *msm_gem_import(struct drm_device *dev, +		uint32_t size, struct sg_table *sgt) +{ +	struct msm_gem_object *msm_obj; +	struct drm_gem_object *obj; +	int ret, npages; + +	/* if we don't have IOMMU, don't bother pretending we can import: */ +	if (!iommu_present(&platform_bus_type)) { +		dev_err(dev->dev, "cannot import without IOMMU\n"); +		return ERR_PTR(-EINVAL); +	} + +	size = PAGE_ALIGN(size); + +	ret = msm_gem_new_impl(dev, size, MSM_BO_WC, &obj); +	if (ret) +		goto fail; + +	drm_gem_private_object_init(dev, obj, size); + +	npages = size / PAGE_SIZE; + +	msm_obj = to_msm_bo(obj); +	msm_obj->sgt = sgt; +	msm_obj->pages = drm_malloc_ab(npages, sizeof(struct page *)); +	if (!msm_obj->pages) { +		ret = -ENOMEM; +		goto fail; +	} + +	ret = drm_prime_sg_to_page_addr_arrays(sgt, msm_obj->pages, NULL, npages); +	if (ret) +		goto fail; + +	return obj; + +fail: +	if (obj) +		drm_gem_object_unreference_unlocked(obj); + +	return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h new file mode 100644 index 00000000000..bfb052688f8 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __MSM_GEM_H__ +#define __MSM_GEM_H__ + +#include <linux/reservation.h> +#include "msm_drv.h" + +struct msm_gem_object { +	struct drm_gem_object base; + +	uint32_t flags; + +	/* And object is either: +	 *  inactive - on priv->inactive_list +	 *  active   - on one one of the gpu's active_list..  well, at +	 *     least for now we don't have (I don't think) hw sync between +	 *     2d and 3d one devices which have both, meaning we need to +	 *     block on submit if a bo is already on other ring +	 * +	 */ +	struct list_head mm_list; +	struct msm_gpu *gpu;     /* non-null if active */ +	uint32_t read_fence, write_fence; + +	/* Transiently in the process of submit ioctl, objects associated +	 * with the submit are on submit->bo_list.. this only lasts for +	 * the duration of the ioctl, so one bo can never be on multiple +	 * submit lists. +	 */ +	struct list_head submit_entry; + +	struct page **pages; +	struct sg_table *sgt; +	void *vaddr; + +	struct { +		// XXX +		uint32_t iova; +	} domain[NUM_DOMAINS]; + +	/* normally (resv == &_resv) except for imported bo's */ +	struct reservation_object *resv; +	struct reservation_object _resv; + +	/* For physically contiguous buffers.  Used when we don't have +	 * an IOMMU. +	 */ +	struct drm_mm_node *vram_node; +}; +#define to_msm_bo(x) container_of(x, struct msm_gem_object, base) + +static inline bool is_active(struct msm_gem_object *msm_obj) +{ +	return msm_obj->gpu != NULL; +} + +#define MAX_CMDS 4 + +/* Created per submit-ioctl, to track bo's and cmdstream bufs, etc, + * associated with the cmdstream submission for synchronization (and + * make it easier to unwind when things go wrong, etc).  This only + * lasts for the duration of the submit-ioctl. + */ +struct msm_gem_submit { +	struct drm_device *dev; +	struct msm_gpu *gpu; +	struct list_head bo_list; +	struct ww_acquire_ctx ticket; +	uint32_t fence; +	bool valid; +	unsigned int nr_cmds; +	unsigned int nr_bos; +	struct { +		uint32_t type; +		uint32_t size;  /* in dwords */ +		uint32_t iova; +		uint32_t idx;   /* cmdstream buffer idx in bos[] */ +	} cmd[MAX_CMDS]; +	struct { +		uint32_t flags; +		struct msm_gem_object *obj; +		uint32_t iova; +	} bos[0]; +}; + +#endif /* __MSM_GEM_H__ */ diff --git a/drivers/gpu/drm/msm/msm_gem_prime.c b/drivers/gpu/drm/msm/msm_gem_prime.c new file mode 100644 index 00000000000..d48f9fc5129 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_gem_prime.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include "msm_drv.h" +#include "msm_gem.h" + + +struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj) +{ +	struct msm_gem_object *msm_obj = to_msm_bo(obj); +	BUG_ON(!msm_obj->sgt);  /* should have already pinned! */ +	return msm_obj->sgt; +} + +void *msm_gem_prime_vmap(struct drm_gem_object *obj) +{ +	return msm_gem_vaddr(obj); +} + +void msm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) +{ +	/* TODO msm_gem_vunmap() */ +} + +struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev, +		size_t size, struct sg_table *sg) +{ +	return msm_gem_import(dev, size, sg); +} + +int msm_gem_prime_pin(struct drm_gem_object *obj) +{ +	if (!obj->import_attach) +		msm_gem_get_pages(obj); +	return 0; +} + +void msm_gem_prime_unpin(struct drm_gem_object *obj) +{ +	if (!obj->import_attach) +		msm_gem_put_pages(obj); +} diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c new file mode 100644 index 00000000000..cd0554f6831 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -0,0 +1,427 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include "msm_drv.h" +#include "msm_gpu.h" +#include "msm_gem.h" + +/* + * Cmdstream submission: + */ + +/* make sure these don't conflict w/ MSM_SUBMIT_BO_x */ +#define BO_VALID    0x8000 +#define BO_LOCKED   0x4000 +#define BO_PINNED   0x2000 + +static inline void __user *to_user_ptr(u64 address) +{ +	return (void __user *)(uintptr_t)address; +} + +static struct msm_gem_submit *submit_create(struct drm_device *dev, +		struct msm_gpu *gpu, int nr) +{ +	struct msm_gem_submit *submit; +	int sz = sizeof(*submit) + (nr * sizeof(submit->bos[0])); + +	submit = kmalloc(sz, GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY); +	if (submit) { +		submit->dev = dev; +		submit->gpu = gpu; + +		/* initially, until copy_from_user() and bo lookup succeeds: */ +		submit->nr_bos = 0; +		submit->nr_cmds = 0; + +		INIT_LIST_HEAD(&submit->bo_list); +		ww_acquire_init(&submit->ticket, &reservation_ww_class); +	} + +	return submit; +} + +static int submit_lookup_objects(struct msm_gem_submit *submit, +		struct drm_msm_gem_submit *args, struct drm_file *file) +{ +	unsigned i; +	int ret = 0; + +	spin_lock(&file->table_lock); + +	for (i = 0; i < args->nr_bos; i++) { +		struct drm_msm_gem_submit_bo submit_bo; +		struct drm_gem_object *obj; +		struct msm_gem_object *msm_obj; +		void __user *userptr = +			to_user_ptr(args->bos + (i * sizeof(submit_bo))); + +		ret = copy_from_user(&submit_bo, userptr, sizeof(submit_bo)); +		if (ret) { +			ret = -EFAULT; +			goto out_unlock; +		} + +		if (submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) { +			DRM_ERROR("invalid flags: %x\n", submit_bo.flags); +			ret = -EINVAL; +			goto out_unlock; +		} + +		submit->bos[i].flags = submit_bo.flags; +		/* in validate_objects() we figure out if this is true: */ +		submit->bos[i].iova  = submit_bo.presumed; + +		/* normally use drm_gem_object_lookup(), but for bulk lookup +		 * all under single table_lock just hit object_idr directly: +		 */ +		obj = idr_find(&file->object_idr, submit_bo.handle); +		if (!obj) { +			DRM_ERROR("invalid handle %u at index %u\n", submit_bo.handle, i); +			ret = -EINVAL; +			goto out_unlock; +		} + +		msm_obj = to_msm_bo(obj); + +		if (!list_empty(&msm_obj->submit_entry)) { +			DRM_ERROR("handle %u at index %u already on submit list\n", +					submit_bo.handle, i); +			ret = -EINVAL; +			goto out_unlock; +		} + +		drm_gem_object_reference(obj); + +		submit->bos[i].obj = msm_obj; + +		list_add_tail(&msm_obj->submit_entry, &submit->bo_list); +	} + +out_unlock: +	submit->nr_bos = i; +	spin_unlock(&file->table_lock); + +	return ret; +} + +static void submit_unlock_unpin_bo(struct msm_gem_submit *submit, int i) +{ +	struct msm_gem_object *msm_obj = submit->bos[i].obj; + +	if (submit->bos[i].flags & BO_PINNED) +		msm_gem_put_iova(&msm_obj->base, submit->gpu->id); + +	if (submit->bos[i].flags & BO_LOCKED) +		ww_mutex_unlock(&msm_obj->resv->lock); + +	if (!(submit->bos[i].flags & BO_VALID)) +		submit->bos[i].iova = 0; + +	submit->bos[i].flags &= ~(BO_LOCKED | BO_PINNED); +} + +/* This is where we make sure all the bo's are reserved and pin'd: */ +static int submit_validate_objects(struct msm_gem_submit *submit) +{ +	int contended, slow_locked = -1, i, ret = 0; + +retry: +	submit->valid = true; + +	for (i = 0; i < submit->nr_bos; i++) { +		struct msm_gem_object *msm_obj = submit->bos[i].obj; +		uint32_t iova; + +		if (slow_locked == i) +			slow_locked = -1; + +		contended = i; + +		if (!(submit->bos[i].flags & BO_LOCKED)) { +			ret = ww_mutex_lock_interruptible(&msm_obj->resv->lock, +					&submit->ticket); +			if (ret) +				goto fail; +			submit->bos[i].flags |= BO_LOCKED; +		} + + +		/* if locking succeeded, pin bo: */ +		ret = msm_gem_get_iova_locked(&msm_obj->base, +				submit->gpu->id, &iova); + +		/* this would break the logic in the fail path.. there is no +		 * reason for this to happen, but just to be on the safe side +		 * let's notice if this starts happening in the future: +		 */ +		WARN_ON(ret == -EDEADLK); + +		if (ret) +			goto fail; + +		submit->bos[i].flags |= BO_PINNED; + +		if (iova == submit->bos[i].iova) { +			submit->bos[i].flags |= BO_VALID; +		} else { +			submit->bos[i].iova = iova; +			submit->bos[i].flags &= ~BO_VALID; +			submit->valid = false; +		} +	} + +	ww_acquire_done(&submit->ticket); + +	return 0; + +fail: +	for (; i >= 0; i--) +		submit_unlock_unpin_bo(submit, i); + +	if (slow_locked > 0) +		submit_unlock_unpin_bo(submit, slow_locked); + +	if (ret == -EDEADLK) { +		struct msm_gem_object *msm_obj = submit->bos[contended].obj; +		/* we lost out in a seqno race, lock and retry.. */ +		ret = ww_mutex_lock_slow_interruptible(&msm_obj->resv->lock, +				&submit->ticket); +		if (!ret) { +			submit->bos[contended].flags |= BO_LOCKED; +			slow_locked = contended; +			goto retry; +		} +	} + +	return ret; +} + +static int submit_bo(struct msm_gem_submit *submit, uint32_t idx, +		struct msm_gem_object **obj, uint32_t *iova, bool *valid) +{ +	if (idx >= submit->nr_bos) { +		DRM_ERROR("invalid buffer index: %u (out of %u)\n", +				idx, submit->nr_bos); +		return -EINVAL; +	} + +	if (obj) +		*obj = submit->bos[idx].obj; +	if (iova) +		*iova = submit->bos[idx].iova; +	if (valid) +		*valid = !!(submit->bos[idx].flags & BO_VALID); + +	return 0; +} + +/* process the reloc's and patch up the cmdstream as needed: */ +static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *obj, +		uint32_t offset, uint32_t nr_relocs, uint64_t relocs) +{ +	uint32_t i, last_offset = 0; +	uint32_t *ptr; +	int ret; + +	if (offset % 4) { +		DRM_ERROR("non-aligned cmdstream buffer: %u\n", offset); +		return -EINVAL; +	} + +	/* For now, just map the entire thing.  Eventually we probably +	 * to do it page-by-page, w/ kmap() if not vmap()d.. +	 */ +	ptr = msm_gem_vaddr_locked(&obj->base); + +	if (IS_ERR(ptr)) { +		ret = PTR_ERR(ptr); +		DBG("failed to map: %d", ret); +		return ret; +	} + +	for (i = 0; i < nr_relocs; i++) { +		struct drm_msm_gem_submit_reloc submit_reloc; +		void __user *userptr = +			to_user_ptr(relocs + (i * sizeof(submit_reloc))); +		uint32_t iova, off; +		bool valid; + +		ret = copy_from_user(&submit_reloc, userptr, sizeof(submit_reloc)); +		if (ret) +			return -EFAULT; + +		if (submit_reloc.submit_offset % 4) { +			DRM_ERROR("non-aligned reloc offset: %u\n", +					submit_reloc.submit_offset); +			return -EINVAL; +		} + +		/* offset in dwords: */ +		off = submit_reloc.submit_offset / 4; + +		if ((off >= (obj->base.size / 4)) || +				(off < last_offset)) { +			DRM_ERROR("invalid offset %u at reloc %u\n", off, i); +			return -EINVAL; +		} + +		ret = submit_bo(submit, submit_reloc.reloc_idx, NULL, &iova, &valid); +		if (ret) +			return ret; + +		if (valid) +			continue; + +		iova += submit_reloc.reloc_offset; + +		if (submit_reloc.shift < 0) +			iova >>= -submit_reloc.shift; +		else +			iova <<= submit_reloc.shift; + +		ptr[off] = iova | submit_reloc.or; + +		last_offset = off; +	} + +	return 0; +} + +static void submit_cleanup(struct msm_gem_submit *submit, bool fail) +{ +	unsigned i; + +	for (i = 0; i < submit->nr_bos; i++) { +		struct msm_gem_object *msm_obj = submit->bos[i].obj; +		submit_unlock_unpin_bo(submit, i); +		list_del_init(&msm_obj->submit_entry); +		drm_gem_object_unreference(&msm_obj->base); +	} + +	ww_acquire_fini(&submit->ticket); +	kfree(submit); +} + +int msm_ioctl_gem_submit(struct drm_device *dev, void *data, +		struct drm_file *file) +{ +	struct msm_drm_private *priv = dev->dev_private; +	struct drm_msm_gem_submit *args = data; +	struct msm_file_private *ctx = file->driver_priv; +	struct msm_gem_submit *submit; +	struct msm_gpu *gpu; +	unsigned i; +	int ret; + +	/* for now, we just have 3d pipe.. eventually this would need to +	 * be more clever to dispatch to appropriate gpu module: +	 */ +	if (args->pipe != MSM_PIPE_3D0) +		return -EINVAL; + +	gpu = priv->gpu; + +	if (args->nr_cmds > MAX_CMDS) +		return -EINVAL; + +	mutex_lock(&dev->struct_mutex); + +	submit = submit_create(dev, gpu, args->nr_bos); +	if (!submit) { +		ret = -ENOMEM; +		goto out; +	} + +	ret = submit_lookup_objects(submit, args, file); +	if (ret) +		goto out; + +	ret = submit_validate_objects(submit); +	if (ret) +		goto out; + +	for (i = 0; i < args->nr_cmds; i++) { +		struct drm_msm_gem_submit_cmd submit_cmd; +		void __user *userptr = +			to_user_ptr(args->cmds + (i * sizeof(submit_cmd))); +		struct msm_gem_object *msm_obj; +		uint32_t iova; + +		ret = copy_from_user(&submit_cmd, userptr, sizeof(submit_cmd)); +		if (ret) { +			ret = -EFAULT; +			goto out; +		} + +		/* validate input from userspace: */ +		switch (submit_cmd.type) { +		case MSM_SUBMIT_CMD_BUF: +		case MSM_SUBMIT_CMD_IB_TARGET_BUF: +		case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: +			break; +		default: +			DRM_ERROR("invalid type: %08x\n", submit_cmd.type); +			ret = -EINVAL; +			goto out; +		} + +		ret = submit_bo(submit, submit_cmd.submit_idx, +				&msm_obj, &iova, NULL); +		if (ret) +			goto out; + +		if (submit_cmd.size % 4) { +			DRM_ERROR("non-aligned cmdstream buffer size: %u\n", +					submit_cmd.size); +			ret = -EINVAL; +			goto out; +		} + +		if ((submit_cmd.size + submit_cmd.submit_offset) >= +				msm_obj->base.size) { +			DRM_ERROR("invalid cmdstream size: %u\n", submit_cmd.size); +			ret = -EINVAL; +			goto out; +		} + +		submit->cmd[i].type = submit_cmd.type; +		submit->cmd[i].size = submit_cmd.size / 4; +		submit->cmd[i].iova = iova + submit_cmd.submit_offset; +		submit->cmd[i].idx  = submit_cmd.submit_idx; + +		if (submit->valid) +			continue; + +		ret = submit_reloc(submit, msm_obj, submit_cmd.submit_offset, +				submit_cmd.nr_relocs, submit_cmd.relocs); +		if (ret) +			goto out; +	} + +	submit->nr_cmds = i; + +	ret = msm_gpu_submit(gpu, submit, ctx); + +	args->fence = submit->fence; + +out: +	if (submit) +		submit_cleanup(submit, !!ret); +	mutex_unlock(&dev->struct_mutex); +	return ret; +} diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c new file mode 100644 index 00000000000..c6322197db8 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -0,0 +1,655 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include "msm_gpu.h" +#include "msm_gem.h" +#include "msm_mmu.h" + + +/* + * Power Management: + */ + +#ifdef CONFIG_MSM_BUS_SCALING +#include <mach/board.h> +static void bs_init(struct msm_gpu *gpu) +{ +	if (gpu->bus_scale_table) { +		gpu->bsc = msm_bus_scale_register_client(gpu->bus_scale_table); +		DBG("bus scale client: %08x", gpu->bsc); +	} +} + +static void bs_fini(struct msm_gpu *gpu) +{ +	if (gpu->bsc) { +		msm_bus_scale_unregister_client(gpu->bsc); +		gpu->bsc = 0; +	} +} + +static void bs_set(struct msm_gpu *gpu, int idx) +{ +	if (gpu->bsc) { +		DBG("set bus scaling: %d", idx); +		msm_bus_scale_client_update_request(gpu->bsc, idx); +	} +} +#else +static void bs_init(struct msm_gpu *gpu) {} +static void bs_fini(struct msm_gpu *gpu) {} +static void bs_set(struct msm_gpu *gpu, int idx) {} +#endif + +static int enable_pwrrail(struct msm_gpu *gpu) +{ +	struct drm_device *dev = gpu->dev; +	int ret = 0; + +	if (gpu->gpu_reg) { +		ret = regulator_enable(gpu->gpu_reg); +		if (ret) { +			dev_err(dev->dev, "failed to enable 'gpu_reg': %d\n", ret); +			return ret; +		} +	} + +	if (gpu->gpu_cx) { +		ret = regulator_enable(gpu->gpu_cx); +		if (ret) { +			dev_err(dev->dev, "failed to enable 'gpu_cx': %d\n", ret); +			return ret; +		} +	} + +	return 0; +} + +static int disable_pwrrail(struct msm_gpu *gpu) +{ +	if (gpu->gpu_cx) +		regulator_disable(gpu->gpu_cx); +	if (gpu->gpu_reg) +		regulator_disable(gpu->gpu_reg); +	return 0; +} + +static int enable_clk(struct msm_gpu *gpu) +{ +	struct clk *rate_clk = NULL; +	int i; + +	/* NOTE: kgsl_pwrctrl_clk() ignores grp_clks[0].. */ +	for (i = ARRAY_SIZE(gpu->grp_clks) - 1; i > 0; i--) { +		if (gpu->grp_clks[i]) { +			clk_prepare(gpu->grp_clks[i]); +			rate_clk = gpu->grp_clks[i]; +		} +	} + +	if (rate_clk && gpu->fast_rate) +		clk_set_rate(rate_clk, gpu->fast_rate); + +	for (i = ARRAY_SIZE(gpu->grp_clks) - 1; i > 0; i--) +		if (gpu->grp_clks[i]) +			clk_enable(gpu->grp_clks[i]); + +	return 0; +} + +static int disable_clk(struct msm_gpu *gpu) +{ +	struct clk *rate_clk = NULL; +	int i; + +	/* NOTE: kgsl_pwrctrl_clk() ignores grp_clks[0].. */ +	for (i = ARRAY_SIZE(gpu->grp_clks) - 1; i > 0; i--) { +		if (gpu->grp_clks[i]) { +			clk_disable(gpu->grp_clks[i]); +			rate_clk = gpu->grp_clks[i]; +		} +	} + +	if (rate_clk && gpu->slow_rate) +		clk_set_rate(rate_clk, gpu->slow_rate); + +	for (i = ARRAY_SIZE(gpu->grp_clks) - 1; i > 0; i--) +		if (gpu->grp_clks[i]) +			clk_unprepare(gpu->grp_clks[i]); + +	return 0; +} + +static int enable_axi(struct msm_gpu *gpu) +{ +	if (gpu->ebi1_clk) +		clk_prepare_enable(gpu->ebi1_clk); +	if (gpu->bus_freq) +		bs_set(gpu, gpu->bus_freq); +	return 0; +} + +static int disable_axi(struct msm_gpu *gpu) +{ +	if (gpu->ebi1_clk) +		clk_disable_unprepare(gpu->ebi1_clk); +	if (gpu->bus_freq) +		bs_set(gpu, 0); +	return 0; +} + +int msm_gpu_pm_resume(struct msm_gpu *gpu) +{ +	struct drm_device *dev = gpu->dev; +	int ret; + +	DBG("%s: active_cnt=%d", gpu->name, gpu->active_cnt); + +	WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + +	if (gpu->active_cnt++ > 0) +		return 0; + +	if (WARN_ON(gpu->active_cnt <= 0)) +		return -EINVAL; + +	ret = enable_pwrrail(gpu); +	if (ret) +		return ret; + +	ret = enable_clk(gpu); +	if (ret) +		return ret; + +	ret = enable_axi(gpu); +	if (ret) +		return ret; + +	return 0; +} + +int msm_gpu_pm_suspend(struct msm_gpu *gpu) +{ +	struct drm_device *dev = gpu->dev; +	int ret; + +	DBG("%s: active_cnt=%d", gpu->name, gpu->active_cnt); + +	WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + +	if (--gpu->active_cnt > 0) +		return 0; + +	if (WARN_ON(gpu->active_cnt < 0)) +		return -EINVAL; + +	ret = disable_axi(gpu); +	if (ret) +		return ret; + +	ret = disable_clk(gpu); +	if (ret) +		return ret; + +	ret = disable_pwrrail(gpu); +	if (ret) +		return ret; + +	return 0; +} + +/* + * Inactivity detection (for suspend): + */ + +static void inactive_worker(struct work_struct *work) +{ +	struct msm_gpu *gpu = container_of(work, struct msm_gpu, inactive_work); +	struct drm_device *dev = gpu->dev; + +	if (gpu->inactive) +		return; + +	DBG("%s: inactive!\n", gpu->name); +	mutex_lock(&dev->struct_mutex); +	if (!(msm_gpu_active(gpu) || gpu->inactive)) { +		disable_axi(gpu); +		disable_clk(gpu); +		gpu->inactive = true; +	} +	mutex_unlock(&dev->struct_mutex); +} + +static void inactive_handler(unsigned long data) +{ +	struct msm_gpu *gpu = (struct msm_gpu *)data; +	struct msm_drm_private *priv = gpu->dev->dev_private; + +	queue_work(priv->wq, &gpu->inactive_work); +} + +/* cancel inactive timer and make sure we are awake: */ +static void inactive_cancel(struct msm_gpu *gpu) +{ +	DBG("%s", gpu->name); +	del_timer(&gpu->inactive_timer); +	if (gpu->inactive) { +		enable_clk(gpu); +		enable_axi(gpu); +		gpu->inactive = false; +	} +} + +static void inactive_start(struct msm_gpu *gpu) +{ +	DBG("%s", gpu->name); +	mod_timer(&gpu->inactive_timer, +			round_jiffies_up(jiffies + DRM_MSM_INACTIVE_JIFFIES)); +} + +/* + * Hangcheck detection for locked gpu: + */ + +static void recover_worker(struct work_struct *work) +{ +	struct msm_gpu *gpu = container_of(work, struct msm_gpu, recover_work); +	struct drm_device *dev = gpu->dev; + +	dev_err(dev->dev, "%s: hangcheck recover!\n", gpu->name); + +	mutex_lock(&dev->struct_mutex); +	if (msm_gpu_active(gpu)) { +		inactive_cancel(gpu); +		gpu->funcs->recover(gpu); +	} +	mutex_unlock(&dev->struct_mutex); + +	msm_gpu_retire(gpu); +} + +static void hangcheck_timer_reset(struct msm_gpu *gpu) +{ +	DBG("%s", gpu->name); +	mod_timer(&gpu->hangcheck_timer, +			round_jiffies_up(jiffies + DRM_MSM_HANGCHECK_JIFFIES)); +} + +static void hangcheck_handler(unsigned long data) +{ +	struct msm_gpu *gpu = (struct msm_gpu *)data; +	struct drm_device *dev = gpu->dev; +	struct msm_drm_private *priv = dev->dev_private; +	uint32_t fence = gpu->funcs->last_fence(gpu); + +	if (fence != gpu->hangcheck_fence) { +		/* some progress has been made.. ya! */ +		gpu->hangcheck_fence = fence; +	} else if (fence < gpu->submitted_fence) { +		/* no progress and not done.. hung! */ +		gpu->hangcheck_fence = fence; +		dev_err(dev->dev, "%s: hangcheck detected gpu lockup!\n", +				gpu->name); +		dev_err(dev->dev, "%s:     completed fence: %u\n", +				gpu->name, fence); +		dev_err(dev->dev, "%s:     submitted fence: %u\n", +				gpu->name, gpu->submitted_fence); +		queue_work(priv->wq, &gpu->recover_work); +	} + +	/* if still more pending work, reset the hangcheck timer: */ +	if (gpu->submitted_fence > gpu->hangcheck_fence) +		hangcheck_timer_reset(gpu); + +	/* workaround for missing irq: */ +	queue_work(priv->wq, &gpu->retire_work); +} + +/* + * Performance Counters: + */ + +/* called under perf_lock */ +static int update_hw_cntrs(struct msm_gpu *gpu, uint32_t ncntrs, uint32_t *cntrs) +{ +	uint32_t current_cntrs[ARRAY_SIZE(gpu->last_cntrs)]; +	int i, n = min(ncntrs, gpu->num_perfcntrs); + +	/* read current values: */ +	for (i = 0; i < gpu->num_perfcntrs; i++) +		current_cntrs[i] = gpu_read(gpu, gpu->perfcntrs[i].sample_reg); + +	/* update cntrs: */ +	for (i = 0; i < n; i++) +		cntrs[i] = current_cntrs[i] - gpu->last_cntrs[i]; + +	/* save current values: */ +	for (i = 0; i < gpu->num_perfcntrs; i++) +		gpu->last_cntrs[i] = current_cntrs[i]; + +	return n; +} + +static void update_sw_cntrs(struct msm_gpu *gpu) +{ +	ktime_t time; +	uint32_t elapsed; +	unsigned long flags; + +	spin_lock_irqsave(&gpu->perf_lock, flags); +	if (!gpu->perfcntr_active) +		goto out; + +	time = ktime_get(); +	elapsed = ktime_to_us(ktime_sub(time, gpu->last_sample.time)); + +	gpu->totaltime += elapsed; +	if (gpu->last_sample.active) +		gpu->activetime += elapsed; + +	gpu->last_sample.active = msm_gpu_active(gpu); +	gpu->last_sample.time = time; + +out: +	spin_unlock_irqrestore(&gpu->perf_lock, flags); +} + +void msm_gpu_perfcntr_start(struct msm_gpu *gpu) +{ +	unsigned long flags; + +	spin_lock_irqsave(&gpu->perf_lock, flags); +	/* we could dynamically enable/disable perfcntr registers too.. */ +	gpu->last_sample.active = msm_gpu_active(gpu); +	gpu->last_sample.time = ktime_get(); +	gpu->activetime = gpu->totaltime = 0; +	gpu->perfcntr_active = true; +	update_hw_cntrs(gpu, 0, NULL); +	spin_unlock_irqrestore(&gpu->perf_lock, flags); +} + +void msm_gpu_perfcntr_stop(struct msm_gpu *gpu) +{ +	gpu->perfcntr_active = false; +} + +/* returns -errno or # of cntrs sampled */ +int msm_gpu_perfcntr_sample(struct msm_gpu *gpu, uint32_t *activetime, +		uint32_t *totaltime, uint32_t ncntrs, uint32_t *cntrs) +{ +	unsigned long flags; +	int ret; + +	spin_lock_irqsave(&gpu->perf_lock, flags); + +	if (!gpu->perfcntr_active) { +		ret = -EINVAL; +		goto out; +	} + +	*activetime = gpu->activetime; +	*totaltime = gpu->totaltime; + +	gpu->activetime = gpu->totaltime = 0; + +	ret = update_hw_cntrs(gpu, ncntrs, cntrs); + +out: +	spin_unlock_irqrestore(&gpu->perf_lock, flags); + +	return ret; +} + +/* + * Cmdstream submission/retirement: + */ + +static void retire_worker(struct work_struct *work) +{ +	struct msm_gpu *gpu = container_of(work, struct msm_gpu, retire_work); +	struct drm_device *dev = gpu->dev; +	uint32_t fence = gpu->funcs->last_fence(gpu); + +	msm_update_fence(gpu->dev, fence); + +	mutex_lock(&dev->struct_mutex); + +	while (!list_empty(&gpu->active_list)) { +		struct msm_gem_object *obj; + +		obj = list_first_entry(&gpu->active_list, +				struct msm_gem_object, mm_list); + +		if ((obj->read_fence <= fence) && +				(obj->write_fence <= fence)) { +			/* move to inactive: */ +			msm_gem_move_to_inactive(&obj->base); +			msm_gem_put_iova(&obj->base, gpu->id); +			drm_gem_object_unreference(&obj->base); +		} else { +			break; +		} +	} + +	mutex_unlock(&dev->struct_mutex); + +	if (!msm_gpu_active(gpu)) +		inactive_start(gpu); +} + +/* call from irq handler to schedule work to retire bo's */ +void msm_gpu_retire(struct msm_gpu *gpu) +{ +	struct msm_drm_private *priv = gpu->dev->dev_private; +	queue_work(priv->wq, &gpu->retire_work); +	update_sw_cntrs(gpu); +} + +/* add bo's to gpu's ring, and kick gpu: */ +int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, +		struct msm_file_private *ctx) +{ +	struct drm_device *dev = gpu->dev; +	struct msm_drm_private *priv = dev->dev_private; +	int i, ret; + +	submit->fence = ++priv->next_fence; + +	gpu->submitted_fence = submit->fence; + +	inactive_cancel(gpu); + +	msm_rd_dump_submit(submit); + +	gpu->submitted_fence = submit->fence; + +	update_sw_cntrs(gpu); + +	ret = gpu->funcs->submit(gpu, submit, ctx); +	priv->lastctx = ctx; + +	for (i = 0; i < submit->nr_bos; i++) { +		struct msm_gem_object *msm_obj = submit->bos[i].obj; + +		/* can't happen yet.. but when we add 2d support we'll have +		 * to deal w/ cross-ring synchronization: +		 */ +		WARN_ON(is_active(msm_obj) && (msm_obj->gpu != gpu)); + +		if (!is_active(msm_obj)) { +			uint32_t iova; + +			/* ring takes a reference to the bo and iova: */ +			drm_gem_object_reference(&msm_obj->base); +			msm_gem_get_iova_locked(&msm_obj->base, +					submit->gpu->id, &iova); +		} + +		if (submit->bos[i].flags & MSM_SUBMIT_BO_READ) +			msm_gem_move_to_active(&msm_obj->base, gpu, false, submit->fence); + +		if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE) +			msm_gem_move_to_active(&msm_obj->base, gpu, true, submit->fence); +	} +	hangcheck_timer_reset(gpu); + +	return ret; +} + +/* + * Init/Cleanup: + */ + +static irqreturn_t irq_handler(int irq, void *data) +{ +	struct msm_gpu *gpu = data; +	return gpu->funcs->irq(gpu); +} + +static const char *clk_names[] = { +		"src_clk", "core_clk", "iface_clk", "mem_clk", "mem_iface_clk", +}; + +int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, +		struct msm_gpu *gpu, const struct msm_gpu_funcs *funcs, +		const char *name, const char *ioname, const char *irqname, int ringsz) +{ +	struct iommu_domain *iommu; +	int i, ret; + +	if (WARN_ON(gpu->num_perfcntrs > ARRAY_SIZE(gpu->last_cntrs))) +		gpu->num_perfcntrs = ARRAY_SIZE(gpu->last_cntrs); + +	gpu->dev = drm; +	gpu->funcs = funcs; +	gpu->name = name; +	gpu->inactive = true; + +	INIT_LIST_HEAD(&gpu->active_list); +	INIT_WORK(&gpu->retire_work, retire_worker); +	INIT_WORK(&gpu->inactive_work, inactive_worker); +	INIT_WORK(&gpu->recover_work, recover_worker); + +	setup_timer(&gpu->inactive_timer, inactive_handler, +			(unsigned long)gpu); +	setup_timer(&gpu->hangcheck_timer, hangcheck_handler, +			(unsigned long)gpu); + +	spin_lock_init(&gpu->perf_lock); + +	BUG_ON(ARRAY_SIZE(clk_names) != ARRAY_SIZE(gpu->grp_clks)); + +	/* Map registers: */ +	gpu->mmio = msm_ioremap(pdev, ioname, name); +	if (IS_ERR(gpu->mmio)) { +		ret = PTR_ERR(gpu->mmio); +		goto fail; +	} + +	/* Get Interrupt: */ +	gpu->irq = platform_get_irq_byname(pdev, irqname); +	if (gpu->irq < 0) { +		ret = gpu->irq; +		dev_err(drm->dev, "failed to get irq: %d\n", ret); +		goto fail; +	} + +	ret = devm_request_irq(&pdev->dev, gpu->irq, irq_handler, +			IRQF_TRIGGER_HIGH, gpu->name, gpu); +	if (ret) { +		dev_err(drm->dev, "failed to request IRQ%u: %d\n", gpu->irq, ret); +		goto fail; +	} + +	/* Acquire clocks: */ +	for (i = 0; i < ARRAY_SIZE(clk_names); i++) { +		gpu->grp_clks[i] = devm_clk_get(&pdev->dev, clk_names[i]); +		DBG("grp_clks[%s]: %p", clk_names[i], gpu->grp_clks[i]); +		if (IS_ERR(gpu->grp_clks[i])) +			gpu->grp_clks[i] = NULL; +	} + +	gpu->ebi1_clk = devm_clk_get(&pdev->dev, "bus_clk"); +	DBG("ebi1_clk: %p", gpu->ebi1_clk); +	if (IS_ERR(gpu->ebi1_clk)) +		gpu->ebi1_clk = NULL; + +	/* Acquire regulators: */ +	gpu->gpu_reg = devm_regulator_get(&pdev->dev, "vdd"); +	DBG("gpu_reg: %p", gpu->gpu_reg); +	if (IS_ERR(gpu->gpu_reg)) +		gpu->gpu_reg = NULL; + +	gpu->gpu_cx = devm_regulator_get(&pdev->dev, "vddcx"); +	DBG("gpu_cx: %p", gpu->gpu_cx); +	if (IS_ERR(gpu->gpu_cx)) +		gpu->gpu_cx = NULL; + +	/* Setup IOMMU.. eventually we will (I think) do this once per context +	 * and have separate page tables per context.  For now, to keep things +	 * simple and to get something working, just use a single address space: +	 */ +	iommu = iommu_domain_alloc(&platform_bus_type); +	if (iommu) { +		dev_info(drm->dev, "%s: using IOMMU\n", name); +		gpu->mmu = msm_iommu_new(drm, iommu); +	} else { +		dev_info(drm->dev, "%s: no IOMMU, fallback to VRAM carveout!\n", name); +	} +	gpu->id = msm_register_mmu(drm, gpu->mmu); + +	/* Create ringbuffer: */ +	gpu->rb = msm_ringbuffer_new(gpu, ringsz); +	if (IS_ERR(gpu->rb)) { +		ret = PTR_ERR(gpu->rb); +		gpu->rb = NULL; +		dev_err(drm->dev, "could not create ringbuffer: %d\n", ret); +		goto fail; +	} + +	ret = msm_gem_get_iova_locked(gpu->rb->bo, gpu->id, &gpu->rb_iova); +	if (ret) { +		gpu->rb_iova = 0; +		dev_err(drm->dev, "could not map ringbuffer: %d\n", ret); +		goto fail; +	} + +	bs_init(gpu); + +	return 0; + +fail: +	return ret; +} + +void msm_gpu_cleanup(struct msm_gpu *gpu) +{ +	DBG("%s", gpu->name); + +	WARN_ON(!list_empty(&gpu->active_list)); + +	bs_fini(gpu); + +	if (gpu->rb) { +		if (gpu->rb_iova) +			msm_gem_put_iova(gpu->rb->bo, gpu->id); +		msm_ringbuffer_destroy(gpu->rb); +	} + +	if (gpu->mmu) +		gpu->mmu->funcs->destroy(gpu->mmu); +} diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h new file mode 100644 index 00000000000..9b579b79284 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __MSM_GPU_H__ +#define __MSM_GPU_H__ + +#include <linux/clk.h> +#include <linux/regulator/consumer.h> + +#include "msm_drv.h" +#include "msm_ringbuffer.h" + +struct msm_gem_submit; +struct msm_gpu_perfcntr; + +/* So far, with hardware that I've seen to date, we can have: + *  + zero, one, or two z180 2d cores + *  + a3xx or a2xx 3d core, which share a common CP (the firmware + *    for the CP seems to implement some different PM4 packet types + *    but the basics of cmdstream submission are the same) + * + * Which means that the eventual complete "class" hierarchy, once + * support for all past and present hw is in place, becomes: + *  + msm_gpu + *    + adreno_gpu + *      + a3xx_gpu + *      + a2xx_gpu + *    + z180_gpu + */ +struct msm_gpu_funcs { +	int (*get_param)(struct msm_gpu *gpu, uint32_t param, uint64_t *value); +	int (*hw_init)(struct msm_gpu *gpu); +	int (*pm_suspend)(struct msm_gpu *gpu); +	int (*pm_resume)(struct msm_gpu *gpu); +	int (*submit)(struct msm_gpu *gpu, struct msm_gem_submit *submit, +			struct msm_file_private *ctx); +	void (*flush)(struct msm_gpu *gpu); +	void (*idle)(struct msm_gpu *gpu); +	irqreturn_t (*irq)(struct msm_gpu *irq); +	uint32_t (*last_fence)(struct msm_gpu *gpu); +	void (*recover)(struct msm_gpu *gpu); +	void (*destroy)(struct msm_gpu *gpu); +#ifdef CONFIG_DEBUG_FS +	/* show GPU status in debugfs: */ +	void (*show)(struct msm_gpu *gpu, struct seq_file *m); +#endif +}; + +struct msm_gpu { +	const char *name; +	struct drm_device *dev; +	const struct msm_gpu_funcs *funcs; + +	/* performance counters (hw & sw): */ +	spinlock_t perf_lock; +	bool perfcntr_active; +	struct { +		bool active; +		ktime_t time; +	} last_sample; +	uint32_t totaltime, activetime;    /* sw counters */ +	uint32_t last_cntrs[5];            /* hw counters */ +	const struct msm_gpu_perfcntr *perfcntrs; +	uint32_t num_perfcntrs; + +	struct msm_ringbuffer *rb; +	uint32_t rb_iova; + +	/* list of GEM active objects: */ +	struct list_head active_list; + +	uint32_t submitted_fence; + +	/* is gpu powered/active? */ +	int active_cnt; +	bool inactive; + +	/* worker for handling active-list retiring: */ +	struct work_struct retire_work; + +	void __iomem *mmio; +	int irq; + +	struct msm_mmu *mmu; +	int id; + +	/* Power Control: */ +	struct regulator *gpu_reg, *gpu_cx; +	struct clk *ebi1_clk, *grp_clks[5]; +	uint32_t fast_rate, slow_rate, bus_freq; + +#ifdef CONFIG_MSM_BUS_SCALING +	struct msm_bus_scale_pdata *bus_scale_table; +	uint32_t bsc; +#endif + +	/* Hang and Inactivity Detection: +	 */ +#define DRM_MSM_INACTIVE_PERIOD   66 /* in ms (roughly four frames) */ +#define DRM_MSM_INACTIVE_JIFFIES  msecs_to_jiffies(DRM_MSM_INACTIVE_PERIOD) +	struct timer_list inactive_timer; +	struct work_struct inactive_work; +#define DRM_MSM_HANGCHECK_PERIOD 500 /* in ms */ +#define DRM_MSM_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_MSM_HANGCHECK_PERIOD) +	struct timer_list hangcheck_timer; +	uint32_t hangcheck_fence; +	struct work_struct recover_work; +}; + +static inline bool msm_gpu_active(struct msm_gpu *gpu) +{ +	return gpu->submitted_fence > gpu->funcs->last_fence(gpu); +} + +/* Perf-Counters: + * The select_reg and select_val are just there for the benefit of the child + * class that actually enables the perf counter..  but msm_gpu base class + * will handle sampling/displaying the counters. + */ + +struct msm_gpu_perfcntr { +	uint32_t select_reg; +	uint32_t sample_reg; +	uint32_t select_val; +	const char *name; +}; + +static inline void gpu_write(struct msm_gpu *gpu, u32 reg, u32 data) +{ +	msm_writel(data, gpu->mmio + (reg << 2)); +} + +static inline u32 gpu_read(struct msm_gpu *gpu, u32 reg) +{ +	return msm_readl(gpu->mmio + (reg << 2)); +} + +int msm_gpu_pm_suspend(struct msm_gpu *gpu); +int msm_gpu_pm_resume(struct msm_gpu *gpu); + +void msm_gpu_perfcntr_start(struct msm_gpu *gpu); +void msm_gpu_perfcntr_stop(struct msm_gpu *gpu); +int msm_gpu_perfcntr_sample(struct msm_gpu *gpu, uint32_t *activetime, +		uint32_t *totaltime, uint32_t ncntrs, uint32_t *cntrs); + +void msm_gpu_retire(struct msm_gpu *gpu); +int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, +		struct msm_file_private *ctx); + +int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, +		struct msm_gpu *gpu, const struct msm_gpu_funcs *funcs, +		const char *name, const char *ioname, const char *irqname, int ringsz); +void msm_gpu_cleanup(struct msm_gpu *gpu); + +struct msm_gpu *a3xx_gpu_init(struct drm_device *dev); +void __init a3xx_register(void); +void __exit a3xx_unregister(void); + +#endif /* __MSM_GPU_H__ */ diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c new file mode 100644 index 00000000000..4b2ad9181ed --- /dev/null +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include "msm_drv.h" +#include "msm_mmu.h" + +struct msm_iommu { +	struct msm_mmu base; +	struct iommu_domain *domain; +}; +#define to_msm_iommu(x) container_of(x, struct msm_iommu, base) + +static int msm_fault_handler(struct iommu_domain *iommu, struct device *dev, +		unsigned long iova, int flags, void *arg) +{ +	DBG("*** fault: iova=%08lx, flags=%d", iova, flags); +	return -ENOSYS; +} + +static int msm_iommu_attach(struct msm_mmu *mmu, const char **names, int cnt) +{ +	struct drm_device *dev = mmu->dev; +	struct msm_iommu *iommu = to_msm_iommu(mmu); +	int i, ret; + +	for (i = 0; i < cnt; i++) { +		struct device *msm_iommu_get_ctx(const char *ctx_name); +		struct device *ctx = msm_iommu_get_ctx(names[i]); +		if (IS_ERR_OR_NULL(ctx)) { +			dev_warn(dev->dev, "couldn't get %s context", names[i]); +			continue; +		} +		ret = iommu_attach_device(iommu->domain, ctx); +		if (ret) { +			dev_warn(dev->dev, "could not attach iommu to %s", names[i]); +			return ret; +		} +	} + +	return 0; +} + +static void msm_iommu_detach(struct msm_mmu *mmu, const char **names, int cnt) +{ +	struct msm_iommu *iommu = to_msm_iommu(mmu); +	int i; + +	for (i = 0; i < cnt; i++) { +		struct device *msm_iommu_get_ctx(const char *ctx_name); +		struct device *ctx = msm_iommu_get_ctx(names[i]); +		if (IS_ERR_OR_NULL(ctx)) +			continue; +		iommu_detach_device(iommu->domain, ctx); +	} +} + +static int msm_iommu_map(struct msm_mmu *mmu, uint32_t iova, +		struct sg_table *sgt, unsigned len, int prot) +{ +	struct msm_iommu *iommu = to_msm_iommu(mmu); +	struct iommu_domain *domain = iommu->domain; +	struct scatterlist *sg; +	unsigned int da = iova; +	unsigned int i, j; +	int ret; + +	if (!domain || !sgt) +		return -EINVAL; + +	for_each_sg(sgt->sgl, sg, sgt->nents, i) { +		u32 pa = sg_phys(sg) - sg->offset; +		size_t bytes = sg->length + sg->offset; + +		VERB("map[%d]: %08x %08x(%x)", i, iova, pa, bytes); + +		ret = iommu_map(domain, da, pa, bytes, prot); +		if (ret) +			goto fail; + +		da += bytes; +	} + +	return 0; + +fail: +	da = iova; + +	for_each_sg(sgt->sgl, sg, i, j) { +		size_t bytes = sg->length + sg->offset; +		iommu_unmap(domain, da, bytes); +		da += bytes; +	} +	return ret; +} + +static int msm_iommu_unmap(struct msm_mmu *mmu, uint32_t iova, +		struct sg_table *sgt, unsigned len) +{ +	struct msm_iommu *iommu = to_msm_iommu(mmu); +	struct iommu_domain *domain = iommu->domain; +	struct scatterlist *sg; +	unsigned int da = iova; +	int i; + +	for_each_sg(sgt->sgl, sg, sgt->nents, i) { +		size_t bytes = sg->length + sg->offset; +		size_t unmapped; + +		unmapped = iommu_unmap(domain, da, bytes); +		if (unmapped < bytes) +			return unmapped; + +		VERB("unmap[%d]: %08x(%x)", i, iova, bytes); + +		BUG_ON(!PAGE_ALIGNED(bytes)); + +		da += bytes; +	} + +	return 0; +} + +static void msm_iommu_destroy(struct msm_mmu *mmu) +{ +	struct msm_iommu *iommu = to_msm_iommu(mmu); +	iommu_domain_free(iommu->domain); +	kfree(iommu); +} + +static const struct msm_mmu_funcs funcs = { +		.attach = msm_iommu_attach, +		.detach = msm_iommu_detach, +		.map = msm_iommu_map, +		.unmap = msm_iommu_unmap, +		.destroy = msm_iommu_destroy, +}; + +struct msm_mmu *msm_iommu_new(struct drm_device *dev, struct iommu_domain *domain) +{ +	struct msm_iommu *iommu; + +	iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); +	if (!iommu) +		return ERR_PTR(-ENOMEM); + +	iommu->domain = domain; +	msm_mmu_init(&iommu->base, dev, &funcs); +	iommu_set_fault_handler(domain, msm_fault_handler, dev); + +	return &iommu->base; +} diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h new file mode 100644 index 00000000000..06437745bc2 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __MSM_KMS_H__ +#define __MSM_KMS_H__ + +#include <linux/clk.h> +#include <linux/regulator/consumer.h> + +#include "msm_drv.h" + +/* As there are different display controller blocks depending on the + * snapdragon version, the kms support is split out and the appropriate + * implementation is loaded at runtime.  The kms module is responsible + * for constructing the appropriate planes/crtcs/encoders/connectors. + */ +struct msm_kms_funcs { +	/* hw initialization: */ +	int (*hw_init)(struct msm_kms *kms); +	/* irq handling: */ +	void (*irq_preinstall)(struct msm_kms *kms); +	int (*irq_postinstall)(struct msm_kms *kms); +	void (*irq_uninstall)(struct msm_kms *kms); +	irqreturn_t (*irq)(struct msm_kms *kms); +	int (*enable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc); +	void (*disable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc); +	/* misc: */ +	const struct msm_format *(*get_format)(struct msm_kms *kms, uint32_t format); +	long (*round_pixclk)(struct msm_kms *kms, unsigned long rate, +			struct drm_encoder *encoder); +	/* cleanup: */ +	void (*preclose)(struct msm_kms *kms, struct drm_file *file); +	void (*destroy)(struct msm_kms *kms); +}; + +struct msm_kms { +	const struct msm_kms_funcs *funcs; + +	/* irq handling: */ +	bool in_irq; +	struct list_head irq_list;    /* list of mdp4_irq */ +	uint32_t vblank_mask;         /* irq bits set for userspace vblank */ +}; + +static inline void msm_kms_init(struct msm_kms *kms, +		const struct msm_kms_funcs *funcs) +{ +	kms->funcs = funcs; +} + +struct msm_kms *mdp4_kms_init(struct drm_device *dev); +struct msm_kms *mdp5_kms_init(struct drm_device *dev); + +#endif /* __MSM_KMS_H__ */ diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h new file mode 100644 index 00000000000..21da6d154f7 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __MSM_MMU_H__ +#define __MSM_MMU_H__ + +#include <linux/iommu.h> + +struct msm_mmu_funcs { +	int (*attach)(struct msm_mmu *mmu, const char **names, int cnt); +	void (*detach)(struct msm_mmu *mmu, const char **names, int cnt); +	int (*map)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt, +			unsigned len, int prot); +	int (*unmap)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt, +			unsigned len); +	void (*destroy)(struct msm_mmu *mmu); +}; + +struct msm_mmu { +	const struct msm_mmu_funcs *funcs; +	struct drm_device *dev; +}; + +static inline void msm_mmu_init(struct msm_mmu *mmu, struct drm_device *dev, +		const struct msm_mmu_funcs *funcs) +{ +	mmu->dev = dev; +	mmu->funcs = funcs; +} + +struct msm_mmu *msm_iommu_new(struct drm_device *dev, struct iommu_domain *domain); +struct msm_mmu *msm_gpummu_new(struct drm_device *dev, struct msm_gpu *gpu); + +#endif /* __MSM_MMU_H__ */ diff --git a/drivers/gpu/drm/msm/msm_perf.c b/drivers/gpu/drm/msm/msm_perf.c new file mode 100644 index 00000000000..830857c47c8 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_perf.c @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +/* For profiling, userspace can: + * + *   tail -f /sys/kernel/debug/dri/<minor>/gpu + * + * This will enable performance counters/profiling to track the busy time + * and any gpu specific performance counters that are supported. + */ + +#ifdef CONFIG_DEBUG_FS + +#include <linux/debugfs.h> + +#include "msm_drv.h" +#include "msm_gpu.h" + +struct msm_perf_state { +	struct drm_device *dev; + +	bool open; +	int cnt; +	struct mutex read_lock; + +	char buf[256]; +	int buftot, bufpos; + +	unsigned long next_jiffies; + +	struct dentry *ent; +	struct drm_info_node *node; +}; + +#define SAMPLE_TIME (HZ/4) + +/* wait for next sample time: */ +static int wait_sample(struct msm_perf_state *perf) +{ +	unsigned long start_jiffies = jiffies; + +	if (time_after(perf->next_jiffies, start_jiffies)) { +		unsigned long remaining_jiffies = +			perf->next_jiffies - start_jiffies; +		int ret = schedule_timeout_interruptible(remaining_jiffies); +		if (ret > 0) { +			/* interrupted */ +			return -ERESTARTSYS; +		} +	} +	perf->next_jiffies += SAMPLE_TIME; +	return 0; +} + +static int refill_buf(struct msm_perf_state *perf) +{ +	struct msm_drm_private *priv = perf->dev->dev_private; +	struct msm_gpu *gpu = priv->gpu; +	char *ptr = perf->buf; +	int rem = sizeof(perf->buf); +	int i, n; + +	if ((perf->cnt++ % 32) == 0) { +		/* Header line: */ +		n = snprintf(ptr, rem, "%%BUSY"); +		ptr += n; +		rem -= n; + +		for (i = 0; i < gpu->num_perfcntrs; i++) { +			const struct msm_gpu_perfcntr *perfcntr = &gpu->perfcntrs[i]; +			n = snprintf(ptr, rem, "\t%s", perfcntr->name); +			ptr += n; +			rem -= n; +		} +	} else { +		/* Sample line: */ +		uint32_t activetime = 0, totaltime = 0; +		uint32_t cntrs[5]; +		uint32_t val; +		int ret; + +		/* sleep until next sample time: */ +		ret = wait_sample(perf); +		if (ret) +			return ret; + +		ret = msm_gpu_perfcntr_sample(gpu, &activetime, &totaltime, +				ARRAY_SIZE(cntrs), cntrs); +		if (ret < 0) +			return ret; + +		val = totaltime ? 1000 * activetime / totaltime : 0; +		n = snprintf(ptr, rem, "%3d.%d%%", val / 10, val % 10); +		ptr += n; +		rem -= n; + +		for (i = 0; i < ret; i++) { +			/* cycle counters (I think).. convert to MHz.. */ +			val = cntrs[i] / 10000; +			n = snprintf(ptr, rem, "\t%5d.%02d", +					val / 100, val % 100); +			ptr += n; +			rem -= n; +		} +	} + +	n = snprintf(ptr, rem, "\n"); +	ptr += n; +	rem -= n; + +	perf->bufpos = 0; +	perf->buftot = ptr - perf->buf; + +	return 0; +} + +static ssize_t perf_read(struct file *file, char __user *buf, +		size_t sz, loff_t *ppos) +{ +	struct msm_perf_state *perf = file->private_data; +	int n = 0, ret; + +	mutex_lock(&perf->read_lock); + +	if (perf->bufpos >= perf->buftot) { +		ret = refill_buf(perf); +		if (ret) +			goto out; +	} + +	n = min((int)sz, perf->buftot - perf->bufpos); +	ret = copy_to_user(buf, &perf->buf[perf->bufpos], n); +	if (ret) +		goto out; + +	perf->bufpos += n; +	*ppos += n; + +out: +	mutex_unlock(&perf->read_lock); +	if (ret) +		return ret; +	return n; +} + +static int perf_open(struct inode *inode, struct file *file) +{ +	struct msm_perf_state *perf = inode->i_private; +	struct drm_device *dev = perf->dev; +	struct msm_drm_private *priv = dev->dev_private; +	struct msm_gpu *gpu = priv->gpu; +	int ret = 0; + +	mutex_lock(&dev->struct_mutex); + +	if (perf->open || !gpu) { +		ret = -EBUSY; +		goto out; +	} + +	file->private_data = perf; +	perf->open = true; +	perf->cnt = 0; +	perf->buftot = 0; +	perf->bufpos = 0; +	msm_gpu_perfcntr_start(gpu); +	perf->next_jiffies = jiffies + SAMPLE_TIME; + +out: +	mutex_unlock(&dev->struct_mutex); +	return ret; +} + +static int perf_release(struct inode *inode, struct file *file) +{ +	struct msm_perf_state *perf = inode->i_private; +	struct msm_drm_private *priv = perf->dev->dev_private; +	msm_gpu_perfcntr_stop(priv->gpu); +	perf->open = false; +	return 0; +} + + +static const struct file_operations perf_debugfs_fops = { +	.owner = THIS_MODULE, +	.open = perf_open, +	.read = perf_read, +	.llseek = no_llseek, +	.release = perf_release, +}; + +int msm_perf_debugfs_init(struct drm_minor *minor) +{ +	struct msm_drm_private *priv = minor->dev->dev_private; +	struct msm_perf_state *perf; + +	/* only create on first minor: */ +	if (priv->perf) +		return 0; + +	perf = kzalloc(sizeof(*perf), GFP_KERNEL); +	if (!perf) +		return -ENOMEM; + +	perf->dev = minor->dev; + +	mutex_init(&perf->read_lock); +	priv->perf = perf; + +	perf->node = kzalloc(sizeof(*perf->node), GFP_KERNEL); +	if (!perf->node) +		goto fail; + +	perf->ent = debugfs_create_file("perf", S_IFREG | S_IRUGO, +			minor->debugfs_root, perf, &perf_debugfs_fops); +	if (!perf->ent) { +		DRM_ERROR("Cannot create /sys/kernel/debug/dri/%s/perf\n", +				minor->debugfs_root->d_name.name); +		goto fail; +	} + +	perf->node->minor = minor; +	perf->node->dent  = perf->ent; +	perf->node->info_ent = NULL; + +	mutex_lock(&minor->debugfs_lock); +	list_add(&perf->node->list, &minor->debugfs_list); +	mutex_unlock(&minor->debugfs_lock); + +	return 0; + +fail: +	msm_perf_debugfs_cleanup(minor); +	return -1; +} + +void msm_perf_debugfs_cleanup(struct drm_minor *minor) +{ +	struct msm_drm_private *priv = minor->dev->dev_private; +	struct msm_perf_state *perf = priv->perf; + +	if (!perf) +		return; + +	priv->perf = NULL; + +	debugfs_remove(perf->ent); + +	if (perf->node) { +		mutex_lock(&minor->debugfs_lock); +		list_del(&perf->node->list); +		mutex_unlock(&minor->debugfs_lock); +		kfree(perf->node); +	} + +	mutex_destroy(&perf->read_lock); + +	kfree(perf); +} + +#endif diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c new file mode 100644 index 00000000000..9a78c48817c --- /dev/null +++ b/drivers/gpu/drm/msm/msm_rd.c @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +/* For debugging crashes, userspace can: + * + *   tail -f /sys/kernel/debug/dri/<minor>/rd > logfile.rd + * + * To log the cmdstream in a format that is understood by freedreno/cffdump + * utility.  By comparing the last successfully completed fence #, to the + * cmdstream for the next fence, you can narrow down which process and submit + * caused the gpu crash/lockup. + * + * This bypasses drm_debugfs_create_files() mainly because we need to use + * our own fops for a bit more control.  In particular, we don't want to + * do anything if userspace doesn't have the debugfs file open. + */ + +#ifdef CONFIG_DEBUG_FS + +#include <linux/kfifo.h> +#include <linux/debugfs.h> +#include <linux/circ_buf.h> +#include <linux/wait.h> + +#include "msm_drv.h" +#include "msm_gpu.h" +#include "msm_gem.h" + +enum rd_sect_type { +	RD_NONE, +	RD_TEST,       /* ascii text */ +	RD_CMD,        /* ascii text */ +	RD_GPUADDR,    /* u32 gpuaddr, u32 size */ +	RD_CONTEXT,    /* raw dump */ +	RD_CMDSTREAM,  /* raw dump */ +	RD_CMDSTREAM_ADDR, /* gpu addr of cmdstream */ +	RD_PARAM,      /* u32 param_type, u32 param_val, u32 bitlen */ +	RD_FLUSH,      /* empty, clear previous params */ +	RD_PROGRAM,    /* shader program, raw dump */ +	RD_VERT_SHADER, +	RD_FRAG_SHADER, +	RD_BUFFER_CONTENTS, +	RD_GPU_ID, +}; + +#define BUF_SZ 512  /* should be power of 2 */ + +/* space used: */ +#define circ_count(circ) \ +	(CIRC_CNT((circ)->head, (circ)->tail, BUF_SZ)) +#define circ_count_to_end(circ) \ +	(CIRC_CNT_TO_END((circ)->head, (circ)->tail, BUF_SZ)) +/* space available: */ +#define circ_space(circ) \ +	(CIRC_SPACE((circ)->head, (circ)->tail, BUF_SZ)) +#define circ_space_to_end(circ) \ +	(CIRC_SPACE_TO_END((circ)->head, (circ)->tail, BUF_SZ)) + +struct msm_rd_state { +	struct drm_device *dev; + +	bool open; + +	struct dentry *ent; +	struct drm_info_node *node; + +	/* current submit to read out: */ +	struct msm_gem_submit *submit; + +	/* fifo access is synchronized on the producer side by +	 * struct_mutex held by submit code (otherwise we could +	 * end up w/ cmds logged in different order than they +	 * were executed).  And read_lock synchronizes the reads +	 */ +	struct mutex read_lock; + +	wait_queue_head_t fifo_event; +	struct circ_buf fifo; + +	char buf[BUF_SZ]; +}; + +static void rd_write(struct msm_rd_state *rd, const void *buf, int sz) +{ +	struct circ_buf *fifo = &rd->fifo; +	const char *ptr = buf; + +	while (sz > 0) { +		char *fptr = &fifo->buf[fifo->head]; +		int n; + +		wait_event(rd->fifo_event, circ_space(&rd->fifo) > 0); + +		n = min(sz, circ_space_to_end(&rd->fifo)); +		memcpy(fptr, ptr, n); + +		fifo->head = (fifo->head + n) & (BUF_SZ - 1); +		sz  -= n; +		ptr += n; + +		wake_up_all(&rd->fifo_event); +	} +} + +static void rd_write_section(struct msm_rd_state *rd, +		enum rd_sect_type type, const void *buf, int sz) +{ +	rd_write(rd, &type, 4); +	rd_write(rd, &sz, 4); +	rd_write(rd, buf, sz); +} + +static ssize_t rd_read(struct file *file, char __user *buf, +		size_t sz, loff_t *ppos) +{ +	struct msm_rd_state *rd = file->private_data; +	struct circ_buf *fifo = &rd->fifo; +	const char *fptr = &fifo->buf[fifo->tail]; +	int n = 0, ret = 0; + +	mutex_lock(&rd->read_lock); + +	ret = wait_event_interruptible(rd->fifo_event, +			circ_count(&rd->fifo) > 0); +	if (ret) +		goto out; + +	n = min_t(int, sz, circ_count_to_end(&rd->fifo)); +	ret = copy_to_user(buf, fptr, n); +	if (ret) +		goto out; + +	fifo->tail = (fifo->tail + n) & (BUF_SZ - 1); +	*ppos += n; + +	wake_up_all(&rd->fifo_event); + +out: +	mutex_unlock(&rd->read_lock); +	if (ret) +		return ret; +	return n; +} + +static int rd_open(struct inode *inode, struct file *file) +{ +	struct msm_rd_state *rd = inode->i_private; +	struct drm_device *dev = rd->dev; +	struct msm_drm_private *priv = dev->dev_private; +	struct msm_gpu *gpu = priv->gpu; +	uint64_t val; +	uint32_t gpu_id; +	int ret = 0; + +	mutex_lock(&dev->struct_mutex); + +	if (rd->open || !gpu) { +		ret = -EBUSY; +		goto out; +	} + +	file->private_data = rd; +	rd->open = true; + +	/* the parsing tools need to know gpu-id to know which +	 * register database to load. +	 */ +	gpu->funcs->get_param(gpu, MSM_PARAM_GPU_ID, &val); +	gpu_id = val; + +	rd_write_section(rd, RD_GPU_ID, &gpu_id, sizeof(gpu_id)); + +out: +	mutex_unlock(&dev->struct_mutex); +	return ret; +} + +static int rd_release(struct inode *inode, struct file *file) +{ +	struct msm_rd_state *rd = inode->i_private; +	rd->open = false; +	return 0; +} + + +static const struct file_operations rd_debugfs_fops = { +	.owner = THIS_MODULE, +	.open = rd_open, +	.read = rd_read, +	.llseek = no_llseek, +	.release = rd_release, +}; + +int msm_rd_debugfs_init(struct drm_minor *minor) +{ +	struct msm_drm_private *priv = minor->dev->dev_private; +	struct msm_rd_state *rd; + +	/* only create on first minor: */ +	if (priv->rd) +		return 0; + +	rd = kzalloc(sizeof(*rd), GFP_KERNEL); +	if (!rd) +		return -ENOMEM; + +	rd->dev = minor->dev; +	rd->fifo.buf = rd->buf; + +	mutex_init(&rd->read_lock); +	priv->rd = rd; + +	init_waitqueue_head(&rd->fifo_event); + +	rd->node = kzalloc(sizeof(*rd->node), GFP_KERNEL); +	if (!rd->node) +		goto fail; + +	rd->ent = debugfs_create_file("rd", S_IFREG | S_IRUGO, +			minor->debugfs_root, rd, &rd_debugfs_fops); +	if (!rd->ent) { +		DRM_ERROR("Cannot create /sys/kernel/debug/dri/%s/rd\n", +				minor->debugfs_root->d_name.name); +		goto fail; +	} + +	rd->node->minor = minor; +	rd->node->dent  = rd->ent; +	rd->node->info_ent = NULL; + +	mutex_lock(&minor->debugfs_lock); +	list_add(&rd->node->list, &minor->debugfs_list); +	mutex_unlock(&minor->debugfs_lock); + +	return 0; + +fail: +	msm_rd_debugfs_cleanup(minor); +	return -1; +} + +void msm_rd_debugfs_cleanup(struct drm_minor *minor) +{ +	struct msm_drm_private *priv = minor->dev->dev_private; +	struct msm_rd_state *rd = priv->rd; + +	if (!rd) +		return; + +	priv->rd = NULL; + +	debugfs_remove(rd->ent); + +	if (rd->node) { +		mutex_lock(&minor->debugfs_lock); +		list_del(&rd->node->list); +		mutex_unlock(&minor->debugfs_lock); +		kfree(rd->node); +	} + +	mutex_destroy(&rd->read_lock); + +	kfree(rd); +} + +/* called under struct_mutex */ +void msm_rd_dump_submit(struct msm_gem_submit *submit) +{ +	struct drm_device *dev = submit->dev; +	struct msm_drm_private *priv = dev->dev_private; +	struct msm_rd_state *rd = priv->rd; +	char msg[128]; +	int i, n; + +	if (!rd->open) +		return; + +	/* writing into fifo is serialized by caller, and +	 * rd->read_lock is used to serialize the reads +	 */ +	WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + +	n = snprintf(msg, sizeof(msg), "%.*s/%d: fence=%u", +			TASK_COMM_LEN, current->comm, task_pid_nr(current), +			submit->fence); + +	rd_write_section(rd, RD_CMD, msg, ALIGN(n, 4)); + +	/* could be nice to have an option (module-param?) to snapshot +	 * all the bo's associated with the submit.  Handy to see vtx +	 * buffers, etc.  For now just the cmdstream bo's is enough. +	 */ + +	for (i = 0; i < submit->nr_cmds; i++) { +		uint32_t idx  = submit->cmd[i].idx; +		uint32_t iova = submit->cmd[i].iova; +		uint32_t szd  = submit->cmd[i].size; /* in dwords */ +		struct msm_gem_object *obj = submit->bos[idx].obj; +		const char *buf = msm_gem_vaddr_locked(&obj->base); + +		buf += iova - submit->bos[idx].iova; + +		rd_write_section(rd, RD_GPUADDR, +				(uint32_t[2]){ iova, szd * 4 }, 8); +		rd_write_section(rd, RD_BUFFER_CONTENTS, +				buf, szd * 4); + +		switch (submit->cmd[i].type) { +		case MSM_SUBMIT_CMD_IB_TARGET_BUF: +			/* ignore IB-targets, we've logged the buffer, the +			 * parser tool will follow the IB based on the logged +			 * buffer/gpuaddr, so nothing more to do. +			 */ +			break; +		case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: +		case MSM_SUBMIT_CMD_BUF: +			rd_write_section(rd, RD_CMDSTREAM_ADDR, +					(uint32_t[2]){ iova, szd }, 8); +			break; +		} +	} +} +#endif diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c new file mode 100644 index 00000000000..8171537dd7d --- /dev/null +++ b/drivers/gpu/drm/msm/msm_ringbuffer.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#include "msm_ringbuffer.h" +#include "msm_gpu.h" + +struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int size) +{ +	struct msm_ringbuffer *ring; +	int ret; + +	size = ALIGN(size, 4);   /* size should be dword aligned */ + +	ring = kzalloc(sizeof(*ring), GFP_KERNEL); +	if (!ring) { +		ret = -ENOMEM; +		goto fail; +	} + +	ring->gpu = gpu; +	ring->bo = msm_gem_new(gpu->dev, size, MSM_BO_WC); +	if (IS_ERR(ring->bo)) { +		ret = PTR_ERR(ring->bo); +		ring->bo = NULL; +		goto fail; +	} + +	ring->start = msm_gem_vaddr_locked(ring->bo); +	ring->end   = ring->start + (size / 4); +	ring->cur   = ring->start; + +	ring->size = size; + +	return ring; + +fail: +	if (ring) +		msm_ringbuffer_destroy(ring); +	return ERR_PTR(ret); +} + +void msm_ringbuffer_destroy(struct msm_ringbuffer *ring) +{ +	if (ring->bo) +		drm_gem_object_unreference(ring->bo); +	kfree(ring); +} diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.h b/drivers/gpu/drm/msm/msm_ringbuffer.h new file mode 100644 index 00000000000..6e0e1049fa4 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_ringbuffer.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __MSM_RINGBUFFER_H__ +#define __MSM_RINGBUFFER_H__ + +#include "msm_drv.h" + +struct msm_ringbuffer { +	struct msm_gpu *gpu; +	int size; +	struct drm_gem_object *bo; +	uint32_t *start, *end, *cur; +}; + +struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int size); +void msm_ringbuffer_destroy(struct msm_ringbuffer *ring); + +/* ringbuffer helpers (the parts that are same for a3xx/a2xx/z180..) */ + +static inline void +OUT_RING(struct msm_ringbuffer *ring, uint32_t data) +{ +	if (ring->cur == ring->end) +		ring->cur = ring->start; +	*(ring->cur++) = data; +} + +#endif /* __MSM_RINGBUFFER_H__ */  | 
