mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge branch 'drm-next' of git://people.freedesktop.org/~robclark/linux into drm-next
Merge the MSM driver from Rob Clark * 'drm-next' of git://people.freedesktop.org/~robclark/linux: drm/msm: add basic hangcheck/recovery mechanism drm/msm: add a3xx gpu support drm/msm: add register definitions for gpu drm/msm: basic KMS driver for snapdragon drm/msm: add register definitions
This commit is contained in:
@@ -223,3 +223,5 @@ source "drivers/gpu/drm/omapdrm/Kconfig"
|
||||
source "drivers/gpu/drm/tilcdc/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/qxl/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/msm/Kconfig"
|
||||
|
||||
@@ -54,4 +54,5 @@ obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
|
||||
obj-$(CONFIG_DRM_OMAP) += omapdrm/
|
||||
obj-$(CONFIG_DRM_TILCDC) += tilcdc/
|
||||
obj-$(CONFIG_DRM_QXL) += qxl/
|
||||
obj-$(CONFIG_DRM_MSM) += msm/
|
||||
obj-y += i2c/
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
config DRM_MSM
|
||||
tristate "MSM DRM"
|
||||
depends on DRM
|
||||
depends on ARCH_MSM
|
||||
depends on ARCH_MSM8960
|
||||
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 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.
|
||||
@@ -0,0 +1,30 @@
|
||||
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_connector.o \
|
||||
hdmi/hdmi_i2c.o \
|
||||
hdmi/hdmi_phy_8960.o \
|
||||
hdmi/hdmi_phy_8x60.o \
|
||||
mdp4/mdp4_crtc.o \
|
||||
mdp4/mdp4_dtv_encoder.o \
|
||||
mdp4/mdp4_format.o \
|
||||
mdp4/mdp4_irq.o \
|
||||
mdp4/mdp4_kms.o \
|
||||
mdp4/mdp4_plane.o \
|
||||
msm_connector.o \
|
||||
msm_drv.o \
|
||||
msm_fb.o \
|
||||
msm_gem.o \
|
||||
msm_gem_submit.o \
|
||||
msm_gpu.o \
|
||||
msm_ringbuffer.o
|
||||
|
||||
msm-$(CONFIG_DRM_MSM_FBDEV) += msm_fbdev.o
|
||||
|
||||
obj-$(CONFIG_DRM_MSM) += msm.o
|
||||
@@ -0,0 +1,69 @@
|
||||
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)
|
||||
+ MDSS - 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.
|
||||
|
||||
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.
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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;
|
||||
};
|
||||
#define to_a3xx_gpu(x) container_of(x, struct a3xx_gpu, base)
|
||||
|
||||
#endif /* __A3XX_GPU_H__ */
|
||||
@@ -0,0 +1,432 @@
|
||||
#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://0x04.net/cgit/index.cgi/rules-ng-ng
|
||||
git clone git://0x04.net/rules-ng-ng
|
||||
|
||||
The rules-ng-ng source files this header was generated from are:
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 327 bytes, from 2013-07-05 19:21:12)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/a2xx/a2xx.xml ( 30005 bytes, from 2013-07-19 21:30:48)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/adreno_common.xml ( 8983 bytes, from 2013-07-24 01:38:36)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/adreno_pm4.xml ( 9712 bytes, from 2013-05-26 15:22:37)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/a3xx/a3xx.xml ( 51415 bytes, from 2013-08-03 14:26:05)
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
enum adreno_mmu_clnt_beh {
|
||||
BEH_NEVR = 0,
|
||||
BEH_TRAN_RNG = 1,
|
||||
BEH_TRAN_FLT = 2,
|
||||
};
|
||||
|
||||
#define REG_AXXX_MH_MMU_CONFIG 0x00000040
|
||||
#define AXXX_MH_MMU_CONFIG_MMU_ENABLE 0x00000001
|
||||
#define AXXX_MH_MMU_CONFIG_SPLIT_MODE_ENABLE 0x00000002
|
||||
#define AXXX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__MASK 0x00000030
|
||||
#define AXXX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__SHIFT 4
|
||||
static inline uint32_t AXXX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
|
||||
{
|
||||
return ((val) << AXXX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__MASK;
|
||||
}
|
||||
#define AXXX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__MASK 0x000000c0
|
||||
#define AXXX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__SHIFT 6
|
||||
static inline uint32_t AXXX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
|
||||
{
|
||||
return ((val) << AXXX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__MASK;
|
||||
}
|
||||
#define AXXX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__MASK 0x00000300
|
||||
#define AXXX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__SHIFT 8
|
||||
static inline uint32_t AXXX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
|
||||
{
|
||||
return ((val) << AXXX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__MASK;
|
||||
}
|
||||
#define AXXX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__MASK 0x00000c00
|
||||
#define AXXX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__SHIFT 10
|
||||
static inline uint32_t AXXX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
|
||||
{
|
||||
return ((val) << AXXX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__MASK;
|
||||
}
|
||||
#define AXXX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__MASK 0x00003000
|
||||
#define AXXX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__SHIFT 12
|
||||
static inline uint32_t AXXX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
|
||||
{
|
||||
return ((val) << AXXX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__MASK;
|
||||
}
|
||||
#define AXXX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__MASK 0x0000c000
|
||||
#define AXXX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__SHIFT 14
|
||||
static inline uint32_t AXXX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
|
||||
{
|
||||
return ((val) << AXXX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__MASK;
|
||||
}
|
||||
#define AXXX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__MASK 0x00030000
|
||||
#define AXXX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__SHIFT 16
|
||||
static inline uint32_t AXXX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
|
||||
{
|
||||
return ((val) << AXXX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__MASK;
|
||||
}
|
||||
#define AXXX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__MASK 0x000c0000
|
||||
#define AXXX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__SHIFT 18
|
||||
static inline uint32_t AXXX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
|
||||
{
|
||||
return ((val) << AXXX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__MASK;
|
||||
}
|
||||
#define AXXX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__MASK 0x00300000
|
||||
#define AXXX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__SHIFT 20
|
||||
static inline uint32_t AXXX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
|
||||
{
|
||||
return ((val) << AXXX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__MASK;
|
||||
}
|
||||
#define AXXX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__MASK 0x00c00000
|
||||
#define AXXX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__SHIFT 22
|
||||
static inline uint32_t AXXX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
|
||||
{
|
||||
return ((val) << AXXX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__MASK;
|
||||
}
|
||||
#define AXXX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__MASK 0x03000000
|
||||
#define AXXX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__SHIFT 24
|
||||
static inline uint32_t AXXX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
|
||||
{
|
||||
return ((val) << AXXX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__MASK;
|
||||
}
|
||||
|
||||
#define REG_AXXX_MH_MMU_VA_RANGE 0x00000041
|
||||
|
||||
#define REG_AXXX_MH_MMU_PT_BASE 0x00000042
|
||||
|
||||
#define REG_AXXX_MH_MMU_PAGE_FAULT 0x00000043
|
||||
|
||||
#define REG_AXXX_MH_MMU_TRAN_ERROR 0x00000044
|
||||
|
||||
#define REG_AXXX_MH_MMU_INVALIDATE 0x00000045
|
||||
|
||||
#define REG_AXXX_MH_MMU_MPU_BASE 0x00000046
|
||||
|
||||
#define REG_AXXX_MH_MMU_MPU_END 0x00000047
|
||||
|
||||
#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 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_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_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
|
||||
|
||||
|
||||
#endif /* ADRENO_COMMON_XML */
|
||||
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
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, 0),
|
||||
.revn = 330,
|
||||
.name = "A330",
|
||||
.pm4fw = "a330_pm4.fw",
|
||||
.pfpfw = "a330_pfp.fw",
|
||||
.gmem = SZ_1M,
|
||||
},
|
||||
};
|
||||
|
||||
#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->info->gmem;
|
||||
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(RB_BLKSIZE));
|
||||
|
||||
/* 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;
|
||||
|
||||
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 rptr, wptr = get_wptr(gpu->rb);
|
||||
unsigned long t;
|
||||
|
||||
t = jiffies + ADRENO_IDLE_TIMEOUT;
|
||||
|
||||
/* then wait for CP to drain ringbuffer: */
|
||||
do {
|
||||
rptr = adreno_gpu->memptrs->rptr;
|
||||
if (rptr == wptr)
|
||||
return;
|
||||
} while(time_before(jiffies, t));
|
||||
|
||||
DRM_ERROR("timeout waiting for %s 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
|
||||
|
||||
void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords)
|
||||
{
|
||||
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
|
||||
uint32_t freedwords;
|
||||
do {
|
||||
uint32_t size = gpu->rb->size / 4;
|
||||
uint32_t wptr = get_wptr(gpu->rb);
|
||||
uint32_t rptr = adreno_gpu->memptrs->rptr;
|
||||
freedwords = (rptr + (size - 1) - wptr) % size;
|
||||
} while(freedwords < ndwords);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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->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;
|
||||
|
||||
ret = msm_iommu_attach(drm, gpu->base.iommu,
|
||||
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);
|
||||
}
|
||||
@@ -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/>.
|
||||
*/
|
||||
|
||||
#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 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;
|
||||
};
|
||||
|
||||
#define ADRENO_IDLE_TIMEOUT (20 * 1000)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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_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__ */
|
||||
@@ -0,0 +1,254 @@
|
||||
#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://0x04.net/cgit/index.cgi/rules-ng-ng
|
||||
git clone git://0x04.net/rules-ng-ng
|
||||
|
||||
The rules-ng-ng source files this header was generated from are:
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 327 bytes, from 2013-07-05 19:21:12)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/a2xx/a2xx.xml ( 30005 bytes, from 2013-07-19 21:30:48)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/adreno_common.xml ( 8983 bytes, from 2013-07-24 01:38:36)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/adreno_pm4.xml ( 9712 bytes, from 2013-05-26 15:22:37)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/a3xx/a3xx.xml ( 51415 bytes, from 2013-08-03 14:26:05)
|
||||
|
||||
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 = 1,
|
||||
DI_PT_LINELIST = 2,
|
||||
DI_PT_LINESTRIP = 3,
|
||||
DI_PT_TRILIST = 4,
|
||||
DI_PT_TRIFAN = 5,
|
||||
DI_PT_TRISTRIP = 6,
|
||||
DI_PT_RECTLIST = 8,
|
||||
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_WAT_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_BIN_BASE_OFFSET = 75,
|
||||
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,
|
||||
};
|
||||
|
||||
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 */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,114 @@
|
||||
#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://0x04.net/cgit/index.cgi/rules-ng-ng
|
||||
git clone git://0x04.net/rules-ng-ng
|
||||
|
||||
The rules-ng-ng source files this header was generated from are:
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 595 bytes, from 2013-07-05 19:21:12)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml ( 19332 bytes, from 2013-08-16 22:16:36)
|
||||
- /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 ( 19288 bytes, from 2013-08-11 18:14:15)
|
||||
|
||||
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 */
|
||||
@@ -0,0 +1,48 @@
|
||||
#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://0x04.net/cgit/index.cgi/rules-ng-ng
|
||||
git clone git://0x04.net/rules-ng-ng
|
||||
|
||||
The rules-ng-ng source files this header was generated from are:
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 595 bytes, from 2013-07-05 19:21:12)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml ( 19332 bytes, from 2013-08-16 22:16:36)
|
||||
- /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 ( 19288 bytes, from 2013-08-11 18:14:15)
|
||||
|
||||
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 */
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
static struct platform_device *hdmi_pdev;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static 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 hdmi *hdmi)
|
||||
{
|
||||
struct hdmi_phy *phy = hdmi->phy;
|
||||
|
||||
if (phy)
|
||||
phy->funcs->destroy(phy);
|
||||
|
||||
if (hdmi->i2c)
|
||||
hdmi_i2c_destroy(hdmi->i2c);
|
||||
|
||||
put_device(&hdmi->pdev->dev);
|
||||
}
|
||||
|
||||
/* initialize connector */
|
||||
int hdmi_init(struct hdmi *hdmi, struct drm_device *dev,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct platform_device *pdev = hdmi_pdev;
|
||||
struct hdmi_platform_config *config;
|
||||
int ret;
|
||||
|
||||
if (!pdev) {
|
||||
dev_err(dev->dev, "no hdmi device\n");
|
||||
ret = -ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
config = pdev->dev.platform_data;
|
||||
|
||||
get_device(&pdev->dev);
|
||||
|
||||
hdmi->dev = dev;
|
||||
hdmi->pdev = pdev;
|
||||
hdmi->connector = connector;
|
||||
|
||||
/* 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, "hdmi_msm_hdmi_addr", "HDMI");
|
||||
if (IS_ERR(hdmi->mmio)) {
|
||||
ret = PTR_ERR(hdmi->mmio);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hdmi->mvs = devm_regulator_get(&pdev->dev, "8901_hdmi_mvs");
|
||||
if (IS_ERR(hdmi->mvs))
|
||||
hdmi->mvs = devm_regulator_get(&pdev->dev, "hdmi_mvs");
|
||||
if (IS_ERR(hdmi->mvs)) {
|
||||
ret = PTR_ERR(hdmi->mvs);
|
||||
dev_err(dev->dev, "failed to get mvs regulator: %d\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hdmi->mpp0 = devm_regulator_get(&pdev->dev, "8901_mpp0");
|
||||
if (IS_ERR(hdmi->mpp0))
|
||||
hdmi->mpp0 = NULL;
|
||||
|
||||
hdmi->clk = devm_clk_get(&pdev->dev, "core_clk");
|
||||
if (IS_ERR(hdmi->clk)) {
|
||||
ret = PTR_ERR(hdmi->clk);
|
||||
dev_err(dev->dev, "failed to get 'clk': %d\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hdmi->m_pclk = devm_clk_get(&pdev->dev, "master_iface_clk");
|
||||
if (IS_ERR(hdmi->m_pclk)) {
|
||||
ret = PTR_ERR(hdmi->m_pclk);
|
||||
dev_err(dev->dev, "failed to get 'm_pclk': %d\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hdmi->s_pclk = devm_clk_get(&pdev->dev, "slave_iface_clk");
|
||||
if (IS_ERR(hdmi->s_pclk)) {
|
||||
ret = PTR_ERR(hdmi->s_pclk);
|
||||
dev_err(dev->dev, "failed to get 's_pclk': %d\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
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->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;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (hdmi)
|
||||
hdmi_destroy(hdmi);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* The hdmi device:
|
||||
*/
|
||||
|
||||
static int hdmi_dev_probe(struct platform_device *pdev)
|
||||
{
|
||||
static struct hdmi_platform_config config = {};
|
||||
#ifdef CONFIG_OF
|
||||
/* TODO */
|
||||
#else
|
||||
if (cpu_is_apq8064()) {
|
||||
config.phy_init = hdmi_phy_8960_init;
|
||||
config.ddc_clk_gpio = 70;
|
||||
config.ddc_data_gpio = 71;
|
||||
config.hpd_gpio = 72;
|
||||
config.pmic_gpio = 13 + NR_GPIO_IRQS;
|
||||
} else if (cpu_is_msm8960()) {
|
||||
config.phy_init = hdmi_phy_8960_init;
|
||||
config.ddc_clk_gpio = 100;
|
||||
config.ddc_data_gpio = 101;
|
||||
config.hpd_gpio = 102;
|
||||
config.pmic_gpio = -1;
|
||||
} else if (cpu_is_msm8x60()) {
|
||||
config.phy_init = hdmi_phy_8x60_init;
|
||||
config.ddc_clk_gpio = 170;
|
||||
config.ddc_data_gpio = 171;
|
||||
config.hpd_gpio = 172;
|
||||
config.pmic_gpio = -1;
|
||||
}
|
||||
#endif
|
||||
pdev->dev.platform_data = &config;
|
||||
hdmi_pdev = pdev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdmi_dev_remove(struct platform_device *pdev)
|
||||
{
|
||||
hdmi_pdev = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver hdmi_driver = {
|
||||
.probe = hdmi_dev_probe,
|
||||
.remove = hdmi_dev_remove,
|
||||
.driver.name = "hdmi_msm",
|
||||
};
|
||||
|
||||
void __init hdmi_register(void)
|
||||
{
|
||||
platform_driver_register(&hdmi_driver);
|
||||
}
|
||||
|
||||
void __exit hdmi_unregister(void)
|
||||
{
|
||||
platform_driver_unregister(&hdmi_driver);
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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 "msm_drv.h"
|
||||
#include "hdmi.xml.h"
|
||||
|
||||
|
||||
struct hdmi_phy;
|
||||
|
||||
struct hdmi {
|
||||
struct drm_device *dev;
|
||||
struct platform_device *pdev;
|
||||
|
||||
void __iomem *mmio;
|
||||
|
||||
struct regulator *mvs; /* HDMI_5V */
|
||||
struct regulator *mpp0; /* External 5V */
|
||||
|
||||
struct clk *clk;
|
||||
struct clk *m_pclk;
|
||||
struct clk *s_pclk;
|
||||
|
||||
struct hdmi_phy *phy;
|
||||
struct i2c_adapter *i2c;
|
||||
struct drm_connector *connector;
|
||||
|
||||
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);
|
||||
int ddc_clk_gpio, ddc_data_gpio, hpd_gpio, pmic_gpio;
|
||||
};
|
||||
|
||||
void hdmi_set_mode(struct hdmi *hdmi, bool power_on);
|
||||
void hdmi_destroy(struct hdmi *hdmi);
|
||||
int hdmi_init(struct hdmi *hdmi, struct drm_device *dev,
|
||||
struct drm_connector *connector);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
};
|
||||
|
||||
/*
|
||||
* phy can be different on different generations:
|
||||
*/
|
||||
struct hdmi_phy *hdmi_phy_8960_init(struct hdmi *hdmi);
|
||||
struct hdmi_phy *hdmi_phy_8x60_init(struct hdmi *hdmi);
|
||||
|
||||
/*
|
||||
* hdmi connector:
|
||||
*/
|
||||
|
||||
void hdmi_connector_irq(struct drm_connector *connector);
|
||||
|
||||
/*
|
||||
* 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__ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,461 @@
|
||||
/*
|
||||
* 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_connector.h"
|
||||
#include "hdmi.h"
|
||||
|
||||
struct hdmi_connector {
|
||||
struct msm_connector base;
|
||||
struct hdmi hdmi;
|
||||
unsigned long int pixclock;
|
||||
bool enabled;
|
||||
};
|
||||
#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;
|
||||
struct hdmi_platform_config *config =
|
||||
hdmi->pdev->dev.platform_data;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (config->pmic_gpio != -1) {
|
||||
ret = gpio_request(config->pmic_gpio, "PMIC_HDMI_MUX_SEL");
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n",
|
||||
"PMIC_HDMI_MUX_SEL", config->pmic_gpio, ret);
|
||||
goto error4;
|
||||
}
|
||||
gpio_set_value_cansleep(config->pmic_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->pmic_gpio != -1) {
|
||||
gpio_set_value_cansleep(config->pmic_gpio, 1);
|
||||
gpio_free(config->pmic_gpio);
|
||||
}
|
||||
DBG("gpio off");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
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;
|
||||
struct drm_device *dev = hdmi_connector->base.base.dev;
|
||||
struct hdmi_phy *phy = hdmi->phy;
|
||||
uint32_t hpd_ctrl;
|
||||
int ret;
|
||||
|
||||
ret = gpio_config(hdmi, true);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to configure GPIOs: %d\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(hdmi->clk);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to enable 'clk': %d\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(hdmi->m_pclk);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to enable 'm_pclk': %d\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(hdmi->s_pclk);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to enable 's_pclk': %d\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (hdmi->mpp0)
|
||||
ret = regulator_enable(hdmi->mpp0);
|
||||
if (!ret)
|
||||
ret = regulator_enable(hdmi->mvs);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to enable regulators: %d\n", 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;
|
||||
struct drm_device *dev = hdmi_connector->base.base.dev;
|
||||
int ret = 0;
|
||||
|
||||
/* Disable HPD interrupt */
|
||||
hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0);
|
||||
|
||||
hdmi_set_mode(hdmi, false);
|
||||
|
||||
if (hdmi->mpp0)
|
||||
ret = regulator_disable(hdmi->mpp0);
|
||||
if (!ret)
|
||||
ret = regulator_disable(hdmi->mvs);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to enable regulators: %d\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
clk_disable_unprepare(hdmi->clk);
|
||||
clk_disable_unprepare(hdmi->m_pclk);
|
||||
clk_disable_unprepare(hdmi->s_pclk);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void hdmi_connector_irq(struct drm_connector *connector)
|
||||
{
|
||||
struct msm_connector *msm_connector = to_msm_connector(connector);
|
||||
struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
|
||||
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);
|
||||
|
||||
drm_helper_hpd_irq_event(connector->dev);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
static enum drm_connector_status hdmi_connector_detect(
|
||||
struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct msm_connector *msm_connector = to_msm_connector(connector);
|
||||
struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
|
||||
struct hdmi *hdmi = &hdmi_connector->hdmi;
|
||||
uint32_t hpd_int_status;
|
||||
int retry = 20;
|
||||
|
||||
hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
|
||||
|
||||
/* sense seems to in some cases be momentarily de-asserted, don't
|
||||
* let that trick us into thinking the monitor is gone:
|
||||
*/
|
||||
while (retry-- && !(hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED)) {
|
||||
mdelay(10);
|
||||
hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
|
||||
DBG("status=%08x", hpd_int_status);
|
||||
}
|
||||
|
||||
return (hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED) ?
|
||||
connector_status_connected : connector_status_disconnected;
|
||||
}
|
||||
|
||||
static void hdmi_connector_destroy(struct drm_connector *connector)
|
||||
{
|
||||
struct msm_connector *msm_connector = to_msm_connector(connector);
|
||||
struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
|
||||
|
||||
hdp_disable(hdmi_connector);
|
||||
|
||||
drm_sysfs_connector_remove(connector);
|
||||
drm_connector_cleanup(connector);
|
||||
|
||||
hdmi_destroy(&hdmi_connector->hdmi);
|
||||
|
||||
kfree(hdmi_connector);
|
||||
}
|
||||
|
||||
static int hdmi_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct msm_connector *msm_connector = to_msm_connector(connector);
|
||||
struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_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 msm_connector *msm_connector = to_msm_connector(connector);
|
||||
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, msm_connector->encoder);
|
||||
|
||||
DBG("requested=%ld, actual=%ld", requested, actual);
|
||||
|
||||
if (actual != requested)
|
||||
return MODE_CLOCK_RANGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 = msm_connector_attached_encoder,
|
||||
};
|
||||
|
||||
static void hdmi_connector_dpms(struct msm_connector *msm_connector, int mode)
|
||||
{
|
||||
struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
|
||||
struct hdmi *hdmi = &hdmi_connector->hdmi;
|
||||
struct hdmi_phy *phy = hdmi->phy;
|
||||
bool enabled = (mode == DRM_MODE_DPMS_ON);
|
||||
|
||||
DBG("mode=%d", mode);
|
||||
|
||||
if (enabled == hdmi_connector->enabled)
|
||||
return;
|
||||
|
||||
if (enabled) {
|
||||
phy->funcs->powerup(phy, hdmi_connector->pixclock);
|
||||
hdmi_set_mode(hdmi, true);
|
||||
} else {
|
||||
hdmi_set_mode(hdmi, false);
|
||||
phy->funcs->powerdown(phy);
|
||||
}
|
||||
|
||||
hdmi_connector->enabled = enabled;
|
||||
}
|
||||
|
||||
static void hdmi_connector_mode_set(struct msm_connector *msm_connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
|
||||
struct hdmi *hdmi = &hdmi_connector->hdmi;
|
||||
int hstart, hend, vstart, vend;
|
||||
uint32_t frame_ctrl;
|
||||
|
||||
hdmi_connector->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);
|
||||
|
||||
// TODO until we have audio, this might be safest:
|
||||
if (hdmi->hdmi_mode)
|
||||
hdmi_write(hdmi, REG_HDMI_GC, HDMI_GC_MUTE);
|
||||
}
|
||||
|
||||
static const struct msm_connector_funcs msm_connector_funcs = {
|
||||
.dpms = hdmi_connector_dpms,
|
||||
.mode_set = hdmi_connector_mode_set,
|
||||
};
|
||||
|
||||
/* initialize connector */
|
||||
struct drm_connector *hdmi_connector_init(struct drm_device *dev,
|
||||
struct drm_encoder *encoder)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
connector = &hdmi_connector->base.base;
|
||||
|
||||
msm_connector_init(&hdmi_connector->base,
|
||||
&msm_connector_funcs, encoder);
|
||||
drm_connector_init(dev, connector, &hdmi_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_HDMIA);
|
||||
drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
|
||||
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
|
||||
connector->interlace_allowed = 1;
|
||||
connector->doublescan_allowed = 0;
|
||||
|
||||
drm_sysfs_connector_add(connector);
|
||||
|
||||
ret = hdmi_init(&hdmi_connector->hdmi, dev, connector);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
ret = hpd_enable(hdmi_connector);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to enable HPD: %d\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
drm_mode_connector_attach_encoder(connector, encoder);
|
||||
|
||||
return connector;
|
||||
|
||||
fail:
|
||||
if (connector)
|
||||
hdmi_connector_destroy(connector);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user