Merge branch 'msm-next' of git://people.freedesktop.org/~robclark/linux into drm-next

1) includes all the drm/msm side of things for upstream kernel working
on dragonboard 410c (still some pending work on adv7533 bridge chip)
2) initial support for msm8x94 (snapdragon 810)
3) support for msm8x74v1 (in addition to existing v2 support)
4) support for dma planes on mdp5 (additional planes that cannot scale/csc)
5) more yuv format support for mdp5 (single plane vyuy/uyvy/yuyv/yvyu,
two plane nv16/nv61, and three plane yuv420/yvu420)
6) rotation support for mdp5
7) initial hdcp support
8) fixes, etc

* 'msm-next' of git://people.freedesktop.org/~robclark/linux: (46 commits)
  drm/msm/dsi: Introduce DSI configuration module
  drm/msm/dsi: Make each PHY type compilation independent
  drm/msm/dsi: Split PHY drivers to separate files
  drm/msm/dsi: Return void from msm_dsi_phy_disable()
  drm/msm/dsi: Specify bitmask to set source PLL
  drm/msm/mdp: Clear pending interrupt status before enable interrupt
  drm/msm/mdp5: Add rotation (hflip/vflip) support to MDP5 planes (v2)
  drm/msm: add calls to prepare and unprepare panel
  drm/msm/dsi: Modify dsi manager bridge ops to work with external bridges
  drm/msm/dsi: Allow dsi to connect to an external bridge
  drm/msm/dsi: Create a helper to check if there is a connected device
  drm/msm/dsi: Refer to connected device as 'device' instead of 'panel'
  drm/msm/dsi: Make TE gpio optional
  drm/msm: mdp4 lvds: get panel node via of graph parsing
  drm/msm: dsi host: Use device graph parsing to parse connected panel
  drm/msm: dsi host: add missing of_node_put()
  drm/msm: Enable clocks during enable/disable_vblank() callbacks
  drm/msm/mdp5: Add support for msm8x74v1
  drm/msm/mdp5: Add DMA pipe planes for MDP5
  drm/msm/mdp: Add capabilities to MDP planes (v2)
  ...
This commit is contained in:
Dave Airlie 2015-08-17 14:33:11 +10:00
commit 3be66711b6
65 changed files with 4498 additions and 1346 deletions

View File

@ -30,20 +30,27 @@ Optional properties:
- panel@0: Node of panel connected to this DSI controller.
See files in Documentation/devicetree/bindings/panel/ for each supported
panel.
- qcom,dual-panel-mode: Boolean value indicating if the DSI controller is
- qcom,dual-dsi-mode: Boolean value indicating if the DSI controller is
driving a panel which needs 2 DSI links.
- qcom,master-panel: Boolean value indicating if the DSI controller is driving
- qcom,master-dsi: Boolean value indicating if the DSI controller is driving
the master link of the 2-DSI panel.
- qcom,sync-dual-panel: Boolean value indicating if the DSI controller is
- qcom,sync-dual-dsi: Boolean value indicating if the DSI controller is
driving a 2-DSI panel whose 2 links need receive command simultaneously.
- interrupt-parent: phandle to the MDP block if the interrupt signal is routed
through MDP block
- pinctrl-names: the pin control state names; should contain "default"
- pinctrl-0: the default pinctrl state (active)
- pinctrl-n: the "sleep" pinctrl state
- port: DSI controller output port. This contains one endpoint subnode, with its
remote-endpoint set to the phandle of the connected panel's endpoint.
See Documentation/devicetree/bindings/graph.txt for device graph info.
DSI PHY:
Required properties:
- compatible: Could be the following
* "qcom,dsi-phy-28nm-hpm"
* "qcom,dsi-phy-28nm-lp"
* "qcom,dsi-phy-20nm"
- reg: Physical base address and length of the registers of PLL, PHY and PHY
regulator
- reg-names: The names of register regions. The following regions are required:
@ -59,6 +66,10 @@ Required properties:
* "iface_clk"
- vddio-supply: phandle to vdd-io regulator device node
Optional properties:
- qcom,dsi-phy-regulator-ldo-mode: Boolean value indicating if the LDO mode PHY
regulator is wanted.
Example:
mdss_dsi0: qcom,mdss_dsi@fd922800 {
compatible = "qcom,mdss-dsi-ctrl";
@ -90,9 +101,13 @@ Example:
qcom,dsi-phy = <&mdss_dsi_phy0>;
qcom,dual-panel-mode;
qcom,master-panel;
qcom,sync-dual-panel;
qcom,dual-dsi-mode;
qcom,master-dsi;
qcom,sync-dual-dsi;
pinctrl-names = "default", "sleep";
pinctrl-0 = <&mdss_dsi_active>;
pinctrl-1 = <&mdss_dsi_suspend>;
panel: panel@0 {
compatible = "sharp,lq101r1sx01";
@ -101,6 +116,18 @@ Example:
power-supply = <...>;
backlight = <...>;
port {
panel_in: endpoint {
remote-endpoint = <&dsi0_out>;
};
};
};
port {
dsi0_out: endpoint {
remote-endpoint = <&panel_in>;
};
};
};
@ -117,4 +144,6 @@ Example:
clock-names = "iface_clk";
clocks = <&mmcc MDSS_AHB_CLK>;
vddio-supply = <&pma8084_l12>;
qcom,dsi-phy-regulator-ldo-mode;
};

View File

@ -2,8 +2,9 @@ Qualcomm adreno/snapdragon hdmi output
Required properties:
- compatible: one of the following
* "qcom,hdmi-tx-8994"
* "qcom,hdmi-tx-8084"
* "qcom,hdmi-tx-8074"
* "qcom,hdmi-tx-8974"
* "qcom,hdmi-tx-8660"
* "qcom,hdmi-tx-8960"
- reg: Physical base address and length of the controller's registers

View File

@ -9,6 +9,7 @@ config DRM_MSM
select DRM_PANEL
select SHMEM
select TMPFS
select QCOM_SCM
default y
help
DRM/KMS driver for MSM/snapdragon.
@ -53,3 +54,17 @@ config DRM_MSM_DSI_PLL
help
Choose this option to enable DSI PLL driver which provides DSI
source clocks under common clock framework.
config DRM_MSM_DSI_28NM_PHY
bool "Enable DSI 28nm PHY driver in MSM DRM"
depends on DRM_MSM_DSI
default y
help
Choose this option if the 28nm DSI PHY is used on the platform.
config DRM_MSM_DSI_20NM_PHY
bool "Enable DSI 20nm PHY driver in MSM DRM"
depends on DRM_MSM_DSI
default y
help
Choose this option if the 20nm DSI PHY is used on the platform.

View File

@ -1,5 +1,5 @@
ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/msm
ccflags-$(CONFIG_DRM_MSM_DSI_PLL) += -Idrivers/gpu/drm/msm/dsi
ccflags-$(CONFIG_DRM_MSM_DSI) += -Idrivers/gpu/drm/msm/dsi
msm-y := \
adreno/adreno_device.o \
@ -10,6 +10,7 @@ msm-y := \
hdmi/hdmi_audio.o \
hdmi/hdmi_bridge.o \
hdmi/hdmi_connector.o \
hdmi/hdmi_hdcp.o \
hdmi/hdmi_i2c.o \
hdmi/hdmi_phy_8960.o \
hdmi/hdmi_phy_8x60.o \
@ -53,12 +54,18 @@ msm-$(CONFIG_DRM_MSM_FBDEV) += msm_fbdev.o
msm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o
msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \
dsi/dsi_cfg.o \
dsi/dsi_host.o \
dsi/dsi_manager.o \
dsi/dsi_phy.o \
dsi/phy/dsi_phy.o \
mdp/mdp5/mdp5_cmd_encoder.o
msm-$(CONFIG_DRM_MSM_DSI_PLL) += dsi/pll/dsi_pll.o \
dsi/pll/dsi_pll_28nm.o
msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/phy/dsi_phy_28nm.o
msm-$(CONFIG_DRM_MSM_DSI_20NM_PHY) += dsi/phy/dsi_phy_20nm.o
ifeq ($(CONFIG_DRM_MSM_DSI_PLL),y)
msm-y += dsi/pll/dsi_pll.o
msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/pll/dsi_pll_28nm.o
endif
obj-$(CONFIG_DRM_MSM) += msm.o

View File

@ -8,15 +8,15 @@ 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 ( 32901 bytes, from 2014-06-02 15:21:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2014-11-13 22:44:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14895 bytes, from 2015-04-19 15:23:28)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 66709 bytes, from 2015-04-12 18:16:35)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 60633 bytes, from 2015-05-20 14:48:19)
- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 364 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14968 bytes, from 2015-05-20 20:12:27)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 67120 bytes, from 2015-08-14 23:22:03)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63785 bytes, from 2015-08-14 18:27:06)
Copyright (C) 2013-2014 by the following authors:
Copyright (C) 2013-2015 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
Permission is hereby granted, free of charge, to any person obtaining

View File

@ -8,13 +8,13 @@ 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 ( 32901 bytes, from 2014-06-02 15:21:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2014-11-13 22:44:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14895 bytes, from 2015-04-19 15:23:28)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 66709 bytes, from 2015-04-12 18:16:35)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 60633 bytes, from 2015-05-20 14:48:19)
- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 364 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14968 bytes, from 2015-05-20 20:12:27)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 67120 bytes, from 2015-08-14 23:22:03)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63785 bytes, from 2015-08-14 18:27:06)
Copyright (C) 2013-2015 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
@ -326,6 +326,13 @@ enum a3xx_tex_type {
A3XX_TEX_3D = 3,
};
enum a3xx_tex_msaa {
A3XX_TPL1_MSAA1X = 0,
A3XX_TPL1_MSAA2X = 1,
A3XX_TPL1_MSAA4X = 2,
A3XX_TPL1_MSAA8X = 3,
};
#define A3XX_INT0_RBBM_GPU_IDLE 0x00000001
#define A3XX_INT0_RBBM_AHB_ERROR 0x00000002
#define A3XX_INT0_RBBM_REG_TIMEOUT 0x00000004
@ -2652,6 +2659,7 @@ static inline uint32_t A3XX_VGT_DRAW_INITIATOR_NUM_INSTANCES(uint32_t val)
#define REG_A3XX_VGT_IMMED_DATA 0x000021fd
#define REG_A3XX_TEX_SAMP_0 0x00000000
#define A3XX_TEX_SAMP_0_CLAMPENABLE 0x00000001
#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
@ -2695,6 +2703,7 @@ static inline uint32_t A3XX_TEX_SAMP_0_COMPARE_FUNC(enum adreno_compare_func val
{
return ((val) << A3XX_TEX_SAMP_0_COMPARE_FUNC__SHIFT) & A3XX_TEX_SAMP_0_COMPARE_FUNC__MASK;
}
#define A3XX_TEX_SAMP_0_CUBEMAPSEAMLESSFILTOFF 0x01000000
#define A3XX_TEX_SAMP_0_UNNORM_COORDS 0x80000000
#define REG_A3XX_TEX_SAMP_1 0x00000001
@ -2750,6 +2759,12 @@ 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_MSAATEX__MASK 0x00300000
#define A3XX_TEX_CONST_0_MSAATEX__SHIFT 20
static inline uint32_t A3XX_TEX_CONST_0_MSAATEX(enum a3xx_tex_msaa val)
{
return ((val) << A3XX_TEX_CONST_0_MSAATEX__SHIFT) & A3XX_TEX_CONST_0_MSAATEX__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)
@ -2785,7 +2800,7 @@ static inline uint32_t A3XX_TEX_CONST_1_FETCHSIZE(enum a3xx_tex_fetchsize val)
}
#define REG_A3XX_TEX_CONST_2 0x00000002
#define A3XX_TEX_CONST_2_INDX__MASK 0x000000ff
#define A3XX_TEX_CONST_2_INDX__MASK 0x000001ff
#define A3XX_TEX_CONST_2_INDX__SHIFT 0
static inline uint32_t A3XX_TEX_CONST_2_INDX(uint32_t val)
{
@ -2805,7 +2820,7 @@ static inline uint32_t A3XX_TEX_CONST_2_SWAP(enum a3xx_color_swap val)
}
#define REG_A3XX_TEX_CONST_3 0x00000003
#define A3XX_TEX_CONST_3_LAYERSZ1__MASK 0x00007fff
#define A3XX_TEX_CONST_3_LAYERSZ1__MASK 0x0001ffff
#define A3XX_TEX_CONST_3_LAYERSZ1__SHIFT 0
static inline uint32_t A3XX_TEX_CONST_3_LAYERSZ1(uint32_t val)
{

View File

@ -8,13 +8,13 @@ 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 ( 32901 bytes, from 2014-06-02 15:21:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2014-11-13 22:44:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14895 bytes, from 2015-04-19 15:23:28)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 66709 bytes, from 2015-04-12 18:16:35)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 60633 bytes, from 2015-05-20 14:48:19)
- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 364 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14968 bytes, from 2015-05-20 20:12:27)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 67120 bytes, from 2015-08-14 23:22:03)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63785 bytes, from 2015-08-14 18:27:06)
Copyright (C) 2013-2015 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
@ -227,6 +227,7 @@ enum a4xx_depth_format {
DEPTH4_NONE = 0,
DEPTH4_16 = 1,
DEPTH4_24_8 = 2,
DEPTH4_32 = 3,
};
enum a4xx_tess_spacing {
@ -429,7 +430,7 @@ static inline uint32_t A4XX_RB_MRT_BUF_INFO_COLOR_SWAP(enum a3xx_color_swap val)
return ((val) << A4XX_RB_MRT_BUF_INFO_COLOR_SWAP__SHIFT) & A4XX_RB_MRT_BUF_INFO_COLOR_SWAP__MASK;
}
#define A4XX_RB_MRT_BUF_INFO_COLOR_SRGB 0x00002000
#define A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH__MASK 0x007fc000
#define A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH__MASK 0xffffc000
#define A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH__SHIFT 14
static inline uint32_t A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH(uint32_t val)
{
@ -439,7 +440,7 @@ static inline uint32_t A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH(uint32_t val)
static inline uint32_t REG_A4XX_RB_MRT_BASE(uint32_t i0) { return 0x000020a6 + 0x5*i0; }
static inline uint32_t REG_A4XX_RB_MRT_CONTROL3(uint32_t i0) { return 0x000020a7 + 0x5*i0; }
#define A4XX_RB_MRT_CONTROL3_STRIDE__MASK 0x0001fff8
#define A4XX_RB_MRT_CONTROL3_STRIDE__MASK 0x03fffff8
#define A4XX_RB_MRT_CONTROL3_STRIDE__SHIFT 3
static inline uint32_t A4XX_RB_MRT_CONTROL3_STRIDE(uint32_t val)
{
@ -570,6 +571,15 @@ static inline uint32_t A4XX_RB_FS_OUTPUT_SAMPLE_MASK(uint32_t val)
return ((val) << A4XX_RB_FS_OUTPUT_SAMPLE_MASK__SHIFT) & A4XX_RB_FS_OUTPUT_SAMPLE_MASK__MASK;
}
#define REG_A4XX_RB_SAMPLE_COUNT_CONTROL 0x000020fa
#define A4XX_RB_SAMPLE_COUNT_CONTROL_COPY 0x00000002
#define A4XX_RB_SAMPLE_COUNT_CONTROL_ADDR__MASK 0xfffffffc
#define A4XX_RB_SAMPLE_COUNT_CONTROL_ADDR__SHIFT 2
static inline uint32_t A4XX_RB_SAMPLE_COUNT_CONTROL_ADDR(uint32_t val)
{
return ((val >> 2) << A4XX_RB_SAMPLE_COUNT_CONTROL_ADDR__SHIFT) & A4XX_RB_SAMPLE_COUNT_CONTROL_ADDR__MASK;
}
#define REG_A4XX_RB_RENDER_COMPONENTS 0x000020fb
#define A4XX_RB_RENDER_COMPONENTS_RT0__MASK 0x0000000f
#define A4XX_RB_RENDER_COMPONENTS_RT0__SHIFT 0
@ -811,6 +821,23 @@ static inline uint32_t A4XX_RB_STENCIL_CONTROL_ZFAIL_BF(enum adreno_stencil_op v
#define REG_A4XX_RB_STENCIL_CONTROL2 0x00002107
#define A4XX_RB_STENCIL_CONTROL2_STENCIL_BUFFER 0x00000001
#define REG_A4XX_RB_STENCIL_INFO 0x00002108
#define A4XX_RB_STENCIL_INFO_SEPARATE_STENCIL 0x00000001
#define A4XX_RB_STENCIL_INFO_STENCIL_BASE__MASK 0xfffff000
#define A4XX_RB_STENCIL_INFO_STENCIL_BASE__SHIFT 12
static inline uint32_t A4XX_RB_STENCIL_INFO_STENCIL_BASE(uint32_t val)
{
return ((val >> 12) << A4XX_RB_STENCIL_INFO_STENCIL_BASE__SHIFT) & A4XX_RB_STENCIL_INFO_STENCIL_BASE__MASK;
}
#define REG_A4XX_RB_STENCIL_PITCH 0x00002109
#define A4XX_RB_STENCIL_PITCH__MASK 0xffffffff
#define A4XX_RB_STENCIL_PITCH__SHIFT 0
static inline uint32_t A4XX_RB_STENCIL_PITCH(uint32_t val)
{
return ((val >> 5) << A4XX_RB_STENCIL_PITCH__SHIFT) & A4XX_RB_STENCIL_PITCH__MASK;
}
#define REG_A4XX_RB_STENCILREFMASK 0x0000210b
#define A4XX_RB_STENCILREFMASK_STENCILREF__MASK 0x000000ff
#define A4XX_RB_STENCILREFMASK_STENCILREF__SHIFT 0
@ -1433,6 +1460,7 @@ static inline uint32_t A4XX_SP_FS_MRT_REG_MRTFORMAT(enum a4xx_color_fmt val)
{
return ((val) << A4XX_SP_FS_MRT_REG_MRTFORMAT__SHIFT) & A4XX_SP_FS_MRT_REG_MRTFORMAT__MASK;
}
#define A4XX_SP_FS_MRT_REG_COLOR_SRGB 0x00040000
#define REG_A4XX_SP_CS_CTRL_REG0 0x00002300
@ -1470,6 +1498,76 @@ static inline uint32_t A4XX_SP_HS_OBJ_OFFSET_REG_SHADEROBJOFFSET(uint32_t val)
#define REG_A4XX_SP_HS_LENGTH_REG 0x00002312
#define REG_A4XX_SP_DS_PARAM_REG 0x0000231a
#define A4XX_SP_DS_PARAM_REG_POSREGID__MASK 0x000000ff
#define A4XX_SP_DS_PARAM_REG_POSREGID__SHIFT 0
static inline uint32_t A4XX_SP_DS_PARAM_REG_POSREGID(uint32_t val)
{
return ((val) << A4XX_SP_DS_PARAM_REG_POSREGID__SHIFT) & A4XX_SP_DS_PARAM_REG_POSREGID__MASK;
}
#define A4XX_SP_DS_PARAM_REG_TOTALGSOUTVAR__MASK 0xfff00000
#define A4XX_SP_DS_PARAM_REG_TOTALGSOUTVAR__SHIFT 20
static inline uint32_t A4XX_SP_DS_PARAM_REG_TOTALGSOUTVAR(uint32_t val)
{
return ((val) << A4XX_SP_DS_PARAM_REG_TOTALGSOUTVAR__SHIFT) & A4XX_SP_DS_PARAM_REG_TOTALGSOUTVAR__MASK;
}
static inline uint32_t REG_A4XX_SP_DS_OUT(uint32_t i0) { return 0x0000231b + 0x1*i0; }
static inline uint32_t REG_A4XX_SP_DS_OUT_REG(uint32_t i0) { return 0x0000231b + 0x1*i0; }
#define A4XX_SP_DS_OUT_REG_A_REGID__MASK 0x000001ff
#define A4XX_SP_DS_OUT_REG_A_REGID__SHIFT 0
static inline uint32_t A4XX_SP_DS_OUT_REG_A_REGID(uint32_t val)
{
return ((val) << A4XX_SP_DS_OUT_REG_A_REGID__SHIFT) & A4XX_SP_DS_OUT_REG_A_REGID__MASK;
}
#define A4XX_SP_DS_OUT_REG_A_COMPMASK__MASK 0x00001e00
#define A4XX_SP_DS_OUT_REG_A_COMPMASK__SHIFT 9
static inline uint32_t A4XX_SP_DS_OUT_REG_A_COMPMASK(uint32_t val)
{
return ((val) << A4XX_SP_DS_OUT_REG_A_COMPMASK__SHIFT) & A4XX_SP_DS_OUT_REG_A_COMPMASK__MASK;
}
#define A4XX_SP_DS_OUT_REG_B_REGID__MASK 0x01ff0000
#define A4XX_SP_DS_OUT_REG_B_REGID__SHIFT 16
static inline uint32_t A4XX_SP_DS_OUT_REG_B_REGID(uint32_t val)
{
return ((val) << A4XX_SP_DS_OUT_REG_B_REGID__SHIFT) & A4XX_SP_DS_OUT_REG_B_REGID__MASK;
}
#define A4XX_SP_DS_OUT_REG_B_COMPMASK__MASK 0x1e000000
#define A4XX_SP_DS_OUT_REG_B_COMPMASK__SHIFT 25
static inline uint32_t A4XX_SP_DS_OUT_REG_B_COMPMASK(uint32_t val)
{
return ((val) << A4XX_SP_DS_OUT_REG_B_COMPMASK__SHIFT) & A4XX_SP_DS_OUT_REG_B_COMPMASK__MASK;
}
static inline uint32_t REG_A4XX_SP_DS_VPC_DST(uint32_t i0) { return 0x0000232c + 0x1*i0; }
static inline uint32_t REG_A4XX_SP_DS_VPC_DST_REG(uint32_t i0) { return 0x0000232c + 0x1*i0; }
#define A4XX_SP_DS_VPC_DST_REG_OUTLOC0__MASK 0x000000ff
#define A4XX_SP_DS_VPC_DST_REG_OUTLOC0__SHIFT 0
static inline uint32_t A4XX_SP_DS_VPC_DST_REG_OUTLOC0(uint32_t val)
{
return ((val) << A4XX_SP_DS_VPC_DST_REG_OUTLOC0__SHIFT) & A4XX_SP_DS_VPC_DST_REG_OUTLOC0__MASK;
}
#define A4XX_SP_DS_VPC_DST_REG_OUTLOC1__MASK 0x0000ff00
#define A4XX_SP_DS_VPC_DST_REG_OUTLOC1__SHIFT 8
static inline uint32_t A4XX_SP_DS_VPC_DST_REG_OUTLOC1(uint32_t val)
{
return ((val) << A4XX_SP_DS_VPC_DST_REG_OUTLOC1__SHIFT) & A4XX_SP_DS_VPC_DST_REG_OUTLOC1__MASK;
}
#define A4XX_SP_DS_VPC_DST_REG_OUTLOC2__MASK 0x00ff0000
#define A4XX_SP_DS_VPC_DST_REG_OUTLOC2__SHIFT 16
static inline uint32_t A4XX_SP_DS_VPC_DST_REG_OUTLOC2(uint32_t val)
{
return ((val) << A4XX_SP_DS_VPC_DST_REG_OUTLOC2__SHIFT) & A4XX_SP_DS_VPC_DST_REG_OUTLOC2__MASK;
}
#define A4XX_SP_DS_VPC_DST_REG_OUTLOC3__MASK 0xff000000
#define A4XX_SP_DS_VPC_DST_REG_OUTLOC3__SHIFT 24
static inline uint32_t A4XX_SP_DS_VPC_DST_REG_OUTLOC3(uint32_t val)
{
return ((val) << A4XX_SP_DS_VPC_DST_REG_OUTLOC3__SHIFT) & A4XX_SP_DS_VPC_DST_REG_OUTLOC3__MASK;
}
#define REG_A4XX_SP_DS_OBJ_OFFSET_REG 0x00002334
#define A4XX_SP_DS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK 0x01ff0000
#define A4XX_SP_DS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__SHIFT 16
@ -1492,6 +1590,82 @@ static inline uint32_t A4XX_SP_DS_OBJ_OFFSET_REG_SHADEROBJOFFSET(uint32_t val)
#define REG_A4XX_SP_DS_LENGTH_REG 0x00002339
#define REG_A4XX_SP_GS_PARAM_REG 0x00002341
#define A4XX_SP_GS_PARAM_REG_POSREGID__MASK 0x000000ff
#define A4XX_SP_GS_PARAM_REG_POSREGID__SHIFT 0
static inline uint32_t A4XX_SP_GS_PARAM_REG_POSREGID(uint32_t val)
{
return ((val) << A4XX_SP_GS_PARAM_REG_POSREGID__SHIFT) & A4XX_SP_GS_PARAM_REG_POSREGID__MASK;
}
#define A4XX_SP_GS_PARAM_REG_PRIMREGID__MASK 0x0000ff00
#define A4XX_SP_GS_PARAM_REG_PRIMREGID__SHIFT 8
static inline uint32_t A4XX_SP_GS_PARAM_REG_PRIMREGID(uint32_t val)
{
return ((val) << A4XX_SP_GS_PARAM_REG_PRIMREGID__SHIFT) & A4XX_SP_GS_PARAM_REG_PRIMREGID__MASK;
}
#define A4XX_SP_GS_PARAM_REG_TOTALGSOUTVAR__MASK 0xfff00000
#define A4XX_SP_GS_PARAM_REG_TOTALGSOUTVAR__SHIFT 20
static inline uint32_t A4XX_SP_GS_PARAM_REG_TOTALGSOUTVAR(uint32_t val)
{
return ((val) << A4XX_SP_GS_PARAM_REG_TOTALGSOUTVAR__SHIFT) & A4XX_SP_GS_PARAM_REG_TOTALGSOUTVAR__MASK;
}
static inline uint32_t REG_A4XX_SP_GS_OUT(uint32_t i0) { return 0x00002342 + 0x1*i0; }
static inline uint32_t REG_A4XX_SP_GS_OUT_REG(uint32_t i0) { return 0x00002342 + 0x1*i0; }
#define A4XX_SP_GS_OUT_REG_A_REGID__MASK 0x000001ff
#define A4XX_SP_GS_OUT_REG_A_REGID__SHIFT 0
static inline uint32_t A4XX_SP_GS_OUT_REG_A_REGID(uint32_t val)
{
return ((val) << A4XX_SP_GS_OUT_REG_A_REGID__SHIFT) & A4XX_SP_GS_OUT_REG_A_REGID__MASK;
}
#define A4XX_SP_GS_OUT_REG_A_COMPMASK__MASK 0x00001e00
#define A4XX_SP_GS_OUT_REG_A_COMPMASK__SHIFT 9
static inline uint32_t A4XX_SP_GS_OUT_REG_A_COMPMASK(uint32_t val)
{
return ((val) << A4XX_SP_GS_OUT_REG_A_COMPMASK__SHIFT) & A4XX_SP_GS_OUT_REG_A_COMPMASK__MASK;
}
#define A4XX_SP_GS_OUT_REG_B_REGID__MASK 0x01ff0000
#define A4XX_SP_GS_OUT_REG_B_REGID__SHIFT 16
static inline uint32_t A4XX_SP_GS_OUT_REG_B_REGID(uint32_t val)
{
return ((val) << A4XX_SP_GS_OUT_REG_B_REGID__SHIFT) & A4XX_SP_GS_OUT_REG_B_REGID__MASK;
}
#define A4XX_SP_GS_OUT_REG_B_COMPMASK__MASK 0x1e000000
#define A4XX_SP_GS_OUT_REG_B_COMPMASK__SHIFT 25
static inline uint32_t A4XX_SP_GS_OUT_REG_B_COMPMASK(uint32_t val)
{
return ((val) << A4XX_SP_GS_OUT_REG_B_COMPMASK__SHIFT) & A4XX_SP_GS_OUT_REG_B_COMPMASK__MASK;
}
static inline uint32_t REG_A4XX_SP_GS_VPC_DST(uint32_t i0) { return 0x00002353 + 0x1*i0; }
static inline uint32_t REG_A4XX_SP_GS_VPC_DST_REG(uint32_t i0) { return 0x00002353 + 0x1*i0; }
#define A4XX_SP_GS_VPC_DST_REG_OUTLOC0__MASK 0x000000ff
#define A4XX_SP_GS_VPC_DST_REG_OUTLOC0__SHIFT 0
static inline uint32_t A4XX_SP_GS_VPC_DST_REG_OUTLOC0(uint32_t val)
{
return ((val) << A4XX_SP_GS_VPC_DST_REG_OUTLOC0__SHIFT) & A4XX_SP_GS_VPC_DST_REG_OUTLOC0__MASK;
}
#define A4XX_SP_GS_VPC_DST_REG_OUTLOC1__MASK 0x0000ff00
#define A4XX_SP_GS_VPC_DST_REG_OUTLOC1__SHIFT 8
static inline uint32_t A4XX_SP_GS_VPC_DST_REG_OUTLOC1(uint32_t val)
{
return ((val) << A4XX_SP_GS_VPC_DST_REG_OUTLOC1__SHIFT) & A4XX_SP_GS_VPC_DST_REG_OUTLOC1__MASK;
}
#define A4XX_SP_GS_VPC_DST_REG_OUTLOC2__MASK 0x00ff0000
#define A4XX_SP_GS_VPC_DST_REG_OUTLOC2__SHIFT 16
static inline uint32_t A4XX_SP_GS_VPC_DST_REG_OUTLOC2(uint32_t val)
{
return ((val) << A4XX_SP_GS_VPC_DST_REG_OUTLOC2__SHIFT) & A4XX_SP_GS_VPC_DST_REG_OUTLOC2__MASK;
}
#define A4XX_SP_GS_VPC_DST_REG_OUTLOC3__MASK 0xff000000
#define A4XX_SP_GS_VPC_DST_REG_OUTLOC3__SHIFT 24
static inline uint32_t A4XX_SP_GS_VPC_DST_REG_OUTLOC3(uint32_t val)
{
return ((val) << A4XX_SP_GS_VPC_DST_REG_OUTLOC3__SHIFT) & A4XX_SP_GS_VPC_DST_REG_OUTLOC3__MASK;
}
#define REG_A4XX_SP_GS_OBJ_OFFSET_REG 0x0000235b
#define A4XX_SP_GS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK 0x01ff0000
#define A4XX_SP_GS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__SHIFT 16
@ -1693,6 +1867,18 @@ static inline uint32_t A4XX_VFD_CONTROL_3_REGID_VTXCNT(uint32_t val)
{
return ((val) << A4XX_VFD_CONTROL_3_REGID_VTXCNT__SHIFT) & A4XX_VFD_CONTROL_3_REGID_VTXCNT__MASK;
}
#define A4XX_VFD_CONTROL_3_REGID_TESSX__MASK 0x00ff0000
#define A4XX_VFD_CONTROL_3_REGID_TESSX__SHIFT 16
static inline uint32_t A4XX_VFD_CONTROL_3_REGID_TESSX(uint32_t val)
{
return ((val) << A4XX_VFD_CONTROL_3_REGID_TESSX__SHIFT) & A4XX_VFD_CONTROL_3_REGID_TESSX__MASK;
}
#define A4XX_VFD_CONTROL_3_REGID_TESSY__MASK 0xff000000
#define A4XX_VFD_CONTROL_3_REGID_TESSY__SHIFT 24
static inline uint32_t A4XX_VFD_CONTROL_3_REGID_TESSY(uint32_t val)
{
return ((val) << A4XX_VFD_CONTROL_3_REGID_TESSY__SHIFT) & A4XX_VFD_CONTROL_3_REGID_TESSY__MASK;
}
#define REG_A4XX_VFD_CONTROL_4 0x00002204
@ -2489,6 +2675,8 @@ static inline uint32_t A4XX_UNKNOWN_20F7(float val)
#define REG_A4XX_UNKNOWN_22D7 0x000022d7
#define REG_A4XX_UNKNOWN_2352 0x00002352
#define REG_A4XX_TEX_SAMP_0 0x00000000
#define A4XX_TEX_SAMP_0_MIPFILTER_LINEAR_NEAR 0x00000001
#define A4XX_TEX_SAMP_0_XY_MAG__MASK 0x00000006

View File

@ -8,15 +8,15 @@ 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 ( 32901 bytes, from 2014-06-02 15:21:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2014-11-13 22:44:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14895 bytes, from 2015-04-19 15:23:28)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 66709 bytes, from 2015-04-12 18:16:35)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 60633 bytes, from 2015-05-20 14:48:19)
- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 364 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14968 bytes, from 2015-05-20 20:12:27)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 67120 bytes, from 2015-08-14 23:22:03)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63785 bytes, from 2015-08-14 18:27:06)
Copyright (C) 2013-2014 by the following authors:
Copyright (C) 2013-2015 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
Permission is hereby granted, free of charge, to any person obtaining

View File

@ -8,13 +8,13 @@ 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 ( 32901 bytes, from 2014-06-02 15:21:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2014-11-13 22:44:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14895 bytes, from 2015-04-19 15:23:28)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 66709 bytes, from 2015-04-12 18:16:35)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 60633 bytes, from 2015-05-20 14:48:19)
- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 364 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14968 bytes, from 2015-05-20 20:12:27)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 67120 bytes, from 2015-08-14 23:22:03)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63785 bytes, from 2015-08-14 18:27:06)
Copyright (C) 2013-2015 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
@ -67,7 +67,7 @@ enum vgt_event_type {
enum pc_di_primtype {
DI_PT_NONE = 0,
DI_PT_POINTLIST_A2XX = 1,
DI_PT_POINTLIST_PSIZE = 1,
DI_PT_LINELIST = 2,
DI_PT_LINESTRIP = 3,
DI_PT_TRILIST = 4,
@ -75,7 +75,7 @@ enum pc_di_primtype {
DI_PT_TRISTRIP = 6,
DI_PT_LINELOOP = 7,
DI_PT_RECTLIST = 8,
DI_PT_POINTLIST_A3XX = 9,
DI_PT_POINTLIST = 9,
DI_PT_LINE_ADJ = 10,
DI_PT_LINESTRIP_ADJ = 11,
DI_PT_TRI_ADJ = 12,

View File

@ -15,10 +15,10 @@
struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
{
if (!msm_dsi || !msm_dsi->panel)
if (!msm_dsi || !msm_dsi_device_connected(msm_dsi))
return NULL;
return (msm_dsi->panel_flags & MIPI_DSI_MODE_VIDEO) ?
return (msm_dsi->device_flags & MIPI_DSI_MODE_VIDEO) ?
msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID] :
msm_dsi->encoders[MSM_DSI_CMD_ENCODER_ID];
}
@ -74,19 +74,15 @@ static void dsi_destroy(struct msm_dsi *msm_dsi)
static struct msm_dsi *dsi_init(struct platform_device *pdev)
{
struct msm_dsi *msm_dsi = NULL;
struct msm_dsi *msm_dsi;
int ret;
if (!pdev) {
ret = -ENXIO;
goto fail;
}
if (!pdev)
return ERR_PTR(-ENXIO);
msm_dsi = devm_kzalloc(&pdev->dev, sizeof(*msm_dsi), GFP_KERNEL);
if (!msm_dsi) {
ret = -ENOMEM;
goto fail;
}
if (!msm_dsi)
return ERR_PTR(-ENOMEM);
DBG("dsi probed=%p", msm_dsi);
msm_dsi->pdev = pdev;
@ -95,24 +91,22 @@ static struct msm_dsi *dsi_init(struct platform_device *pdev)
/* Init dsi host */
ret = msm_dsi_host_init(msm_dsi);
if (ret)
goto fail;
goto destroy_dsi;
/* GET dsi PHY */
ret = dsi_get_phy(msm_dsi);
if (ret)
goto fail;
goto destroy_dsi;
/* Register to dsi manager */
ret = msm_dsi_manager_register(msm_dsi);
if (ret)
goto fail;
goto destroy_dsi;
return msm_dsi;
fail:
if (msm_dsi)
dsi_destroy(msm_dsi);
destroy_dsi:
dsi_destroy(msm_dsi);
return ERR_PTR(ret);
}
@ -196,6 +190,7 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
struct drm_encoder *encoders[MSM_DSI_ENCODER_NUM])
{
struct msm_drm_private *priv = dev->dev_private;
struct drm_bridge *ext_bridge;
int ret, i;
if (WARN_ON(!encoders[MSM_DSI_VIDEO_ENCODER_ID] ||
@ -223,10 +218,25 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
msm_dsi->encoders[i] = encoders[i];
}
msm_dsi->connector = msm_dsi_manager_connector_init(msm_dsi->id);
/*
* check if the dsi encoder output is connected to a panel or an
* external bridge. We create a connector only if we're connected to a
* drm_panel device. When we're connected to an external bridge, we
* assume that the drm_bridge driver will create the connector itself.
*/
ext_bridge = msm_dsi_host_get_bridge(msm_dsi->host);
if (ext_bridge)
msm_dsi->connector =
msm_dsi_manager_ext_bridge_init(msm_dsi->id);
else
msm_dsi->connector =
msm_dsi_manager_connector_init(msm_dsi->id);
if (IS_ERR(msm_dsi->connector)) {
ret = PTR_ERR(msm_dsi->connector);
dev_err(dev->dev, "failed to create dsi connector: %d\n", ret);
dev_err(dev->dev,
"failed to create dsi connector: %d\n", ret);
msm_dsi->connector = NULL;
goto fail;
}
@ -242,10 +252,12 @@ fail:
msm_dsi_manager_bridge_destroy(msm_dsi->bridge);
msm_dsi->bridge = NULL;
}
if (msm_dsi->connector) {
/* don't destroy connector if we didn't make it */
if (msm_dsi->connector && !msm_dsi->external_bridge)
msm_dsi->connector->funcs->destroy(msm_dsi->connector);
msm_dsi->connector = NULL;
}
msm_dsi->connector = NULL;
}
return ret;

View File

@ -27,21 +27,10 @@
#define DSI_1 1
#define DSI_MAX 2
#define DSI_CLOCK_MASTER DSI_0
#define DSI_CLOCK_SLAVE DSI_1
#define DSI_LEFT DSI_0
#define DSI_RIGHT DSI_1
/* According to the current drm framework sequence, take the encoder of
* DSI_1 as master encoder
*/
#define DSI_ENCODER_MASTER DSI_1
#define DSI_ENCODER_SLAVE DSI_0
enum msm_dsi_phy_type {
MSM_DSI_PHY_28NM_HPM,
MSM_DSI_PHY_28NM_LP,
MSM_DSI_PHY_20NM,
MSM_DSI_PHY_MAX
};
@ -65,13 +54,21 @@ struct msm_dsi {
struct drm_device *dev;
struct platform_device *pdev;
/* connector managed by us when we're connected to a drm_panel */
struct drm_connector *connector;
/* internal dsi bridge attached to MDP interface */
struct drm_bridge *bridge;
struct mipi_dsi_host *host;
struct msm_dsi_phy *phy;
/*
* panel/external_bridge connected to dsi bridge output, only one of the
* two can be valid at a time
*/
struct drm_panel *panel;
unsigned long panel_flags;
struct drm_bridge *external_bridge;
unsigned long device_flags;
struct device *phy_dev;
bool phy_enabled;
@ -86,6 +83,7 @@ struct msm_dsi {
struct drm_bridge *msm_dsi_manager_bridge_init(u8 id);
void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge);
struct drm_connector *msm_dsi_manager_connector_init(u8 id);
struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id);
int msm_dsi_manager_phy_enable(int id,
const unsigned long bit_rate, const unsigned long esc_rate,
u32 *clk_pre, u32 *clk_post);
@ -96,6 +94,11 @@ int msm_dsi_manager_register(struct msm_dsi *msm_dsi);
void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi);
/* msm dsi */
static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi)
{
return msm_dsi->panel || msm_dsi->external_bridge;
}
struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
/* dsi pll */
@ -106,6 +109,8 @@ struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev,
void msm_dsi_pll_destroy(struct msm_dsi_pll *pll);
int msm_dsi_pll_get_clk_provider(struct msm_dsi_pll *pll,
struct clk **byte_clk_provider, struct clk **pixel_clk_provider);
void msm_dsi_pll_save_state(struct msm_dsi_pll *pll);
int msm_dsi_pll_restore_state(struct msm_dsi_pll *pll);
#else
static inline struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev,
enum msm_dsi_phy_type type, int id) {
@ -119,6 +124,13 @@ static inline int msm_dsi_pll_get_clk_provider(struct msm_dsi_pll *pll,
{
return -ENODEV;
}
static inline void msm_dsi_pll_save_state(struct msm_dsi_pll *pll)
{
}
static inline int msm_dsi_pll_restore_state(struct msm_dsi_pll *pll)
{
return 0;
}
#endif
/* dsi host */
@ -140,6 +152,7 @@ int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
struct drm_display_mode *mode);
struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host,
unsigned long *panel_flags);
struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host);
int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer);
void msm_dsi_host_unregister(struct mipi_dsi_host *host);
int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host,
@ -153,9 +166,9 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi);
struct msm_dsi_phy;
void msm_dsi_phy_driver_register(void);
void msm_dsi_phy_driver_unregister(void);
int msm_dsi_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel,
int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
const unsigned long bit_rate, const unsigned long esc_rate);
int msm_dsi_phy_disable(struct msm_dsi_phy *phy);
void msm_dsi_phy_disable(struct msm_dsi_phy *phy);
void msm_dsi_phy_get_clk_pre_post(struct msm_dsi_phy *phy,
u32 *clk_pre, u32 *clk_post);
struct msm_dsi_pll *msm_dsi_phy_get_pll(struct msm_dsi_phy *phy);

View File

@ -8,17 +8,17 @@ 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 ( 676 bytes, from 2014-12-05 15:34:49)
- /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 ( 20915 bytes, from 2015-03-24 22:05:22)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2352 bytes, from 2015-04-12 15:02:42)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 35083 bytes, from 2015-04-12 15:04:03)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 22094 bytes, from 2015-05-12 12:45:23)
- /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 ( 1686 bytes, from 2014-10-31 16:48:57)
- /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 ( 29012 bytes, from 2015-05-12 12:45:23)
- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-12 12:45:23)
- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2576 bytes, from 2015-07-09 22:10:24)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 36021 bytes, from 2015-07-09 22:10:24)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 26057 bytes, from 2015-08-14 21:47:57)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29154 bytes, from 2015-08-10 21:25:43)
- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-20 20:03:14)
Copyright (C) 2013-2015 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
@ -382,6 +382,11 @@ static inline uint32_t DSI_TRIG_CTRL_STREAM(uint32_t val)
#define REG_DSI_TRIG_DMA 0x0000008c
#define REG_DSI_DLN0_PHY_ERR 0x000000b0
#define DSI_DLN0_PHY_ERR_DLN0_ERR_ESC 0x00000001
#define DSI_DLN0_PHY_ERR_DLN0_ERR_SYNC_ESC 0x00000010
#define DSI_DLN0_PHY_ERR_DLN0_ERR_CONTROL 0x00000100
#define DSI_DLN0_PHY_ERR_DLN0_ERR_CONTENTION_LP0 0x00001000
#define DSI_DLN0_PHY_ERR_DLN0_ERR_CONTENTION_LP1 0x00010000
#define REG_DSI_TIMEOUT_STATUS 0x000000bc
@ -435,6 +440,9 @@ static inline uint32_t DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL(enum dsi_lane_swap val)
#define REG_DSI_PHY_RESET 0x00000128
#define DSI_PHY_RESET_RESET 0x00000001
#define REG_DSI_T_CLK_PRE_EXTEND 0x0000017c
#define DSI_T_CLK_PRE_EXTEND_INC_BY_2_BYTECLK 0x00000001
#define REG_DSI_RDBK_DATA_CTRL 0x000001d0
#define DSI_RDBK_DATA_CTRL_COUNT__MASK 0x00ff0000
#define DSI_RDBK_DATA_CTRL_COUNT__SHIFT 16
@ -830,6 +838,7 @@ static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD(uint32_t val)
#define REG_DSI_28nm_PHY_BIST_CTRL_5 0x000001c8
#define REG_DSI_28nm_PHY_GLBL_TEST_CTRL 0x000001d4
#define DSI_28nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL 0x00000001
#define REG_DSI_28nm_PHY_LDO_CNTRL 0x000001dc
@ -994,5 +1003,185 @@ static inline uint32_t DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8(uint32_t val)
#define REG_DSI_28nm_PHY_PLL_CTRL_54 0x000000d4
static inline uint32_t REG_DSI_20nm_PHY_LN(uint32_t i0) { return 0x00000000 + 0x40*i0; }
static inline uint32_t REG_DSI_20nm_PHY_LN_CFG_0(uint32_t i0) { return 0x00000000 + 0x40*i0; }
static inline uint32_t REG_DSI_20nm_PHY_LN_CFG_1(uint32_t i0) { return 0x00000004 + 0x40*i0; }
static inline uint32_t REG_DSI_20nm_PHY_LN_CFG_2(uint32_t i0) { return 0x00000008 + 0x40*i0; }
static inline uint32_t REG_DSI_20nm_PHY_LN_CFG_3(uint32_t i0) { return 0x0000000c + 0x40*i0; }
static inline uint32_t REG_DSI_20nm_PHY_LN_CFG_4(uint32_t i0) { return 0x00000010 + 0x40*i0; }
static inline uint32_t REG_DSI_20nm_PHY_LN_TEST_DATAPATH(uint32_t i0) { return 0x00000014 + 0x40*i0; }
static inline uint32_t REG_DSI_20nm_PHY_LN_DEBUG_SEL(uint32_t i0) { return 0x00000018 + 0x40*i0; }
static inline uint32_t REG_DSI_20nm_PHY_LN_TEST_STR_0(uint32_t i0) { return 0x0000001c + 0x40*i0; }
static inline uint32_t REG_DSI_20nm_PHY_LN_TEST_STR_1(uint32_t i0) { return 0x00000020 + 0x40*i0; }
#define REG_DSI_20nm_PHY_LNCK_CFG_0 0x00000100
#define REG_DSI_20nm_PHY_LNCK_CFG_1 0x00000104
#define REG_DSI_20nm_PHY_LNCK_CFG_2 0x00000108
#define REG_DSI_20nm_PHY_LNCK_CFG_3 0x0000010c
#define REG_DSI_20nm_PHY_LNCK_CFG_4 0x00000110
#define REG_DSI_20nm_PHY_LNCK_TEST_DATAPATH 0x00000114
#define REG_DSI_20nm_PHY_LNCK_DEBUG_SEL 0x00000118
#define REG_DSI_20nm_PHY_LNCK_TEST_STR0 0x0000011c
#define REG_DSI_20nm_PHY_LNCK_TEST_STR1 0x00000120
#define REG_DSI_20nm_PHY_TIMING_CTRL_0 0x00000140
#define DSI_20nm_PHY_TIMING_CTRL_0_CLK_ZERO__MASK 0x000000ff
#define DSI_20nm_PHY_TIMING_CTRL_0_CLK_ZERO__SHIFT 0
static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_0_CLK_ZERO(uint32_t val)
{
return ((val) << DSI_20nm_PHY_TIMING_CTRL_0_CLK_ZERO__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_0_CLK_ZERO__MASK;
}
#define REG_DSI_20nm_PHY_TIMING_CTRL_1 0x00000144
#define DSI_20nm_PHY_TIMING_CTRL_1_CLK_TRAIL__MASK 0x000000ff
#define DSI_20nm_PHY_TIMING_CTRL_1_CLK_TRAIL__SHIFT 0
static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_1_CLK_TRAIL(uint32_t val)
{
return ((val) << DSI_20nm_PHY_TIMING_CTRL_1_CLK_TRAIL__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_1_CLK_TRAIL__MASK;
}
#define REG_DSI_20nm_PHY_TIMING_CTRL_2 0x00000148
#define DSI_20nm_PHY_TIMING_CTRL_2_CLK_PREPARE__MASK 0x000000ff
#define DSI_20nm_PHY_TIMING_CTRL_2_CLK_PREPARE__SHIFT 0
static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_2_CLK_PREPARE(uint32_t val)
{
return ((val) << DSI_20nm_PHY_TIMING_CTRL_2_CLK_PREPARE__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_2_CLK_PREPARE__MASK;
}
#define REG_DSI_20nm_PHY_TIMING_CTRL_3 0x0000014c
#define DSI_20nm_PHY_TIMING_CTRL_3_CLK_ZERO_8 0x00000001
#define REG_DSI_20nm_PHY_TIMING_CTRL_4 0x00000150
#define DSI_20nm_PHY_TIMING_CTRL_4_HS_EXIT__MASK 0x000000ff
#define DSI_20nm_PHY_TIMING_CTRL_4_HS_EXIT__SHIFT 0
static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_4_HS_EXIT(uint32_t val)
{
return ((val) << DSI_20nm_PHY_TIMING_CTRL_4_HS_EXIT__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_4_HS_EXIT__MASK;
}
#define REG_DSI_20nm_PHY_TIMING_CTRL_5 0x00000154
#define DSI_20nm_PHY_TIMING_CTRL_5_HS_ZERO__MASK 0x000000ff
#define DSI_20nm_PHY_TIMING_CTRL_5_HS_ZERO__SHIFT 0
static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_5_HS_ZERO(uint32_t val)
{
return ((val) << DSI_20nm_PHY_TIMING_CTRL_5_HS_ZERO__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_5_HS_ZERO__MASK;
}
#define REG_DSI_20nm_PHY_TIMING_CTRL_6 0x00000158
#define DSI_20nm_PHY_TIMING_CTRL_6_HS_PREPARE__MASK 0x000000ff
#define DSI_20nm_PHY_TIMING_CTRL_6_HS_PREPARE__SHIFT 0
static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_6_HS_PREPARE(uint32_t val)
{
return ((val) << DSI_20nm_PHY_TIMING_CTRL_6_HS_PREPARE__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_6_HS_PREPARE__MASK;
}
#define REG_DSI_20nm_PHY_TIMING_CTRL_7 0x0000015c
#define DSI_20nm_PHY_TIMING_CTRL_7_HS_TRAIL__MASK 0x000000ff
#define DSI_20nm_PHY_TIMING_CTRL_7_HS_TRAIL__SHIFT 0
static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_7_HS_TRAIL(uint32_t val)
{
return ((val) << DSI_20nm_PHY_TIMING_CTRL_7_HS_TRAIL__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_7_HS_TRAIL__MASK;
}
#define REG_DSI_20nm_PHY_TIMING_CTRL_8 0x00000160
#define DSI_20nm_PHY_TIMING_CTRL_8_HS_RQST__MASK 0x000000ff
#define DSI_20nm_PHY_TIMING_CTRL_8_HS_RQST__SHIFT 0
static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_8_HS_RQST(uint32_t val)
{
return ((val) << DSI_20nm_PHY_TIMING_CTRL_8_HS_RQST__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_8_HS_RQST__MASK;
}
#define REG_DSI_20nm_PHY_TIMING_CTRL_9 0x00000164
#define DSI_20nm_PHY_TIMING_CTRL_9_TA_GO__MASK 0x00000007
#define DSI_20nm_PHY_TIMING_CTRL_9_TA_GO__SHIFT 0
static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_9_TA_GO(uint32_t val)
{
return ((val) << DSI_20nm_PHY_TIMING_CTRL_9_TA_GO__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_9_TA_GO__MASK;
}
#define DSI_20nm_PHY_TIMING_CTRL_9_TA_SURE__MASK 0x00000070
#define DSI_20nm_PHY_TIMING_CTRL_9_TA_SURE__SHIFT 4
static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_9_TA_SURE(uint32_t val)
{
return ((val) << DSI_20nm_PHY_TIMING_CTRL_9_TA_SURE__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_9_TA_SURE__MASK;
}
#define REG_DSI_20nm_PHY_TIMING_CTRL_10 0x00000168
#define DSI_20nm_PHY_TIMING_CTRL_10_TA_GET__MASK 0x00000007
#define DSI_20nm_PHY_TIMING_CTRL_10_TA_GET__SHIFT 0
static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_10_TA_GET(uint32_t val)
{
return ((val) << DSI_20nm_PHY_TIMING_CTRL_10_TA_GET__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_10_TA_GET__MASK;
}
#define REG_DSI_20nm_PHY_TIMING_CTRL_11 0x0000016c
#define DSI_20nm_PHY_TIMING_CTRL_11_TRIG3_CMD__MASK 0x000000ff
#define DSI_20nm_PHY_TIMING_CTRL_11_TRIG3_CMD__SHIFT 0
static inline uint32_t DSI_20nm_PHY_TIMING_CTRL_11_TRIG3_CMD(uint32_t val)
{
return ((val) << DSI_20nm_PHY_TIMING_CTRL_11_TRIG3_CMD__SHIFT) & DSI_20nm_PHY_TIMING_CTRL_11_TRIG3_CMD__MASK;
}
#define REG_DSI_20nm_PHY_CTRL_0 0x00000170
#define REG_DSI_20nm_PHY_CTRL_1 0x00000174
#define REG_DSI_20nm_PHY_CTRL_2 0x00000178
#define REG_DSI_20nm_PHY_CTRL_3 0x0000017c
#define REG_DSI_20nm_PHY_CTRL_4 0x00000180
#define REG_DSI_20nm_PHY_STRENGTH_0 0x00000184
#define REG_DSI_20nm_PHY_STRENGTH_1 0x00000188
#define REG_DSI_20nm_PHY_BIST_CTRL_0 0x000001b4
#define REG_DSI_20nm_PHY_BIST_CTRL_1 0x000001b8
#define REG_DSI_20nm_PHY_BIST_CTRL_2 0x000001bc
#define REG_DSI_20nm_PHY_BIST_CTRL_3 0x000001c0
#define REG_DSI_20nm_PHY_BIST_CTRL_4 0x000001c4
#define REG_DSI_20nm_PHY_BIST_CTRL_5 0x000001c8
#define REG_DSI_20nm_PHY_GLBL_TEST_CTRL 0x000001d4
#define DSI_20nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL 0x00000001
#define REG_DSI_20nm_PHY_LDO_CNTRL 0x000001dc
#define REG_DSI_20nm_PHY_REGULATOR_CTRL_0 0x00000000
#define REG_DSI_20nm_PHY_REGULATOR_CTRL_1 0x00000004
#define REG_DSI_20nm_PHY_REGULATOR_CTRL_2 0x00000008
#define REG_DSI_20nm_PHY_REGULATOR_CTRL_3 0x0000000c
#define REG_DSI_20nm_PHY_REGULATOR_CTRL_4 0x00000010
#define REG_DSI_20nm_PHY_REGULATOR_CTRL_5 0x00000014
#define REG_DSI_20nm_PHY_REGULATOR_CAL_PWR_CFG 0x00000018
#endif /* DSI_XML */

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "dsi_cfg.h"
/* DSI v2 has not been supported by now */
static const struct msm_dsi_config dsi_v2_cfg = {
.io_offset = 0,
};
static const struct msm_dsi_config msm8974_apq8084_dsi_cfg = {
.io_offset = DSI_6G_REG_SHIFT,
.reg_cfg = {
.num = 4,
.regs = {
{"gdsc", -1, -1, -1, -1},
{"vdd", 3000000, 3000000, 150000, 100},
{"vdda", 1200000, 1200000, 100000, 100},
{"vddio", 1800000, 1800000, 100000, 100},
},
},
};
static const struct msm_dsi_config msm8916_dsi_cfg = {
.io_offset = DSI_6G_REG_SHIFT,
.reg_cfg = {
.num = 4,
.regs = {
{"gdsc", -1, -1, -1, -1},
{"vdd", 2850000, 2850000, 100000, 100},
{"vdda", 1200000, 1200000, 100000, 100},
{"vddio", 1800000, 1800000, 100000, 100},
},
},
};
static const struct msm_dsi_config msm8994_dsi_cfg = {
.io_offset = DSI_6G_REG_SHIFT,
.reg_cfg = {
.num = 7,
.regs = {
{"gdsc", -1, -1, -1, -1},
{"vdda", 1250000, 1250000, 100000, 100},
{"vddio", 1800000, 1800000, 100000, 100},
{"vcca", 1000000, 1000000, 10000, 100},
{"vdd", 1800000, 1800000, 100000, 100},
{"lab_reg", -1, -1, -1, -1},
{"ibb_reg", -1, -1, -1, -1},
},
}
};
static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = {
{MSM_DSI_VER_MAJOR_V2, U32_MAX, &dsi_v2_cfg},
{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_0,
&msm8974_apq8084_dsi_cfg},
{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_1,
&msm8974_apq8084_dsi_cfg},
{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_1_1,
&msm8974_apq8084_dsi_cfg},
{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_2,
&msm8974_apq8084_dsi_cfg},
{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_3, &msm8994_dsi_cfg},
{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_3_1, &msm8916_dsi_cfg},
};
const struct msm_dsi_cfg_handler *msm_dsi_cfg_get(u32 major, u32 minor)
{
const struct msm_dsi_cfg_handler *cfg_hnd = NULL;
int i;
for (i = ARRAY_SIZE(dsi_cfg_handlers) - 1; i >= 0; i--) {
if ((dsi_cfg_handlers[i].major == major) &&
(dsi_cfg_handlers[i].minor == minor)) {
cfg_hnd = &dsi_cfg_handlers[i];
break;
}
}
return cfg_hnd;
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __MSM_DSI_CFG_H__
#define __MSM_DSI_CFG_H__
#include "dsi.h"
#define MSM_DSI_VER_MAJOR_V2 0x02
#define MSM_DSI_VER_MAJOR_6G 0x03
#define MSM_DSI_6G_VER_MINOR_V1_0 0x10000000
#define MSM_DSI_6G_VER_MINOR_V1_1 0x10010000
#define MSM_DSI_6G_VER_MINOR_V1_1_1 0x10010001
#define MSM_DSI_6G_VER_MINOR_V1_2 0x10020000
#define MSM_DSI_6G_VER_MINOR_V1_3 0x10030000
#define MSM_DSI_6G_VER_MINOR_V1_3_1 0x10030001
#define DSI_6G_REG_SHIFT 4
struct msm_dsi_config {
u32 io_offset;
struct dsi_reg_config reg_cfg;
};
struct msm_dsi_cfg_handler {
u32 major;
u32 minor;
const struct msm_dsi_config *cfg;
};
const struct msm_dsi_cfg_handler *msm_dsi_cfg_get(u32 major, u32 minor);
#endif /* __MSM_DSI_CFG_H__ */

View File

@ -20,103 +20,15 @@
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/pinctrl/consumer.h>
#include <linux/of_graph.h>
#include <linux/regulator/consumer.h>
#include <linux/spinlock.h>
#include <video/mipi_display.h>
#include "dsi.h"
#include "dsi.xml.h"
#define MSM_DSI_VER_MAJOR_V2 0x02
#define MSM_DSI_VER_MAJOR_6G 0x03
#define MSM_DSI_6G_VER_MINOR_V1_0 0x10000000
#define MSM_DSI_6G_VER_MINOR_V1_1 0x10010000
#define MSM_DSI_6G_VER_MINOR_V1_1_1 0x10010001
#define MSM_DSI_6G_VER_MINOR_V1_2 0x10020000
#define MSM_DSI_6G_VER_MINOR_V1_3_1 0x10030001
#define DSI_6G_REG_SHIFT 4
struct dsi_config {
u32 major;
u32 minor;
u32 io_offset;
struct dsi_reg_config reg_cfg;
};
static const struct dsi_config dsi_cfgs[] = {
{MSM_DSI_VER_MAJOR_V2, 0, 0, {0,} },
{ /* 8974 v1 */
.major = MSM_DSI_VER_MAJOR_6G,
.minor = MSM_DSI_6G_VER_MINOR_V1_0,
.io_offset = DSI_6G_REG_SHIFT,
.reg_cfg = {
.num = 4,
.regs = {
{"gdsc", -1, -1, -1, -1},
{"vdd", 3000000, 3000000, 150000, 100},
{"vdda", 1200000, 1200000, 100000, 100},
{"vddio", 1800000, 1800000, 100000, 100},
},
},
},
{ /* 8974 v2 */
.major = MSM_DSI_VER_MAJOR_6G,
.minor = MSM_DSI_6G_VER_MINOR_V1_1,
.io_offset = DSI_6G_REG_SHIFT,
.reg_cfg = {
.num = 4,
.regs = {
{"gdsc", -1, -1, -1, -1},
{"vdd", 3000000, 3000000, 150000, 100},
{"vdda", 1200000, 1200000, 100000, 100},
{"vddio", 1800000, 1800000, 100000, 100},
},
},
},
{ /* 8974 v3 */
.major = MSM_DSI_VER_MAJOR_6G,
.minor = MSM_DSI_6G_VER_MINOR_V1_1_1,
.io_offset = DSI_6G_REG_SHIFT,
.reg_cfg = {
.num = 4,
.regs = {
{"gdsc", -1, -1, -1, -1},
{"vdd", 3000000, 3000000, 150000, 100},
{"vdda", 1200000, 1200000, 100000, 100},
{"vddio", 1800000, 1800000, 100000, 100},
},
},
},
{ /* 8084 */
.major = MSM_DSI_VER_MAJOR_6G,
.minor = MSM_DSI_6G_VER_MINOR_V1_2,
.io_offset = DSI_6G_REG_SHIFT,
.reg_cfg = {
.num = 4,
.regs = {
{"gdsc", -1, -1, -1, -1},
{"vdd", 3000000, 3000000, 150000, 100},
{"vdda", 1200000, 1200000, 100000, 100},
{"vddio", 1800000, 1800000, 100000, 100},
},
},
},
{ /* 8916 */
.major = MSM_DSI_VER_MAJOR_6G,
.minor = MSM_DSI_6G_VER_MINOR_V1_3_1,
.io_offset = DSI_6G_REG_SHIFT,
.reg_cfg = {
.num = 4,
.regs = {
{"gdsc", -1, -1, -1, -1},
{"vdd", 2850000, 2850000, 100000, 100},
{"vdda", 1200000, 1200000, 100000, 100},
{"vddio", 1800000, 1800000, 100000, 100},
},
},
},
};
#include "dsi_cfg.h"
static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor)
{
@ -194,7 +106,7 @@ struct msm_dsi_host {
struct gpio_desc *disp_en_gpio;
struct gpio_desc *te_gpio;
const struct dsi_config *cfg;
const struct msm_dsi_cfg_handler *cfg_hnd;
struct completion dma_comp;
struct completion video_comp;
@ -212,8 +124,8 @@ struct msm_dsi_host {
struct drm_display_mode *mode;
/* Panel info */
struct device_node *panel_node;
/* connected device info */
struct device_node *device_node;
unsigned int channel;
unsigned int lanes;
enum mipi_dsi_pixel_format format;
@ -239,61 +151,58 @@ static u32 dsi_get_bpp(const enum mipi_dsi_pixel_format fmt)
static inline u32 dsi_read(struct msm_dsi_host *msm_host, u32 reg)
{
return msm_readl(msm_host->ctrl_base + msm_host->cfg->io_offset + reg);
return msm_readl(msm_host->ctrl_base + reg);
}
static inline void dsi_write(struct msm_dsi_host *msm_host, u32 reg, u32 data)
{
msm_writel(data, msm_host->ctrl_base + msm_host->cfg->io_offset + reg);
msm_writel(data, msm_host->ctrl_base + reg);
}
static int dsi_host_regulator_enable(struct msm_dsi_host *msm_host);
static void dsi_host_regulator_disable(struct msm_dsi_host *msm_host);
static const struct dsi_config *dsi_get_config(struct msm_dsi_host *msm_host)
static const struct msm_dsi_cfg_handler *dsi_get_config(
struct msm_dsi_host *msm_host)
{
const struct dsi_config *cfg;
const struct msm_dsi_cfg_handler *cfg_hnd = NULL;
struct regulator *gdsc_reg;
int i, ret;
int ret;
u32 major = 0, minor = 0;
gdsc_reg = regulator_get(&msm_host->pdev->dev, "gdsc");
if (IS_ERR(gdsc_reg)) {
pr_err("%s: cannot get gdsc\n", __func__);
goto fail;
goto exit;
}
ret = regulator_enable(gdsc_reg);
if (ret) {
pr_err("%s: unable to enable gdsc\n", __func__);
regulator_put(gdsc_reg);
goto fail;
goto put_gdsc;
}
ret = clk_prepare_enable(msm_host->ahb_clk);
if (ret) {
pr_err("%s: unable to enable ahb_clk\n", __func__);
regulator_disable(gdsc_reg);
regulator_put(gdsc_reg);
goto fail;
goto disable_gdsc;
}
ret = dsi_get_version(msm_host->ctrl_base, &major, &minor);
clk_disable_unprepare(msm_host->ahb_clk);
regulator_disable(gdsc_reg);
regulator_put(gdsc_reg);
if (ret) {
pr_err("%s: Invalid version\n", __func__);
goto fail;
goto disable_clks;
}
for (i = 0; i < ARRAY_SIZE(dsi_cfgs); i++) {
cfg = dsi_cfgs + i;
if ((cfg->major == major) && (cfg->minor == minor))
return cfg;
}
pr_err("%s: Version %x:%x not support\n", __func__, major, minor);
cfg_hnd = msm_dsi_cfg_get(major, minor);
fail:
return NULL;
DBG("%s: Version %x:%x\n", __func__, major, minor);
disable_clks:
clk_disable_unprepare(msm_host->ahb_clk);
disable_gdsc:
regulator_disable(gdsc_reg);
put_gdsc:
regulator_put(gdsc_reg);
exit:
return cfg_hnd;
}
static inline struct msm_dsi_host *to_msm_dsi_host(struct mipi_dsi_host *host)
@ -304,8 +213,8 @@ static inline struct msm_dsi_host *to_msm_dsi_host(struct mipi_dsi_host *host)
static void dsi_host_regulator_disable(struct msm_dsi_host *msm_host)
{
struct regulator_bulk_data *s = msm_host->supplies;
const struct dsi_reg_entry *regs = msm_host->cfg->reg_cfg.regs;
int num = msm_host->cfg->reg_cfg.num;
const struct dsi_reg_entry *regs = msm_host->cfg_hnd->cfg->reg_cfg.regs;
int num = msm_host->cfg_hnd->cfg->reg_cfg.num;
int i;
DBG("");
@ -320,8 +229,8 @@ static void dsi_host_regulator_disable(struct msm_dsi_host *msm_host)
static int dsi_host_regulator_enable(struct msm_dsi_host *msm_host)
{
struct regulator_bulk_data *s = msm_host->supplies;
const struct dsi_reg_entry *regs = msm_host->cfg->reg_cfg.regs;
int num = msm_host->cfg->reg_cfg.num;
const struct dsi_reg_entry *regs = msm_host->cfg_hnd->cfg->reg_cfg.regs;
int num = msm_host->cfg_hnd->cfg->reg_cfg.num;
int ret, i;
DBG("");
@ -354,8 +263,8 @@ fail:
static int dsi_regulator_init(struct msm_dsi_host *msm_host)
{
struct regulator_bulk_data *s = msm_host->supplies;
const struct dsi_reg_entry *regs = msm_host->cfg->reg_cfg.regs;
int num = msm_host->cfg->reg_cfg.num;
const struct dsi_reg_entry *regs = msm_host->cfg_hnd->cfg->reg_cfg.regs;
int num = msm_host->cfg_hnd->cfg->reg_cfg.num;
int i, ret;
for (i = 0; i < num; i++)
@ -697,6 +606,7 @@ static void dsi_ctrl_config(struct msm_dsi_host *msm_host, bool enable,
{
u32 flags = msm_host->mode_flags;
enum mipi_dsi_pixel_format mipi_fmt = msm_host->format;
const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
u32 data = 0;
if (!enable) {
@ -750,8 +660,8 @@ static void dsi_ctrl_config(struct msm_dsi_host *msm_host, bool enable,
data |= DSI_TRIG_CTRL_MDP_TRIGGER(TRIGGER_NONE);
data |= DSI_TRIG_CTRL_DMA_TRIGGER(TRIGGER_SW);
data |= DSI_TRIG_CTRL_STREAM(msm_host->channel);
if ((msm_host->cfg->major == MSM_DSI_VER_MAJOR_6G) &&
(msm_host->cfg->minor >= MSM_DSI_6G_VER_MINOR_V1_2))
if ((cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) &&
(cfg_hnd->minor >= MSM_DSI_6G_VER_MINOR_V1_2))
data |= DSI_TRIG_CTRL_BLOCK_DMA_WITHIN_FRAME;
dsi_write(msm_host, REG_DSI_TRIG_CTRL, data);
@ -1257,7 +1167,11 @@ static void dsi_dln0_phy_err(struct msm_dsi_host *msm_host)
status = dsi_read(msm_host, REG_DSI_DLN0_PHY_ERR);
if (status) {
if (status & (DSI_DLN0_PHY_ERR_DLN0_ERR_ESC |
DSI_DLN0_PHY_ERR_DLN0_ERR_SYNC_ESC |
DSI_DLN0_PHY_ERR_DLN0_ERR_CONTROL |
DSI_DLN0_PHY_ERR_DLN0_ERR_CONTENTION_LP0 |
DSI_DLN0_PHY_ERR_DLN0_ERR_CONTENTION_LP1)) {
dsi_write(msm_host, REG_DSI_DLN0_PHY_ERR, status);
msm_host->err_work_state |= DSI_ERR_STATE_DLN0_PHY;
}
@ -1359,7 +1273,8 @@ static int dsi_host_init_panel_gpios(struct msm_dsi_host *msm_host,
return PTR_ERR(msm_host->disp_en_gpio);
}
msm_host->te_gpio = devm_gpiod_get(panel_device, "disp-te", GPIOD_IN);
msm_host->te_gpio = devm_gpiod_get_optional(panel_device, "disp-te",
GPIOD_IN);
if (IS_ERR(msm_host->te_gpio)) {
DBG("cannot get disp-te-gpios %ld", PTR_ERR(msm_host->te_gpio));
return PTR_ERR(msm_host->te_gpio);
@ -1379,7 +1294,7 @@ static int dsi_host_attach(struct mipi_dsi_host *host,
msm_host->format = dsi->format;
msm_host->mode_flags = dsi->mode_flags;
msm_host->panel_node = dsi->dev.of_node;
WARN_ON(dsi->dev.of_node != msm_host->device_node);
/* Some gpios defined in panel DT need to be controlled by host */
ret = dsi_host_init_panel_gpios(msm_host, &dsi->dev);
@ -1398,7 +1313,7 @@ static int dsi_host_detach(struct mipi_dsi_host *host,
{
struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
msm_host->panel_node = NULL;
msm_host->device_node = NULL;
DBG("id=%d", msm_host->id);
if (msm_host->dev)
@ -1429,6 +1344,48 @@ static struct mipi_dsi_host_ops dsi_host_ops = {
.transfer = dsi_host_transfer,
};
static int dsi_host_parse_dt(struct msm_dsi_host *msm_host)
{
struct device *dev = &msm_host->pdev->dev;
struct device_node *np = dev->of_node;
struct device_node *endpoint, *device_node;
int ret;
ret = of_property_read_u32(np, "qcom,dsi-host-index", &msm_host->id);
if (ret) {
dev_err(dev, "%s: host index not specified, ret=%d\n",
__func__, ret);
return ret;
}
/*
* Get the first endpoint node. In our case, dsi has one output port
* to which the panel is connected. Don't return an error if a port
* isn't defined. It's possible that there is nothing connected to
* the dsi output.
*/
endpoint = of_graph_get_next_endpoint(np, NULL);
if (!endpoint) {
dev_dbg(dev, "%s: no endpoint\n", __func__);
return 0;
}
/* Get panel node from the output port's endpoint data */
device_node = of_graph_get_remote_port_parent(endpoint);
if (!device_node) {
dev_err(dev, "%s: no valid device\n", __func__);
of_node_put(endpoint);
return -ENODEV;
}
of_node_put(endpoint);
of_node_put(device_node);
msm_host->device_node = device_node;
return 0;
}
int msm_dsi_host_init(struct msm_dsi *msm_dsi)
{
struct msm_dsi_host *msm_host = NULL;
@ -1443,15 +1400,13 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
goto fail;
}
ret = of_property_read_u32(pdev->dev.of_node,
"qcom,dsi-host-index", &msm_host->id);
msm_host->pdev = pdev;
ret = dsi_host_parse_dt(msm_host);
if (ret) {
dev_err(&pdev->dev,
"%s: host index not specified, ret=%d\n",
__func__, ret);
pr_err("%s: failed to parse dt\n", __func__);
goto fail;
}
msm_host->pdev = pdev;
ret = dsi_clk_init(msm_host);
if (ret) {
@ -1466,13 +1421,16 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
goto fail;
}
msm_host->cfg = dsi_get_config(msm_host);
if (!msm_host->cfg) {
msm_host->cfg_hnd = dsi_get_config(msm_host);
if (!msm_host->cfg_hnd) {
ret = -EINVAL;
pr_err("%s: get config failed\n", __func__);
goto fail;
}
/* fixup base address by io offset */
msm_host->ctrl_base += msm_host->cfg_hnd->cfg->io_offset;
ret = dsi_regulator_init(msm_host);
if (ret) {
pr_err("%s: regulator init failed\n", __func__);
@ -1559,7 +1517,6 @@ int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,
int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer)
{
struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
struct device_node *node;
int ret;
/* Register mipi dsi host */
@ -1577,14 +1534,13 @@ int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer)
* It makes sure panel is connected when fbcon detects
* connector status and gets the proper display mode to
* create framebuffer.
* Don't try to defer if there is nothing connected to the dsi
* output
*/
if (check_defer) {
node = of_get_child_by_name(msm_host->pdev->dev.of_node,
"panel");
if (node) {
if (!of_drm_find_panel(node))
if (check_defer && msm_host->device_node) {
if (!of_drm_find_panel(msm_host->device_node))
if (!of_drm_find_bridge(msm_host->device_node))
return -EPROBE_DEFER;
}
}
}
@ -1663,6 +1619,7 @@ int msm_dsi_host_cmd_rx(struct mipi_dsi_host *host,
const struct mipi_dsi_msg *msg)
{
struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
int data_byte, rx_byte, dlen, end;
int short_response, diff, pkt_size, ret = 0;
char cmd;
@ -1704,8 +1661,8 @@ int msm_dsi_host_cmd_rx(struct mipi_dsi_host *host,
return -EINVAL;
}
if ((msm_host->cfg->major == MSM_DSI_VER_MAJOR_6G) &&
(msm_host->cfg->minor >= MSM_DSI_6G_VER_MINOR_V1_1)) {
if ((cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) &&
(cfg_hnd->minor >= MSM_DSI_6G_VER_MINOR_V1_1)) {
/* Clear the RDBK_DATA registers */
dsi_write(msm_host, REG_DSI_RDBK_DATA_CTRL,
DSI_RDBK_DATA_CTRL_CLR);
@ -1919,6 +1876,13 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host)
goto fail_disable_reg;
}
ret = pinctrl_pm_select_default_state(&msm_host->pdev->dev);
if (ret) {
pr_err("%s: failed to set pinctrl default state, %d\n",
__func__, ret);
goto fail_disable_clk;
}
dsi_timing_setup(msm_host);
dsi_sw_reset(msm_host);
dsi_ctrl_config(msm_host, true, clk_pre, clk_post);
@ -1931,6 +1895,8 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host)
return 0;
fail_disable_clk:
dsi_clk_ctrl(msm_host, 0);
fail_disable_reg:
dsi_host_regulator_disable(msm_host);
unlock_ret:
@ -1953,6 +1919,8 @@ int msm_dsi_host_power_off(struct mipi_dsi_host *host)
if (msm_host->disp_en_gpio)
gpiod_set_value(msm_host->disp_en_gpio, 0);
pinctrl_pm_select_sleep_state(&msm_host->pdev->dev);
msm_dsi_manager_phy_disable(msm_host->id);
dsi_clk_ctrl(msm_host, 0);
@ -1993,10 +1961,16 @@ struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host,
struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
struct drm_panel *panel;
panel = of_drm_find_panel(msm_host->panel_node);
panel = of_drm_find_panel(msm_host->device_node);
if (panel_flags)
*panel_flags = msm_host->mode_flags;
return panel;
}
struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host)
{
struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
return of_drm_find_bridge(msm_host->device_node);
}

View File

@ -14,19 +14,31 @@
#include "msm_kms.h"
#include "dsi.h"
#define DSI_CLOCK_MASTER DSI_0
#define DSI_CLOCK_SLAVE DSI_1
#define DSI_LEFT DSI_0
#define DSI_RIGHT DSI_1
/* According to the current drm framework sequence, take the encoder of
* DSI_1 as master encoder
*/
#define DSI_ENCODER_MASTER DSI_1
#define DSI_ENCODER_SLAVE DSI_0
struct msm_dsi_manager {
struct msm_dsi *dsi[DSI_MAX];
bool is_dual_panel;
bool is_dual_dsi;
bool is_sync_needed;
int master_panel_id;
int master_dsi_link_id;
};
static struct msm_dsi_manager msm_dsim_glb;
#define IS_DUAL_PANEL() (msm_dsim_glb.is_dual_panel)
#define IS_DUAL_DSI() (msm_dsim_glb.is_dual_dsi)
#define IS_SYNC_NEEDED() (msm_dsim_glb.is_sync_needed)
#define IS_MASTER_PANEL(id) (msm_dsim_glb.master_panel_id == id)
#define IS_MASTER_DSI_LINK(id) (msm_dsim_glb.master_dsi_link_id == id)
static inline struct msm_dsi *dsi_mgr_get_dsi(int id)
{
@ -38,23 +50,23 @@ static inline struct msm_dsi *dsi_mgr_get_other_dsi(int id)
return msm_dsim_glb.dsi[(id + 1) % DSI_MAX];
}
static int dsi_mgr_parse_dual_panel(struct device_node *np, int id)
static int dsi_mgr_parse_dual_dsi(struct device_node *np, int id)
{
struct msm_dsi_manager *msm_dsim = &msm_dsim_glb;
/* We assume 2 dsi nodes have the same information of dual-panel and
/* We assume 2 dsi nodes have the same information of dual-dsi and
* sync-mode, and only one node specifies master in case of dual mode.
*/
if (!msm_dsim->is_dual_panel)
msm_dsim->is_dual_panel = of_property_read_bool(
np, "qcom,dual-panel-mode");
if (!msm_dsim->is_dual_dsi)
msm_dsim->is_dual_dsi = of_property_read_bool(
np, "qcom,dual-dsi-mode");
if (msm_dsim->is_dual_panel) {
if (of_property_read_bool(np, "qcom,master-panel"))
msm_dsim->master_panel_id = id;
if (msm_dsim->is_dual_dsi) {
if (of_property_read_bool(np, "qcom,master-dsi"))
msm_dsim->master_dsi_link_id = id;
if (!msm_dsim->is_sync_needed)
msm_dsim->is_sync_needed = of_property_read_bool(
np, "qcom,sync-dual-panel");
np, "qcom,sync-dual-dsi");
}
return 0;
@ -68,7 +80,7 @@ static int dsi_mgr_host_register(int id)
struct msm_dsi_pll *src_pll;
int ret;
if (!IS_DUAL_PANEL()) {
if (!IS_DUAL_DSI()) {
ret = msm_dsi_host_register(msm_dsi->host, true);
if (ret)
return ret;
@ -78,9 +90,9 @@ static int dsi_mgr_host_register(int id)
} else if (!other_dsi) {
ret = 0;
} else {
struct msm_dsi *mdsi = IS_MASTER_PANEL(id) ?
struct msm_dsi *mdsi = IS_MASTER_DSI_LINK(id) ?
msm_dsi : other_dsi;
struct msm_dsi *sdsi = IS_MASTER_PANEL(id) ?
struct msm_dsi *sdsi = IS_MASTER_DSI_LINK(id) ?
other_dsi : msm_dsi;
/* Register slave host first, so that slave DSI device
* has a chance to probe, and do not block the master
@ -144,28 +156,28 @@ static enum drm_connector_status dsi_mgr_connector_detect(
DBG("id=%d", id);
if (!msm_dsi->panel) {
msm_dsi->panel = msm_dsi_host_get_panel(msm_dsi->host,
&msm_dsi->panel_flags);
&msm_dsi->device_flags);
/* There is only 1 panel in the global panel list
* for dual panel mode. Therefore slave dsi should get
* for dual DSI mode. Therefore slave dsi should get
* the drm_panel instance from master dsi, and
* keep using the panel flags got from the current DSI link.
*/
if (!msm_dsi->panel && IS_DUAL_PANEL() &&
!IS_MASTER_PANEL(id) && other_dsi)
if (!msm_dsi->panel && IS_DUAL_DSI() &&
!IS_MASTER_DSI_LINK(id) && other_dsi)
msm_dsi->panel = msm_dsi_host_get_panel(
other_dsi->host, NULL);
if (msm_dsi->panel && IS_DUAL_PANEL())
if (msm_dsi->panel && IS_DUAL_DSI())
drm_object_attach_property(&connector->base,
connector->dev->mode_config.tile_property, 0);
/* Set split display info to kms once dual panel is connected
* to both hosts
/* Set split display info to kms once dual DSI panel is
* connected to both hosts.
*/
if (msm_dsi->panel && IS_DUAL_PANEL() &&
if (msm_dsi->panel && IS_DUAL_DSI() &&
other_dsi && other_dsi->panel) {
bool cmd_mode = !(msm_dsi->panel_flags &
bool cmd_mode = !(msm_dsi->device_flags &
MIPI_DSI_MODE_VIDEO);
struct drm_encoder *encoder = msm_dsi_get_encoder(
dsi_mgr_get_dsi(DSI_ENCODER_MASTER));
@ -176,7 +188,7 @@ static enum drm_connector_status dsi_mgr_connector_detect(
kms->funcs->set_split_display(kms, encoder,
slave_enc, cmd_mode);
else
pr_err("mdp does not support dual panel\n");
pr_err("mdp does not support dual DSI\n");
}
}
@ -273,7 +285,7 @@ static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
if (!num)
return 0;
if (IS_DUAL_PANEL()) {
if (IS_DUAL_DSI()) {
/* report half resolution to user */
dsi_dual_connector_fix_modes(connector);
ret = dsi_dual_connector_tile_init(connector, id);
@ -328,11 +340,12 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
struct mipi_dsi_host *host = msm_dsi->host;
struct drm_panel *panel = msm_dsi->panel;
bool is_dual_panel = IS_DUAL_PANEL();
bool is_dual_dsi = IS_DUAL_DSI();
int ret;
DBG("id=%d", id);
if (!panel || (is_dual_panel && (DSI_1 == id)))
if (!msm_dsi_device_connected(msm_dsi) ||
(is_dual_dsi && (DSI_1 == id)))
return;
ret = msm_dsi_host_power_on(host);
@ -341,7 +354,7 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
goto host_on_fail;
}
if (is_dual_panel && msm_dsi1) {
if (is_dual_dsi && msm_dsi1) {
ret = msm_dsi_host_power_on(msm_dsi1->host);
if (ret) {
pr_err("%s: power on host1 failed, %d\n",
@ -353,10 +366,13 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
/* Always call panel functions once, because even for dual panels,
* there is only one drm_panel instance.
*/
ret = drm_panel_prepare(panel);
if (ret) {
pr_err("%s: prepare panel %d failed, %d\n", __func__, id, ret);
goto panel_prep_fail;
if (panel) {
ret = drm_panel_prepare(panel);
if (ret) {
pr_err("%s: prepare panel %d failed, %d\n", __func__,
id, ret);
goto panel_prep_fail;
}
}
ret = msm_dsi_host_enable(host);
@ -365,7 +381,7 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
goto host_en_fail;
}
if (is_dual_panel && msm_dsi1) {
if (is_dual_dsi && msm_dsi1) {
ret = msm_dsi_host_enable(msm_dsi1->host);
if (ret) {
pr_err("%s: enable host1 failed, %d\n", __func__, ret);
@ -373,23 +389,27 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
}
}
ret = drm_panel_enable(panel);
if (ret) {
pr_err("%s: enable panel %d failed, %d\n", __func__, id, ret);
goto panel_en_fail;
if (panel) {
ret = drm_panel_enable(panel);
if (ret) {
pr_err("%s: enable panel %d failed, %d\n", __func__, id,
ret);
goto panel_en_fail;
}
}
return;
panel_en_fail:
if (is_dual_panel && msm_dsi1)
if (is_dual_dsi && msm_dsi1)
msm_dsi_host_disable(msm_dsi1->host);
host1_en_fail:
msm_dsi_host_disable(host);
host_en_fail:
drm_panel_unprepare(panel);
if (panel)
drm_panel_unprepare(panel);
panel_prep_fail:
if (is_dual_panel && msm_dsi1)
if (is_dual_dsi && msm_dsi1)
msm_dsi_host_power_off(msm_dsi1->host);
host1_on_fail:
msm_dsi_host_power_off(host);
@ -414,37 +434,44 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
struct mipi_dsi_host *host = msm_dsi->host;
struct drm_panel *panel = msm_dsi->panel;
bool is_dual_panel = IS_DUAL_PANEL();
bool is_dual_dsi = IS_DUAL_DSI();
int ret;
DBG("id=%d", id);
if (!panel || (is_dual_panel && (DSI_1 == id)))
if (!msm_dsi_device_connected(msm_dsi) ||
(is_dual_dsi && (DSI_1 == id)))
return;
ret = drm_panel_disable(panel);
if (ret)
pr_err("%s: Panel %d OFF failed, %d\n", __func__, id, ret);
if (panel) {
ret = drm_panel_disable(panel);
if (ret)
pr_err("%s: Panel %d OFF failed, %d\n", __func__, id,
ret);
}
ret = msm_dsi_host_disable(host);
if (ret)
pr_err("%s: host %d disable failed, %d\n", __func__, id, ret);
if (is_dual_panel && msm_dsi1) {
if (is_dual_dsi && msm_dsi1) {
ret = msm_dsi_host_disable(msm_dsi1->host);
if (ret)
pr_err("%s: host1 disable failed, %d\n", __func__, ret);
}
ret = drm_panel_unprepare(panel);
if (ret)
pr_err("%s: Panel %d unprepare failed,%d\n", __func__, id, ret);
if (panel) {
ret = drm_panel_unprepare(panel);
if (ret)
pr_err("%s: Panel %d unprepare failed,%d\n", __func__,
id, ret);
}
ret = msm_dsi_host_power_off(host);
if (ret)
pr_err("%s: host %d power off failed,%d\n", __func__, id, ret);
if (is_dual_panel && msm_dsi1) {
if (is_dual_dsi && msm_dsi1) {
ret = msm_dsi_host_power_off(msm_dsi1->host);
if (ret)
pr_err("%s: host1 power off failed, %d\n",
@ -460,7 +487,7 @@ static void dsi_mgr_bridge_mode_set(struct drm_bridge *bridge,
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
struct mipi_dsi_host *host = msm_dsi->host;
bool is_dual_panel = IS_DUAL_PANEL();
bool is_dual_dsi = IS_DUAL_DSI();
DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
mode->base.id, mode->name,
@ -471,11 +498,11 @@ static void dsi_mgr_bridge_mode_set(struct drm_bridge *bridge,
mode->vsync_end, mode->vtotal,
mode->type, mode->flags);
if (is_dual_panel && (DSI_1 == id))
if (is_dual_dsi && (DSI_1 == id))
return;
msm_dsi_host_set_display_mode(host, adjusted_mode);
if (is_dual_panel && other_dsi)
if (is_dual_dsi && other_dsi)
msm_dsi_host_set_display_mode(other_dsi->host, adjusted_mode);
}
@ -503,7 +530,7 @@ static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
.mode_set = dsi_mgr_bridge_mode_set,
};
/* initialize connector */
/* initialize connector when we're connected to a drm_panel */
struct drm_connector *msm_dsi_manager_connector_init(u8 id)
{
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
@ -588,6 +615,53 @@ fail:
return ERR_PTR(ret);
}
struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
{
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
struct drm_device *dev = msm_dsi->dev;
struct drm_encoder *encoder;
struct drm_bridge *int_bridge, *ext_bridge;
struct drm_connector *connector;
struct list_head *connector_list;
int_bridge = msm_dsi->bridge;
ext_bridge = msm_dsi->external_bridge =
msm_dsi_host_get_bridge(msm_dsi->host);
/*
* HACK: we may not know the external DSI bridge device's mode
* flags here. We'll get to know them only when the device
* attaches to the dsi host. For now, assume the bridge supports
* DSI video mode
*/
encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
/* link the internal dsi bridge to the external bridge */
int_bridge->next = ext_bridge;
/* set the external bridge's encoder as dsi's encoder */
ext_bridge->encoder = encoder;
drm_bridge_attach(dev, ext_bridge);
/*
* we need the drm_connector created by the external bridge
* driver (or someone else) to feed it to our driver's
* priv->connector[] list, mainly for msm_fbdev_init()
*/
connector_list = &dev->mode_config.connector_list;
list_for_each_entry(connector, connector_list, head) {
int i;
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
if (connector->encoder_ids[i] == encoder->base.id)
return connector;
}
}
return ERR_PTR(-ENODEV);
}
void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge)
{
}
@ -598,12 +672,29 @@ int msm_dsi_manager_phy_enable(int id,
{
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
struct msm_dsi_phy *phy = msm_dsi->phy;
int src_pll_id = IS_DUAL_DSI() ? DSI_CLOCK_MASTER : id;
struct msm_dsi_pll *pll = msm_dsi_phy_get_pll(msm_dsi->phy);
int ret;
ret = msm_dsi_phy_enable(phy, IS_DUAL_PANEL(), bit_rate, esc_rate);
ret = msm_dsi_phy_enable(phy, src_pll_id, bit_rate, esc_rate);
if (ret)
return ret;
/*
* Reset DSI PHY silently changes its PLL registers to reset status,
* which will confuse clock driver and result in wrong output rate of
* link clocks. Restore PLL status if its PLL is being used as clock
* source.
*/
if (!IS_DUAL_DSI() || (id == DSI_CLOCK_MASTER)) {
ret = msm_dsi_pll_restore_state(pll);
if (ret) {
pr_err("%s: failed to restore pll state\n", __func__);
msm_dsi_phy_disable(phy);
return ret;
}
}
msm_dsi->phy_enabled = true;
msm_dsi_phy_get_clk_pre_post(phy, clk_pre, clk_post);
@ -616,13 +707,18 @@ void msm_dsi_manager_phy_disable(int id)
struct msm_dsi *mdsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER);
struct msm_dsi *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
struct msm_dsi_phy *phy = msm_dsi->phy;
struct msm_dsi_pll *pll = msm_dsi_phy_get_pll(msm_dsi->phy);
/* Save PLL status if it is a clock source */
if (!IS_DUAL_DSI() || (id == DSI_CLOCK_MASTER))
msm_dsi_pll_save_state(pll);
/* disable DSI phy
* In dual-dsi configuration, the phy should be disabled for the
* first controller only when the second controller is disabled.
*/
msm_dsi->phy_enabled = false;
if (IS_DUAL_PANEL() && mdsi && sdsi) {
if (IS_DUAL_DSI() && mdsi && sdsi) {
if (!mdsi->phy_enabled && !sdsi->phy_enabled) {
msm_dsi_phy_disable(sdsi->phy);
msm_dsi_phy_disable(mdsi->phy);
@ -713,9 +809,9 @@ int msm_dsi_manager_register(struct msm_dsi *msm_dsi)
msm_dsim->dsi[id] = msm_dsi;
ret = dsi_mgr_parse_dual_panel(msm_dsi->pdev->dev.of_node, id);
ret = dsi_mgr_parse_dual_dsi(msm_dsi->pdev->dev.of_node, id);
if (ret) {
pr_err("%s: failed to parse dual panel info\n", __func__);
pr_err("%s: failed to parse dual DSI info\n", __func__);
goto fail;
}

View File

@ -8,19 +8,19 @@ 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 ( 676 bytes, from 2014-12-05 15:34:49)
- /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 ( 20915 bytes, from 2015-03-24 22:05:22)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2352 bytes, from 2015-04-12 15:02:42)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 35083 bytes, from 2015-04-12 15:04:03)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 22094 bytes, from 2015-05-12 12:45:23)
- /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 ( 1686 bytes, from 2014-10-31 16:48:57)
- /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 ( 29012 bytes, from 2015-05-12 12:45:23)
- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-12 12:45:23)
- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2576 bytes, from 2015-07-09 22:10:24)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 36021 bytes, from 2015-07-09 22:10:24)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 26057 bytes, from 2015-08-14 21:47:57)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29154 bytes, from 2015-08-10 21:25:43)
- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-20 20:03:14)
Copyright (C) 2013-2014 by the following authors:
Copyright (C) 2013-2015 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
Permission is hereby granted, free of charge, to any person obtaining

View File

@ -12,142 +12,8 @@
*/
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include "dsi.h"
#include "dsi.xml.h"
#define dsi_phy_read(offset) msm_readl((offset))
#define dsi_phy_write(offset, data) msm_writel((data), (offset))
struct dsi_phy_ops {
int (*enable)(struct msm_dsi_phy *phy, bool is_dual_panel,
const unsigned long bit_rate, const unsigned long esc_rate);
int (*disable)(struct msm_dsi_phy *phy);
};
struct dsi_phy_cfg {
enum msm_dsi_phy_type type;
struct dsi_reg_config reg_cfg;
struct dsi_phy_ops ops;
};
struct dsi_dphy_timing {
u32 clk_pre;
u32 clk_post;
u32 clk_zero;
u32 clk_trail;
u32 clk_prepare;
u32 hs_exit;
u32 hs_zero;
u32 hs_prepare;
u32 hs_trail;
u32 hs_rqst;
u32 ta_go;
u32 ta_sure;
u32 ta_get;
};
struct msm_dsi_phy {
struct platform_device *pdev;
void __iomem *base;
void __iomem *reg_base;
int id;
struct clk *ahb_clk;
struct regulator_bulk_data supplies[DSI_DEV_REGULATOR_MAX];
struct dsi_dphy_timing timing;
const struct dsi_phy_cfg *cfg;
struct msm_dsi_pll *pll;
};
static int dsi_phy_regulator_init(struct msm_dsi_phy *phy)
{
struct regulator_bulk_data *s = phy->supplies;
const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
struct device *dev = &phy->pdev->dev;
int num = phy->cfg->reg_cfg.num;
int i, ret;
for (i = 0; i < num; i++)
s[i].supply = regs[i].name;
ret = devm_regulator_bulk_get(&phy->pdev->dev, num, s);
if (ret < 0) {
dev_err(dev, "%s: failed to init regulator, ret=%d\n",
__func__, ret);
return ret;
}
for (i = 0; i < num; i++) {
if ((regs[i].min_voltage >= 0) && (regs[i].max_voltage >= 0)) {
ret = regulator_set_voltage(s[i].consumer,
regs[i].min_voltage, regs[i].max_voltage);
if (ret < 0) {
dev_err(dev,
"regulator %d set voltage failed, %d\n",
i, ret);
return ret;
}
}
}
return 0;
}
static void dsi_phy_regulator_disable(struct msm_dsi_phy *phy)
{
struct regulator_bulk_data *s = phy->supplies;
const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
int num = phy->cfg->reg_cfg.num;
int i;
DBG("");
for (i = num - 1; i >= 0; i--)
if (regs[i].disable_load >= 0)
regulator_set_load(s[i].consumer,
regs[i].disable_load);
regulator_bulk_disable(num, s);
}
static int dsi_phy_regulator_enable(struct msm_dsi_phy *phy)
{
struct regulator_bulk_data *s = phy->supplies;
const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
struct device *dev = &phy->pdev->dev;
int num = phy->cfg->reg_cfg.num;
int ret, i;
DBG("");
for (i = 0; i < num; i++) {
if (regs[i].enable_load >= 0) {
ret = regulator_set_load(s[i].consumer,
regs[i].enable_load);
if (ret < 0) {
dev_err(dev,
"regulator %d set op mode failed, %d\n",
i, ret);
goto fail;
}
}
}
ret = regulator_bulk_enable(num, s);
if (ret < 0) {
dev_err(dev, "regulator enable failed, %d\n", ret);
goto fail;
}
return 0;
fail:
for (i--; i >= 0; i--)
regulator_set_load(s[i].consumer, regs[i].disable_load);
return ret;
}
#include "dsi_phy.h"
#define S_DIV_ROUND_UP(n, d) \
(((n) >= 0) ? (((n) + (d) - 1) / (d)) : (((n) - (d) + 1) / (d)))
@ -156,6 +22,7 @@ static inline s32 linear_inter(s32 tmax, s32 tmin, s32 percent,
s32 min_result, bool even)
{
s32 v;
v = (tmax - tmin) * percent;
v = S_DIV_ROUND_UP(v, 100) + tmin;
if (even && (v & 0x1))
@ -164,7 +31,7 @@ static inline s32 linear_inter(s32 tmax, s32 tmin, s32 percent,
return max_t(s32, min_result, v);
}
static void dsi_dphy_timing_calc_clk_zero(struct dsi_dphy_timing *timing,
static void dsi_dphy_timing_calc_clk_zero(struct msm_dsi_dphy_timing *timing,
s32 ui, s32 coeff, s32 pcnt)
{
s32 tmax, tmin, clk_z;
@ -186,7 +53,7 @@ static void dsi_dphy_timing_calc_clk_zero(struct dsi_dphy_timing *timing,
timing->clk_zero = clk_z + 8 - temp;
}
static int dsi_dphy_timing_calc(struct dsi_dphy_timing *timing,
int msm_dsi_dphy_timing_calc(struct msm_dsi_dphy_timing *timing,
const unsigned long bit_rate, const unsigned long esc_rate)
{
s32 ui, lpx;
@ -256,9 +123,8 @@ static int dsi_dphy_timing_calc(struct dsi_dphy_timing *timing,
temp += 8 * ui + lpx;
tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1;
if (tmin > tmax) {
temp = linear_inter(2 * tmax, tmin, pcnt2, 0, false) >> 1;
temp = linear_inter(2 * tmax, tmin, pcnt2, 0, false);
timing->clk_pre = temp >> 1;
temp = (2 * tmax - tmin) * pcnt2;
} else {
timing->clk_pre = linear_inter(tmax, tmin, pcnt2, 0, false);
}
@ -276,130 +142,119 @@ static int dsi_dphy_timing_calc(struct dsi_dphy_timing *timing,
return 0;
}
static void dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable)
void msm_dsi_phy_set_src_pll(struct msm_dsi_phy *phy, int pll_id, u32 reg,
u32 bit_mask)
{
void __iomem *base = phy->reg_base;
int phy_id = phy->id;
u32 val;
if (!enable) {
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 0);
if ((phy_id >= DSI_MAX) || (pll_id >= DSI_MAX))
return;
}
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x0);
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 1);
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_5, 0);
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_3, 0);
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_2, 0x3);
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_1, 0x9);
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x7);
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_4, 0x20);
val = dsi_phy_read(phy->base + reg);
if (phy->cfg->src_pll_truthtable[phy_id][pll_id])
dsi_phy_write(phy->base + reg, val | bit_mask);
else
dsi_phy_write(phy->base + reg, val & (~bit_mask));
}
static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel,
const unsigned long bit_rate, const unsigned long esc_rate)
static int dsi_phy_regulator_init(struct msm_dsi_phy *phy)
{
struct dsi_dphy_timing *timing = &phy->timing;
struct regulator_bulk_data *s = phy->supplies;
const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
struct device *dev = &phy->pdev->dev;
int num = phy->cfg->reg_cfg.num;
int i, ret;
for (i = 0; i < num; i++)
s[i].supply = regs[i].name;
ret = devm_regulator_bulk_get(dev, num, s);
if (ret < 0) {
dev_err(dev, "%s: failed to init regulator, ret=%d\n",
__func__, ret);
return ret;
}
for (i = 0; i < num; i++) {
if ((regs[i].min_voltage >= 0) && (regs[i].max_voltage >= 0)) {
ret = regulator_set_voltage(s[i].consumer,
regs[i].min_voltage, regs[i].max_voltage);
if (ret < 0) {
dev_err(dev,
"regulator %d set voltage failed, %d\n",
i, ret);
return ret;
}
}
}
return 0;
}
static void dsi_phy_regulator_disable(struct msm_dsi_phy *phy)
{
struct regulator_bulk_data *s = phy->supplies;
const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
int num = phy->cfg->reg_cfg.num;
int i;
void __iomem *base = phy->base;
DBG("");
for (i = num - 1; i >= 0; i--)
if (regs[i].disable_load >= 0)
regulator_set_load(s[i].consumer, regs[i].disable_load);
if (dsi_dphy_timing_calc(timing, bit_rate, esc_rate)) {
pr_err("%s: D-PHY timing calculation failed\n", __func__);
return -EINVAL;
}
dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_0, 0xff);
dsi_28nm_phy_regulator_ctrl(phy, true);
dsi_phy_write(base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x00);
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_0,
DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero));
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_1,
DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail));
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_2,
DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare));
if (timing->clk_zero & BIT(8))
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_3,
DSI_28nm_PHY_TIMING_CTRL_3_CLK_ZERO_8);
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_4,
DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit));
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_5,
DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero));
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_6,
DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare));
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_7,
DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail));
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_8,
DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst));
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_9,
DSI_28nm_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) |
DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure));
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_10,
DSI_28nm_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get));
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_11,
DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD(0));
dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_1, 0x00);
dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f);
dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_1, 0x6);
for (i = 0; i < 4; i++) {
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_0(i), 0);
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_1(i), 0);
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_2(i), 0);
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_3(i), 0);
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_DATAPATH(i), 0);
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_DEBUG_SEL(i), 0);
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_0(i), 0x1);
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_1(i), 0x97);
}
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(0), 0);
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(1), 0x5);
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(2), 0xa);
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(3), 0xf);
dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_CFG_1, 0xc0);
dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR0, 0x1);
dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR1, 0xbb);
dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f);
if (is_dual_panel && (phy->id != DSI_CLOCK_MASTER))
dsi_phy_write(base + REG_DSI_28nm_PHY_GLBL_TEST_CTRL, 0x00);
else
dsi_phy_write(base + REG_DSI_28nm_PHY_GLBL_TEST_CTRL, 0x01);
return 0;
regulator_bulk_disable(num, s);
}
static int dsi_28nm_phy_disable(struct msm_dsi_phy *phy)
static int dsi_phy_regulator_enable(struct msm_dsi_phy *phy)
{
dsi_phy_write(phy->base + REG_DSI_28nm_PHY_CTRL_0, 0);
dsi_28nm_phy_regulator_ctrl(phy, false);
struct regulator_bulk_data *s = phy->supplies;
const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
struct device *dev = &phy->pdev->dev;
int num = phy->cfg->reg_cfg.num;
int ret, i;
/*
* Wait for the registers writes to complete in order to
* ensure that the phy is completely disabled
*/
wmb();
DBG("");
for (i = 0; i < num; i++) {
if (regs[i].enable_load >= 0) {
ret = regulator_set_load(s[i].consumer,
regs[i].enable_load);
if (ret < 0) {
dev_err(dev,
"regulator %d set op mode failed, %d\n",
i, ret);
goto fail;
}
}
}
ret = regulator_bulk_enable(num, s);
if (ret < 0) {
dev_err(dev, "regulator enable failed, %d\n", ret);
goto fail;
}
return 0;
fail:
for (i--; i >= 0; i--)
regulator_set_load(s[i].consumer, regs[i].disable_load);
return ret;
}
static int dsi_phy_enable_resource(struct msm_dsi_phy *phy)
{
struct device *dev = &phy->pdev->dev;
int ret;
pm_runtime_get_sync(&phy->pdev->dev);
pm_runtime_get_sync(dev);
ret = clk_prepare_enable(phy->ahb_clk);
if (ret) {
pr_err("%s: can't enable ahb clk, %d\n", __func__, ret);
pm_runtime_put_sync(&phy->pdev->dev);
dev_err(dev, "%s: can't enable ahb clk, %d\n", __func__, ret);
pm_runtime_put_sync(dev);
}
return ret;
@ -411,92 +266,74 @@ static void dsi_phy_disable_resource(struct msm_dsi_phy *phy)
pm_runtime_put_sync(&phy->pdev->dev);
}
static const struct dsi_phy_cfg dsi_phy_cfgs[MSM_DSI_PHY_MAX] = {
[MSM_DSI_PHY_28NM_HPM] = {
.type = MSM_DSI_PHY_28NM_HPM,
.reg_cfg = {
.num = 1,
.regs = {
{"vddio", 1800000, 1800000, 100000, 100},
},
},
.ops = {
.enable = dsi_28nm_phy_enable,
.disable = dsi_28nm_phy_disable,
}
},
[MSM_DSI_PHY_28NM_LP] = {
.type = MSM_DSI_PHY_28NM_LP,
.reg_cfg = {
.num = 1,
.regs = {
{"vddio", 1800000, 1800000, 100000, 100},
},
},
.ops = {
.enable = dsi_28nm_phy_enable,
.disable = dsi_28nm_phy_disable,
}
},
};
static const struct of_device_id dsi_phy_dt_match[] = {
#ifdef CONFIG_DRM_MSM_DSI_28NM_PHY
{ .compatible = "qcom,dsi-phy-28nm-hpm",
.data = &dsi_phy_cfgs[MSM_DSI_PHY_28NM_HPM],},
.data = &dsi_phy_28nm_hpm_cfgs },
{ .compatible = "qcom,dsi-phy-28nm-lp",
.data = &dsi_phy_cfgs[MSM_DSI_PHY_28NM_LP],},
.data = &dsi_phy_28nm_lp_cfgs },
#endif
#ifdef CONFIG_DRM_MSM_DSI_20NM_PHY
{ .compatible = "qcom,dsi-phy-20nm",
.data = &dsi_phy_20nm_cfgs },
#endif
{}
};
static int dsi_phy_driver_probe(struct platform_device *pdev)
{
struct msm_dsi_phy *phy;
struct device *dev = &pdev->dev;
const struct of_device_id *match;
int ret;
phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
if (!phy)
return -ENOMEM;
match = of_match_node(dsi_phy_dt_match, pdev->dev.of_node);
match = of_match_node(dsi_phy_dt_match, dev->of_node);
if (!match)
return -ENODEV;
phy->cfg = match->data;
phy->pdev = pdev;
ret = of_property_read_u32(pdev->dev.of_node,
ret = of_property_read_u32(dev->of_node,
"qcom,dsi-phy-index", &phy->id);
if (ret) {
dev_err(&pdev->dev,
"%s: PHY index not specified, ret=%d\n",
dev_err(dev, "%s: PHY index not specified, %d\n",
__func__, ret);
goto fail;
}
phy->regulator_ldo_mode = of_property_read_bool(dev->of_node,
"qcom,dsi-phy-regulator-ldo-mode");
phy->base = msm_ioremap(pdev, "dsi_phy", "DSI_PHY");
if (IS_ERR(phy->base)) {
dev_err(&pdev->dev, "%s: failed to map phy base\n", __func__);
dev_err(dev, "%s: failed to map phy base\n", __func__);
ret = -ENOMEM;
goto fail;
}
phy->reg_base = msm_ioremap(pdev, "dsi_phy_regulator", "DSI_PHY_REG");
phy->reg_base = msm_ioremap(pdev, "dsi_phy_regulator",
"DSI_PHY_REG");
if (IS_ERR(phy->reg_base)) {
dev_err(&pdev->dev,
"%s: failed to map phy regulator base\n", __func__);
dev_err(dev, "%s: failed to map phy regulator base\n",
__func__);
ret = -ENOMEM;
goto fail;
}
ret = dsi_phy_regulator_init(phy);
if (ret) {
dev_err(&pdev->dev, "%s: failed to init regulator\n", __func__);
dev_err(dev, "%s: failed to init regulator\n", __func__);
goto fail;
}
phy->ahb_clk = devm_clk_get(&pdev->dev, "iface_clk");
phy->ahb_clk = devm_clk_get(dev, "iface_clk");
if (IS_ERR(phy->ahb_clk)) {
pr_err("%s: Unable to get ahb clk\n", __func__);
dev_err(dev, "%s: Unable to get ahb clk\n", __func__);
ret = PTR_ERR(phy->ahb_clk);
goto fail;
}
@ -510,7 +347,7 @@ static int dsi_phy_driver_probe(struct platform_device *pdev)
phy->pll = msm_dsi_pll_init(pdev, phy->cfg->type, phy->id);
if (!phy->pll)
dev_info(&pdev->dev,
dev_info(dev,
"%s: pll init failed, need separate pll clk driver\n",
__func__);
@ -557,9 +394,10 @@ void __exit msm_dsi_phy_driver_unregister(void)
platform_driver_unregister(&dsi_phy_platform_driver);
}
int msm_dsi_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel,
int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
const unsigned long bit_rate, const unsigned long esc_rate)
{
struct device *dev = &phy->pdev->dev;
int ret;
if (!phy || !phy->cfg->ops.enable)
@ -567,30 +405,37 @@ int msm_dsi_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel,
ret = dsi_phy_regulator_enable(phy);
if (ret) {
dev_err(&phy->pdev->dev, "%s: regulator enable failed, %d\n",
dev_err(dev, "%s: regulator enable failed, %d\n",
__func__, ret);
return ret;
}
return phy->cfg->ops.enable(phy, is_dual_panel, bit_rate, esc_rate);
}
int msm_dsi_phy_disable(struct msm_dsi_phy *phy)
{
if (!phy || !phy->cfg->ops.disable)
return -EINVAL;
phy->cfg->ops.disable(phy);
dsi_phy_regulator_disable(phy);
ret = phy->cfg->ops.enable(phy, src_pll_id, bit_rate, esc_rate);
if (ret) {
dev_err(dev, "%s: phy enable failed, %d\n", __func__, ret);
dsi_phy_regulator_disable(phy);
return ret;
}
return 0;
}
void msm_dsi_phy_disable(struct msm_dsi_phy *phy)
{
if (!phy || !phy->cfg->ops.disable)
return;
phy->cfg->ops.disable(phy);
dsi_phy_regulator_disable(phy);
}
void msm_dsi_phy_get_clk_pre_post(struct msm_dsi_phy *phy,
u32 *clk_pre, u32 *clk_post)
u32 *clk_pre, u32 *clk_post)
{
if (!phy)
return;
if (clk_pre)
*clk_pre = phy->timing.clk_pre;
if (clk_post)

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __DSI_PHY_H__
#define __DSI_PHY_H__
#include <linux/regulator/consumer.h>
#include "dsi.h"
#define dsi_phy_read(offset) msm_readl((offset))
#define dsi_phy_write(offset, data) msm_writel((data), (offset))
struct msm_dsi_phy_ops {
int (*enable)(struct msm_dsi_phy *phy, int src_pll_id,
const unsigned long bit_rate, const unsigned long esc_rate);
void (*disable)(struct msm_dsi_phy *phy);
};
struct msm_dsi_phy_cfg {
enum msm_dsi_phy_type type;
struct dsi_reg_config reg_cfg;
struct msm_dsi_phy_ops ops;
/*
* Each cell {phy_id, pll_id} of the truth table indicates
* if the source PLL selection bit should be set for each PHY.
* Fill default H/W values in illegal cells, eg. cell {0, 1}.
*/
bool src_pll_truthtable[DSI_MAX][DSI_MAX];
};
extern const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs;
struct msm_dsi_dphy_timing {
u32 clk_pre;
u32 clk_post;
u32 clk_zero;
u32 clk_trail;
u32 clk_prepare;
u32 hs_exit;
u32 hs_zero;
u32 hs_prepare;
u32 hs_trail;
u32 hs_rqst;
u32 ta_go;
u32 ta_sure;
u32 ta_get;
};
struct msm_dsi_phy {
struct platform_device *pdev;
void __iomem *base;
void __iomem *reg_base;
int id;
struct clk *ahb_clk;
struct regulator_bulk_data supplies[DSI_DEV_REGULATOR_MAX];
struct msm_dsi_dphy_timing timing;
const struct msm_dsi_phy_cfg *cfg;
bool regulator_ldo_mode;
struct msm_dsi_pll *pll;
};
/*
* PHY internal functions
*/
int msm_dsi_dphy_timing_calc(struct msm_dsi_dphy_timing *timing,
const unsigned long bit_rate, const unsigned long esc_rate);
void msm_dsi_phy_set_src_pll(struct msm_dsi_phy *phy, int pll_id, u32 reg,
u32 bit_mask);
#endif /* __DSI_PHY_H__ */

View File

@ -0,0 +1,150 @@
/*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "dsi_phy.h"
#include "dsi.xml.h"
static void dsi_20nm_dphy_set_timing(struct msm_dsi_phy *phy,
struct msm_dsi_dphy_timing *timing)
{
void __iomem *base = phy->base;
dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_0,
DSI_20nm_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero));
dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_1,
DSI_20nm_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail));
dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_2,
DSI_20nm_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare));
if (timing->clk_zero & BIT(8))
dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_3,
DSI_20nm_PHY_TIMING_CTRL_3_CLK_ZERO_8);
dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_4,
DSI_20nm_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit));
dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_5,
DSI_20nm_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero));
dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_6,
DSI_20nm_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare));
dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_7,
DSI_20nm_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail));
dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_8,
DSI_20nm_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst));
dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_9,
DSI_20nm_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) |
DSI_20nm_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure));
dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_10,
DSI_20nm_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get));
dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_11,
DSI_20nm_PHY_TIMING_CTRL_11_TRIG3_CMD(0));
}
static void dsi_20nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable)
{
void __iomem *base = phy->reg_base;
if (!enable) {
dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CAL_PWR_CFG, 0);
return;
}
if (phy->regulator_ldo_mode) {
dsi_phy_write(phy->base + REG_DSI_20nm_PHY_LDO_CNTRL, 0x1d);
return;
}
/* non LDO mode */
dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_1, 0x03);
dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_2, 0x03);
dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_3, 0x00);
dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_4, 0x20);
dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CAL_PWR_CFG, 0x01);
dsi_phy_write(phy->base + REG_DSI_20nm_PHY_LDO_CNTRL, 0x00);
dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_0, 0x03);
}
static int dsi_20nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
const unsigned long bit_rate, const unsigned long esc_rate)
{
struct msm_dsi_dphy_timing *timing = &phy->timing;
int i;
void __iomem *base = phy->base;
u32 cfg_4[4] = {0x20, 0x40, 0x20, 0x00};
DBG("");
if (msm_dsi_dphy_timing_calc(timing, bit_rate, esc_rate)) {
dev_err(&phy->pdev->dev,
"%s: D-PHY timing calculation failed\n", __func__);
return -EINVAL;
}
dsi_20nm_phy_regulator_ctrl(phy, true);
dsi_phy_write(base + REG_DSI_20nm_PHY_STRENGTH_0, 0xff);
msm_dsi_phy_set_src_pll(phy, src_pll_id,
REG_DSI_20nm_PHY_GLBL_TEST_CTRL,
DSI_20nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL);
for (i = 0; i < 4; i++) {
dsi_phy_write(base + REG_DSI_20nm_PHY_LN_CFG_3(i),
(i >> 1) * 0x40);
dsi_phy_write(base + REG_DSI_20nm_PHY_LN_TEST_STR_0(i), 0x01);
dsi_phy_write(base + REG_DSI_20nm_PHY_LN_TEST_STR_1(i), 0x46);
dsi_phy_write(base + REG_DSI_20nm_PHY_LN_CFG_0(i), 0x02);
dsi_phy_write(base + REG_DSI_20nm_PHY_LN_CFG_1(i), 0xa0);
dsi_phy_write(base + REG_DSI_20nm_PHY_LN_CFG_4(i), cfg_4[i]);
}
dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_3, 0x80);
dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_TEST_STR0, 0x01);
dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_TEST_STR1, 0x46);
dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_0, 0x00);
dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_1, 0xa0);
dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_2, 0x00);
dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_4, 0x00);
dsi_20nm_dphy_set_timing(phy, timing);
dsi_phy_write(base + REG_DSI_20nm_PHY_CTRL_1, 0x00);
dsi_phy_write(base + REG_DSI_20nm_PHY_STRENGTH_1, 0x06);
/* make sure everything is written before enable */
wmb();
dsi_phy_write(base + REG_DSI_20nm_PHY_CTRL_0, 0x7f);
return 0;
}
static void dsi_20nm_phy_disable(struct msm_dsi_phy *phy)
{
dsi_phy_write(phy->base + REG_DSI_20nm_PHY_CTRL_0, 0);
dsi_20nm_phy_regulator_ctrl(phy, false);
}
const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs = {
.type = MSM_DSI_PHY_20NM,
.src_pll_truthtable = { {false, true}, {false, true} },
.reg_cfg = {
.num = 2,
.regs = {
{"vddio", 1800000, 1800000, 100000, 100},
{"vcca", 1000000, 1000000, 10000, 100},
},
},
.ops = {
.enable = dsi_20nm_phy_enable,
.disable = dsi_20nm_phy_disable,
}
};

View File

@ -0,0 +1,166 @@
/*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "dsi_phy.h"
#include "dsi.xml.h"
static void dsi_28nm_dphy_set_timing(struct msm_dsi_phy *phy,
struct msm_dsi_dphy_timing *timing)
{
void __iomem *base = phy->base;
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_0,
DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero));
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_1,
DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail));
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_2,
DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare));
if (timing->clk_zero & BIT(8))
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_3,
DSI_28nm_PHY_TIMING_CTRL_3_CLK_ZERO_8);
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_4,
DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit));
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_5,
DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero));
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_6,
DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare));
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_7,
DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail));
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_8,
DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst));
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_9,
DSI_28nm_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) |
DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure));
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_10,
DSI_28nm_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get));
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_11,
DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD(0));
}
static void dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable)
{
void __iomem *base = phy->reg_base;
if (!enable) {
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 0);
return;
}
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x0);
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 1);
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_5, 0);
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_3, 0);
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_2, 0x3);
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_1, 0x9);
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x7);
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_4, 0x20);
}
static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
const unsigned long bit_rate, const unsigned long esc_rate)
{
struct msm_dsi_dphy_timing *timing = &phy->timing;
int i;
void __iomem *base = phy->base;
DBG("");
if (msm_dsi_dphy_timing_calc(timing, bit_rate, esc_rate)) {
dev_err(&phy->pdev->dev,
"%s: D-PHY timing calculation failed\n", __func__);
return -EINVAL;
}
dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_0, 0xff);
dsi_28nm_phy_regulator_ctrl(phy, true);
dsi_phy_write(base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x00);
dsi_28nm_dphy_set_timing(phy, timing);
dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_1, 0x00);
dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f);
dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_1, 0x6);
for (i = 0; i < 4; i++) {
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_0(i), 0);
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_1(i), 0);
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_2(i), 0);
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_3(i), 0);
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_DATAPATH(i), 0);
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_DEBUG_SEL(i), 0);
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_0(i), 0x1);
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_1(i), 0x97);
}
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(0), 0);
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(1), 0x5);
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(2), 0xa);
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(3), 0xf);
dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_CFG_1, 0xc0);
dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR0, 0x1);
dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR1, 0xbb);
dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f);
msm_dsi_phy_set_src_pll(phy, src_pll_id,
REG_DSI_28nm_PHY_GLBL_TEST_CTRL,
DSI_28nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL);
return 0;
}
static void dsi_28nm_phy_disable(struct msm_dsi_phy *phy)
{
dsi_phy_write(phy->base + REG_DSI_28nm_PHY_CTRL_0, 0);
dsi_28nm_phy_regulator_ctrl(phy, false);
/*
* Wait for the registers writes to complete in order to
* ensure that the phy is completely disabled
*/
wmb();
}
const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs = {
.type = MSM_DSI_PHY_28NM_HPM,
.src_pll_truthtable = { {true, true}, {false, true} },
.reg_cfg = {
.num = 1,
.regs = {
{"vddio", 1800000, 1800000, 100000, 100},
},
},
.ops = {
.enable = dsi_28nm_phy_enable,
.disable = dsi_28nm_phy_disable,
},
};
const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs = {
.type = MSM_DSI_PHY_28NM_LP,
.src_pll_truthtable = { {true, true}, {true, true} },
.reg_cfg = {
.num = 1,
.regs = {
{"vddio", 1800000, 1800000, 100000, 100},
},
},
.ops = {
.enable = dsi_28nm_phy_enable,
.disable = dsi_28nm_phy_disable,
},
};

View File

@ -72,31 +72,14 @@ long msm_dsi_pll_helper_clk_round_rate(struct clk_hw *hw,
int msm_dsi_pll_helper_clk_prepare(struct clk_hw *hw)
{
struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
int ret;
/*
* Certain PLLs need to update the same VCO rate and registers
* after resume in suspend/resume scenario.
*/
if (pll->restore_state) {
ret = pll->restore_state(pll);
if (ret)
goto error;
}
ret = dsi_pll_enable(pll);
error:
return ret;
return dsi_pll_enable(pll);
}
void msm_dsi_pll_helper_clk_unprepare(struct clk_hw *hw)
{
struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
if (pll->save_state)
pll->save_state(pll);
dsi_pll_disable(pll);
}
@ -134,6 +117,29 @@ void msm_dsi_pll_destroy(struct msm_dsi_pll *pll)
pll->destroy(pll);
}
void msm_dsi_pll_save_state(struct msm_dsi_pll *pll)
{
if (pll->save_state) {
pll->save_state(pll);
pll->state_saved = true;
}
}
int msm_dsi_pll_restore_state(struct msm_dsi_pll *pll)
{
int ret;
if (pll->restore_state && pll->state_saved) {
ret = pll->restore_state(pll);
if (ret)
return ret;
pll->state_saved = false;
}
return 0;
}
struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev,
enum msm_dsi_phy_type type, int id)
{

View File

@ -27,6 +27,7 @@ struct msm_dsi_pll {
struct clk_hw clk_hw;
bool pll_on;
bool state_saved;
unsigned long min_rate;
unsigned long max_rate;
@ -82,8 +83,16 @@ void msm_dsi_pll_helper_unregister_clks(struct platform_device *pdev,
/*
* Initialization for Each PLL Type
*/
#ifdef CONFIG_DRM_MSM_DSI_28NM_PHY
struct msm_dsi_pll *msm_dsi_pll_28nm_init(struct platform_device *pdev,
enum msm_dsi_phy_type type, int id);
#else
static inline struct msm_dsi_pll *msm_dsi_pll_28nm_init(
struct platform_device *pdev, enum msm_dsi_phy_type type, int id)
{
return ERR_PTR(-ENODEV);
}
#endif
#endif /* __DSI_PLL_H__ */

View File

@ -465,26 +465,21 @@ static int dsi_pll_28nm_restore_state(struct msm_dsi_pll *pll)
void __iomem *base = pll_28nm->mmio;
int ret;
if ((cached_state->vco_rate != 0) &&
(cached_state->vco_rate == __clk_get_rate(pll->clk_hw.clk))) {
ret = dsi_pll_28nm_clk_set_rate(&pll->clk_hw,
cached_state->vco_rate, 0);
if (ret) {
dev_err(&pll_28nm->pdev->dev,
"restore vco rate failed. ret=%d\n", ret);
return ret;
}
pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG,
cached_state->postdiv3);
pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG,
cached_state->postdiv1);
pll_write(base + REG_DSI_28nm_PHY_PLL_VREG_CFG,
cached_state->byte_mux);
cached_state->vco_rate = 0;
ret = dsi_pll_28nm_clk_set_rate(&pll->clk_hw,
cached_state->vco_rate, 0);
if (ret) {
dev_err(&pll_28nm->pdev->dev,
"restore vco rate failed. ret=%d\n", ret);
return ret;
}
pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG,
cached_state->postdiv3);
pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG,
cached_state->postdiv1);
pll_write(base + REG_DSI_28nm_PHY_PLL_VREG_CFG,
cached_state->byte_mux);
return 0;
}

View File

@ -8,19 +8,19 @@ 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 ( 676 bytes, from 2014-12-05 15:34:49)
- /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 ( 20915 bytes, from 2015-03-24 22:05:22)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2352 bytes, from 2015-04-12 15:02:42)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 35083 bytes, from 2015-04-12 15:04:03)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 22094 bytes, from 2015-05-12 12:45:23)
- /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 ( 1686 bytes, from 2014-10-31 16:48:57)
- /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 ( 29012 bytes, from 2015-05-12 12:45:23)
- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-12 12:45:23)
- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2576 bytes, from 2015-07-09 22:10:24)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 36021 bytes, from 2015-07-09 22:10:24)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 26057 bytes, from 2015-08-14 21:47:57)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29154 bytes, from 2015-08-10 21:25:43)
- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-20 20:03:14)
Copyright (C) 2013 by the following authors:
Copyright (C) 2013-2015 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
Permission is hereby granted, free of charge, to any person obtaining

View File

@ -8,17 +8,17 @@ 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 ( 676 bytes, from 2014-12-05 15:34:49)
- /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 ( 20915 bytes, from 2015-03-24 22:05:22)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2352 bytes, from 2015-04-12 15:02:42)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 35083 bytes, from 2015-04-12 15:04:03)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 22094 bytes, from 2015-05-12 12:45:23)
- /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 ( 1686 bytes, from 2014-10-31 16:48:57)
- /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 ( 29012 bytes, from 2015-05-12 12:45:23)
- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-12 12:45:23)
- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2576 bytes, from 2015-07-09 22:10:24)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 36021 bytes, from 2015-07-09 22:10:24)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 26057 bytes, from 2015-08-14 21:47:57)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29154 bytes, from 2015-08-10 21:25:43)
- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-20 20:03:14)
Copyright (C) 2013-2015 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)

View File

@ -373,7 +373,7 @@ static int edp_gpio_config(struct edp_ctrl *ctrl)
struct device *dev = &ctrl->pdev->dev;
int ret;
ctrl->panel_hpd_gpio = devm_gpiod_get(dev, "panel-hpd");
ctrl->panel_hpd_gpio = devm_gpiod_get(dev, "panel-hpd", GPIOD_IN);
if (IS_ERR(ctrl->panel_hpd_gpio)) {
ret = PTR_ERR(ctrl->panel_hpd_gpio);
ctrl->panel_hpd_gpio = NULL;
@ -381,13 +381,7 @@ static int edp_gpio_config(struct edp_ctrl *ctrl)
return ret;
}
ret = gpiod_direction_input(ctrl->panel_hpd_gpio);
if (ret) {
pr_err("%s: Set direction for hpd failed, %d\n", __func__, ret);
return ret;
}
ctrl->panel_en_gpio = devm_gpiod_get(dev, "panel-en");
ctrl->panel_en_gpio = devm_gpiod_get(dev, "panel-en", GPIOD_OUT_LOW);
if (IS_ERR(ctrl->panel_en_gpio)) {
ret = PTR_ERR(ctrl->panel_en_gpio);
ctrl->panel_en_gpio = NULL;
@ -395,13 +389,6 @@ static int edp_gpio_config(struct edp_ctrl *ctrl)
return ret;
}
ret = gpiod_direction_output(ctrl->panel_en_gpio, 0);
if (ret) {
pr_err("%s: Set direction for panel_en failed, %d\n",
__func__, ret);
return ret;
}
DBG("gpio on");
return 0;

View File

@ -22,7 +22,9 @@
void hdmi_set_mode(struct hdmi *hdmi, bool power_on)
{
uint32_t ctrl = 0;
unsigned long flags;
spin_lock_irqsave(&hdmi->reg_lock, flags);
if (power_on) {
ctrl |= HDMI_CTRL_ENABLE;
if (!hdmi->hdmi_mode) {
@ -37,6 +39,7 @@ void hdmi_set_mode(struct hdmi *hdmi, bool power_on)
}
hdmi_write(hdmi, REG_HDMI_CTRL, ctrl);
spin_unlock_irqrestore(&hdmi->reg_lock, flags);
DBG("HDMI Core: %s, HDMI_CTRL=0x%08x",
power_on ? "Enable" : "Disable", ctrl);
}
@ -51,6 +54,10 @@ static irqreturn_t hdmi_irq(int irq, void *dev_id)
/* Process DDC: */
hdmi_i2c_irq(hdmi->i2c);
/* Process HDCP: */
if (hdmi->hdcp_ctrl)
hdmi_hdcp_irq(hdmi->hdcp_ctrl);
/* TODO audio.. */
return IRQ_HANDLED;
@ -60,6 +67,15 @@ static void hdmi_destroy(struct hdmi *hdmi)
{
struct hdmi_phy *phy = hdmi->phy;
/*
* at this point, hpd has been disabled,
* after flush workq, it's safe to deinit hdcp
*/
if (hdmi->workq) {
flush_workqueue(hdmi->workq);
destroy_workqueue(hdmi->workq);
}
hdmi_hdcp_destroy(hdmi);
if (phy)
phy->funcs->destroy(phy);
@ -77,6 +93,7 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
{
struct hdmi_platform_config *config = pdev->dev.platform_data;
struct hdmi *hdmi = NULL;
struct resource *res;
int i, ret;
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
@ -87,18 +104,18 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
hdmi->pdev = pdev;
hdmi->config = config;
spin_lock_init(&hdmi->reg_lock);
/* not sure about which phy maps to which msm.. probably I miss some */
if (config->phy_init)
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(&pdev->dev, "failed to load phy: %d\n", ret);
hdmi->phy = NULL;
goto fail;
if (IS_ERR(hdmi->phy)) {
ret = PTR_ERR(hdmi->phy);
dev_err(&pdev->dev, "failed to load phy: %d\n", ret);
hdmi->phy = NULL;
goto fail;
}
}
hdmi->mmio = msm_ioremap(pdev, config->mmio_name, "HDMI");
@ -107,6 +124,18 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
goto fail;
}
/* HDCP needs physical address of hdmi register */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
config->mmio_name);
hdmi->mmio_phy_addr = res->start;
hdmi->qfprom_mmio = msm_ioremap(pdev,
config->qfprom_mmio_name, "HDMI_QFPROM");
if (IS_ERR(hdmi->qfprom_mmio)) {
dev_info(&pdev->dev, "can't find qfprom resource\n");
hdmi->qfprom_mmio = NULL;
}
hdmi->hpd_regs = devm_kzalloc(&pdev->dev, sizeof(hdmi->hpd_regs[0]) *
config->hpd_reg_cnt, GFP_KERNEL);
if (!hdmi->hpd_regs) {
@ -189,6 +218,8 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
hdmi->pwr_clks[i] = clk;
}
hdmi->workq = alloc_ordered_workqueue("msm_hdmi", 0);
hdmi->i2c = hdmi_i2c_init(hdmi);
if (IS_ERR(hdmi->i2c)) {
ret = PTR_ERR(hdmi->i2c);
@ -197,6 +228,12 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
goto fail;
}
hdmi->hdcp_ctrl = hdmi_hdcp_init(hdmi);
if (IS_ERR(hdmi->hdcp_ctrl)) {
dev_warn(&pdev->dev, "failed to init hdcp: disabled\n");
hdmi->hdcp_ctrl = NULL;
}
return hdmi;
fail:
@ -310,7 +347,7 @@ static const char *pwr_clk_names_8x74[] = {"extp_clk", "alt_iface_clk"};
static const char *hpd_clk_names_8x74[] = {"iface_clk", "core_clk", "mdp_core_clk"};
static unsigned long hpd_clk_freq_8x74[] = {0, 19200000, 0};
static struct hdmi_platform_config hdmi_tx_8074_config = {
static struct hdmi_platform_config hdmi_tx_8974_config = {
.phy_init = hdmi_phy_8x74_init,
HDMI_CFG(pwr_reg, 8x74),
HDMI_CFG(hpd_reg, 8x74),
@ -330,9 +367,21 @@ static struct hdmi_platform_config hdmi_tx_8084_config = {
.hpd_freq = hpd_clk_freq_8x74,
};
static const char *hpd_reg_names_8x94[] = {};
static struct hdmi_platform_config hdmi_tx_8994_config = {
.phy_init = NULL, /* nothing to do for this HDMI PHY 20nm */
HDMI_CFG(pwr_reg, 8x74),
HDMI_CFG(hpd_reg, 8x94),
HDMI_CFG(pwr_clk, 8x74),
HDMI_CFG(hpd_clk, 8x74),
.hpd_freq = hpd_clk_freq_8x74,
};
static const struct of_device_id dt_match[] = {
{ .compatible = "qcom,hdmi-tx-8994", .data = &hdmi_tx_8994_config },
{ .compatible = "qcom,hdmi-tx-8084", .data = &hdmi_tx_8084_config },
{ .compatible = "qcom,hdmi-tx-8074", .data = &hdmi_tx_8074_config },
{ .compatible = "qcom,hdmi-tx-8974", .data = &hdmi_tx_8974_config },
{ .compatible = "qcom,hdmi-tx-8960", .data = &hdmi_tx_8960_config },
{ .compatible = "qcom,hdmi-tx-8660", .data = &hdmi_tx_8660_config },
{}
@ -347,8 +396,7 @@ static int get_gpio(struct device *dev, struct device_node *of_node, const char
snprintf(name2, sizeof(name2), "%s-gpio", name);
gpio = of_get_named_gpio(of_node, name2, 0);
if (gpio < 0) {
dev_err(dev, "failed to get gpio: %s (%d)\n",
name, gpio);
DBG("failed to get gpio: %s (%d)", name, gpio);
gpio = -1;
}
}
@ -376,6 +424,7 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
}
hdmi_cfg->mmio_name = "core_physical";
hdmi_cfg->qfprom_mmio_name = "qfprom_physical";
hdmi_cfg->ddc_clk_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-ddc-clk");
hdmi_cfg->ddc_data_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-ddc-data");
hdmi_cfg->hpd_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-hpd");
@ -391,7 +440,6 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
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;
@ -404,7 +452,6 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
} 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;
@ -419,7 +466,6 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
"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;
@ -430,6 +476,9 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
config.mux_en_gpio = -1;
config.mux_sel_gpio = -1;
}
config.mmio_name = "hdmi_msm_hdmi_addr";
config.qfprom_mmio_name = "hdmi_msm_qfprom_addr";
hdmi_cfg = &config;
#endif
dev->platform_data = hdmi_cfg;

View File

@ -37,6 +37,8 @@ struct hdmi_audio {
int rate;
};
struct hdmi_hdcp_ctrl;
struct hdmi {
struct drm_device *dev;
struct platform_device *pdev;
@ -51,6 +53,8 @@ struct hdmi {
unsigned long int pixclock;
void __iomem *mmio;
void __iomem *qfprom_mmio;
phys_addr_t mmio_phy_addr;
struct regulator **hpd_regs;
struct regulator **pwr_regs;
@ -68,12 +72,25 @@ struct hdmi {
bool hdmi_mode; /* are we in hdmi mode? */
int irq;
struct workqueue_struct *workq;
struct hdmi_hdcp_ctrl *hdcp_ctrl;
/*
* spinlock to protect registers shared by different execution
* REG_HDMI_CTRL
* REG_HDMI_DDC_ARBITRATION
* REG_HDMI_HDCP_INT_CTRL
* REG_HDMI_HPD_CTRL
*/
spinlock_t reg_lock;
};
/* platform config data (ie. from DT, or pdata) */
struct hdmi_platform_config {
struct hdmi_phy *(*phy_init)(struct hdmi *hdmi);
const char *mmio_name;
const char *qfprom_mmio_name;
/* regulators that need to be on for hpd: */
const char **hpd_reg_names;
@ -109,6 +126,11 @@ static inline u32 hdmi_read(struct hdmi *hdmi, u32 reg)
return msm_readl(hdmi->mmio + reg);
}
static inline u32 hdmi_qfprom_read(struct hdmi *hdmi, u32 reg)
{
return msm_readl(hdmi->qfprom_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
@ -117,7 +139,6 @@ static inline u32 hdmi_read(struct hdmi *hdmi, u32 reg)
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);
};
@ -163,4 +184,13 @@ 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);
/*
* hdcp
*/
struct hdmi_hdcp_ctrl *hdmi_hdcp_init(struct hdmi *hdmi);
void hdmi_hdcp_destroy(struct hdmi *hdmi);
void hdmi_hdcp_on(struct hdmi_hdcp_ctrl *hdcp_ctrl);
void hdmi_hdcp_off(struct hdmi_hdcp_ctrl *hdcp_ctrl);
void hdmi_hdcp_irq(struct hdmi_hdcp_ctrl *hdcp_ctrl);
#endif /* __HDMI_CONNECTOR_H__ */

View File

@ -8,17 +8,17 @@ 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 ( 676 bytes, from 2014-12-05 15:34:49)
- /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 ( 20915 bytes, from 2015-03-24 22:05:22)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2352 bytes, from 2015-04-12 15:02:42)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 35083 bytes, from 2015-04-12 15:04:03)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 22094 bytes, from 2015-05-12 12:45:23)
- /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 ( 1686 bytes, from 2014-10-31 16:48:57)
- /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 ( 29012 bytes, from 2015-05-12 12:45:23)
- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-12 12:45:23)
- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2576 bytes, from 2015-07-09 22:10:24)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 36021 bytes, from 2015-07-09 22:10:24)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 26057 bytes, from 2015-08-14 21:47:57)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29154 bytes, from 2015-08-10 21:25:43)
- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-20 20:03:14)
Copyright (C) 2013-2015 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
@ -441,6 +441,12 @@ static inline uint32_t HDMI_DDC_REF_REFTIMER(uint32_t val)
#define REG_HDMI_HDCP_SW_LOWER_AKSV 0x00000288
#define REG_HDMI_CEC_CTRL 0x0000028c
#define REG_HDMI_CEC_WR_DATA 0x00000290
#define REG_HDMI_CEC_CEC_RETRANSMIT 0x00000294
#define REG_HDMI_CEC_STATUS 0x00000298
#define REG_HDMI_CEC_INT 0x0000029c

View File

@ -203,7 +203,6 @@ int hdmi_audio_update(struct hdmi *hdmi)
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;

View File

@ -100,8 +100,13 @@ static void hdmi_bridge_pre_enable(struct drm_bridge *bridge)
hdmi_audio_update(hdmi);
}
phy->funcs->powerup(phy, hdmi->pixclock);
if (phy)
phy->funcs->powerup(phy, hdmi->pixclock);
hdmi_set_mode(hdmi, true);
if (hdmi->hdcp_ctrl)
hdmi_hdcp_on(hdmi->hdcp_ctrl);
}
static void hdmi_bridge_enable(struct drm_bridge *bridge)
@ -118,9 +123,14 @@ static void hdmi_bridge_post_disable(struct drm_bridge *bridge)
struct hdmi *hdmi = hdmi_bridge->hdmi;
struct hdmi_phy *phy = hdmi->phy;
if (hdmi->hdcp_ctrl)
hdmi_hdcp_off(hdmi->hdcp_ctrl);
DBG("power down");
hdmi_set_mode(hdmi, false);
phy->funcs->powerdown(phy);
if (phy)
phy->funcs->powerdown(phy);
if (hdmi->power_on) {
power_off(bridge);
@ -142,8 +152,6 @@ static void hdmi_bridge_mode_set(struct drm_bridge *bridge,
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;

View File

@ -28,6 +28,55 @@ struct hdmi_connector {
};
#define to_hdmi_connector(x) container_of(x, struct hdmi_connector, base)
static void hdmi_phy_reset(struct hdmi *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 int gpio_config(struct hdmi *hdmi, bool on)
{
struct device *dev = &hdmi->pdev->dev;
@ -35,21 +84,25 @@ static int gpio_config(struct hdmi *hdmi, bool on)
int ret;
if (on) {
ret = gpio_request(config->ddc_clk_gpio, "HDMI_DDC_CLK");
if (ret) {
dev_err(dev, "'%s'(%d) gpio_request failed: %d\n",
"HDMI_DDC_CLK", config->ddc_clk_gpio, ret);
goto error1;
if (config->ddc_clk_gpio != -1) {
ret = gpio_request(config->ddc_clk_gpio, "HDMI_DDC_CLK");
if (ret) {
dev_err(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);
}
gpio_set_value_cansleep(config->ddc_clk_gpio, 1);
ret = gpio_request(config->ddc_data_gpio, "HDMI_DDC_DATA");
if (ret) {
dev_err(dev, "'%s'(%d) gpio_request failed: %d\n",
"HDMI_DDC_DATA", config->ddc_data_gpio, ret);
goto error2;
if (config->ddc_data_gpio != -1) {
ret = gpio_request(config->ddc_data_gpio, "HDMI_DDC_DATA");
if (ret) {
dev_err(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);
}
gpio_set_value_cansleep(config->ddc_data_gpio, 1);
ret = gpio_request(config->hpd_gpio, "HDMI_HPD");
if (ret) {
@ -94,8 +147,12 @@ static int gpio_config(struct hdmi *hdmi, bool on)
}
DBG("gpio on");
} else {
gpio_free(config->ddc_clk_gpio);
gpio_free(config->ddc_data_gpio);
if (config->ddc_clk_gpio != -1)
gpio_free(config->ddc_clk_gpio);
if (config->ddc_data_gpio != -1)
gpio_free(config->ddc_data_gpio);
gpio_free(config->hpd_gpio);
if (config->mux_en_gpio != -1) {
@ -126,9 +183,11 @@ error5:
error4:
gpio_free(config->hpd_gpio);
error3:
gpio_free(config->ddc_data_gpio);
if (config->ddc_data_gpio != -1)
gpio_free(config->ddc_data_gpio);
error2:
gpio_free(config->ddc_clk_gpio);
if (config->ddc_clk_gpio != -1)
gpio_free(config->ddc_clk_gpio);
error1:
return ret;
}
@ -138,9 +197,9 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
struct hdmi *hdmi = hdmi_connector->hdmi;
const struct hdmi_platform_config *config = hdmi->config;
struct device *dev = &hdmi->pdev->dev;
struct hdmi_phy *phy = hdmi->phy;
uint32_t hpd_ctrl;
int i, ret;
unsigned long flags;
for (i = 0; i < config->hpd_reg_cnt; i++) {
ret = regulator_enable(hdmi->hpd_regs[i]);
@ -181,7 +240,7 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
}
hdmi_set_mode(hdmi, false);
phy->funcs->reset(phy);
hdmi_phy_reset(hdmi);
hdmi_set_mode(hdmi, true);
hdmi_write(hdmi, REG_HDMI_USEC_REFTIMER, 0x0001001b);
@ -192,6 +251,7 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
HDMI_HPD_INT_CTRL_INT_EN);
/* set timeout to 4.1ms (max) for hardware debounce */
spin_lock_irqsave(&hdmi->reg_lock, flags);
hpd_ctrl = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
hpd_ctrl |= HDMI_HPD_CTRL_TIMEOUT(0x1fff);
@ -200,6 +260,7 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
~HDMI_HPD_CTRL_ENABLE & hpd_ctrl);
hdmi_write(hdmi, REG_HDMI_HPD_CTRL,
HDMI_HPD_CTRL_ENABLE | hpd_ctrl);
spin_unlock_irqrestore(&hdmi->reg_lock, flags);
return 0;
@ -250,7 +311,6 @@ hotplug_work(struct work_struct *work)
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;
@ -274,7 +334,7 @@ void hdmi_connector_irq(struct drm_connector *connector)
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);
queue_work(hdmi->workq, &hdmi_connector->hpd_work);
}
}
@ -350,6 +410,7 @@ static int hdmi_connector_get_modes(struct drm_connector *connector)
hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl);
hdmi->hdmi_mode = drm_detect_hdmi_monitor(edid);
drm_mode_connector_update_edid_property(connector, edid);
if (edid) {

File diff suppressed because it is too large Load Diff

View File

@ -426,57 +426,6 @@ static void hdmi_phy_8960_destroy(struct hdmi_phy *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)
{
@ -511,7 +460,6 @@ static void hdmi_phy_8960_powerdown(struct hdmi_phy *phy)
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,
};

View File

@ -29,37 +29,6 @@ static void hdmi_phy_8x60_destroy(struct hdmi_phy *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)
{
@ -182,7 +151,6 @@ static void hdmi_phy_8x60_powerdown(struct hdmi_phy *phy)
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,
};

View File

@ -19,7 +19,6 @@
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)
@ -41,59 +40,6 @@ static void hdmi_phy_8x74_destroy(struct hdmi_phy *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)
{
@ -117,7 +63,6 @@ static void hdmi_phy_8x74_powerdown(struct hdmi_phy *phy)
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,
};
@ -138,8 +83,6 @@ struct hdmi_phy *hdmi_phy_8x74_init(struct hdmi *hdmi)
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");

View File

@ -8,19 +8,19 @@ 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 ( 676 bytes, from 2014-12-05 15:34:49)
- /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 ( 20915 bytes, from 2015-03-24 22:05:22)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2352 bytes, from 2015-04-12 15:02:42)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 35083 bytes, from 2015-04-12 15:04:03)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 22094 bytes, from 2015-05-12 12:45:23)
- /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 ( 1686 bytes, from 2014-10-31 16:48:57)
- /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 ( 29012 bytes, from 2015-05-12 12:45:23)
- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-12 12:45:23)
- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2576 bytes, from 2015-07-09 22:10:24)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 36021 bytes, from 2015-07-09 22:10:24)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 26057 bytes, from 2015-08-14 21:47:57)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29154 bytes, from 2015-08-10 21:25:43)
- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-20 20:03:14)
Copyright (C) 2013 by the following authors:
Copyright (C) 2013-2015 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
Permission is hereby granted, free of charge, to any person obtaining

View File

@ -8,17 +8,17 @@ 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 ( 676 bytes, from 2014-12-05 15:34:49)
- /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 ( 20915 bytes, from 2015-03-24 22:05:22)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2352 bytes, from 2015-04-12 15:02:42)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 35083 bytes, from 2015-04-12 15:04:03)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 22094 bytes, from 2015-05-12 12:45:23)
- /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 ( 1686 bytes, from 2014-10-31 16:48:57)
- /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 ( 29012 bytes, from 2015-05-12 12:45:23)
- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-12 12:45:23)
- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2576 bytes, from 2015-07-09 22:10:24)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 36021 bytes, from 2015-07-09 22:10:24)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 26057 bytes, from 2015-08-14 21:47:57)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29154 bytes, from 2015-08-10 21:25:43)
- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-20 20:03:14)
Copyright (C) 2013-2015 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)

View File

@ -682,7 +682,5 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs);
plane->crtc = crtc;
mdp4_plane_install_properties(plane, &crtc->base);
return crtc;
}

View File

@ -19,8 +19,11 @@
#include "msm_drv.h"
#include "mdp4_kms.h"
void mdp4_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask)
void mdp4_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
uint32_t old_irqmask)
{
mdp4_write(to_mdp4_kms(mdp_kms), REG_MDP4_INTR_CLEAR,
irqmask ^ (irqmask & old_irqmask));
mdp4_write(to_mdp4_kms(mdp_kms), REG_MDP4_INTR_ENABLE, irqmask);
}
@ -68,9 +71,10 @@ irqreturn_t mdp4_irq(struct msm_kms *kms)
struct drm_device *dev = mdp4_kms->dev;
struct msm_drm_private *priv = dev->dev_private;
unsigned int id;
uint32_t status;
uint32_t status, enable;
status = mdp4_read(mdp4_kms, REG_MDP4_INTR_STATUS);
enable = mdp4_read(mdp4_kms, REG_MDP4_INTR_ENABLE);
status = mdp4_read(mdp4_kms, REG_MDP4_INTR_STATUS) & enable;
mdp4_write(mdp4_kms, REG_MDP4_INTR_CLEAR, status);
VERB("status=%08x", status);
@ -86,13 +90,22 @@ irqreturn_t mdp4_irq(struct msm_kms *kms)
int mdp4_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
{
struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
mdp4_enable(mdp4_kms);
mdp_update_vblank_mask(to_mdp_kms(kms),
mdp4_crtc_vblank(crtc), true);
mdp4_disable(mdp4_kms);
return 0;
}
void mdp4_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
{
struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
mdp4_enable(mdp4_kms);
mdp_update_vblank_mask(to_mdp_kms(kms),
mdp4_crtc_vblank(crtc), false);
mdp4_disable(mdp4_kms);
}

View File

@ -241,22 +241,37 @@ int mdp4_enable(struct mdp4_kms *mdp4_kms)
}
#ifdef CONFIG_OF
static struct drm_panel *detect_panel(struct drm_device *dev, const char *name)
static struct drm_panel *detect_panel(struct drm_device *dev)
{
struct device_node *n;
struct device_node *endpoint, *panel_node;
struct device_node *np = dev->dev->of_node;
struct drm_panel *panel = NULL;
n = of_parse_phandle(dev->dev->of_node, name, 0);
if (n) {
panel = of_drm_find_panel(n);
if (!panel)
panel = ERR_PTR(-EPROBE_DEFER);
endpoint = of_graph_get_next_endpoint(np, NULL);
if (!endpoint) {
dev_err(dev->dev, "no valid endpoint\n");
return ERR_PTR(-ENODEV);
}
panel_node = of_graph_get_remote_port_parent(endpoint);
if (!panel_node) {
dev_err(dev->dev, "no valid panel node\n");
of_node_put(endpoint);
return ERR_PTR(-ENODEV);
}
of_node_put(endpoint);
panel = of_drm_find_panel(panel_node);
if (!panel) {
of_node_put(panel_node);
return ERR_PTR(-EPROBE_DEFER);
}
return panel;
}
#else
static struct drm_panel *detect_panel(struct drm_device *dev, const char *name)
static struct drm_panel *detect_panel(struct drm_device *dev)
{
// ??? maybe use a module param to specify which panel is attached?
}
@ -294,7 +309,7 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
* Setup the LCDC/LVDS path: RGB2 -> DMA_P -> LCDC -> LVDS:
*/
panel = detect_panel(dev, "qcom,lvds-panel");
panel = detect_panel(dev);
if (IS_ERR(panel)) {
ret = PTR_ERR(panel);
dev_err(dev->dev, "failed to detect LVDS panel: %d\n", ret);
@ -527,6 +542,11 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
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;
return kms;
fail:

View File

@ -167,7 +167,8 @@ static inline uint32_t mixercfg(uint32_t mixer_cfg, int mixer,
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_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
uint32_t old_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);
@ -175,29 +176,24 @@ 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 bool pipe_supports_yuv(enum mdp4_pipe pipe)
static inline uint32_t mdp4_pipe_caps(enum mdp4_pipe pipe)
{
switch (pipe) {
case VG1:
case VG2:
case VG3:
case VG4:
return true;
return MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC;
case RGB1:
case RGB2:
case RGB3:
return MDP_PIPE_CAP_SCALE;
default:
return false;
return 0;
}
}
static inline
uint32_t mdp4_get_formats(enum mdp4_pipe pipe_id, uint32_t *pixel_formats,
uint32_t max_formats)
{
return mdp_get_formats(pixel_formats, max_formats,
!pipe_supports_yuv(pipe_id));
}
void mdp4_plane_install_properties(struct drm_plane *plane,
struct drm_mode_object *obj);
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);

View File

@ -346,8 +346,10 @@ static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder)
mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
if (panel)
if (panel) {
drm_panel_disable(panel);
drm_panel_unprepare(panel);
}
/*
* Wait for a vsync so we know the ENABLE=0 latched before
@ -412,8 +414,10 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder)
if (ret)
dev_err(dev->dev, "failed to enable lcdc_clk: %d\n", ret);
if (panel)
if (panel) {
drm_panel_prepare(panel);
drm_panel_enable(panel);
}
setup_phy(encoder);

View File

@ -26,6 +26,7 @@ struct mdp4_plane {
enum mdp4_pipe pipe;
uint32_t caps;
uint32_t nformats;
uint32_t formats[32];
@ -74,7 +75,7 @@ static void mdp4_plane_destroy(struct drm_plane *plane)
}
/* helper to install properties which are common to planes and crtcs */
void mdp4_plane_install_properties(struct drm_plane *plane,
static void mdp4_plane_install_properties(struct drm_plane *plane,
struct drm_mode_object *obj)
{
// XXX
@ -382,9 +383,11 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev,
mdp4_plane->pipe = pipe_id;
mdp4_plane->name = pipe_names[pipe_id];
mdp4_plane->caps = mdp4_pipe_caps(pipe_id);
mdp4_plane->nformats = mdp4_get_formats(pipe_id, mdp4_plane->formats,
ARRAY_SIZE(mdp4_plane->formats));
mdp4_plane->nformats = mdp_get_formats(mdp4_plane->formats,
ARRAY_SIZE(mdp4_plane->formats),
!pipe_supports_yuv(mdp4_plane->caps));
type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
ret = drm_universal_plane_init(dev, plane, 0xff, &mdp4_plane_funcs,

View File

@ -8,17 +8,17 @@ 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 ( 676 bytes, from 2014-12-05 15:34:49)
- /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 ( 20915 bytes, from 2015-03-24 22:05:22)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2352 bytes, from 2015-04-12 15:02:42)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 35083 bytes, from 2015-04-12 15:04:03)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 22094 bytes, from 2015-05-12 12:45:23)
- /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 ( 1686 bytes, from 2014-10-31 16:48:57)
- /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 ( 29012 bytes, from 2015-05-12 12:45:23)
- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-12 12:45:23)
- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2576 bytes, from 2015-07-09 22:10:24)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 36021 bytes, from 2015-07-09 22:10:24)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 26057 bytes, from 2015-08-14 21:47:57)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29154 bytes, from 2015-08-10 21:25:43)
- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-20 20:03:14)
Copyright (C) 2013-2015 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
@ -381,49 +381,49 @@ static inline uint32_t REG_MDP5_CTL_LAYER(uint32_t i0, uint32_t i1) { return 0x0
static inline uint32_t REG_MDP5_CTL_LAYER_REG(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_CTL(i0) + __offset_LAYER(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)
static inline uint32_t MDP5_CTL_LAYER_REG_VIG0(uint32_t 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)
static inline uint32_t MDP5_CTL_LAYER_REG_VIG1(uint32_t 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)
static inline uint32_t MDP5_CTL_LAYER_REG_VIG2(uint32_t 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)
static inline uint32_t MDP5_CTL_LAYER_REG_RGB0(uint32_t 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)
static inline uint32_t MDP5_CTL_LAYER_REG_RGB1(uint32_t 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)
static inline uint32_t MDP5_CTL_LAYER_REG_RGB2(uint32_t 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)
static inline uint32_t MDP5_CTL_LAYER_REG_DMA0(uint32_t 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)
static inline uint32_t MDP5_CTL_LAYER_REG_DMA1(uint32_t val)
{
return ((val) << MDP5_CTL_LAYER_REG_DMA1__SHIFT) & MDP5_CTL_LAYER_REG_DMA1__MASK;
}
@ -431,13 +431,13 @@ static inline uint32_t MDP5_CTL_LAYER_REG_DMA1(enum mdp_mixer_stage_id val)
#define MDP5_CTL_LAYER_REG_CURSOR_OUT 0x02000000
#define MDP5_CTL_LAYER_REG_VIG3__MASK 0x1c000000
#define MDP5_CTL_LAYER_REG_VIG3__SHIFT 26
static inline uint32_t MDP5_CTL_LAYER_REG_VIG3(enum mdp_mixer_stage_id val)
static inline uint32_t MDP5_CTL_LAYER_REG_VIG3(uint32_t val)
{
return ((val) << MDP5_CTL_LAYER_REG_VIG3__SHIFT) & MDP5_CTL_LAYER_REG_VIG3__MASK;
}
#define MDP5_CTL_LAYER_REG_RGB3__MASK 0xe0000000
#define MDP5_CTL_LAYER_REG_RGB3__SHIFT 29
static inline uint32_t MDP5_CTL_LAYER_REG_RGB3(enum mdp_mixer_stage_id val)
static inline uint32_t MDP5_CTL_LAYER_REG_RGB3(uint32_t val)
{
return ((val) << MDP5_CTL_LAYER_REG_RGB3__SHIFT) & MDP5_CTL_LAYER_REG_RGB3__MASK;
}
@ -499,6 +499,44 @@ static inline uint32_t REG_MDP5_CTL_START(uint32_t i0) { return 0x0000001c + __o
static inline uint32_t REG_MDP5_CTL_PACK_3D(uint32_t i0) { return 0x00000020 + __offset_CTL(i0); }
static inline uint32_t __offset_LAYER_EXT(uint32_t idx)
{
switch (idx) {
case 0: return 0x00000040;
case 1: return 0x00000044;
case 2: return 0x00000048;
case 3: return 0x0000004c;
case 4: return 0x00000050;
case 5: return 0x00000054;
default: return INVALID_IDX(idx);
}
}
static inline uint32_t REG_MDP5_CTL_LAYER_EXT(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_CTL(i0) + __offset_LAYER_EXT(i1); }
static inline uint32_t REG_MDP5_CTL_LAYER_EXT_REG(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_CTL(i0) + __offset_LAYER_EXT(i1); }
#define MDP5_CTL_LAYER_EXT_REG_VIG0_BIT3 0x00000001
#define MDP5_CTL_LAYER_EXT_REG_VIG1_BIT3 0x00000004
#define MDP5_CTL_LAYER_EXT_REG_VIG2_BIT3 0x00000010
#define MDP5_CTL_LAYER_EXT_REG_VIG3_BIT3 0x00000040
#define MDP5_CTL_LAYER_EXT_REG_RGB0_BIT3 0x00000100
#define MDP5_CTL_LAYER_EXT_REG_RGB1_BIT3 0x00000400
#define MDP5_CTL_LAYER_EXT_REG_RGB2_BIT3 0x00001000
#define MDP5_CTL_LAYER_EXT_REG_RGB3_BIT3 0x00004000
#define MDP5_CTL_LAYER_EXT_REG_DMA0_BIT3 0x00010000
#define MDP5_CTL_LAYER_EXT_REG_DMA1_BIT3 0x00040000
#define MDP5_CTL_LAYER_EXT_REG_CURSOR0__MASK 0x00f00000
#define MDP5_CTL_LAYER_EXT_REG_CURSOR0__SHIFT 20
static inline uint32_t MDP5_CTL_LAYER_EXT_REG_CURSOR0(enum mdp_mixer_stage_id val)
{
return ((val) << MDP5_CTL_LAYER_EXT_REG_CURSOR0__SHIFT) & MDP5_CTL_LAYER_EXT_REG_CURSOR0__MASK;
}
#define MDP5_CTL_LAYER_EXT_REG_CURSOR1__MASK 0x3c000000
#define MDP5_CTL_LAYER_EXT_REG_CURSOR1__SHIFT 26
static inline uint32_t MDP5_CTL_LAYER_EXT_REG_CURSOR1(enum mdp_mixer_stage_id val)
{
return ((val) << MDP5_CTL_LAYER_EXT_REG_CURSOR1__SHIFT) & MDP5_CTL_LAYER_EXT_REG_CURSOR1__MASK;
}
static inline uint32_t __offset_PIPE(enum mdp5_pipe idx)
{
switch (idx) {
@ -803,11 +841,11 @@ static inline uint32_t MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(uint32_t val)
}
#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 0x00180000
#define MDP5_PIPE_SRC_FORMAT_NUM_PLANES__SHIFT 19
static inline uint32_t MDP5_PIPE_SRC_FORMAT_NUM_PLANES(enum mdp_fetch_type val)
#define MDP5_PIPE_SRC_FORMAT_FETCH_TYPE__MASK 0x00180000
#define MDP5_PIPE_SRC_FORMAT_FETCH_TYPE__SHIFT 19
static inline uint32_t MDP5_PIPE_SRC_FORMAT_FETCH_TYPE(enum mdp_fetch_type val)
{
return ((val) << MDP5_PIPE_SRC_FORMAT_NUM_PLANES__SHIFT) & MDP5_PIPE_SRC_FORMAT_NUM_PLANES__MASK;
return ((val) << MDP5_PIPE_SRC_FORMAT_FETCH_TYPE__SHIFT) & MDP5_PIPE_SRC_FORMAT_FETCH_TYPE__MASK;
}
#define MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK 0x01800000
#define MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT 23
@ -897,41 +935,41 @@ static inline uint32_t MDP5_PIPE_DECIMATION_HORZ(uint32_t val)
static inline uint32_t REG_MDP5_PIPE_SCALE_CONFIG(enum mdp5_pipe i0) { return 0x00000204 + __offset_PIPE(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)
#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0__MASK 0x00000300
#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0__SHIFT 8
static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(enum mdp5_scale_filter val)
{
return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER__MASK;
return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0__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)
#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0__MASK 0x00000c00
#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0__SHIFT 10
static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(enum mdp5_scale_filter val)
{
return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER__MASK;
return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0__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)
#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2__MASK 0x00003000
#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2__SHIFT 12
static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2(enum mdp5_scale_filter val)
{
return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER__MASK;
return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2__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)
#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2__MASK 0x0000c000
#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2__SHIFT 14
static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2(enum mdp5_scale_filter val)
{
return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER__MASK;
return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2__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)
#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3__MASK 0x00030000
#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3__SHIFT 16
static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(enum mdp5_scale_filter val)
{
return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER__MASK;
return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3__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)
#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3__MASK 0x000c0000
#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3__SHIFT 18
static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(enum mdp5_scale_filter val)
{
return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER__MASK;
return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3__MASK;
}
static inline uint32_t REG_MDP5_PIPE_SCALE_PHASE_STEP_X(enum mdp5_pipe i0) { return 0x00000210 + __offset_PIPE(i0); }
@ -984,9 +1022,22 @@ static inline uint32_t REG_MDP5_LM_BORDER_COLOR_0(uint32_t i0) { return 0x000000
static inline uint32_t REG_MDP5_LM_BORDER_COLOR_1(uint32_t i0) { return 0x00000010 + __offset_LM(i0); }
static inline uint32_t REG_MDP5_LM_BLEND(uint32_t i0, uint32_t i1) { return 0x00000020 + __offset_LM(i0) + 0x30*i1; }
static inline uint32_t __offset_BLEND(uint32_t idx)
{
switch (idx) {
case 0: return 0x00000020;
case 1: return 0x00000050;
case 2: return 0x00000080;
case 3: return 0x000000b0;
case 4: return 0x00000230;
case 5: return 0x00000260;
case 6: return 0x00000290;
default: return INVALID_IDX(idx);
}
}
static inline uint32_t REG_MDP5_LM_BLEND(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_LM(i0) + __offset_BLEND(i1); }
static inline uint32_t REG_MDP5_LM_BLEND_OP_MODE(uint32_t i0, uint32_t i1) { return 0x00000020 + __offset_LM(i0) + 0x30*i1; }
static inline uint32_t REG_MDP5_LM_BLEND_OP_MODE(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_LM(i0) + __offset_BLEND(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)
@ -1008,25 +1059,25 @@ static inline uint32_t MDP5_LM_BLEND_OP_MODE_BG_ALPHA(enum mdp_alpha_type val)
#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 0x00000024 + __offset_LM(i0) + 0x30*i1; }
static inline uint32_t REG_MDP5_LM_BLEND_FG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00000004 + __offset_LM(i0) + __offset_BLEND(i1); }
static inline uint32_t REG_MDP5_LM_BLEND_BG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00000028 + __offset_LM(i0) + 0x30*i1; }
static inline uint32_t REG_MDP5_LM_BLEND_BG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00000008 + __offset_LM(i0) + __offset_BLEND(i1); }
static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_LOW0(uint32_t i0, uint32_t i1) { return 0x0000002c + __offset_LM(i0) + 0x30*i1; }
static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_LOW0(uint32_t i0, uint32_t i1) { return 0x0000000c + __offset_LM(i0) + __offset_BLEND(i1); }
static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_LOW1(uint32_t i0, uint32_t i1) { return 0x00000030 + __offset_LM(i0) + 0x30*i1; }
static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_LOW1(uint32_t i0, uint32_t i1) { return 0x00000010 + __offset_LM(i0) + __offset_BLEND(i1); }
static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_HIGH0(uint32_t i0, uint32_t i1) { return 0x00000034 + __offset_LM(i0) + 0x30*i1; }
static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_HIGH0(uint32_t i0, uint32_t i1) { return 0x00000014 + __offset_LM(i0) + __offset_BLEND(i1); }
static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00000038 + __offset_LM(i0) + 0x30*i1; }
static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00000018 + __offset_LM(i0) + __offset_BLEND(i1); }
static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_LOW0(uint32_t i0, uint32_t i1) { return 0x0000003c + __offset_LM(i0) + 0x30*i1; }
static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_LOW0(uint32_t i0, uint32_t i1) { return 0x0000001c + __offset_LM(i0) + __offset_BLEND(i1); }
static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_LOW1(uint32_t i0, uint32_t i1) { return 0x00000040 + __offset_LM(i0) + 0x30*i1; }
static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_LOW1(uint32_t i0, uint32_t i1) { return 0x00000020 + __offset_LM(i0) + __offset_BLEND(i1); }
static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH0(uint32_t i0, uint32_t i1) { return 0x00000044 + __offset_LM(i0) + 0x30*i1; }
static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH0(uint32_t i0, uint32_t i1) { return 0x00000024 + __offset_LM(i0) + __offset_BLEND(i1); }
static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00000048 + __offset_LM(i0) + 0x30*i1; }
static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00000028 + __offset_LM(i0) + __offset_BLEND(i1); }
static inline uint32_t REG_MDP5_LM_CURSOR_IMG_SIZE(uint32_t i0) { return 0x000000e0 + __offset_LM(i0); }
#define MDP5_LM_CURSOR_IMG_SIZE_SRC_W__MASK 0x0000ffff
@ -1260,6 +1311,13 @@ static inline uint32_t REG_MDP5_PP_FBC_LOSSY_MODE(uint32_t i0) { return 0x000000
static inline uint32_t __offset_WB(uint32_t idx)
{
switch (idx) {
#if 0 /* TEMPORARY until patch that adds wb.base[] is merged */
case 0: return (mdp5_cfg->wb.base[0]);
case 1: return (mdp5_cfg->wb.base[1]);
case 2: return (mdp5_cfg->wb.base[2]);
case 3: return (mdp5_cfg->wb.base[3]);
case 4: return (mdp5_cfg->wb.base[4]);
#endif
default: return INVALID_IDX(idx);
}
}

View File

@ -22,7 +22,76 @@ struct mdp5_cfg_handler {
/* mdp5_cfg must be exposed (used in mdp5.xml.h) */
const struct mdp5_cfg_hw *mdp5_cfg = NULL;
const struct mdp5_cfg_hw msm8x74_config = {
const struct mdp5_cfg_hw msm8x74v1_config = {
.name = "msm8x74v1",
.mdp = {
.count = 1,
.base = { 0x00100 },
},
.smp = {
.mmb_count = 22,
.mmb_size = 4096,
.clients = {
[SSPP_VIG0] = 1, [SSPP_VIG1] = 4, [SSPP_VIG2] = 7,
[SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
[SSPP_RGB0] = 16, [SSPP_RGB1] = 17, [SSPP_RGB2] = 18,
},
},
.ctl = {
.count = 5,
.base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 },
.flush_hw_mask = 0x0003ffff,
},
.pipe_vig = {
.count = 3,
.base = { 0x01200, 0x01600, 0x01a00 },
.caps = MDP_PIPE_CAP_HFLIP |
MDP_PIPE_CAP_VFLIP |
MDP_PIPE_CAP_SCALE |
MDP_PIPE_CAP_CSC |
0,
},
.pipe_rgb = {
.count = 3,
.base = { 0x01e00, 0x02200, 0x02600 },
.caps = MDP_PIPE_CAP_HFLIP |
MDP_PIPE_CAP_VFLIP |
MDP_PIPE_CAP_SCALE |
0,
},
.pipe_dma = {
.count = 2,
.base = { 0x02a00, 0x02e00 },
.caps = MDP_PIPE_CAP_HFLIP |
MDP_PIPE_CAP_VFLIP |
0,
},
.lm = {
.count = 5,
.base = { 0x03200, 0x03600, 0x03a00, 0x03e00, 0x04200 },
.nb_stages = 5,
},
.dspp = {
.count = 3,
.base = { 0x04600, 0x04a00, 0x04e00 },
},
.pp = {
.count = 3,
.base = { 0x21b00, 0x21c00, 0x21d00 },
},
.intf = {
.base = { 0x21100, 0x21300, 0x21500, 0x21700 },
.connect = {
[0] = INTF_eDP,
[1] = INTF_DSI,
[2] = INTF_DSI,
[3] = INTF_HDMI,
},
},
.max_clk = 200000000,
};
const struct mdp5_cfg_hw msm8x74v2_config = {
.name = "msm8x74",
.mdp = {
.count = 1,
@ -45,19 +114,27 @@ const struct mdp5_cfg_hw msm8x74_config = {
.pipe_vig = {
.count = 3,
.base = { 0x01200, 0x01600, 0x01a00 },
.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC |
MDP_PIPE_CAP_DECIMATION,
},
.pipe_rgb = {
.count = 3,
.base = { 0x01e00, 0x02200, 0x02600 },
.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION,
},
.pipe_dma = {
.count = 2,
.base = { 0x02a00, 0x02e00 },
.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP,
},
.lm = {
.count = 5,
.base = { 0x03200, 0x03600, 0x03a00, 0x03e00, 0x04200 },
.nb_stages = 5,
.max_width = 2048,
.max_height = 0xFFFF,
},
.dspp = {
.count = 3,
@ -65,7 +142,7 @@ const struct mdp5_cfg_hw msm8x74_config = {
},
.ad = {
.count = 2,
.base = { 0x13100, 0x13300 }, /* NOTE: no ad in v1.0 */
.base = { 0x13100, 0x13300 },
},
.pp = {
.count = 3,
@ -113,19 +190,27 @@ const struct mdp5_cfg_hw apq8084_config = {
.pipe_vig = {
.count = 4,
.base = { 0x01200, 0x01600, 0x01a00, 0x01e00 },
.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC |
MDP_PIPE_CAP_DECIMATION,
},
.pipe_rgb = {
.count = 4,
.base = { 0x02200, 0x02600, 0x02a00, 0x02e00 },
.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION,
},
.pipe_dma = {
.count = 2,
.base = { 0x03200, 0x03600 },
.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP,
},
.lm = {
.count = 6,
.base = { 0x03a00, 0x03e00, 0x04200, 0x04600, 0x04a00, 0x04e00 },
.nb_stages = 5,
.max_width = 2048,
.max_height = 0xFFFF,
},
.dspp = {
.count = 4,
@ -174,19 +259,27 @@ const struct mdp5_cfg_hw msm8x16_config = {
.pipe_vig = {
.count = 1,
.base = { 0x05000 },
.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC |
MDP_PIPE_CAP_DECIMATION,
},
.pipe_rgb = {
.count = 2,
.base = { 0x15000, 0x17000 },
.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION,
},
.pipe_dma = {
.count = 1,
.base = { 0x25000 },
.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP,
},
.lm = {
.count = 2, /* LM0 and LM3 */
.base = { 0x45000, 0x48000 },
.nb_stages = 5,
.max_width = 2048,
.max_height = 0xFFFF,
},
.dspp = {
.count = 1,
@ -203,13 +296,90 @@ const struct mdp5_cfg_hw msm8x16_config = {
.max_clk = 320000000,
};
static const struct mdp5_cfg_handler cfg_handlers[] = {
{ .revision = 0, .config = { .hw = &msm8x74_config } },
{ .revision = 2, .config = { .hw = &msm8x74_config } },
{ .revision = 3, .config = { .hw = &apq8084_config } },
{ .revision = 6, .config = { .hw = &msm8x16_config } },
const struct mdp5_cfg_hw msm8x94_config = {
.name = "msm8x94",
.mdp = {
.count = 1,
.base = { 0x01000 },
},
.smp = {
.mmb_count = 44,
.mmb_size = 8192,
.clients = {
[SSPP_VIG0] = 1, [SSPP_VIG1] = 4,
[SSPP_VIG2] = 7, [SSPP_VIG3] = 19,
[SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
[SSPP_RGB0] = 16, [SSPP_RGB1] = 17,
[SSPP_RGB2] = 18, [SSPP_RGB3] = 22,
},
.reserved_state[0] = GENMASK(23, 0), /* first 24 MMBs */
.reserved = {
[1] = 1, [4] = 1, [7] = 1, [19] = 1,
[16] = 5, [17] = 5, [18] = 5, [22] = 5,
},
},
.ctl = {
.count = 5,
.base = { 0x02000, 0x02200, 0x02400, 0x02600, 0x02800 },
.flush_hw_mask = 0xf0ffffff,
},
.pipe_vig = {
.count = 4,
.base = { 0x05000, 0x07000, 0x09000, 0x0b000 },
.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC |
MDP_PIPE_CAP_DECIMATION,
},
.pipe_rgb = {
.count = 4,
.base = { 0x15000, 0x17000, 0x19000, 0x1b000 },
.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION,
},
.pipe_dma = {
.count = 2,
.base = { 0x25000, 0x27000 },
.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP,
},
.lm = {
.count = 6,
.base = { 0x45000, 0x46000, 0x47000, 0x48000, 0x49000, 0x4a000 },
.nb_stages = 8,
.max_width = 2048,
.max_height = 0xFFFF,
},
.dspp = {
.count = 4,
.base = { 0x55000, 0x57000, 0x59000, 0x5b000 },
},
.ad = {
.count = 3,
.base = { 0x79000, 0x79800, 0x7a000 },
},
.pp = {
.count = 4,
.base = { 0x71000, 0x71800, 0x72000, 0x72800 },
},
.intf = {
.base = { 0x6b000, 0x6b800, 0x6c000, 0x6c800, 0x6d000 },
.connect = {
[0] = INTF_DISABLED,
[1] = INTF_DSI,
[2] = INTF_DSI,
[3] = INTF_HDMI,
},
},
.max_clk = 320000000,
};
static const struct mdp5_cfg_handler cfg_handlers[] = {
{ .revision = 0, .config = { .hw = &msm8x74v1_config } },
{ .revision = 2, .config = { .hw = &msm8x74v2_config } },
{ .revision = 3, .config = { .hw = &apq8084_config } },
{ .revision = 6, .config = { .hw = &msm8x16_config } },
{ .revision = 9, .config = { .hw = &msm8x94_config } },
};
static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev);

View File

@ -42,6 +42,13 @@ struct mdp5_sub_block {
struct mdp5_lm_block {
MDP5_SUB_BLOCK_DEFINITION;
uint32_t nb_stages; /* number of stages per blender */
uint32_t max_width; /* Maximum output resolution */
uint32_t max_height;
};
struct mdp5_pipe_block {
MDP5_SUB_BLOCK_DEFINITION;
uint32_t caps; /* pipe capabilities */
};
struct mdp5_ctl_block {
@ -70,9 +77,9 @@ struct mdp5_cfg_hw {
struct mdp5_sub_block mdp;
struct mdp5_smp_block smp;
struct mdp5_ctl_block ctl;
struct mdp5_sub_block pipe_vig;
struct mdp5_sub_block pipe_rgb;
struct mdp5_sub_block pipe_dma;
struct mdp5_pipe_block pipe_vig;
struct mdp5_pipe_block pipe_rgb;
struct mdp5_pipe_block pipe_dma;
struct mdp5_lm_block lm;
struct mdp5_sub_block dspp;
struct mdp5_sub_block ad;

View File

@ -21,6 +21,8 @@ struct mdp5_cmd_encoder {
struct mdp5_interface intf;
bool enabled;
uint32_t bsc;
struct mdp5_ctl *ctl;
};
#define to_mdp5_cmd_encoder(x) container_of(x, struct mdp5_cmd_encoder, base)
@ -210,13 +212,14 @@ static void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
mode->vsync_end, mode->vtotal,
mode->type, mode->flags);
pingpong_tearcheck_setup(encoder, mode);
mdp5_crtc_set_intf(encoder->crtc, &mdp5_cmd_enc->intf);
mdp5_crtc_set_pipeline(encoder->crtc, &mdp5_cmd_enc->intf,
mdp5_cmd_enc->ctl);
}
static void mdp5_cmd_encoder_disable(struct drm_encoder *encoder)
{
struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc);
struct mdp5_ctl *ctl = mdp5_cmd_enc->ctl;
struct mdp5_interface *intf = &mdp5_cmd_enc->intf;
if (WARN_ON(!mdp5_cmd_enc->enabled))
@ -235,7 +238,7 @@ static void mdp5_cmd_encoder_disable(struct drm_encoder *encoder)
static void mdp5_cmd_encoder_enable(struct drm_encoder *encoder)
{
struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc);
struct mdp5_ctl *ctl = mdp5_cmd_enc->ctl;
struct mdp5_interface *intf = &mdp5_cmd_enc->intf;
if (WARN_ON(mdp5_cmd_enc->enabled))
@ -300,7 +303,7 @@ int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
/* initialize command mode encoder */
struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
struct mdp5_interface *intf)
struct mdp5_interface *intf, struct mdp5_ctl *ctl)
{
struct drm_encoder *encoder = NULL;
struct mdp5_cmd_encoder *mdp5_cmd_enc;
@ -320,6 +323,7 @@ struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
memcpy(&mdp5_cmd_enc->intf, intf, sizeof(mdp5_cmd_enc->intf));
encoder = &mdp5_cmd_enc->base;
mdp5_cmd_enc->ctl = ctl;
drm_encoder_init(dev, encoder, &mdp5_cmd_encoder_funcs,
DRM_MODE_ENCODER_DSI);

View File

@ -160,8 +160,7 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
if (mdp5_crtc->ctl && !crtc->state->enable) {
/* set STAGE_UNUSED for all layers */
mdp5_ctl_blend(mdp5_crtc->ctl, mdp5_crtc->lm, 0x00000000);
mdp5_ctl_release(mdp5_crtc->ctl);
mdp5_ctl_blend(mdp5_crtc->ctl, NULL, 0, 0);
mdp5_crtc->ctl = NULL;
}
}
@ -196,13 +195,9 @@ static bool mdp5_crtc_mode_fixup(struct drm_crtc *crtc,
/*
* blend_setup() - blend all the planes of a CRTC
*
* When border is enabled, the border color will ALWAYS be the base layer.
* Therefore, the first plane (private RGB pipe) will start at STAGE0.
* If disabled, the first plane starts at STAGE_BASE.
*
* Note:
* Border is not enabled here because the private plane is exactly
* the CRTC resolution.
* If no base layer is available, border will be enabled as the base layer.
* Otherwise all layers will be blended based on their stage calculated
* in mdp5_crtc_atomic_check.
*/
static void blend_setup(struct drm_crtc *crtc)
{
@ -210,9 +205,14 @@ static void blend_setup(struct drm_crtc *crtc)
struct mdp5_kms *mdp5_kms = get_kms(crtc);
struct drm_plane *plane;
const struct mdp5_cfg_hw *hw_cfg;
uint32_t lm = mdp5_crtc->lm, blend_cfg = 0;
struct mdp5_plane_state *pstate, *pstates[STAGE_MAX + 1] = {NULL};
const struct mdp_format *format;
uint32_t lm = mdp5_crtc->lm;
uint32_t blend_op, fg_alpha, bg_alpha, ctl_blend_flags = 0;
unsigned long flags;
#define blender(stage) ((stage) - STAGE_BASE)
uint8_t stage[STAGE_MAX + 1];
int i, plane_cnt = 0;
#define blender(stage) ((stage) - STAGE0)
hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
@ -222,33 +222,73 @@ static void blend_setup(struct drm_crtc *crtc)
if (!mdp5_crtc->ctl)
goto out;
/* Collect all plane information */
drm_atomic_crtc_for_each_plane(plane, crtc) {
enum mdp_mixer_stage_id stage =
to_mdp5_plane_state(plane->state)->stage;
/*
* Note: This cannot happen with current implementation but
* we need to check this condition once z property is added
*/
BUG_ON(stage > hw_cfg->lm.nb_stages);
/* LM */
mdp5_write(mdp5_kms,
REG_MDP5_LM_BLEND_OP_MODE(lm, blender(stage)),
MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_CONST) |
MDP5_LM_BLEND_OP_MODE_BG_ALPHA(BG_CONST));
mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_FG_ALPHA(lm,
blender(stage)), 0xff);
mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(lm,
blender(stage)), 0x00);
/* CTL */
blend_cfg |= mdp_ctl_blend_mask(mdp5_plane_pipe(plane), stage);
DBG("%s: blending pipe %s on stage=%d", mdp5_crtc->name,
pipe2name(mdp5_plane_pipe(plane)), stage);
pstate = to_mdp5_plane_state(plane->state);
pstates[pstate->stage] = pstate;
stage[pstate->stage] = mdp5_plane_pipe(plane);
plane_cnt++;
}
DBG("%s: lm%d: blend config = 0x%08x", mdp5_crtc->name, lm, blend_cfg);
mdp5_ctl_blend(mdp5_crtc->ctl, lm, blend_cfg);
/*
* If there is no base layer, enable border color.
* Although it's not possbile in current blend logic,
* put it here as a reminder.
*/
if (!pstates[STAGE_BASE] && plane_cnt) {
ctl_blend_flags |= MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT;
DBG("Border Color is enabled");
}
/* The reset for blending */
for (i = STAGE0; i <= STAGE_MAX; i++) {
if (!pstates[i])
continue;
format = to_mdp_format(
msm_framebuffer_format(pstates[i]->base.fb));
plane = pstates[i]->base.plane;
blend_op = MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_CONST) |
MDP5_LM_BLEND_OP_MODE_BG_ALPHA(BG_CONST);
fg_alpha = pstates[i]->alpha;
bg_alpha = 0xFF - pstates[i]->alpha;
DBG("Stage %d fg_alpha %x bg_alpha %x", i, fg_alpha, bg_alpha);
if (format->alpha_enable && pstates[i]->premultiplied) {
blend_op = MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_CONST) |
MDP5_LM_BLEND_OP_MODE_BG_ALPHA(FG_PIXEL);
if (fg_alpha != 0xff) {
bg_alpha = fg_alpha;
blend_op |=
MDP5_LM_BLEND_OP_MODE_BG_MOD_ALPHA |
MDP5_LM_BLEND_OP_MODE_BG_INV_MOD_ALPHA;
} else {
blend_op |= MDP5_LM_BLEND_OP_MODE_BG_INV_ALPHA;
}
} else if (format->alpha_enable) {
blend_op = MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_PIXEL) |
MDP5_LM_BLEND_OP_MODE_BG_ALPHA(FG_PIXEL);
if (fg_alpha != 0xff) {
bg_alpha = fg_alpha;
blend_op |=
MDP5_LM_BLEND_OP_MODE_FG_MOD_ALPHA |
MDP5_LM_BLEND_OP_MODE_FG_INV_MOD_ALPHA |
MDP5_LM_BLEND_OP_MODE_BG_MOD_ALPHA |
MDP5_LM_BLEND_OP_MODE_BG_INV_MOD_ALPHA;
} else {
blend_op |= MDP5_LM_BLEND_OP_MODE_BG_INV_ALPHA;
}
}
mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_OP_MODE(lm,
blender(i)), blend_op);
mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_FG_ALPHA(lm,
blender(i)), fg_alpha);
mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(lm,
blender(i)), bg_alpha);
}
mdp5_ctl_blend(mdp5_crtc->ctl, stage, plane_cnt, ctl_blend_flags);
out:
spin_unlock_irqrestore(&mdp5_crtc->lm_lock, flags);
@ -339,25 +379,19 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
struct mdp5_kms *mdp5_kms = get_kms(crtc);
struct drm_plane *plane;
struct drm_device *dev = crtc->dev;
struct plane_state pstates[STAGE3 + 1];
struct plane_state pstates[STAGE_MAX + 1];
const struct mdp5_cfg_hw *hw_cfg;
int cnt = 0, i;
DBG("%s: check", mdp5_crtc->name);
/* request a free CTL, if none is already allocated for this CRTC */
if (state->enable && !mdp5_crtc->ctl) {
mdp5_crtc->ctl = mdp5_ctlm_request(mdp5_kms->ctlm, crtc);
if (WARN_ON(!mdp5_crtc->ctl))
return -EINVAL;
}
/* verify that there are not too many planes attached to crtc
* and that we don't have conflicting mixer stages:
*/
hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
drm_atomic_crtc_state_for_each_plane(plane, state) {
struct drm_plane_state *pstate;
if (cnt >= ARRAY_SIZE(pstates)) {
if (cnt >= (hw_cfg->lm.nb_stages)) {
dev_err(dev->dev, "too many planes!\n");
return -EINVAL;
}
@ -369,13 +403,13 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
*/
if (!pstate)
pstate = plane->state;
pstates[cnt].plane = plane;
pstates[cnt].state = to_mdp5_plane_state(pstate);
cnt++;
}
/* assign a stage based on sorted zpos property */
sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL);
for (i = 0; i < cnt; i++) {
@ -693,8 +727,8 @@ void mdp5_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file)
complete_flip(crtc, file);
}
/* set interface for routing crtc->encoder: */
void mdp5_crtc_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf)
void mdp5_crtc_set_pipeline(struct drm_crtc *crtc,
struct mdp5_interface *intf, struct mdp5_ctl *ctl)
{
struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
struct mdp5_kms *mdp5_kms = get_kms(crtc);
@ -717,7 +751,8 @@ void mdp5_crtc_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf)
mdp_irq_update(&mdp5_kms->base);
mdp5_ctl_set_intf(mdp5_crtc->ctl, intf);
mdp5_crtc->ctl = ctl;
mdp5_ctl_set_pipeline(ctl, intf, lm);
}
int mdp5_crtc_get_lm(struct drm_crtc *crtc)
@ -726,12 +761,6 @@ int mdp5_crtc_get_lm(struct drm_crtc *crtc)
return WARN_ON(!crtc) ? -EINVAL : mdp5_crtc->lm;
}
struct mdp5_ctl *mdp5_crtc_get_ctl(struct drm_crtc *crtc)
{
struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
return WARN_ON(!crtc) ? NULL : mdp5_crtc->ctl;
}
void mdp5_crtc_wait_for_commit_done(struct drm_crtc *crtc)
{
struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
@ -776,7 +805,5 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs);
plane->crtc = crtc;
mdp5_plane_install_properties(plane, &crtc->base);
return crtc;
}

View File

@ -17,7 +17,7 @@
/*
* CTL - MDP Control Pool Manager
*
* Controls are shared between all CRTCs.
* Controls are shared between all display interfaces.
*
* They are intended to be used for data path configuration.
* The top level register programming describes the complete data path for
@ -27,12 +27,11 @@
*
* In certain use cases (high-resolution dual pipe), one single CTL can be
* shared across multiple CRTCs.
*
* Because the number of CTLs can be less than the number of CRTCs,
* CTLs are dynamically allocated from a pool of CTLs, only once a CRTC is
* requested by the client (in mdp5_crtc_mode_set()).
*/
#define CTL_STAT_BUSY 0x1
#define CTL_STAT_BOOKED 0x2
struct op_mode {
struct mdp5_interface intf;
@ -46,8 +45,8 @@ struct mdp5_ctl {
u32 id;
int lm;
/* whether this CTL has been allocated or not: */
bool busy;
/* CTL status bitmask */
u32 status;
/* Operation Mode Configuration for the Pipeline */
struct op_mode pipeline;
@ -61,7 +60,10 @@ struct mdp5_ctl {
bool cursor_on;
struct drm_crtc *crtc;
/* True if the current CTL has FLUSH bits pending for single FLUSH. */
bool flush_pending;
struct mdp5_ctl *pair; /* Paired CTL to be flushed together */
};
struct mdp5_ctl_manager {
@ -74,6 +76,10 @@ struct mdp5_ctl_manager {
/* to filter out non-present bits in the current hardware config */
u32 flush_hw_mask;
/* status for single FLUSH */
bool single_flush_supported;
u32 single_flush_pending_mask;
/* pool of CTLs + lock to protect resource allocation (ctls[i].busy) */
spinlock_t pool_lock;
struct mdp5_ctl ctls[MAX_CTL];
@ -168,11 +174,21 @@ static void set_ctl_op(struct mdp5_ctl *ctl, struct mdp5_interface *intf)
spin_unlock_irqrestore(&ctl->hw_lock, flags);
}
int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, struct mdp5_interface *intf)
int mdp5_ctl_set_pipeline(struct mdp5_ctl *ctl,
struct mdp5_interface *intf, int lm)
{
struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
struct mdp5_kms *mdp5_kms = get_kms(ctl_mgr);
if (unlikely(WARN_ON(intf->num != ctl->pipeline.intf.num))) {
dev_err(mdp5_kms->dev->dev,
"CTL %d is allocated by INTF %d, but used by INTF %d\n",
ctl->id, ctl->pipeline.intf.num, intf->num);
return -EINVAL;
}
ctl->lm = lm;
memcpy(&ctl->pipeline.intf, intf, sizeof(*intf));
ctl->pipeline.start_mask = mdp_ctl_flush_mask_lm(ctl->lm) |
@ -287,29 +303,85 @@ int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, int cursor_id, bool enable)
blend_cfg &= ~MDP5_CTL_LAYER_REG_CURSOR_OUT;
ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, lm), blend_cfg);
ctl->cursor_on = enable;
spin_unlock_irqrestore(&ctl->hw_lock, flags);
ctl->pending_ctl_trigger = mdp_ctl_flush_mask_cursor(cursor_id);
ctl->cursor_on = enable;
return 0;
}
int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg)
static u32 mdp_ctl_blend_mask(enum mdp5_pipe pipe,
enum mdp_mixer_stage_id stage)
{
switch (pipe) {
case SSPP_VIG0: return MDP5_CTL_LAYER_REG_VIG0(stage);
case SSPP_VIG1: return MDP5_CTL_LAYER_REG_VIG1(stage);
case SSPP_VIG2: return MDP5_CTL_LAYER_REG_VIG2(stage);
case SSPP_RGB0: return MDP5_CTL_LAYER_REG_RGB0(stage);
case SSPP_RGB1: return MDP5_CTL_LAYER_REG_RGB1(stage);
case SSPP_RGB2: return MDP5_CTL_LAYER_REG_RGB2(stage);
case SSPP_DMA0: return MDP5_CTL_LAYER_REG_DMA0(stage);
case SSPP_DMA1: return MDP5_CTL_LAYER_REG_DMA1(stage);
case SSPP_VIG3: return MDP5_CTL_LAYER_REG_VIG3(stage);
case SSPP_RGB3: return MDP5_CTL_LAYER_REG_RGB3(stage);
default: return 0;
}
}
static u32 mdp_ctl_blend_ext_mask(enum mdp5_pipe pipe,
enum mdp_mixer_stage_id stage)
{
if (stage < STAGE6)
return 0;
switch (pipe) {
case SSPP_VIG0: return MDP5_CTL_LAYER_EXT_REG_VIG0_BIT3;
case SSPP_VIG1: return MDP5_CTL_LAYER_EXT_REG_VIG1_BIT3;
case SSPP_VIG2: return MDP5_CTL_LAYER_EXT_REG_VIG2_BIT3;
case SSPP_RGB0: return MDP5_CTL_LAYER_EXT_REG_RGB0_BIT3;
case SSPP_RGB1: return MDP5_CTL_LAYER_EXT_REG_RGB1_BIT3;
case SSPP_RGB2: return MDP5_CTL_LAYER_EXT_REG_RGB2_BIT3;
case SSPP_DMA0: return MDP5_CTL_LAYER_EXT_REG_DMA0_BIT3;
case SSPP_DMA1: return MDP5_CTL_LAYER_EXT_REG_DMA1_BIT3;
case SSPP_VIG3: return MDP5_CTL_LAYER_EXT_REG_VIG3_BIT3;
case SSPP_RGB3: return MDP5_CTL_LAYER_EXT_REG_RGB3_BIT3;
default: return 0;
}
}
int mdp5_ctl_blend(struct mdp5_ctl *ctl, u8 *stage, u32 stage_cnt,
u32 ctl_blend_op_flags)
{
unsigned long flags;
u32 blend_cfg = 0, blend_ext_cfg = 0;
int i, start_stage;
if (ctl->cursor_on)
blend_cfg |= MDP5_CTL_LAYER_REG_CURSOR_OUT;
else
blend_cfg &= ~MDP5_CTL_LAYER_REG_CURSOR_OUT;
if (ctl_blend_op_flags & MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT) {
start_stage = STAGE0;
blend_cfg |= MDP5_CTL_LAYER_REG_BORDER_COLOR;
} else {
start_stage = STAGE_BASE;
}
for (i = start_stage; i < start_stage + stage_cnt; i++) {
blend_cfg |= mdp_ctl_blend_mask(stage[i], i);
blend_ext_cfg |= mdp_ctl_blend_ext_mask(stage[i], i);
}
spin_lock_irqsave(&ctl->hw_lock, flags);
ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, lm), blend_cfg);
if (ctl->cursor_on)
blend_cfg |= MDP5_CTL_LAYER_REG_CURSOR_OUT;
ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, ctl->lm), blend_cfg);
ctl_write(ctl, REG_MDP5_CTL_LAYER_EXT_REG(ctl->id, ctl->lm), blend_ext_cfg);
spin_unlock_irqrestore(&ctl->hw_lock, flags);
ctl->pending_ctl_trigger = mdp_ctl_flush_mask_lm(lm);
ctl->pending_ctl_trigger = mdp_ctl_flush_mask_lm(ctl->lm);
DBG("lm%d: blend config = 0x%08x. ext_cfg = 0x%08x", ctl->lm,
blend_cfg, blend_ext_cfg);
return 0;
}
@ -379,6 +451,31 @@ static u32 fix_sw_flush(struct mdp5_ctl *ctl, u32 flush_mask)
return sw_mask;
}
static void fix_for_single_flush(struct mdp5_ctl *ctl, u32 *flush_mask,
u32 *flush_id)
{
struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
if (ctl->pair) {
DBG("CTL %d FLUSH pending mask %x", ctl->id, *flush_mask);
ctl->flush_pending = true;
ctl_mgr->single_flush_pending_mask |= (*flush_mask);
*flush_mask = 0;
if (ctl->pair->flush_pending) {
*flush_id = min_t(u32, ctl->id, ctl->pair->id);
*flush_mask = ctl_mgr->single_flush_pending_mask;
ctl->flush_pending = false;
ctl->pair->flush_pending = false;
ctl_mgr->single_flush_pending_mask = 0;
DBG("Single FLUSH mask %x,ID %d", *flush_mask,
*flush_id);
}
}
}
/**
* mdp5_ctl_commit() - Register Flush
*
@ -400,6 +497,8 @@ u32 mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask)
struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
struct op_mode *pipeline = &ctl->pipeline;
unsigned long flags;
u32 flush_id = ctl->id;
u32 curr_ctl_flush_mask;
pipeline->start_mask &= ~flush_mask;
@ -415,9 +514,13 @@ u32 mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask)
flush_mask &= ctl_mgr->flush_hw_mask;
curr_ctl_flush_mask = flush_mask;
fix_for_single_flush(ctl, &flush_mask, &flush_id);
if (flush_mask) {
spin_lock_irqsave(&ctl->hw_lock, flags);
ctl_write(ctl, REG_MDP5_CTL_FLUSH(ctl->id), flush_mask);
ctl_write(ctl, REG_MDP5_CTL_FLUSH(flush_id), flush_mask);
spin_unlock_irqrestore(&ctl->hw_lock, flags);
}
@ -426,7 +529,7 @@ u32 mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask)
refill_start_mask(ctl);
}
return flush_mask;
return curr_ctl_flush_mask;
}
u32 mdp5_ctl_get_commit_status(struct mdp5_ctl *ctl)
@ -434,59 +537,85 @@ u32 mdp5_ctl_get_commit_status(struct mdp5_ctl *ctl)
return ctl_read(ctl, REG_MDP5_CTL_FLUSH(ctl->id));
}
void mdp5_ctl_release(struct mdp5_ctl *ctl)
{
struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
unsigned long flags;
if (unlikely(WARN_ON(ctl->id >= MAX_CTL) || !ctl->busy)) {
dev_err(ctl_mgr->dev->dev, "CTL %d in bad state (%d)",
ctl->id, ctl->busy);
return;
}
spin_lock_irqsave(&ctl_mgr->pool_lock, flags);
ctl->busy = false;
spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags);
DBG("CTL %d released", ctl->id);
}
int mdp5_ctl_get_ctl_id(struct mdp5_ctl *ctl)
{
return WARN_ON(!ctl) ? -EINVAL : ctl->id;
}
/*
* mdp5_ctl_request() - CTL dynamic allocation
* mdp5_ctl_pair() - Associate 2 booked CTLs for single FLUSH
*/
int mdp5_ctl_pair(struct mdp5_ctl *ctlx, struct mdp5_ctl *ctly, bool enable)
{
struct mdp5_ctl_manager *ctl_mgr = ctlx->ctlm;
struct mdp5_kms *mdp5_kms = get_kms(ctl_mgr);
/* do nothing silently if hw doesn't support */
if (!ctl_mgr->single_flush_supported)
return 0;
if (!enable) {
ctlx->pair = NULL;
ctly->pair = NULL;
mdp5_write(mdp5_kms, REG_MDP5_MDP_SPARE_0(0), 0);
return 0;
} else if ((ctlx->pair != NULL) || (ctly->pair != NULL)) {
dev_err(ctl_mgr->dev->dev, "CTLs already paired\n");
return -EINVAL;
} else if (!(ctlx->status & ctly->status & CTL_STAT_BOOKED)) {
dev_err(ctl_mgr->dev->dev, "Only pair booked CTLs\n");
return -EINVAL;
}
ctlx->pair = ctly;
ctly->pair = ctlx;
mdp5_write(mdp5_kms, REG_MDP5_MDP_SPARE_0(0),
MDP5_MDP_SPARE_0_SPLIT_DPL_SINGLE_FLUSH_EN);
return 0;
}
/*
* mdp5_ctl_request() - CTL allocation
*
* Note: Current implementation considers that we can only have one CRTC per CTL
* Try to return booked CTL for @intf_num is 1 or 2, unbooked for other INTFs.
* If no CTL is available in preferred category, allocate from the other one.
*
* @return first free CTL
* @return fail if no CTL is available.
*/
struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctl_mgr,
struct drm_crtc *crtc)
int intf_num)
{
struct mdp5_ctl *ctl = NULL;
const u32 checkm = CTL_STAT_BUSY | CTL_STAT_BOOKED;
u32 match = ((intf_num == 1) || (intf_num == 2)) ? CTL_STAT_BOOKED : 0;
unsigned long flags;
int c;
spin_lock_irqsave(&ctl_mgr->pool_lock, flags);
/* search the preferred */
for (c = 0; c < ctl_mgr->nctl; c++)
if (!ctl_mgr->ctls[c].busy)
break;
if ((ctl_mgr->ctls[c].status & checkm) == match)
goto found;
if (unlikely(c >= ctl_mgr->nctl)) {
dev_err(ctl_mgr->dev->dev, "No more CTL available!");
goto unlock;
}
dev_warn(ctl_mgr->dev->dev,
"fall back to the other CTL category for INTF %d!\n", intf_num);
match ^= CTL_STAT_BOOKED;
for (c = 0; c < ctl_mgr->nctl; c++)
if ((ctl_mgr->ctls[c].status & checkm) == match)
goto found;
dev_err(ctl_mgr->dev->dev, "No more CTL available!");
goto unlock;
found:
ctl = &ctl_mgr->ctls[c];
ctl->lm = mdp5_crtc_get_lm(crtc);
ctl->crtc = crtc;
ctl->busy = true;
ctl->pipeline.intf.num = intf_num;
ctl->lm = -1;
ctl->status |= CTL_STAT_BUSY;
ctl->pending_ctl_trigger = 0;
DBG("CTL %d allocated", ctl->id);
@ -515,9 +644,11 @@ void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctl_mgr)
}
struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
void __iomem *mmio_base, const struct mdp5_cfg_hw *hw_cfg)
void __iomem *mmio_base, struct mdp5_cfg_handler *cfg_hnd)
{
struct mdp5_ctl_manager *ctl_mgr;
const struct mdp5_cfg_hw *hw_cfg = mdp5_cfg_get_hw_config(cfg_hnd);
int rev = mdp5_cfg_get_hw_rev(cfg_hnd);
const struct mdp5_ctl_block *ctl_cfg = &hw_cfg->ctl;
unsigned long flags;
int c, ret;
@ -551,14 +682,28 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
if (WARN_ON(!ctl_cfg->base[c])) {
dev_err(dev->dev, "CTL_%d: base is null!\n", c);
ret = -EINVAL;
spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags);
goto fail;
}
ctl->ctlm = ctl_mgr;
ctl->id = c;
ctl->reg_offset = ctl_cfg->base[c];
ctl->busy = false;
ctl->status = 0;
spin_lock_init(&ctl->hw_lock);
}
/*
* In Dual DSI case, CTL0 and CTL1 are always assigned to two DSI
* interfaces to support single FLUSH feature (Flush CTL0 and CTL1 when
* only write into CTL0's FLUSH register) to keep two DSI pipes in sync.
* Single FLUSH is supported from hw rev v3.0.
*/
if (rev >= 3) {
ctl_mgr->single_flush_supported = true;
/* Reserve CTL0/1 for INTF1/2 */
ctl_mgr->ctls[0].status |= CTL_STAT_BOOKED;
ctl_mgr->ctls[1].status |= CTL_STAT_BOOKED;
}
spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags);
DBG("Pool of %d CTLs created.", ctl_mgr->nctl);

View File

@ -23,7 +23,7 @@
*/
struct mdp5_ctl_manager;
struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
void __iomem *mmio_base, const struct mdp5_cfg_hw *hw_cfg);
void __iomem *mmio_base, struct mdp5_cfg_handler *cfg_hnd);
void mdp5_ctlm_hw_reset(struct mdp5_ctl_manager *ctlm);
void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctlm);
@ -32,49 +32,32 @@ void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctlm);
* mdp5_ctl_request(ctlm, ...) returns a ctl (CTL resource) handler,
* which is then used to call the other mdp5_ctl_*(ctl, ...) functions.
*/
struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctlm, struct drm_crtc *crtc);
struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctlm, int intf_num);
int mdp5_ctl_get_ctl_id(struct mdp5_ctl *ctl);
struct mdp5_interface;
int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, struct mdp5_interface *intf);
int mdp5_ctl_set_pipeline(struct mdp5_ctl *ctl, struct mdp5_interface *intf,
int lm);
int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl, bool enabled);
int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, int cursor_id, bool enable);
/*
* blend_cfg (LM blender config):
*
* The function below allows the caller of mdp5_ctl_blend() to specify how pipes
* are being blended according to their stage (z-order), through @blend_cfg arg.
*/
static inline u32 mdp_ctl_blend_mask(enum mdp5_pipe pipe,
enum mdp_mixer_stage_id stage)
{
switch (pipe) {
case SSPP_VIG0: return MDP5_CTL_LAYER_REG_VIG0(stage);
case SSPP_VIG1: return MDP5_CTL_LAYER_REG_VIG1(stage);
case SSPP_VIG2: return MDP5_CTL_LAYER_REG_VIG2(stage);
case SSPP_RGB0: return MDP5_CTL_LAYER_REG_RGB0(stage);
case SSPP_RGB1: return MDP5_CTL_LAYER_REG_RGB1(stage);
case SSPP_RGB2: return MDP5_CTL_LAYER_REG_RGB2(stage);
case SSPP_DMA0: return MDP5_CTL_LAYER_REG_DMA0(stage);
case SSPP_DMA1: return MDP5_CTL_LAYER_REG_DMA1(stage);
case SSPP_VIG3: return MDP5_CTL_LAYER_REG_VIG3(stage);
case SSPP_RGB3: return MDP5_CTL_LAYER_REG_RGB3(stage);
default: return 0;
}
}
int mdp5_ctl_pair(struct mdp5_ctl *ctlx, struct mdp5_ctl *ctly, bool enable);
/*
* mdp5_ctl_blend() - Blend multiple layers on a Layer Mixer (LM)
*
* @blend_cfg: see LM blender config definition below
* @stage: array to contain the pipe num for each stage
* @stage_cnt: valid stage number in stage array
* @ctl_blend_op_flags: blender operation mode flags
*
* Note:
* CTL registers need to be flushed after calling this function
* (call mdp5_ctl_commit() with mdp_ctl_flush_mask_ctl() mask)
*/
int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg);
#define MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT BIT(0)
int mdp5_ctl_blend(struct mdp5_ctl *ctl, u8 *stage, u32 stage_cnt,
u32 ctl_blend_op_flags);
/**
* mdp_ctl_flush_mask...() - Register FLUSH masks
@ -91,8 +74,6 @@ u32 mdp_ctl_flush_mask_encoder(struct mdp5_interface *intf);
u32 mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask);
u32 mdp5_ctl_get_commit_status(struct mdp5_ctl *ctl);
void mdp5_ctl_release(struct mdp5_ctl *ctl);
#endif /* __MDP5_CTL_H__ */

View File

@ -27,6 +27,8 @@ struct mdp5_encoder {
spinlock_t intf_lock; /* protect REG_MDP5_INTF_* registers */
bool enabled;
uint32_t bsc;
struct mdp5_ctl *ctl;
};
#define to_mdp5_encoder(x) container_of(x, struct mdp5_encoder, base)
@ -222,14 +224,15 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
mdp5_crtc_set_intf(encoder->crtc, &mdp5_encoder->intf);
mdp5_crtc_set_pipeline(encoder->crtc, &mdp5_encoder->intf,
mdp5_encoder->ctl);
}
static void mdp5_encoder_disable(struct drm_encoder *encoder)
{
struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
struct mdp5_kms *mdp5_kms = get_kms(encoder);
struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc);
struct mdp5_ctl *ctl = mdp5_encoder->ctl;
int lm = mdp5_crtc_get_lm(encoder->crtc);
struct mdp5_interface *intf = &mdp5_encoder->intf;
int intfn = mdp5_encoder->intf.num;
@ -264,7 +267,7 @@ static void mdp5_encoder_enable(struct drm_encoder *encoder)
{
struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
struct mdp5_kms *mdp5_kms = get_kms(encoder);
struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc);
struct mdp5_ctl *ctl = mdp5_encoder->ctl;
struct mdp5_interface *intf = &mdp5_encoder->intf;
int intfn = mdp5_encoder->intf.num;
unsigned long flags;
@ -294,6 +297,7 @@ int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
struct drm_encoder *slave_encoder)
{
struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
struct mdp5_encoder *mdp5_slave_enc = to_mdp5_encoder(slave_encoder);
struct mdp5_kms *mdp5_kms;
int intf_num;
u32 data = 0;
@ -316,12 +320,13 @@ int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
/* Make sure clocks are on when connectors calling this function. */
mdp5_enable(mdp5_kms);
mdp5_write(mdp5_kms, REG_MDP5_MDP_SPARE_0(0),
MDP5_MDP_SPARE_0_SPLIT_DPL_SINGLE_FLUSH_EN);
/* Dumb Panel, Sync mode */
mdp5_write(mdp5_kms, REG_MDP5_MDP_SPLIT_DPL_UPPER(0), 0);
mdp5_write(mdp5_kms, REG_MDP5_MDP_SPLIT_DPL_LOWER(0), data);
mdp5_write(mdp5_kms, REG_MDP5_MDP_SPLIT_DPL_EN(0), 1);
mdp5_ctl_pair(mdp5_encoder->ctl, mdp5_slave_enc->ctl, true);
mdp5_disable(mdp5_kms);
return 0;
@ -329,7 +334,7 @@ int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
/* initialize encoder */
struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
struct mdp5_interface *intf)
struct mdp5_interface *intf, struct mdp5_ctl *ctl)
{
struct drm_encoder *encoder = NULL;
struct mdp5_encoder *mdp5_encoder;
@ -345,6 +350,7 @@ struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
memcpy(&mdp5_encoder->intf, intf, sizeof(mdp5_encoder->intf));
encoder = &mdp5_encoder->base;
mdp5_encoder->ctl = ctl;
spin_lock_init(&mdp5_encoder->intf_lock);

View File

@ -21,8 +21,11 @@
#include "msm_drv.h"
#include "mdp5_kms.h"
void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask)
void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
uint32_t old_irqmask)
{
mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_MDP_INTR_CLEAR(0),
irqmask ^ (irqmask & old_irqmask));
mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_MDP_INTR_EN(0), irqmask);
}
@ -71,9 +74,10 @@ static void mdp5_irq_mdp(struct mdp_kms *mdp_kms)
struct drm_device *dev = mdp5_kms->dev;
struct msm_drm_private *priv = dev->dev_private;
unsigned int id;
uint32_t status;
uint32_t status, enable;
status = mdp5_read(mdp5_kms, REG_MDP5_MDP_INTR_STATUS(0));
enable = mdp5_read(mdp5_kms, REG_MDP5_MDP_INTR_EN(0));
status = mdp5_read(mdp5_kms, REG_MDP5_MDP_INTR_STATUS(0)) & enable;
mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_CLEAR(0), status);
VERB("status=%08x", status);
@ -112,15 +116,24 @@ irqreturn_t mdp5_irq(struct msm_kms *kms)
int mdp5_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
{
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
mdp5_enable(mdp5_kms);
mdp_update_vblank_mask(to_mdp_kms(kms),
mdp5_crtc_vblank(crtc), true);
mdp5_disable(mdp5_kms);
return 0;
}
void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
{
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
mdp5_enable(mdp5_kms);
mdp_update_vblank_mask(to_mdp_kms(kms),
mdp5_crtc_vblank(crtc), false);
mdp5_disable(mdp5_kms);
}
/*

View File

@ -177,7 +177,8 @@ int mdp5_disable(struct mdp5_kms *mdp5_kms)
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);
if (mdp5_kms->lut_clk)
clk_disable_unprepare(mdp5_kms->lut_clk);
return 0;
}
@ -189,14 +190,15 @@ int mdp5_enable(struct mdp5_kms *mdp5_kms)
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);
if (mdp5_kms->lut_clk)
clk_prepare_enable(mdp5_kms->lut_clk);
return 0;
}
static struct drm_encoder *construct_encoder(struct mdp5_kms *mdp5_kms,
enum mdp5_intf_type intf_type, int intf_num,
enum mdp5_intf_mode intf_mode)
enum mdp5_intf_mode intf_mode, struct mdp5_ctl *ctl)
{
struct drm_device *dev = mdp5_kms->dev;
struct msm_drm_private *priv = dev->dev_private;
@ -209,9 +211,9 @@ static struct drm_encoder *construct_encoder(struct mdp5_kms *mdp5_kms,
if ((intf_type == INTF_DSI) &&
(intf_mode == MDP5_INTF_DSI_MODE_COMMAND))
encoder = mdp5_cmd_encoder_init(dev, &intf);
encoder = mdp5_cmd_encoder_init(dev, &intf, ctl);
else
encoder = mdp5_encoder_init(dev, &intf);
encoder = mdp5_encoder_init(dev, &intf, ctl);
if (IS_ERR(encoder)) {
dev_err(dev->dev, "failed to construct encoder\n");
@ -249,6 +251,8 @@ static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num)
const struct mdp5_cfg_hw *hw_cfg =
mdp5_cfg_get_hw_config(mdp5_kms->cfg);
enum mdp5_intf_type intf_type = hw_cfg->intf.connect[intf_num];
struct mdp5_ctl_manager *ctlm = mdp5_kms->ctlm;
struct mdp5_ctl *ctl;
struct drm_encoder *encoder;
int ret = 0;
@ -259,8 +263,14 @@ static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num)
if (!priv->edp)
break;
ctl = mdp5_ctlm_request(ctlm, intf_num);
if (!ctl) {
ret = -EINVAL;
break;
}
encoder = construct_encoder(mdp5_kms, INTF_eDP, intf_num,
MDP5_INTF_MODE_NONE);
MDP5_INTF_MODE_NONE, ctl);
if (IS_ERR(encoder)) {
ret = PTR_ERR(encoder);
break;
@ -272,8 +282,14 @@ static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num)
if (!priv->hdmi)
break;
ctl = mdp5_ctlm_request(ctlm, intf_num);
if (!ctl) {
ret = -EINVAL;
break;
}
encoder = construct_encoder(mdp5_kms, INTF_HDMI, intf_num,
MDP5_INTF_MODE_NONE);
MDP5_INTF_MODE_NONE, ctl);
if (IS_ERR(encoder)) {
ret = PTR_ERR(encoder);
break;
@ -298,14 +314,20 @@ static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num)
if (!priv->dsi[dsi_id])
break;
ctl = mdp5_ctlm_request(ctlm, intf_num);
if (!ctl) {
ret = -EINVAL;
break;
}
for (i = 0; i < MSM_DSI_ENCODER_NUM; i++) {
mode = (i == MSM_DSI_CMD_ENCODER_ID) ?
MDP5_INTF_DSI_MODE_COMMAND :
MDP5_INTF_DSI_MODE_VIDEO;
dsi_encs[i] = construct_encoder(mdp5_kms, INTF_DSI,
intf_num, mode);
if (IS_ERR(dsi_encs)) {
ret = PTR_ERR(dsi_encs);
intf_num, mode, ctl);
if (IS_ERR(dsi_encs[i])) {
ret = PTR_ERR(dsi_encs[i]);
break;
}
}
@ -327,9 +349,12 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
static const enum mdp5_pipe crtcs[] = {
SSPP_RGB0, SSPP_RGB1, SSPP_RGB2, SSPP_RGB3,
};
static const enum mdp5_pipe pub_planes[] = {
static const enum mdp5_pipe vig_planes[] = {
SSPP_VIG0, SSPP_VIG1, SSPP_VIG2, SSPP_VIG3,
};
static const enum mdp5_pipe dma_planes[] = {
SSPP_DMA0, SSPP_DMA1,
};
struct drm_device *dev = mdp5_kms->dev;
struct msm_drm_private *priv = dev->dev_private;
const struct mdp5_cfg_hw *hw_cfg;
@ -350,7 +375,7 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
struct drm_crtc *crtc;
plane = mdp5_plane_init(dev, crtcs[i], true,
hw_cfg->pipe_rgb.base[i]);
hw_cfg->pipe_rgb.base[i], hw_cfg->pipe_rgb.caps);
if (IS_ERR(plane)) {
ret = PTR_ERR(plane);
dev_err(dev->dev, "failed to construct plane for %s (%d)\n",
@ -368,16 +393,30 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
priv->crtcs[priv->num_crtcs++] = crtc;
}
/* Construct public planes: */
/* Construct video planes: */
for (i = 0; i < hw_cfg->pipe_vig.count; i++) {
struct drm_plane *plane;
plane = mdp5_plane_init(dev, pub_planes[i], false,
hw_cfg->pipe_vig.base[i]);
plane = mdp5_plane_init(dev, vig_planes[i], false,
hw_cfg->pipe_vig.base[i], hw_cfg->pipe_vig.caps);
if (IS_ERR(plane)) {
ret = PTR_ERR(plane);
dev_err(dev->dev, "failed to construct %s plane: %d\n",
pipe2name(pub_planes[i]), ret);
pipe2name(vig_planes[i]), ret);
goto fail;
}
}
/* DMA planes */
for (i = 0; i < hw_cfg->pipe_dma.count; i++) {
struct drm_plane *plane;
plane = mdp5_plane_init(dev, dma_planes[i], false,
hw_cfg->pipe_dma.base[i], hw_cfg->pipe_dma.caps);
if (IS_ERR(plane)) {
ret = PTR_ERR(plane);
dev_err(dev->dev, "failed to construct %s plane: %d\n",
pipe2name(dma_planes[i]), ret);
goto fail;
}
}
@ -489,7 +528,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
goto fail;
ret = get_clk(pdev, &mdp5_kms->lut_clk, "lut_clk");
if (ret)
goto fail;
DBG("failed to get (optional) lut_clk clock");
ret = get_clk(pdev, &mdp5_kms->vsync_clk, "vsync_clk");
if (ret)
goto fail;
@ -521,7 +560,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
goto fail;
}
mdp5_kms->ctlm = mdp5_ctlm_init(dev, mdp5_kms->mmio, config->hw);
mdp5_kms->ctlm = mdp5_ctlm_init(dev, mdp5_kms->mmio, mdp5_kms->cfg);
if (IS_ERR(mdp5_kms->ctlm)) {
ret = PTR_ERR(mdp5_kms->ctlm);
mdp5_kms->ctlm = NULL;
@ -577,6 +616,11 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
goto fail;
}
dev->mode_config.min_width = 0;
dev->mode_config.min_height = 0;
dev->mode_config.max_width = config->hw->lm.max_width;
dev->mode_config.max_height = config->hw->lm.max_height;
return kms;
fail:

View File

@ -70,18 +70,12 @@ struct mdp5_kms {
struct mdp5_plane_state {
struct drm_plane_state base;
/* "virtual" zpos.. we calculate actual mixer-stage at runtime
* by sorting the attached planes by zpos and then assigning
* mixer stage lowest to highest. Private planes get default
* zpos of zero, and public planes a unique value that is
* greater than zero. This way, things work out if a naive
* userspace assigns planes to a crtc without setting zpos.
*/
int zpos;
/* aligned with property */
uint8_t premultiplied;
uint8_t zpos;
uint8_t alpha;
/* the actual mixer stage, calculated in crtc->atomic_check()
* NOTE: this should move to mdp5_crtc_state, when that exists
*/
/* assigned by crtc blender */
enum mdp_mixer_stage_id stage;
/* some additional transactional status to help us know in the
@ -192,7 +186,8 @@ static inline uint32_t lm2ppdone(int lm)
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_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
uint32_t old_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);
@ -202,60 +197,38 @@ void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
int mdp5_irq_domain_init(struct mdp5_kms *mdp5_kms);
void mdp5_irq_domain_fini(struct mdp5_kms *mdp5_kms);
static inline bool pipe_supports_yuv(enum mdp5_pipe pipe)
{
switch (pipe) {
case SSPP_VIG0:
case SSPP_VIG1:
case SSPP_VIG2:
case SSPP_VIG3:
return true;
default:
return false;
}
}
static inline
uint32_t mdp5_get_formats(enum mdp5_pipe pipe, uint32_t *pixel_formats,
uint32_t max_formats)
{
return mdp_get_formats(pixel_formats, max_formats,
!pipe_supports_yuv(pipe));
}
void mdp5_plane_install_properties(struct drm_plane *plane,
struct drm_mode_object *obj);
uint32_t mdp5_plane_get_flush(struct drm_plane *plane);
void mdp5_plane_complete_flip(struct drm_plane *plane);
void mdp5_plane_complete_commit(struct drm_plane *plane,
struct drm_plane_state *state);
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 reg_offset);
enum mdp5_pipe pipe, bool private_plane,
uint32_t reg_offset, uint32_t caps);
uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc);
int mdp5_crtc_get_lm(struct drm_crtc *crtc);
struct mdp5_ctl *mdp5_crtc_get_ctl(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, struct mdp5_interface *intf);
void mdp5_crtc_set_pipeline(struct drm_crtc *crtc,
struct mdp5_interface *intf, struct mdp5_ctl *ctl);
void mdp5_crtc_wait_for_commit_done(struct drm_crtc *crtc);
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,
struct mdp5_interface *intf);
struct mdp5_interface *intf, struct mdp5_ctl *ctl);
int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
struct drm_encoder *slave_encoder);
#ifdef CONFIG_DRM_MSM_DSI
struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
struct mdp5_interface *intf);
struct mdp5_interface *intf, struct mdp5_ctl *ctl);
int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
struct drm_encoder *slave_encoder);
#else
static inline struct drm_encoder *mdp5_cmd_encoder_init(
struct drm_device *dev, struct mdp5_interface *intf)
static inline struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
struct mdp5_interface *intf, struct mdp5_ctl *ctl)
{
return ERR_PTR(-EINVAL);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014 The Linux Foundation. All rights reserved.
* Copyright (C) 2014-2015 The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
*
@ -26,6 +26,7 @@ struct mdp5_plane {
spinlock_t pipe_lock; /* protect REG_MDP5_PIPE_* registers */
uint32_t reg_offset;
uint32_t caps;
uint32_t flush_mask; /* used to commit pipe registers */
@ -40,6 +41,7 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
unsigned int crtc_w, unsigned int crtc_h,
uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h);
static void set_scanout_locked(struct drm_plane *plane,
struct drm_framebuffer *fb);
@ -64,18 +66,122 @@ static void mdp5_plane_destroy(struct drm_plane *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)
static void mdp5_plane_install_rotation_property(struct drm_device *dev,
struct drm_plane *plane)
{
// XXX
struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
if (!(mdp5_plane->caps & MDP_PIPE_CAP_HFLIP) &&
!(mdp5_plane->caps & MDP_PIPE_CAP_VFLIP))
return;
if (!dev->mode_config.rotation_property)
dev->mode_config.rotation_property =
drm_mode_create_rotation_property(dev,
BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y));
if (dev->mode_config.rotation_property)
drm_object_attach_property(&plane->base,
dev->mode_config.rotation_property,
0);
}
int mdp5_plane_set_property(struct drm_plane *plane,
struct drm_property *property, uint64_t val)
/* helper to install properties which are common to planes and crtcs */
static void mdp5_plane_install_properties(struct drm_plane *plane,
struct drm_mode_object *obj)
{
// XXX
return -EINVAL;
struct drm_device *dev = plane->dev;
struct msm_drm_private *dev_priv = dev->dev_private;
struct drm_property *prop;
#define INSTALL_PROPERTY(name, NAME, init_val, fnc, ...) do { \
prop = dev_priv->plane_property[PLANE_PROP_##NAME]; \
if (!prop) { \
prop = drm_property_##fnc(dev, 0, #name, \
##__VA_ARGS__); \
if (!prop) { \
dev_warn(dev->dev, \
"Create property %s failed\n", \
#name); \
return; \
} \
dev_priv->plane_property[PLANE_PROP_##NAME] = prop; \
} \
drm_object_attach_property(&plane->base, prop, init_val); \
} while (0)
#define INSTALL_RANGE_PROPERTY(name, NAME, min, max, init_val) \
INSTALL_PROPERTY(name, NAME, init_val, \
create_range, min, max)
#define INSTALL_ENUM_PROPERTY(name, NAME, init_val) \
INSTALL_PROPERTY(name, NAME, init_val, \
create_enum, name##_prop_enum_list, \
ARRAY_SIZE(name##_prop_enum_list))
INSTALL_RANGE_PROPERTY(zpos, ZPOS, 1, 255, 1);
mdp5_plane_install_rotation_property(dev, plane);
#undef INSTALL_RANGE_PROPERTY
#undef INSTALL_ENUM_PROPERTY
#undef INSTALL_PROPERTY
}
static int mdp5_plane_atomic_set_property(struct drm_plane *plane,
struct drm_plane_state *state, struct drm_property *property,
uint64_t val)
{
struct drm_device *dev = plane->dev;
struct mdp5_plane_state *pstate;
struct msm_drm_private *dev_priv = dev->dev_private;
int ret = 0;
pstate = to_mdp5_plane_state(state);
#define SET_PROPERTY(name, NAME, type) do { \
if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
pstate->name = (type)val; \
DBG("Set property %s %d", #name, (type)val); \
goto done; \
} \
} while (0)
SET_PROPERTY(zpos, ZPOS, uint8_t);
dev_err(dev->dev, "Invalid property\n");
ret = -EINVAL;
done:
return ret;
#undef SET_PROPERTY
}
static int mdp5_plane_atomic_get_property(struct drm_plane *plane,
const struct drm_plane_state *state,
struct drm_property *property, uint64_t *val)
{
struct drm_device *dev = plane->dev;
struct mdp5_plane_state *pstate;
struct msm_drm_private *dev_priv = dev->dev_private;
int ret = 0;
pstate = to_mdp5_plane_state(state);
#define GET_PROPERTY(name, NAME, type) do { \
if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
*val = pstate->name; \
DBG("Get property %s %lld", #name, *val); \
goto done; \
} \
} while (0)
GET_PROPERTY(zpos, ZPOS, uint8_t);
dev_err(dev->dev, "Invalid property\n");
ret = -EINVAL;
done:
return ret;
#undef SET_PROPERTY
}
static void mdp5_plane_reset(struct drm_plane *plane)
@ -88,11 +194,15 @@ static void mdp5_plane_reset(struct drm_plane *plane)
kfree(to_mdp5_plane_state(plane->state));
mdp5_state = kzalloc(sizeof(*mdp5_state), GFP_KERNEL);
if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
mdp5_state->zpos = 0;
} else {
mdp5_state->zpos = 1 + drm_plane_index(plane);
}
/* assign default blend parameters */
mdp5_state->alpha = 255;
mdp5_state->premultiplied = 0;
if (plane->type == DRM_PLANE_TYPE_PRIMARY)
mdp5_state->zpos = STAGE_BASE;
else
mdp5_state->zpos = STAGE0 + drm_plane_index(plane);
mdp5_state->base.plane = plane;
plane->state = &mdp5_state->base;
@ -131,7 +241,9 @@ static const struct drm_plane_funcs mdp5_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = mdp5_plane_destroy,
.set_property = mdp5_plane_set_property,
.set_property = drm_atomic_helper_plane_set_property,
.atomic_set_property = mdp5_plane_atomic_set_property,
.atomic_get_property = mdp5_plane_atomic_get_property,
.reset = mdp5_plane_reset,
.atomic_duplicate_state = mdp5_plane_duplicate_state,
.atomic_destroy_state = mdp5_plane_destroy_state,
@ -164,10 +276,44 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane,
{
struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
struct drm_plane_state *old_state = plane->state;
const struct mdp_format *format;
bool vflip, hflip;
DBG("%s: check (%d -> %d)", mdp5_plane->name,
plane_enabled(old_state), plane_enabled(state));
if (plane_enabled(state)) {
format = to_mdp_format(msm_framebuffer_format(state->fb));
if (MDP_FORMAT_IS_YUV(format) &&
!pipe_supports_yuv(mdp5_plane->caps)) {
dev_err(plane->dev->dev,
"Pipe doesn't support YUV\n");
return -EINVAL;
}
if (!(mdp5_plane->caps & MDP_PIPE_CAP_SCALE) &&
(((state->src_w >> 16) != state->crtc_w) ||
((state->src_h >> 16) != state->crtc_h))) {
dev_err(plane->dev->dev,
"Pipe doesn't support scaling (%dx%d -> %dx%d)\n",
state->src_w >> 16, state->src_h >> 16,
state->crtc_w, state->crtc_h);
return -EINVAL;
}
hflip = !!(state->rotation & BIT(DRM_REFLECT_X));
vflip = !!(state->rotation & BIT(DRM_REFLECT_Y));
if ((vflip && !(mdp5_plane->caps & MDP_PIPE_CAP_VFLIP)) ||
(hflip && !(mdp5_plane->caps & MDP_PIPE_CAP_HFLIP))) {
dev_err(plane->dev->dev,
"Pipe doesn't support flip\n");
return -EINVAL;
}
}
if (plane_enabled(state) && plane_enabled(old_state)) {
/* we cannot change SMP block configuration during scanout: */
bool full_modeset = false;
@ -346,16 +492,21 @@ static int calc_phase_step(uint32_t src, uint32_t dst, uint32_t *out_phase)
return 0;
}
static int calc_scalex_steps(uint32_t pixel_format, uint32_t src, uint32_t dest,
static int calc_scalex_steps(struct drm_plane *plane,
uint32_t pixel_format, uint32_t src, uint32_t dest,
uint32_t phasex_steps[2])
{
struct mdp5_kms *mdp5_kms = get_kms(plane);
struct device *dev = mdp5_kms->dev->dev;
uint32_t phasex_step;
unsigned int hsub;
int ret;
ret = calc_phase_step(src, dest, &phasex_step);
if (ret)
if (ret) {
dev_err(dev, "X scaling (%d->%d) failed: %d\n", src, dest, ret);
return ret;
}
hsub = drm_format_horz_chroma_subsampling(pixel_format);
@ -365,16 +516,21 @@ static int calc_scalex_steps(uint32_t pixel_format, uint32_t src, uint32_t dest,
return 0;
}
static int calc_scaley_steps(uint32_t pixel_format, uint32_t src, uint32_t dest,
static int calc_scaley_steps(struct drm_plane *plane,
uint32_t pixel_format, uint32_t src, uint32_t dest,
uint32_t phasey_steps[2])
{
struct mdp5_kms *mdp5_kms = get_kms(plane);
struct device *dev = mdp5_kms->dev->dev;
uint32_t phasey_step;
unsigned int vsub;
int ret;
ret = calc_phase_step(src, dest, &phasey_step);
if (ret)
if (ret) {
dev_err(dev, "Y scaling (%d->%d) failed: %d\n", src, dest, ret);
return ret;
}
vsub = drm_format_vert_chroma_subsampling(pixel_format);
@ -384,28 +540,38 @@ static int calc_scaley_steps(uint32_t pixel_format, uint32_t src, uint32_t dest,
return 0;
}
static uint32_t get_scalex_config(uint32_t src, uint32_t dest)
static uint32_t get_scale_config(enum mdp_chroma_samp_type chroma_sample,
uint32_t src, uint32_t dest, bool hor)
{
uint32_t filter;
uint32_t y_filter = (src <= dest) ? SCALE_FILTER_CA : SCALE_FILTER_PCMN;
uint32_t y_a_filter = (src <= dest) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
uint32_t uv_filter = ((src / 2) <= dest) ? /* 2x upsample */
SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
uint32_t value = 0;
filter = (src <= dest) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
if (chroma_sample == CHROMA_420 || chroma_sample == CHROMA_H2V1) {
if (hor)
value = MDP5_PIPE_SCALE_CONFIG_SCALEX_EN |
MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(y_filter) |
MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(y_a_filter) |
MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2(uv_filter);
else
value = MDP5_PIPE_SCALE_CONFIG_SCALEY_EN |
MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(y_filter) |
MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(y_a_filter) |
MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2(uv_filter);
} else if (src != dest) {
if (hor)
value = MDP5_PIPE_SCALE_CONFIG_SCALEX_EN |
MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(y_a_filter) |
MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(y_a_filter);
else
value = MDP5_PIPE_SCALE_CONFIG_SCALEY_EN |
MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(y_a_filter) |
MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(y_a_filter);
}
return MDP5_PIPE_SCALE_CONFIG_SCALEX_EN |
MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(filter) |
MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(filter) |
MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(filter);
}
static uint32_t get_scaley_config(uint32_t src, uint32_t dest)
{
uint32_t filter;
filter = (src <= dest) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
return MDP5_PIPE_SCALE_CONFIG_SCALEY_EN |
MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(filter) |
MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(filter) |
MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(filter);
return value;
}
static int mdp5_plane_mode_set(struct drm_plane *plane,
@ -416,8 +582,8 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
uint32_t src_w, uint32_t src_h)
{
struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
struct drm_plane_state *pstate = plane->state;
struct mdp5_kms *mdp5_kms = get_kms(plane);
struct device *dev = mdp5_kms->dev->dev;
enum mdp5_pipe pipe = mdp5_plane->pipe;
const struct mdp_format *format;
uint32_t nplanes, config = 0;
@ -425,6 +591,7 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
uint32_t phasex_step[2] = {0,}, phasey_step[2] = {0,};
uint32_t hdecm = 0, vdecm = 0;
uint32_t pix_format;
bool vflip, hflip;
unsigned long flags;
int ret;
@ -449,7 +616,7 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
/* Request some memory from the SMP: */
ret = mdp5_smp_request(mdp5_kms->smp,
mdp5_plane->pipe, fb->pixel_format, src_w);
mdp5_plane->pipe, format, src_w, false);
if (ret)
return ret;
@ -461,29 +628,23 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
*/
mdp5_smp_configure(mdp5_kms->smp, pipe);
ret = calc_scalex_steps(plane, pix_format, src_w, crtc_w, phasex_step);
if (ret)
return ret;
ret = calc_scaley_steps(plane, pix_format, src_h, crtc_h, phasey_step);
if (ret)
return ret;
/* TODO calc hdecm, vdecm */
/* SCALE is used to both scale and up-sample chroma components */
config |= get_scale_config(format->chroma_sample, src_w, crtc_w, true);
config |= get_scale_config(format->chroma_sample, src_h, crtc_h, false);
DBG("scale config = %x", config);
if ((src_w != crtc_w) || MDP_FORMAT_IS_YUV(format)) {
/* TODO calc hdecm */
ret = calc_scalex_steps(pix_format, src_w, crtc_w, phasex_step);
if (ret) {
dev_err(dev, "X scaling (%d -> %d) failed: %d\n",
src_w, crtc_w, ret);
return ret;
}
config |= get_scalex_config(src_w, crtc_w);
}
if ((src_h != crtc_h) || MDP_FORMAT_IS_YUV(format)) {
/* TODO calc vdecm */
ret = calc_scaley_steps(pix_format, src_h, crtc_h, phasey_step);
if (ret) {
dev_err(dev, "Y scaling (%d -> %d) failed: %d\n",
src_h, crtc_h, ret);
return ret;
}
config |= get_scaley_config(src_h, crtc_h);
}
hflip = !!(pstate->rotation & BIT(DRM_REFLECT_X));
vflip = !!(pstate->rotation & BIT(DRM_REFLECT_Y));
spin_lock_irqsave(&mdp5_plane->pipe_lock, flags);
@ -516,7 +677,7 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
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(format->fetch_type) |
MDP5_PIPE_SRC_FORMAT_FETCH_TYPE(format->fetch_type) |
MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample));
mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe),
@ -526,29 +687,35 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
MDP5_PIPE_SRC_UNPACK_ELEM3(format->unpack[3]));
mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_OP_MODE(pipe),
(hflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_LR : 0) |
(vflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_UD : 0) |
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[0]);
mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe),
phasey_step[0]);
mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe),
phasex_step[1]);
mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe),
phasey_step[1]);
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), config);
if (mdp5_plane->caps & MDP_PIPE_CAP_SCALE) {
mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe),
phasex_step[0]);
mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe),
phasey_step[0]);
mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe),
phasex_step[1]);
mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe),
phasey_step[1]);
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), config);
}
if (MDP_FORMAT_IS_YUV(format))
csc_enable(mdp5_kms, pipe,
mdp_get_default_csc_cfg(CSC_YUV2RGB));
else
csc_disable(mdp5_kms, pipe);
if (mdp5_plane->caps & MDP_PIPE_CAP_CSC) {
if (MDP_FORMAT_IS_YUV(format))
csc_enable(mdp5_kms, pipe,
mdp_get_default_csc_cfg(CSC_YUV2RGB));
else
csc_disable(mdp5_kms, pipe);
}
set_scanout_locked(plane, fb);
@ -599,7 +766,8 @@ void mdp5_plane_complete_commit(struct drm_plane *plane,
/* initialize plane */
struct drm_plane *mdp5_plane_init(struct drm_device *dev,
enum mdp5_pipe pipe, bool private_plane, uint32_t reg_offset)
enum mdp5_pipe pipe, bool private_plane, uint32_t reg_offset,
uint32_t caps)
{
struct drm_plane *plane = NULL;
struct mdp5_plane *mdp5_plane;
@ -616,9 +784,11 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev,
mdp5_plane->pipe = pipe;
mdp5_plane->name = pipe2name(pipe);
mdp5_plane->caps = caps;
mdp5_plane->nformats = mdp5_get_formats(pipe, mdp5_plane->formats,
ARRAY_SIZE(mdp5_plane->formats));
mdp5_plane->nformats = mdp_get_formats(mdp5_plane->formats,
ARRAY_SIZE(mdp5_plane->formats),
!pipe_supports_yuv(mdp5_plane->caps));
mdp5_plane->flush_mask = mdp_ctl_flush_mask_pipe(pipe);
mdp5_plane->reg_offset = reg_offset;

View File

@ -90,6 +90,8 @@
struct mdp5_smp {
struct drm_device *dev;
const struct mdp5_smp_block *cfg;
int blk_cnt;
int blk_size;
@ -137,14 +139,12 @@ static int smp_request_block(struct mdp5_smp *smp,
u32 cid, int nblks)
{
struct mdp5_kms *mdp5_kms = get_kms(smp);
const struct mdp5_cfg_hw *hw_cfg;
struct mdp5_client_smp_state *ps = &smp->client_state[cid];
int i, ret, avail, cur_nblks, cnt = smp->blk_cnt;
int reserved;
unsigned long flags;
hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
reserved = hw_cfg->smp.reserved[cid];
reserved = smp->cfg->reserved[cid];
spin_lock_irqsave(&smp->state_lock, flags);
@ -209,12 +209,14 @@ static void set_fifo_thresholds(struct mdp5_smp *smp,
* decimated width. Ie. SMP buffering sits downstream of decimation (which
* presumably happens during the dma from scanout buffer).
*/
int mdp5_smp_request(struct mdp5_smp *smp, enum mdp5_pipe pipe, u32 fmt, u32 width)
int mdp5_smp_request(struct mdp5_smp *smp, enum mdp5_pipe pipe,
const struct mdp_format *format, u32 width, bool hdecim)
{
struct mdp5_kms *mdp5_kms = get_kms(smp);
struct drm_device *dev = mdp5_kms->dev;
int rev = mdp5_cfg_get_hw_rev(mdp5_kms->cfg);
int i, hsub, nplanes, nlines, nblks, ret;
u32 fmt = format->base.pixel_format;
nplanes = drm_format_num_planes(fmt);
hsub = drm_format_horz_chroma_subsampling(fmt);
@ -222,6 +224,21 @@ int mdp5_smp_request(struct mdp5_smp *smp, enum mdp5_pipe pipe, u32 fmt, u32 wid
/* different if BWC (compressed framebuffer?) enabled: */
nlines = 2;
/* Newer MDPs have split/packing logic, which fetches sub-sampled
* U and V components (splits them from Y if necessary) and packs
* them together, writes to SMP using a single client.
*/
if ((rev > 0) && (format->chroma_sample > CHROMA_FULL)) {
fmt = DRM_FORMAT_NV24;
nplanes = 2;
/* if decimation is enabled, HW decimates less on the
* sub sampled chroma components
*/
if (hdecim && (hsub > 1))
hsub = 1;
}
for (i = 0, nblks = 0; i < nplanes; i++) {
int n, fetch_stride, cpp;
@ -388,6 +405,7 @@ struct mdp5_smp *mdp5_smp_init(struct drm_device *dev, const struct mdp5_smp_blo
}
smp->dev = dev;
smp->cfg = cfg;
smp->blk_cnt = cfg->mmb_count;
smp->blk_size = cfg->mmb_size;

View File

@ -39,7 +39,8 @@ struct mdp5_smp;
struct mdp5_smp *mdp5_smp_init(struct drm_device *dev, const struct mdp5_smp_block *cfg);
void mdp5_smp_destroy(struct mdp5_smp *smp);
int mdp5_smp_request(struct mdp5_smp *smp, enum mdp5_pipe pipe, u32 fmt, u32 width);
int mdp5_smp_request(struct mdp5_smp *smp, enum mdp5_pipe pipe,
const struct mdp_format *format, u32 width, bool hdecim);
void mdp5_smp_configure(struct mdp5_smp *smp, enum mdp5_pipe pipe);
void mdp5_smp_commit(struct mdp5_smp *smp, enum mdp5_pipe pipe);
void mdp5_smp_release(struct mdp5_smp *smp, enum mdp5_pipe pipe);

View File

@ -8,17 +8,17 @@ 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 ( 676 bytes, from 2014-12-05 15:34:49)
- /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 ( 20915 bytes, from 2015-03-24 22:05:22)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2352 bytes, from 2015-04-12 15:02:42)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 35083 bytes, from 2015-04-12 15:04:03)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 22094 bytes, from 2015-05-12 12:45:23)
- /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 ( 1686 bytes, from 2014-10-31 16:48:57)
- /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 ( 29012 bytes, from 2015-05-12 12:45:23)
- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-12 12:45:23)
- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2576 bytes, from 2015-07-09 22:10:24)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 36021 bytes, from 2015-07-09 22:10:24)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 26057 bytes, from 2015-08-14 21:47:57)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2015-05-20 20:03:14)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2015-05-20 20:03:07)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29154 bytes, from 2015-08-10 21:25:43)
- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-20 20:03:14)
Copyright (C) 2013-2015 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
@ -46,7 +46,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
enum mdp_chroma_samp_type {
CHROMA_RGB = 0,
CHROMA_FULL = 0,
CHROMA_H2V1 = 1,
CHROMA_H1V2 = 2,
CHROMA_420 = 3,
@ -65,6 +65,10 @@ enum mdp_mixer_stage_id {
STAGE1 = 3,
STAGE2 = 4,
STAGE3 = 5,
STAGE4 = 6,
STAGE5 = 7,
STAGE6 = 8,
STAGE_MAX = 8,
};
enum mdp_alpha_type {

View File

@ -71,7 +71,7 @@ static struct csc_cfg csc_convert[CSC_MAX] = {
},
};
#define FMT(name, a, r, g, b, e0, e1, e2, e3, alpha, tight, c, cnt, fp, cs) { \
#define FMT(name, a, r, g, b, e0, e1, e2, e3, alpha, tight, c, cnt, fp, cs, yuv) { \
.base = { .pixel_format = DRM_FORMAT_ ## name }, \
.bpc_a = BPC ## a ## A, \
.bpc_r = BPC ## r, \
@ -83,7 +83,8 @@ static struct csc_cfg csc_convert[CSC_MAX] = {
.cpp = c, \
.unpack_count = cnt, \
.fetch_type = fp, \
.chroma_sample = cs \
.chroma_sample = cs, \
.is_yuv = yuv, \
}
#define BPC0A 0
@ -95,30 +96,49 @@ static struct csc_cfg csc_convert[CSC_MAX] = {
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,
MDP_PLANE_INTERLEAVED, CHROMA_RGB),
MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
FMT(ABGR8888, 8, 8, 8, 8, 2, 0, 1, 3, true, true, 4, 4,
MDP_PLANE_INTERLEAVED, CHROMA_RGB),
MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
FMT(RGBA8888, 8, 8, 8, 8, 3, 1, 0, 2, true, true, 4, 4,
MDP_PLANE_INTERLEAVED, CHROMA_RGB),
MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
FMT(BGRA8888, 8, 8, 8, 8, 3, 2, 0, 1, true, true, 4, 4,
MDP_PLANE_INTERLEAVED, CHROMA_RGB),
MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
FMT(XRGB8888, 8, 8, 8, 8, 1, 0, 2, 3, false, true, 4, 4,
MDP_PLANE_INTERLEAVED, CHROMA_RGB),
MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
FMT(RGB888, 0, 8, 8, 8, 1, 0, 2, 0, false, true, 3, 3,
MDP_PLANE_INTERLEAVED, CHROMA_RGB),
MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
FMT(BGR888, 0, 8, 8, 8, 2, 0, 1, 0, false, true, 3, 3,
MDP_PLANE_INTERLEAVED, CHROMA_RGB),
MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
FMT(RGB565, 0, 5, 6, 5, 1, 0, 2, 0, false, true, 2, 3,
MDP_PLANE_INTERLEAVED, CHROMA_RGB),
MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
FMT(BGR565, 0, 5, 6, 5, 2, 0, 1, 0, false, true, 2, 3,
MDP_PLANE_INTERLEAVED, CHROMA_RGB),
MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
/* --- RGB formats above / YUV formats below this line --- */
/* 2 plane YUV */
FMT(NV12, 0, 8, 8, 8, 1, 2, 0, 0, false, true, 2, 2,
MDP_PLANE_PSEUDO_PLANAR, CHROMA_420),
MDP_PLANE_PSEUDO_PLANAR, CHROMA_420, true),
FMT(NV21, 0, 8, 8, 8, 2, 1, 0, 0, false, true, 2, 2,
MDP_PLANE_PSEUDO_PLANAR, CHROMA_420),
MDP_PLANE_PSEUDO_PLANAR, CHROMA_420, true),
FMT(NV16, 0, 8, 8, 8, 1, 2, 0, 0, false, true, 2, 2,
MDP_PLANE_PSEUDO_PLANAR, CHROMA_H2V1, true),
FMT(NV61, 0, 8, 8, 8, 2, 1, 0, 0, false, true, 2, 2,
MDP_PLANE_PSEUDO_PLANAR, CHROMA_H2V1, true),
/* 1 plane YUV */
FMT(VYUY, 0, 8, 8, 8, 2, 0, 1, 0, false, true, 2, 4,
MDP_PLANE_INTERLEAVED, CHROMA_H2V1, true),
FMT(UYVY, 0, 8, 8, 8, 1, 0, 2, 0, false, true, 2, 4,
MDP_PLANE_INTERLEAVED, CHROMA_H2V1, true),
FMT(YUYV, 0, 8, 8, 8, 0, 1, 0, 2, false, true, 2, 4,
MDP_PLANE_INTERLEAVED, CHROMA_H2V1, true),
FMT(YVYU, 0, 8, 8, 8, 0, 2, 0, 1, false, true, 2, 4,
MDP_PLANE_INTERLEAVED, CHROMA_H2V1, true),
/* 3 plane YUV */
FMT(YUV420, 0, 8, 8, 8, 2, 1, 0, 0, false, true, 1, 1,
MDP_PLANE_PLANAR, CHROMA_420, true),
FMT(YVU420, 0, 8, 8, 8, 1, 2, 0, 0, false, true, 1, 1,
MDP_PLANE_PLANAR, CHROMA_420, true),
};
/*

View File

@ -39,7 +39,8 @@ static void update_irq(struct mdp_kms *mdp_kms)
list_for_each_entry(irq, &mdp_kms->irq_list, node)
irqmask |= irq->irqmask;
mdp_kms->funcs->set_irqmask(mdp_kms, irqmask);
mdp_kms->funcs->set_irqmask(mdp_kms, irqmask, mdp_kms->cur_irq_mask);
mdp_kms->cur_irq_mask = irqmask;
}
/* if an mdp_irq's irqmask has changed, such as when mdp5 crtc<->encoder

View File

@ -30,7 +30,8 @@ struct mdp_kms;
struct mdp_kms_funcs {
struct msm_kms_funcs base;
void (*set_irqmask)(struct mdp_kms *mdp_kms, uint32_t irqmask);
void (*set_irqmask)(struct mdp_kms *mdp_kms, uint32_t irqmask,
uint32_t old_irqmask);
};
struct mdp_kms {
@ -42,6 +43,7 @@ struct mdp_kms {
bool in_irq;
struct list_head irq_list; /* list of mdp4_irq */
uint32_t vblank_mask; /* irq bits set for userspace vblank */
uint32_t cur_irq_mask; /* current irq mask */
};
#define to_mdp_kms(x) container_of(x, struct mdp_kms, base)
@ -90,13 +92,27 @@ struct mdp_format {
uint8_t cpp, unpack_count;
enum mdp_fetch_type fetch_type;
enum mdp_chroma_samp_type chroma_sample;
bool is_yuv;
};
#define to_mdp_format(x) container_of(x, struct mdp_format, base)
#define MDP_FORMAT_IS_YUV(mdp_format) ((mdp_format)->chroma_sample > CHROMA_RGB)
#define MDP_FORMAT_IS_YUV(mdp_format) ((mdp_format)->is_yuv)
uint32_t mdp_get_formats(uint32_t *formats, uint32_t max_formats, bool rgb_only);
const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format);
/* MDP pipe capabilities */
#define MDP_PIPE_CAP_HFLIP BIT(0)
#define MDP_PIPE_CAP_VFLIP BIT(1)
#define MDP_PIPE_CAP_SCALE BIT(2)
#define MDP_PIPE_CAP_CSC BIT(3)
#define MDP_PIPE_CAP_DECIMATION BIT(4)
static inline bool pipe_supports_yuv(uint32_t pipe_caps)
{
return (pipe_caps & MDP_PIPE_CAP_SCALE) &&
(pipe_caps & MDP_PIPE_CAP_CSC);
}
enum csc_type {
CSC_RGB2RGB = 0,
CSC_YUV2RGB,

View File

@ -116,6 +116,65 @@ u32 msm_readl(const void __iomem *addr)
return val;
}
struct vblank_event {
struct list_head node;
int crtc_id;
bool enable;
};
static void vblank_ctrl_worker(struct work_struct *work)
{
struct msm_vblank_ctrl *vbl_ctrl = container_of(work,
struct msm_vblank_ctrl, work);
struct msm_drm_private *priv = container_of(vbl_ctrl,
struct msm_drm_private, vblank_ctrl);
struct msm_kms *kms = priv->kms;
struct vblank_event *vbl_ev, *tmp;
unsigned long flags;
spin_lock_irqsave(&vbl_ctrl->lock, flags);
list_for_each_entry_safe(vbl_ev, tmp, &vbl_ctrl->event_list, node) {
list_del(&vbl_ev->node);
spin_unlock_irqrestore(&vbl_ctrl->lock, flags);
if (vbl_ev->enable)
kms->funcs->enable_vblank(kms,
priv->crtcs[vbl_ev->crtc_id]);
else
kms->funcs->disable_vblank(kms,
priv->crtcs[vbl_ev->crtc_id]);
kfree(vbl_ev);
spin_lock_irqsave(&vbl_ctrl->lock, flags);
}
spin_unlock_irqrestore(&vbl_ctrl->lock, flags);
}
static int vblank_ctrl_queue_work(struct msm_drm_private *priv,
int crtc_id, bool enable)
{
struct msm_vblank_ctrl *vbl_ctrl = &priv->vblank_ctrl;
struct vblank_event *vbl_ev;
unsigned long flags;
vbl_ev = kzalloc(sizeof(*vbl_ev), GFP_ATOMIC);
if (!vbl_ev)
return -ENOMEM;
vbl_ev->crtc_id = crtc_id;
vbl_ev->enable = enable;
spin_lock_irqsave(&vbl_ctrl->lock, flags);
list_add_tail(&vbl_ev->node, &vbl_ctrl->event_list);
spin_unlock_irqrestore(&vbl_ctrl->lock, flags);
queue_work(priv->wq, &vbl_ctrl->work);
return 0;
}
/*
* DRM operations:
*/
@ -125,6 +184,18 @@ 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;
struct msm_vblank_ctrl *vbl_ctrl = &priv->vblank_ctrl;
struct vblank_event *vbl_ev, *tmp;
/* We must cancel and cleanup any pending vblank enable/disable
* work before drm_irq_uninstall() to avoid work re-enabling an
* irq after uninstall has disabled it.
*/
cancel_work_sync(&vbl_ctrl->work);
list_for_each_entry_safe(vbl_ev, tmp, &vbl_ctrl->event_list, node) {
list_del(&vbl_ev->node);
kfree(vbl_ev);
}
drm_kms_helper_poll_fini(dev);
drm_mode_config_cleanup(dev);
@ -282,6 +353,9 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
INIT_LIST_HEAD(&priv->inactive_list);
INIT_LIST_HEAD(&priv->fence_cbs);
INIT_LIST_HEAD(&priv->vblank_ctrl.event_list);
INIT_WORK(&priv->vblank_ctrl.work, vblank_ctrl_worker);
spin_lock_init(&priv->vblank_ctrl.lock);
drm_mode_config_init(dev);
@ -331,10 +405,6 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
}
}
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, priv->num_crtcs);
@ -468,7 +538,7 @@ static int msm_enable_vblank(struct drm_device *dev, int crtc_id)
if (!kms)
return -ENXIO;
DBG("dev=%p, crtc=%d", dev, crtc_id);
return kms->funcs->enable_vblank(kms, priv->crtcs[crtc_id]);
return vblank_ctrl_queue_work(priv, crtc_id, true);
}
static void msm_disable_vblank(struct drm_device *dev, int crtc_id)
@ -478,7 +548,7 @@ static void msm_disable_vblank(struct drm_device *dev, int crtc_id)
if (!kms)
return;
DBG("dev=%p, crtc=%d", dev, crtc_id);
kms->funcs->disable_vblank(kms, priv->crtcs[crtc_id]);
vblank_ctrl_queue_work(priv, crtc_id, false);
}
/*

View File

@ -30,6 +30,7 @@
#include <linux/list.h>
#include <linux/iommu.h>
#include <linux/types.h>
#include <linux/of_graph.h>
#include <asm/sizes.h>
#ifndef CONFIG_OF
@ -64,6 +65,19 @@ struct msm_file_private {
int dummy;
};
enum msm_mdp_plane_property {
PLANE_PROP_ZPOS,
PLANE_PROP_ALPHA,
PLANE_PROP_PREMULTIPLIED,
PLANE_PROP_MAX_NUM
};
struct msm_vblank_ctrl {
struct work_struct work;
struct list_head event_list;
spinlock_t lock;
};
struct msm_drm_private {
struct msm_kms *kms;
@ -128,6 +142,9 @@ struct msm_drm_private {
unsigned int num_connectors;
struct drm_connector *connectors[8];
/* Properties */
struct drm_property *plane_property[PLANE_PROP_MAX_NUM];
/* VRAM carveout, used when no IOMMU: */
struct {
unsigned long size;
@ -137,6 +154,8 @@ struct msm_drm_private {
*/
struct drm_mm mm;
} vram;
struct msm_vblank_ctrl vblank_ctrl;
};
struct msm_format {