diff options
Diffstat (limited to 'drivers/gpu/drm/msm/mdp/mdp5')
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h | 399 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c | 102 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c | 343 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c | 86 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c | 315 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h | 75 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c | 83 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c | 26 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 200 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h | 75 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c | 64 |
13 files changed, 1391 insertions, 405 deletions
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h index c276624290af..b9a4ded6e400 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h @@ -8,9 +8,9 @@ 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: -- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp5.xml ( 27229 bytes, from 2015-02-10 17:00:41) +- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp5.xml ( 29312 bytes, from 2015-03-23 21:18:48) - /local/mnt2/workspace2/sviau/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2014-06-02 18:31:15) -- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2015-01-23 16:20:19) +- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2015-03-23 20:38:49) Copyright (C) 2013-2015 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) @@ -37,11 +37,14 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -enum mdp5_intf { +enum mdp5_intf_type { + INTF_DISABLED = 0, INTF_DSI = 1, INTF_HDMI = 3, INTF_LCDC = 5, INTF_eDP = 9, + INTF_VIRTUAL = 100, + INTF_WB = 101, }; enum mdp5_intfnum { @@ -67,11 +70,11 @@ enum mdp5_pipe { enum mdp5_ctl_mode { MODE_NONE = 0, - MODE_ROT0 = 1, - MODE_ROT1 = 2, - MODE_WB0 = 3, - MODE_WB1 = 4, - MODE_WFD = 5, + MODE_WB_0_BLOCK = 1, + MODE_WB_1_BLOCK = 2, + MODE_WB_0_LINE = 3, + MODE_WB_1_LINE = 4, + MODE_WB_2_LINE = 5, }; enum mdp5_pack_3d { @@ -94,33 +97,6 @@ enum mdp5_pipe_bwc { BWC_Q_MED = 2, }; -enum mdp5_client_id { - CID_UNUSED = 0, - CID_VIG0_Y = 1, - CID_VIG0_CR = 2, - CID_VIG0_CB = 3, - CID_VIG1_Y = 4, - CID_VIG1_CR = 5, - CID_VIG1_CB = 6, - CID_VIG2_Y = 7, - CID_VIG2_CR = 8, - CID_VIG2_CB = 9, - CID_DMA0_Y = 10, - CID_DMA0_CR = 11, - CID_DMA0_CB = 12, - CID_DMA1_Y = 13, - CID_DMA1_CR = 14, - CID_DMA1_CB = 15, - CID_RGB0 = 16, - CID_RGB1 = 17, - CID_RGB2 = 18, - CID_VIG3_Y = 19, - CID_VIG3_CR = 20, - CID_VIG3_CB = 21, - CID_RGB3 = 22, - CID_MAX = 23, -}; - enum mdp5_cursor_format { CURSOR_FMT_ARGB8888 = 0, CURSOR_FMT_ARGB1555 = 2, @@ -144,30 +120,25 @@ enum mdp5_data_format { DATA_FORMAT_YUV = 1, }; -#define MDP5_IRQ_INTF0_WB_ROT_COMP 0x00000001 -#define MDP5_IRQ_INTF1_WB_ROT_COMP 0x00000002 -#define MDP5_IRQ_INTF2_WB_ROT_COMP 0x00000004 -#define MDP5_IRQ_INTF3_WB_ROT_COMP 0x00000008 -#define MDP5_IRQ_INTF0_WB_WFD 0x00000010 -#define MDP5_IRQ_INTF1_WB_WFD 0x00000020 -#define MDP5_IRQ_INTF2_WB_WFD 0x00000040 -#define MDP5_IRQ_INTF3_WB_WFD 0x00000080 -#define MDP5_IRQ_INTF0_PING_PONG_COMP 0x00000100 -#define MDP5_IRQ_INTF1_PING_PONG_COMP 0x00000200 -#define MDP5_IRQ_INTF2_PING_PONG_COMP 0x00000400 -#define MDP5_IRQ_INTF3_PING_PONG_COMP 0x00000800 -#define MDP5_IRQ_INTF0_PING_PONG_RD_PTR 0x00001000 -#define MDP5_IRQ_INTF1_PING_PONG_RD_PTR 0x00002000 -#define MDP5_IRQ_INTF2_PING_PONG_RD_PTR 0x00004000 -#define MDP5_IRQ_INTF3_PING_PONG_RD_PTR 0x00008000 -#define MDP5_IRQ_INTF0_PING_PONG_WR_PTR 0x00010000 -#define MDP5_IRQ_INTF1_PING_PONG_WR_PTR 0x00020000 -#define MDP5_IRQ_INTF2_PING_PONG_WR_PTR 0x00040000 -#define MDP5_IRQ_INTF3_PING_PONG_WR_PTR 0x00080000 -#define MDP5_IRQ_INTF0_PING_PONG_AUTO_REF 0x00100000 -#define MDP5_IRQ_INTF1_PING_PONG_AUTO_REF 0x00200000 -#define MDP5_IRQ_INTF2_PING_PONG_AUTO_REF 0x00400000 -#define MDP5_IRQ_INTF3_PING_PONG_AUTO_REF 0x00800000 +#define MDP5_IRQ_WB_0_DONE 0x00000001 +#define MDP5_IRQ_WB_1_DONE 0x00000002 +#define MDP5_IRQ_WB_2_DONE 0x00000010 +#define MDP5_IRQ_PING_PONG_0_DONE 0x00000100 +#define MDP5_IRQ_PING_PONG_1_DONE 0x00000200 +#define MDP5_IRQ_PING_PONG_2_DONE 0x00000400 +#define MDP5_IRQ_PING_PONG_3_DONE 0x00000800 +#define MDP5_IRQ_PING_PONG_0_RD_PTR 0x00001000 +#define MDP5_IRQ_PING_PONG_1_RD_PTR 0x00002000 +#define MDP5_IRQ_PING_PONG_2_RD_PTR 0x00004000 +#define MDP5_IRQ_PING_PONG_3_RD_PTR 0x00008000 +#define MDP5_IRQ_PING_PONG_0_WR_PTR 0x00010000 +#define MDP5_IRQ_PING_PONG_1_WR_PTR 0x00020000 +#define MDP5_IRQ_PING_PONG_2_WR_PTR 0x00040000 +#define MDP5_IRQ_PING_PONG_3_WR_PTR 0x00080000 +#define MDP5_IRQ_PING_PONG_0_AUTO_REF 0x00100000 +#define MDP5_IRQ_PING_PONG_1_AUTO_REF 0x00200000 +#define MDP5_IRQ_PING_PONG_2_AUTO_REF 0x00400000 +#define MDP5_IRQ_PING_PONG_3_AUTO_REF 0x00800000 #define MDP5_IRQ_INTF0_UNDER_RUN 0x01000000 #define MDP5_IRQ_INTF0_VSYNC 0x02000000 #define MDP5_IRQ_INTF1_UNDER_RUN 0x04000000 @@ -176,136 +147,186 @@ enum mdp5_data_format { #define MDP5_IRQ_INTF2_VSYNC 0x20000000 #define MDP5_IRQ_INTF3_UNDER_RUN 0x40000000 #define MDP5_IRQ_INTF3_VSYNC 0x80000000 -#define REG_MDP5_HW_VERSION 0x00000000 +#define REG_MDSS_HW_VERSION 0x00000000 +#define MDSS_HW_VERSION_STEP__MASK 0x0000ffff +#define MDSS_HW_VERSION_STEP__SHIFT 0 +static inline uint32_t MDSS_HW_VERSION_STEP(uint32_t val) +{ + return ((val) << MDSS_HW_VERSION_STEP__SHIFT) & MDSS_HW_VERSION_STEP__MASK; +} +#define MDSS_HW_VERSION_MINOR__MASK 0x0fff0000 +#define MDSS_HW_VERSION_MINOR__SHIFT 16 +static inline uint32_t MDSS_HW_VERSION_MINOR(uint32_t val) +{ + return ((val) << MDSS_HW_VERSION_MINOR__SHIFT) & MDSS_HW_VERSION_MINOR__MASK; +} +#define MDSS_HW_VERSION_MAJOR__MASK 0xf0000000 +#define MDSS_HW_VERSION_MAJOR__SHIFT 28 +static inline uint32_t MDSS_HW_VERSION_MAJOR(uint32_t val) +{ + return ((val) << MDSS_HW_VERSION_MAJOR__SHIFT) & MDSS_HW_VERSION_MAJOR__MASK; +} + +#define REG_MDSS_HW_INTR_STATUS 0x00000010 +#define MDSS_HW_INTR_STATUS_INTR_MDP 0x00000001 +#define MDSS_HW_INTR_STATUS_INTR_DSI0 0x00000010 +#define MDSS_HW_INTR_STATUS_INTR_DSI1 0x00000020 +#define MDSS_HW_INTR_STATUS_INTR_HDMI 0x00000100 +#define MDSS_HW_INTR_STATUS_INTR_EDP 0x00001000 -#define REG_MDP5_HW_INTR_STATUS 0x00000010 -#define MDP5_HW_INTR_STATUS_INTR_MDP 0x00000001 -#define MDP5_HW_INTR_STATUS_INTR_DSI0 0x00000010 -#define MDP5_HW_INTR_STATUS_INTR_DSI1 0x00000020 -#define MDP5_HW_INTR_STATUS_INTR_HDMI 0x00000100 -#define MDP5_HW_INTR_STATUS_INTR_EDP 0x00001000 +static inline uint32_t __offset_MDP(uint32_t idx) +{ + switch (idx) { + case 0: return (mdp5_cfg->mdp.base[0]); + default: return INVALID_IDX(idx); + } +} +static inline uint32_t REG_MDP5_MDP(uint32_t i0) { return 0x00000000 + __offset_MDP(i0); } -#define REG_MDP5_MDP_VERSION 0x00000100 -#define MDP5_MDP_VERSION_MINOR__MASK 0x00ff0000 -#define MDP5_MDP_VERSION_MINOR__SHIFT 16 -static inline uint32_t MDP5_MDP_VERSION_MINOR(uint32_t val) +static inline uint32_t REG_MDP5_MDP_HW_VERSION(uint32_t i0) { return 0x00000000 + __offset_MDP(i0); } +#define MDP5_MDP_HW_VERSION_STEP__MASK 0x0000ffff +#define MDP5_MDP_HW_VERSION_STEP__SHIFT 0 +static inline uint32_t MDP5_MDP_HW_VERSION_STEP(uint32_t val) { - return ((val) << MDP5_MDP_VERSION_MINOR__SHIFT) & MDP5_MDP_VERSION_MINOR__MASK; + return ((val) << MDP5_MDP_HW_VERSION_STEP__SHIFT) & MDP5_MDP_HW_VERSION_STEP__MASK; } -#define MDP5_MDP_VERSION_MAJOR__MASK 0xf0000000 -#define MDP5_MDP_VERSION_MAJOR__SHIFT 28 -static inline uint32_t MDP5_MDP_VERSION_MAJOR(uint32_t val) +#define MDP5_MDP_HW_VERSION_MINOR__MASK 0x0fff0000 +#define MDP5_MDP_HW_VERSION_MINOR__SHIFT 16 +static inline uint32_t MDP5_MDP_HW_VERSION_MINOR(uint32_t val) { - return ((val) << MDP5_MDP_VERSION_MAJOR__SHIFT) & MDP5_MDP_VERSION_MAJOR__MASK; + return ((val) << MDP5_MDP_HW_VERSION_MINOR__SHIFT) & MDP5_MDP_HW_VERSION_MINOR__MASK; +} +#define MDP5_MDP_HW_VERSION_MAJOR__MASK 0xf0000000 +#define MDP5_MDP_HW_VERSION_MAJOR__SHIFT 28 +static inline uint32_t MDP5_MDP_HW_VERSION_MAJOR(uint32_t val) +{ + return ((val) << MDP5_MDP_HW_VERSION_MAJOR__SHIFT) & MDP5_MDP_HW_VERSION_MAJOR__MASK; } -#define REG_MDP5_DISP_INTF_SEL 0x00000104 -#define MDP5_DISP_INTF_SEL_INTF0__MASK 0x000000ff -#define MDP5_DISP_INTF_SEL_INTF0__SHIFT 0 -static inline uint32_t MDP5_DISP_INTF_SEL_INTF0(enum mdp5_intf val) +static inline uint32_t REG_MDP5_MDP_DISP_INTF_SEL(uint32_t i0) { return 0x00000004 + __offset_MDP(i0); } +#define MDP5_MDP_DISP_INTF_SEL_INTF0__MASK 0x000000ff +#define MDP5_MDP_DISP_INTF_SEL_INTF0__SHIFT 0 +static inline uint32_t MDP5_MDP_DISP_INTF_SEL_INTF0(enum mdp5_intf_type val) { - return ((val) << MDP5_DISP_INTF_SEL_INTF0__SHIFT) & MDP5_DISP_INTF_SEL_INTF0__MASK; + return ((val) << MDP5_MDP_DISP_INTF_SEL_INTF0__SHIFT) & MDP5_MDP_DISP_INTF_SEL_INTF0__MASK; } -#define MDP5_DISP_INTF_SEL_INTF1__MASK 0x0000ff00 -#define MDP5_DISP_INTF_SEL_INTF1__SHIFT 8 -static inline uint32_t MDP5_DISP_INTF_SEL_INTF1(enum mdp5_intf val) +#define MDP5_MDP_DISP_INTF_SEL_INTF1__MASK 0x0000ff00 +#define MDP5_MDP_DISP_INTF_SEL_INTF1__SHIFT 8 +static inline uint32_t MDP5_MDP_DISP_INTF_SEL_INTF1(enum mdp5_intf_type val) { - return ((val) << MDP5_DISP_INTF_SEL_INTF1__SHIFT) & MDP5_DISP_INTF_SEL_INTF1__MASK; + return ((val) << MDP5_MDP_DISP_INTF_SEL_INTF1__SHIFT) & MDP5_MDP_DISP_INTF_SEL_INTF1__MASK; } -#define MDP5_DISP_INTF_SEL_INTF2__MASK 0x00ff0000 -#define MDP5_DISP_INTF_SEL_INTF2__SHIFT 16 -static inline uint32_t MDP5_DISP_INTF_SEL_INTF2(enum mdp5_intf val) +#define MDP5_MDP_DISP_INTF_SEL_INTF2__MASK 0x00ff0000 +#define MDP5_MDP_DISP_INTF_SEL_INTF2__SHIFT 16 +static inline uint32_t MDP5_MDP_DISP_INTF_SEL_INTF2(enum mdp5_intf_type val) { - return ((val) << MDP5_DISP_INTF_SEL_INTF2__SHIFT) & MDP5_DISP_INTF_SEL_INTF2__MASK; + return ((val) << MDP5_MDP_DISP_INTF_SEL_INTF2__SHIFT) & MDP5_MDP_DISP_INTF_SEL_INTF2__MASK; } -#define MDP5_DISP_INTF_SEL_INTF3__MASK 0xff000000 -#define MDP5_DISP_INTF_SEL_INTF3__SHIFT 24 -static inline uint32_t MDP5_DISP_INTF_SEL_INTF3(enum mdp5_intf val) +#define MDP5_MDP_DISP_INTF_SEL_INTF3__MASK 0xff000000 +#define MDP5_MDP_DISP_INTF_SEL_INTF3__SHIFT 24 +static inline uint32_t MDP5_MDP_DISP_INTF_SEL_INTF3(enum mdp5_intf_type val) { - return ((val) << MDP5_DISP_INTF_SEL_INTF3__SHIFT) & MDP5_DISP_INTF_SEL_INTF3__MASK; + return ((val) << MDP5_MDP_DISP_INTF_SEL_INTF3__SHIFT) & MDP5_MDP_DISP_INTF_SEL_INTF3__MASK; } -#define REG_MDP5_INTR_EN 0x00000110 +static inline uint32_t REG_MDP5_MDP_INTR_EN(uint32_t i0) { return 0x00000010 + __offset_MDP(i0); } -#define REG_MDP5_INTR_STATUS 0x00000114 +static inline uint32_t REG_MDP5_MDP_INTR_STATUS(uint32_t i0) { return 0x00000014 + __offset_MDP(i0); } -#define REG_MDP5_INTR_CLEAR 0x00000118 +static inline uint32_t REG_MDP5_MDP_INTR_CLEAR(uint32_t i0) { return 0x00000018 + __offset_MDP(i0); } -#define REG_MDP5_HIST_INTR_EN 0x0000011c +static inline uint32_t REG_MDP5_MDP_HIST_INTR_EN(uint32_t i0) { return 0x0000001c + __offset_MDP(i0); } -#define REG_MDP5_HIST_INTR_STATUS 0x00000120 +static inline uint32_t REG_MDP5_MDP_HIST_INTR_STATUS(uint32_t i0) { return 0x00000020 + __offset_MDP(i0); } -#define REG_MDP5_HIST_INTR_CLEAR 0x00000124 +static inline uint32_t REG_MDP5_MDP_HIST_INTR_CLEAR(uint32_t i0) { return 0x00000024 + __offset_MDP(i0); } -static inline uint32_t REG_MDP5_SMP_ALLOC_W(uint32_t i0) { return 0x00000180 + 0x4*i0; } +static inline uint32_t REG_MDP5_MDP_SPARE_0(uint32_t i0) { return 0x00000028 + __offset_MDP(i0); } +#define MDP5_MDP_SPARE_0_SPLIT_DPL_SINGLE_FLUSH_EN 0x00000001 -static inline uint32_t REG_MDP5_SMP_ALLOC_W_REG(uint32_t i0) { return 0x00000180 + 0x4*i0; } -#define MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK 0x000000ff -#define MDP5_SMP_ALLOC_W_REG_CLIENT0__SHIFT 0 -static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT0(enum mdp5_client_id val) +static inline uint32_t REG_MDP5_MDP_SMP_ALLOC_W(uint32_t i0, uint32_t i1) { return 0x00000080 + __offset_MDP(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP5_MDP_SMP_ALLOC_W_REG(uint32_t i0, uint32_t i1) { return 0x00000080 + __offset_MDP(i0) + 0x4*i1; } +#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__MASK 0x000000ff +#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__SHIFT 0 +static inline uint32_t MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0(uint32_t val) { - return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT0__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK; + return ((val) << MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__SHIFT) & MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__MASK; } -#define MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK 0x0000ff00 -#define MDP5_SMP_ALLOC_W_REG_CLIENT1__SHIFT 8 -static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT1(enum mdp5_client_id val) +#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__MASK 0x0000ff00 +#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__SHIFT 8 +static inline uint32_t MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1(uint32_t val) { - return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT1__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK; + return ((val) << MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__SHIFT) & MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__MASK; } -#define MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK 0x00ff0000 -#define MDP5_SMP_ALLOC_W_REG_CLIENT2__SHIFT 16 -static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT2(enum mdp5_client_id val) +#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__MASK 0x00ff0000 +#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__SHIFT 16 +static inline uint32_t MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2(uint32_t val) { - return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT2__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK; + return ((val) << MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__SHIFT) & MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__MASK; } -static inline uint32_t REG_MDP5_SMP_ALLOC_R(uint32_t i0) { return 0x00000230 + 0x4*i0; } +static inline uint32_t REG_MDP5_MDP_SMP_ALLOC_R(uint32_t i0, uint32_t i1) { return 0x00000130 + __offset_MDP(i0) + 0x4*i1; } -static inline uint32_t REG_MDP5_SMP_ALLOC_R_REG(uint32_t i0) { return 0x00000230 + 0x4*i0; } -#define MDP5_SMP_ALLOC_R_REG_CLIENT0__MASK 0x000000ff -#define MDP5_SMP_ALLOC_R_REG_CLIENT0__SHIFT 0 -static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT0(enum mdp5_client_id val) +static inline uint32_t REG_MDP5_MDP_SMP_ALLOC_R_REG(uint32_t i0, uint32_t i1) { return 0x00000130 + __offset_MDP(i0) + 0x4*i1; } +#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0__MASK 0x000000ff +#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0__SHIFT 0 +static inline uint32_t MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0(uint32_t val) { - return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT0__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT0__MASK; + return ((val) << MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0__SHIFT) & MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0__MASK; } -#define MDP5_SMP_ALLOC_R_REG_CLIENT1__MASK 0x0000ff00 -#define MDP5_SMP_ALLOC_R_REG_CLIENT1__SHIFT 8 -static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT1(enum mdp5_client_id val) +#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1__MASK 0x0000ff00 +#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1__SHIFT 8 +static inline uint32_t MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1(uint32_t val) { - return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT1__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT1__MASK; + return ((val) << MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1__SHIFT) & MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1__MASK; } -#define MDP5_SMP_ALLOC_R_REG_CLIENT2__MASK 0x00ff0000 -#define MDP5_SMP_ALLOC_R_REG_CLIENT2__SHIFT 16 -static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT2(enum mdp5_client_id val) +#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2__MASK 0x00ff0000 +#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2__SHIFT 16 +static inline uint32_t MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2(uint32_t val) { - return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT2__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT2__MASK; + return ((val) << MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2__SHIFT) & MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2__MASK; } static inline uint32_t __offset_IGC(enum mdp5_igc_type idx) { switch (idx) { - case IGC_VIG: return 0x00000300; - case IGC_RGB: return 0x00000310; - case IGC_DMA: return 0x00000320; - case IGC_DSPP: return 0x00000400; + case IGC_VIG: return 0x00000200; + case IGC_RGB: return 0x00000210; + case IGC_DMA: return 0x00000220; + case IGC_DSPP: return 0x00000300; default: return INVALID_IDX(idx); } } -static inline uint32_t REG_MDP5_IGC(enum mdp5_igc_type i0) { return 0x00000000 + __offset_IGC(i0); } +static inline uint32_t REG_MDP5_MDP_IGC(uint32_t i0, enum mdp5_igc_type i1) { return 0x00000000 + __offset_MDP(i0) + __offset_IGC(i1); } -static inline uint32_t REG_MDP5_IGC_LUT(enum mdp5_igc_type i0, uint32_t i1) { return 0x00000000 + __offset_IGC(i0) + 0x4*i1; } +static inline uint32_t REG_MDP5_MDP_IGC_LUT(uint32_t i0, enum mdp5_igc_type i1, uint32_t i2) { return 0x00000000 + __offset_MDP(i0) + __offset_IGC(i1) + 0x4*i2; } -static inline uint32_t REG_MDP5_IGC_LUT_REG(enum mdp5_igc_type i0, uint32_t i1) { return 0x00000000 + __offset_IGC(i0) + 0x4*i1; } -#define MDP5_IGC_LUT_REG_VAL__MASK 0x00000fff -#define MDP5_IGC_LUT_REG_VAL__SHIFT 0 -static inline uint32_t MDP5_IGC_LUT_REG_VAL(uint32_t val) +static inline uint32_t REG_MDP5_MDP_IGC_LUT_REG(uint32_t i0, enum mdp5_igc_type i1, uint32_t i2) { return 0x00000000 + __offset_MDP(i0) + __offset_IGC(i1) + 0x4*i2; } +#define MDP5_MDP_IGC_LUT_REG_VAL__MASK 0x00000fff +#define MDP5_MDP_IGC_LUT_REG_VAL__SHIFT 0 +static inline uint32_t MDP5_MDP_IGC_LUT_REG_VAL(uint32_t val) { - return ((val) << MDP5_IGC_LUT_REG_VAL__SHIFT) & MDP5_IGC_LUT_REG_VAL__MASK; + return ((val) << MDP5_MDP_IGC_LUT_REG_VAL__SHIFT) & MDP5_MDP_IGC_LUT_REG_VAL__MASK; } -#define MDP5_IGC_LUT_REG_INDEX_UPDATE 0x02000000 -#define MDP5_IGC_LUT_REG_DISABLE_PIPE_0 0x10000000 -#define MDP5_IGC_LUT_REG_DISABLE_PIPE_1 0x20000000 -#define MDP5_IGC_LUT_REG_DISABLE_PIPE_2 0x40000000 +#define MDP5_MDP_IGC_LUT_REG_INDEX_UPDATE 0x02000000 +#define MDP5_MDP_IGC_LUT_REG_DISABLE_PIPE_0 0x10000000 +#define MDP5_MDP_IGC_LUT_REG_DISABLE_PIPE_1 0x20000000 +#define MDP5_MDP_IGC_LUT_REG_DISABLE_PIPE_2 0x40000000 + +#define REG_MDP5_SPLIT_DPL_EN 0x000003f4 + +#define REG_MDP5_SPLIT_DPL_UPPER 0x000003f8 +#define MDP5_SPLIT_DPL_UPPER_SMART_PANEL 0x00000002 +#define MDP5_SPLIT_DPL_UPPER_SMART_PANEL_FREE_RUN 0x00000004 +#define MDP5_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX 0x00000010 +#define MDP5_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX 0x00000100 + +#define REG_MDP5_SPLIT_DPL_LOWER 0x000004f0 +#define MDP5_SPLIT_DPL_LOWER_SMART_PANEL 0x00000002 +#define MDP5_SPLIT_DPL_LOWER_SMART_PANEL_FREE_RUN 0x00000004 +#define MDP5_SPLIT_DPL_LOWER_INTF1_TG_SYNC 0x00000010 +#define MDP5_SPLIT_DPL_LOWER_INTF2_TG_SYNC 0x00000100 static inline uint32_t __offset_CTL(uint32_t idx) { @@ -437,11 +458,19 @@ static inline uint32_t REG_MDP5_CTL_FLUSH(uint32_t i0) { return 0x00000018 + __o #define MDP5_CTL_FLUSH_DSPP0 0x00002000 #define MDP5_CTL_FLUSH_DSPP1 0x00004000 #define MDP5_CTL_FLUSH_DSPP2 0x00008000 +#define MDP5_CTL_FLUSH_WB 0x00010000 #define MDP5_CTL_FLUSH_CTL 0x00020000 #define MDP5_CTL_FLUSH_VIG3 0x00040000 #define MDP5_CTL_FLUSH_RGB3 0x00080000 #define MDP5_CTL_FLUSH_LM5 0x00100000 #define MDP5_CTL_FLUSH_DSPP3 0x00200000 +#define MDP5_CTL_FLUSH_CURSOR_0 0x00400000 +#define MDP5_CTL_FLUSH_CURSOR_1 0x00800000 +#define MDP5_CTL_FLUSH_CHROMADOWN_0 0x04000000 +#define MDP5_CTL_FLUSH_TIMING_3 0x10000000 +#define MDP5_CTL_FLUSH_TIMING_2 0x20000000 +#define MDP5_CTL_FLUSH_TIMING_1 0x40000000 +#define MDP5_CTL_FLUSH_TIMING_0 0x80000000 static inline uint32_t REG_MDP5_CTL_START(uint32_t i0) { return 0x0000001c + __offset_CTL(i0); } @@ -1117,6 +1146,94 @@ static inline uint32_t REG_MDP5_DSPP_GAMUT_BASE(uint32_t i0) { return 0x000002dc static inline uint32_t REG_MDP5_DSPP_GC_BASE(uint32_t i0) { return 0x000002b0 + __offset_DSPP(i0); } +static inline uint32_t __offset_PP(uint32_t idx) +{ + switch (idx) { + case 0: return (mdp5_cfg->pp.base[0]); + case 1: return (mdp5_cfg->pp.base[1]); + case 2: return (mdp5_cfg->pp.base[2]); + case 3: return (mdp5_cfg->pp.base[3]); + default: return INVALID_IDX(idx); + } +} +static inline uint32_t REG_MDP5_PP(uint32_t i0) { return 0x00000000 + __offset_PP(i0); } + +static inline uint32_t REG_MDP5_PP_TEAR_CHECK_EN(uint32_t i0) { return 0x00000000 + __offset_PP(i0); } + +static inline uint32_t REG_MDP5_PP_SYNC_CONFIG_VSYNC(uint32_t i0) { return 0x00000004 + __offset_PP(i0); } +#define MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__MASK 0x0007ffff +#define MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__SHIFT 0 +static inline uint32_t MDP5_PP_SYNC_CONFIG_VSYNC_COUNT(uint32_t val) +{ + return ((val) << MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__SHIFT) & MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__MASK; +} +#define MDP5_PP_SYNC_CONFIG_VSYNC_COUNTER_EN 0x00080000 +#define MDP5_PP_SYNC_CONFIG_VSYNC_IN_EN 0x00100000 + +static inline uint32_t REG_MDP5_PP_SYNC_CONFIG_HEIGHT(uint32_t i0) { return 0x00000008 + __offset_PP(i0); } + +static inline uint32_t REG_MDP5_PP_SYNC_WRCOUNT(uint32_t i0) { return 0x0000000c + __offset_PP(i0); } +#define MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__MASK 0x0000ffff +#define MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__SHIFT 0 +static inline uint32_t MDP5_PP_SYNC_WRCOUNT_LINE_COUNT(uint32_t val) +{ + return ((val) << MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__SHIFT) & MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__MASK; +} +#define MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__MASK 0xffff0000 +#define MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__SHIFT 16 +static inline uint32_t MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT(uint32_t val) +{ + return ((val) << MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__SHIFT) & MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__MASK; +} + +static inline uint32_t REG_MDP5_PP_VSYNC_INIT_VAL(uint32_t i0) { return 0x00000010 + __offset_PP(i0); } + +static inline uint32_t REG_MDP5_PP_INT_COUNT_VAL(uint32_t i0) { return 0x00000014 + __offset_PP(i0); } +#define MDP5_PP_INT_COUNT_VAL_LINE_COUNT__MASK 0x0000ffff +#define MDP5_PP_INT_COUNT_VAL_LINE_COUNT__SHIFT 0 +static inline uint32_t MDP5_PP_INT_COUNT_VAL_LINE_COUNT(uint32_t val) +{ + return ((val) << MDP5_PP_INT_COUNT_VAL_LINE_COUNT__SHIFT) & MDP5_PP_INT_COUNT_VAL_LINE_COUNT__MASK; +} +#define MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__MASK 0xffff0000 +#define MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__SHIFT 16 +static inline uint32_t MDP5_PP_INT_COUNT_VAL_FRAME_COUNT(uint32_t val) +{ + return ((val) << MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__SHIFT) & MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__MASK; +} + +static inline uint32_t REG_MDP5_PP_SYNC_THRESH(uint32_t i0) { return 0x00000018 + __offset_PP(i0); } +#define MDP5_PP_SYNC_THRESH_START__MASK 0x0000ffff +#define MDP5_PP_SYNC_THRESH_START__SHIFT 0 +static inline uint32_t MDP5_PP_SYNC_THRESH_START(uint32_t val) +{ + return ((val) << MDP5_PP_SYNC_THRESH_START__SHIFT) & MDP5_PP_SYNC_THRESH_START__MASK; +} +#define MDP5_PP_SYNC_THRESH_CONTINUE__MASK 0xffff0000 +#define MDP5_PP_SYNC_THRESH_CONTINUE__SHIFT 16 +static inline uint32_t MDP5_PP_SYNC_THRESH_CONTINUE(uint32_t val) +{ + return ((val) << MDP5_PP_SYNC_THRESH_CONTINUE__SHIFT) & MDP5_PP_SYNC_THRESH_CONTINUE__MASK; +} + +static inline uint32_t REG_MDP5_PP_START_POS(uint32_t i0) { return 0x0000001c + __offset_PP(i0); } + +static inline uint32_t REG_MDP5_PP_RD_PTR_IRQ(uint32_t i0) { return 0x00000020 + __offset_PP(i0); } + +static inline uint32_t REG_MDP5_PP_WR_PTR_IRQ(uint32_t i0) { return 0x00000024 + __offset_PP(i0); } + +static inline uint32_t REG_MDP5_PP_OUT_LINE_COUNT(uint32_t i0) { return 0x00000028 + __offset_PP(i0); } + +static inline uint32_t REG_MDP5_PP_PP_LINE_COUNT(uint32_t i0) { return 0x0000002c + __offset_PP(i0); } + +static inline uint32_t REG_MDP5_PP_AUTOREFRESH_CONFIG(uint32_t i0) { return 0x00000030 + __offset_PP(i0); } + +static inline uint32_t REG_MDP5_PP_FBC_MODE(uint32_t i0) { return 0x00000034 + __offset_PP(i0); } + +static inline uint32_t REG_MDP5_PP_FBC_BUDGET_CTL(uint32_t i0) { return 0x00000038 + __offset_PP(i0); } + +static inline uint32_t REG_MDP5_PP_FBC_LOSSY_MODE(uint32_t i0) { return 0x0000003c + __offset_PP(i0); } + static inline uint32_t __offset_INTF(uint32_t idx) { switch (idx) { diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c index b0a44310cf2a..e001e6b2296a 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2014-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 @@ -24,13 +24,23 @@ const struct mdp5_cfg_hw *mdp5_cfg = NULL; const struct mdp5_cfg_hw msm8x74_config = { .name = "msm8x74", + .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, @@ -57,27 +67,49 @@ const struct mdp5_cfg_hw msm8x74_config = { .count = 2, .base = { 0x13100, 0x13300 }, /* NOTE: no ad in v1.0 */ }, + .pp = { + .count = 3, + .base = { 0x12d00, 0x12e00, 0x12f00 }, + }, .intf = { .count = 4, .base = { 0x12500, 0x12700, 0x12900, 0x12b00 }, }, + .intfs = { + [0] = INTF_eDP, + [1] = INTF_DSI, + [2] = INTF_DSI, + [3] = INTF_HDMI, + }, .max_clk = 200000000, }; const struct mdp5_cfg_hw apq8084_config = { .name = "apq8084", + .mdp = { + .count = 1, + .base = { 0x00100 }, + }, .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(7, 0), /* first 8 MMBs */ - .reserved[CID_RGB0] = 2, - .reserved[CID_RGB1] = 2, - .reserved[CID_RGB2] = 2, - .reserved[CID_RGB3] = 2, + .reserved = { + /* Two SMP blocks are statically tied to RGB pipes: */ + [16] = 2, [17] = 2, [18] = 2, [22] = 2, + }, }, .ctl = { .count = 5, .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 }, + .flush_hw_mask = 0x003fffff, }, .pipe_vig = { .count = 4, @@ -105,10 +137,69 @@ const struct mdp5_cfg_hw apq8084_config = { .count = 3, .base = { 0x13500, 0x13700, 0x13900 }, }, + .pp = { + .count = 4, + .base = { 0x12f00, 0x13000, 0x13100, 0x13200 }, + }, .intf = { .count = 5, .base = { 0x12500, 0x12700, 0x12900, 0x12b00, 0x12d00 }, }, + .intfs = { + [0] = INTF_eDP, + [1] = INTF_DSI, + [2] = INTF_DSI, + [3] = INTF_HDMI, + }, + .max_clk = 320000000, +}; + +const struct mdp5_cfg_hw msm8x16_config = { + .name = "msm8x16", + .mdp = { + .count = 1, + .base = { 0x01000 }, + }, + .smp = { + .mmb_count = 8, + .mmb_size = 8192, + .clients = { + [SSPP_VIG0] = 1, [SSPP_DMA0] = 4, + [SSPP_RGB0] = 7, [SSPP_RGB1] = 8, + }, + }, + .ctl = { + .count = 5, + .base = { 0x02000, 0x02200, 0x02400, 0x02600, 0x02800 }, + .flush_hw_mask = 0x4003ffff, + }, + .pipe_vig = { + .count = 1, + .base = { 0x05000 }, + }, + .pipe_rgb = { + .count = 2, + .base = { 0x15000, 0x17000 }, + }, + .pipe_dma = { + .count = 1, + .base = { 0x25000 }, + }, + .lm = { + .count = 2, /* LM0 and LM3 */ + .base = { 0x45000, 0x48000 }, + .nb_stages = 5, + }, + .dspp = { + .count = 1, + .base = { 0x55000 }, + + }, + .intf = { + .count = 1, /* INTF_1 */ + .base = { 0x6B800 }, + }, + /* TODO enable .intfs[] with [1] = INTF_DSI, once DSI is implemented */ .max_clk = 320000000, }; @@ -116,6 +207,7 @@ 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 } }, }; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h index dba4d52cceeb..3a551b0892d8 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h @@ -44,26 +44,38 @@ struct mdp5_lm_block { uint32_t nb_stages; /* number of stages per blender */ }; +struct mdp5_ctl_block { + MDP5_SUB_BLOCK_DEFINITION; + uint32_t flush_hw_mask; /* FLUSH register's hardware mask */ +}; + struct mdp5_smp_block { int mmb_count; /* number of SMP MMBs */ int mmb_size; /* MMB: size in bytes */ + uint32_t clients[MAX_CLIENTS]; /* SMP port allocation /pipe */ mdp5_smp_state_t reserved_state;/* SMP MMBs statically allocated */ int reserved[MAX_CLIENTS]; /* # of MMBs allocated per client */ }; +#define MDP5_INTF_NUM_MAX 5 + struct mdp5_cfg_hw { char *name; + struct mdp5_sub_block mdp; struct mdp5_smp_block smp; - struct mdp5_sub_block ctl; + 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_lm_block lm; struct mdp5_sub_block dspp; struct mdp5_sub_block ad; + struct mdp5_sub_block pp; struct mdp5_sub_block intf; + u32 intfs[MDP5_INTF_NUM_MAX]; /* array of enum mdp5_intf_type */ + uint32_t max_clk; }; @@ -84,6 +96,10 @@ const struct mdp5_cfg_hw *mdp5_cfg_get_hw_config(struct mdp5_cfg_handler *cfg_hn struct mdp5_cfg *mdp5_cfg_get_config(struct mdp5_cfg_handler *cfg_hnd); int mdp5_cfg_get_hw_rev(struct mdp5_cfg_handler *cfg_hnd); +#define mdp5_cfg_intf_is_virtual(intf_type) ({ \ + typeof(intf_type) __val = (intf_type); \ + (__val) >= INTF_VIRTUAL ? true : false; }) + struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms, uint32_t major, uint32_t minor); void mdp5_cfg_destroy(struct mdp5_cfg_handler *cfg_hnd); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c new file mode 100644 index 000000000000..e4e89567f51d --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c @@ -0,0 +1,343 @@ +/* + * 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 "mdp5_kms.h" + +#include "drm_crtc.h" +#include "drm_crtc_helper.h" + +struct mdp5_cmd_encoder { + struct drm_encoder base; + struct mdp5_interface intf; + bool enabled; + uint32_t bsc; +}; +#define to_mdp5_cmd_encoder(x) container_of(x, struct mdp5_cmd_encoder, base) + +static struct mdp5_kms *get_kms(struct drm_encoder *encoder) +{ + struct msm_drm_private *priv = encoder->dev->dev_private; + return to_mdp5_kms(to_mdp_kms(priv->kms)); +} + +#ifdef CONFIG_MSM_BUS_SCALING +#include <mach/board.h> +#include <linux/msm-bus.h> +#include <linux/msm-bus-board.h> +#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val) \ + { \ + .src = MSM_BUS_MASTER_MDP_PORT0, \ + .dst = MSM_BUS_SLAVE_EBI_CH0, \ + .ab = (ab_val), \ + .ib = (ib_val), \ + } + +static struct msm_bus_vectors mdp_bus_vectors[] = { + MDP_BUS_VECTOR_ENTRY(0, 0), + MDP_BUS_VECTOR_ENTRY(2000000000, 2000000000), +}; +static struct msm_bus_paths mdp_bus_usecases[] = { { + .num_paths = 1, + .vectors = &mdp_bus_vectors[0], +}, { + .num_paths = 1, + .vectors = &mdp_bus_vectors[1], +} }; +static struct msm_bus_scale_pdata mdp_bus_scale_table = { + .usecase = mdp_bus_usecases, + .num_usecases = ARRAY_SIZE(mdp_bus_usecases), + .name = "mdss_mdp", +}; + +static void bs_init(struct mdp5_cmd_encoder *mdp5_cmd_enc) +{ + mdp5_cmd_enc->bsc = msm_bus_scale_register_client( + &mdp_bus_scale_table); + DBG("bus scale client: %08x", mdp5_cmd_enc->bsc); +} + +static void bs_fini(struct mdp5_cmd_encoder *mdp5_cmd_enc) +{ + if (mdp5_cmd_enc->bsc) { + msm_bus_scale_unregister_client(mdp5_cmd_enc->bsc); + mdp5_cmd_enc->bsc = 0; + } +} + +static void bs_set(struct mdp5_cmd_encoder *mdp5_cmd_enc, int idx) +{ + if (mdp5_cmd_enc->bsc) { + DBG("set bus scaling: %d", idx); + /* HACK: scaling down, and then immediately back up + * seems to leave things broken (underflow).. so + * never disable: + */ + idx = 1; + msm_bus_scale_client_update_request(mdp5_cmd_enc->bsc, idx); + } +} +#else +static void bs_init(struct mdp5_cmd_encoder *mdp5_cmd_enc) {} +static void bs_fini(struct mdp5_cmd_encoder *mdp5_cmd_enc) {} +static void bs_set(struct mdp5_cmd_encoder *mdp5_cmd_enc, int idx) {} +#endif + +#define VSYNC_CLK_RATE 19200000 +static int pingpong_tearcheck_setup(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct mdp5_kms *mdp5_kms = get_kms(encoder); + struct device *dev = encoder->dev->dev; + u32 total_lines_x100, vclks_line, cfg; + long vsync_clk_speed; + int pp_id = GET_PING_PONG_ID(mdp5_crtc_get_lm(encoder->crtc)); + + if (IS_ERR_OR_NULL(mdp5_kms->vsync_clk)) { + dev_err(dev, "vsync_clk is not initialized\n"); + return -EINVAL; + } + + total_lines_x100 = mode->vtotal * mode->vrefresh; + if (!total_lines_x100) { + dev_err(dev, "%s: vtotal(%d) or vrefresh(%d) is 0\n", + __func__, mode->vtotal, mode->vrefresh); + return -EINVAL; + } + + vsync_clk_speed = clk_round_rate(mdp5_kms->vsync_clk, VSYNC_CLK_RATE); + if (vsync_clk_speed <= 0) { + dev_err(dev, "vsync_clk round rate failed %ld\n", + vsync_clk_speed); + return -EINVAL; + } + vclks_line = vsync_clk_speed * 100 / total_lines_x100; + + cfg = MDP5_PP_SYNC_CONFIG_VSYNC_COUNTER_EN + | MDP5_PP_SYNC_CONFIG_VSYNC_IN_EN; + cfg |= MDP5_PP_SYNC_CONFIG_VSYNC_COUNT(vclks_line); + + mdp5_write(mdp5_kms, REG_MDP5_PP_SYNC_CONFIG_VSYNC(pp_id), cfg); + mdp5_write(mdp5_kms, + REG_MDP5_PP_SYNC_CONFIG_HEIGHT(pp_id), 0xfff0); + mdp5_write(mdp5_kms, + REG_MDP5_PP_VSYNC_INIT_VAL(pp_id), mode->vdisplay); + mdp5_write(mdp5_kms, REG_MDP5_PP_RD_PTR_IRQ(pp_id), mode->vdisplay + 1); + mdp5_write(mdp5_kms, REG_MDP5_PP_START_POS(pp_id), mode->vdisplay); + mdp5_write(mdp5_kms, REG_MDP5_PP_SYNC_THRESH(pp_id), + MDP5_PP_SYNC_THRESH_START(4) | + MDP5_PP_SYNC_THRESH_CONTINUE(4)); + + return 0; +} + +static int pingpong_tearcheck_enable(struct drm_encoder *encoder) +{ + struct mdp5_kms *mdp5_kms = get_kms(encoder); + int pp_id = GET_PING_PONG_ID(mdp5_crtc_get_lm(encoder->crtc)); + int ret; + + ret = clk_set_rate(mdp5_kms->vsync_clk, + clk_round_rate(mdp5_kms->vsync_clk, VSYNC_CLK_RATE)); + if (ret) { + dev_err(encoder->dev->dev, + "vsync_clk clk_set_rate failed, %d\n", ret); + return ret; + } + ret = clk_prepare_enable(mdp5_kms->vsync_clk); + if (ret) { + dev_err(encoder->dev->dev, + "vsync_clk clk_prepare_enable failed, %d\n", ret); + return ret; + } + + mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 1); + + return 0; +} + +static void pingpong_tearcheck_disable(struct drm_encoder *encoder) +{ + struct mdp5_kms *mdp5_kms = get_kms(encoder); + int pp_id = GET_PING_PONG_ID(mdp5_crtc_get_lm(encoder->crtc)); + + mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 0); + clk_disable_unprepare(mdp5_kms->vsync_clk); +} + +static void mdp5_cmd_encoder_destroy(struct drm_encoder *encoder) +{ + struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder); + bs_fini(mdp5_cmd_enc); + drm_encoder_cleanup(encoder); + kfree(mdp5_cmd_enc); +} + +static const struct drm_encoder_funcs mdp5_cmd_encoder_funcs = { + .destroy = mdp5_cmd_encoder_destroy, +}; + +static bool mdp5_cmd_encoder_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder); + + mode = adjusted_mode; + + DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", + mode->base.id, mode->name, + mode->vrefresh, mode->clock, + mode->hdisplay, mode->hsync_start, + mode->hsync_end, mode->htotal, + mode->vdisplay, mode->vsync_start, + mode->vsync_end, mode->vtotal, + mode->type, mode->flags); + pingpong_tearcheck_setup(encoder, mode); + mdp5_crtc_set_intf(encoder->crtc, &mdp5_cmd_enc->intf); +} + +static void mdp5_cmd_encoder_disable(struct drm_encoder *encoder) +{ + struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder); + struct mdp5_kms *mdp5_kms = get_kms(encoder); + struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc); + struct mdp5_interface *intf = &mdp5_cmd_enc->intf; + int lm = mdp5_crtc_get_lm(encoder->crtc); + + if (WARN_ON(!mdp5_cmd_enc->enabled)) + return; + + /* Wait for the last frame done */ + mdp_irq_wait(&mdp5_kms->base, lm2ppdone(lm)); + pingpong_tearcheck_disable(encoder); + + mdp5_ctl_set_encoder_state(ctl, false); + mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf)); + + bs_set(mdp5_cmd_enc, 0); + + mdp5_cmd_enc->enabled = false; +} + +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_interface *intf = &mdp5_cmd_enc->intf; + + if (WARN_ON(mdp5_cmd_enc->enabled)) + return; + + bs_set(mdp5_cmd_enc, 1); + if (pingpong_tearcheck_enable(encoder)) + return; + + mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf)); + + mdp5_ctl_set_encoder_state(ctl, true); + + mdp5_cmd_enc->enabled = true; +} + +static const struct drm_encoder_helper_funcs mdp5_cmd_encoder_helper_funcs = { + .mode_fixup = mdp5_cmd_encoder_mode_fixup, + .mode_set = mdp5_cmd_encoder_mode_set, + .disable = mdp5_cmd_encoder_disable, + .enable = mdp5_cmd_encoder_enable, +}; + +int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder, + struct drm_encoder *slave_encoder) +{ + struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder); + struct mdp5_kms *mdp5_kms; + int intf_num; + u32 data = 0; + + if (!encoder || !slave_encoder) + return -EINVAL; + + mdp5_kms = get_kms(encoder); + intf_num = mdp5_cmd_enc->intf.num; + + /* Switch slave encoder's trigger MUX, to use the master's + * start signal for the slave encoder + */ + if (intf_num == 1) + data |= MDP5_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX; + else if (intf_num == 2) + data |= MDP5_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX; + else + return -EINVAL; + + /* Smart Panel, Sync mode */ + data |= MDP5_SPLIT_DPL_UPPER_SMART_PANEL; + + /* Make sure clocks are on when connectors calling this function. */ + mdp5_enable(mdp5_kms); + mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, data); + + mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER, + MDP5_SPLIT_DPL_LOWER_SMART_PANEL); + mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1); + mdp5_disable(mdp5_kms); + + return 0; +} + +/* initialize command mode encoder */ +struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev, + struct mdp5_interface *intf) +{ + struct drm_encoder *encoder = NULL; + struct mdp5_cmd_encoder *mdp5_cmd_enc; + int ret; + + if (WARN_ON((intf->type != INTF_DSI) && + (intf->mode != MDP5_INTF_DSI_MODE_COMMAND))) { + ret = -EINVAL; + goto fail; + } + + mdp5_cmd_enc = kzalloc(sizeof(*mdp5_cmd_enc), GFP_KERNEL); + if (!mdp5_cmd_enc) { + ret = -ENOMEM; + goto fail; + } + + memcpy(&mdp5_cmd_enc->intf, intf, sizeof(mdp5_cmd_enc->intf)); + encoder = &mdp5_cmd_enc->base; + + drm_encoder_init(dev, encoder, &mdp5_cmd_encoder_funcs, + DRM_MODE_ENCODER_DSI); + + drm_encoder_helper_add(encoder, &mdp5_cmd_encoder_helper_funcs); + + bs_init(mdp5_cmd_enc); + + return encoder; + +fail: + if (encoder) + mdp5_cmd_encoder_destroy(encoder); + + return ERR_PTR(ret); +} + diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index 2f2863cf8b45..c1530772187d 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -82,8 +82,6 @@ static void request_pending(struct drm_crtc *crtc, uint32_t pending) mdp_irq_register(&get_kms(crtc)->base, &mdp5_crtc->vblank); } -#define mdp5_lm_get_flush(lm) mdp_ctl_flush_mask_lm(lm) - static void crtc_flush(struct drm_crtc *crtc, u32 flush_mask) { struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); @@ -110,8 +108,8 @@ static void crtc_flush_all(struct drm_crtc *crtc) drm_atomic_crtc_for_each_plane(plane, crtc) { flush_mask |= mdp5_plane_get_flush(plane); } - flush_mask |= mdp5_ctl_get_flush(mdp5_crtc->ctl); - flush_mask |= mdp5_lm_get_flush(mdp5_crtc->lm); + + flush_mask |= mdp_ctl_flush_mask_lm(mdp5_crtc->lm); crtc_flush(crtc, flush_mask); } @@ -298,8 +296,6 @@ static void mdp5_crtc_enable(struct drm_crtc *crtc) mdp5_enable(mdp5_kms); mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err); - crtc_flush_all(crtc); - mdp5_crtc->enabled = true; } @@ -444,13 +440,14 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc, struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); struct drm_device *dev = crtc->dev; struct mdp5_kms *mdp5_kms = get_kms(crtc); - struct drm_gem_object *cursor_bo, *old_bo; + struct drm_gem_object *cursor_bo, *old_bo = NULL; uint32_t blendcfg, cursor_addr, stride; int ret, bpp, lm; unsigned int depth; enum mdp5_cursor_alpha cur_alpha = CURSOR_ALPHA_PER_PIXEL; uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0); uint32_t roi_w, roi_h; + bool cursor_enable = true; unsigned long flags; if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) { @@ -463,7 +460,8 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc, if (!handle) { DBG("Cursor off"); - return mdp5_ctl_set_cursor(mdp5_crtc->ctl, false); + cursor_enable = false; + goto set_cursor; } cursor_bo = drm_gem_object_lookup(dev, file, handle); @@ -504,11 +502,14 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc, spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags); - ret = mdp5_ctl_set_cursor(mdp5_crtc->ctl, true); - if (ret) +set_cursor: + ret = mdp5_ctl_set_cursor(mdp5_crtc->ctl, 0, cursor_enable); + if (ret) { + dev_err(dev->dev, "failed to %sable cursor: %d\n", + cursor_enable ? "en" : "dis", ret); goto end; + } - flush_mask |= mdp5_ctl_get_flush(mdp5_crtc->ctl); crtc_flush(crtc, flush_mask); end: @@ -613,64 +614,39 @@ void mdp5_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file) } /* set interface for routing crtc->encoder: */ -void mdp5_crtc_set_intf(struct drm_crtc *crtc, int intf, - enum mdp5_intf intf_id) +void mdp5_crtc_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf) { struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); struct mdp5_kms *mdp5_kms = get_kms(crtc); - uint32_t flush_mask = 0; - uint32_t intf_sel; - unsigned long flags; + int lm = mdp5_crtc_get_lm(crtc); /* now that we know what irq's we want: */ - mdp5_crtc->err.irqmask = intf2err(intf); - mdp5_crtc->vblank.irqmask = intf2vblank(intf); - mdp_irq_update(&mdp5_kms->base); - - spin_lock_irqsave(&mdp5_kms->resource_lock, flags); - intf_sel = mdp5_read(mdp5_kms, REG_MDP5_DISP_INTF_SEL); - - switch (intf) { - case 0: - intf_sel &= ~MDP5_DISP_INTF_SEL_INTF0__MASK; - intf_sel |= MDP5_DISP_INTF_SEL_INTF0(intf_id); - break; - case 1: - intf_sel &= ~MDP5_DISP_INTF_SEL_INTF1__MASK; - intf_sel |= MDP5_DISP_INTF_SEL_INTF1(intf_id); - break; - case 2: - intf_sel &= ~MDP5_DISP_INTF_SEL_INTF2__MASK; - intf_sel |= MDP5_DISP_INTF_SEL_INTF2(intf_id); - break; - case 3: - intf_sel &= ~MDP5_DISP_INTF_SEL_INTF3__MASK; - intf_sel |= MDP5_DISP_INTF_SEL_INTF3(intf_id); - break; - default: - BUG(); - break; - } + mdp5_crtc->err.irqmask = intf2err(intf->num); - mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, intf_sel); - spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags); + /* Register command mode Pingpong done as vblank for now, + * so that atomic commit should wait for it to finish. + * Ideally, in the future, we should take rd_ptr done as vblank, + * and let atomic commit wait for pingpong done for commond mode. + */ + if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND) + mdp5_crtc->vblank.irqmask = lm2ppdone(lm); + else + mdp5_crtc->vblank.irqmask = intf2vblank(lm, intf); + mdp_irq_update(&mdp5_kms->base); - DBG("%s: intf_sel=%08x", mdp5_crtc->name, intf_sel); mdp5_ctl_set_intf(mdp5_crtc->ctl, intf); - flush_mask |= mdp5_ctl_get_flush(mdp5_crtc->ctl); - flush_mask |= mdp5_lm_get_flush(mdp5_crtc->lm); - - crtc_flush(crtc, flush_mask); } int mdp5_crtc_get_lm(struct drm_crtc *crtc) { struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + return WARN_ON(!crtc) ? -EINVAL : mdp5_crtc->lm; +} - if (WARN_ON(!crtc)) - return -EINVAL; - - return 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; } /* initialize crtc */ diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c index 151129032d16..5488b687c8d1 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2014-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 @@ -33,23 +33,31 @@ * requested by the client (in mdp5_crtc_mode_set()). */ +struct op_mode { + struct mdp5_interface intf; + + bool encoder_enabled; + uint32_t start_mask; +}; + struct mdp5_ctl { struct mdp5_ctl_manager *ctlm; u32 id; + int lm; /* whether this CTL has been allocated or not: */ bool busy; - /* memory output connection (@see mdp5_ctl_mode): */ - u32 mode; + /* Operation Mode Configuration for the Pipeline */ + struct op_mode pipeline; /* REG_MDP5_CTL_*(<id>) registers access info + lock: */ spinlock_t hw_lock; u32 reg_offset; - /* flush mask used to commit CTL registers */ - u32 flush_mask; + /* when do CTL registers need to be flushed? (mask of trigger bits) */ + u32 pending_ctl_trigger; bool cursor_on; @@ -63,6 +71,9 @@ struct mdp5_ctl_manager { u32 nlm; u32 nctl; + /* to filter out non-present bits in the current hardware config */ + u32 flush_hw_mask; + /* pool of CTLs + lock to protect resource allocation (ctls[i].busy) */ spinlock_t pool_lock; struct mdp5_ctl ctls[MAX_CTL]; @@ -94,31 +105,172 @@ u32 ctl_read(struct mdp5_ctl *ctl, u32 reg) return mdp5_read(mdp5_kms, reg); } +static void set_display_intf(struct mdp5_kms *mdp5_kms, + struct mdp5_interface *intf) +{ + unsigned long flags; + u32 intf_sel; + + spin_lock_irqsave(&mdp5_kms->resource_lock, flags); + intf_sel = mdp5_read(mdp5_kms, REG_MDP5_MDP_DISP_INTF_SEL(0)); + + switch (intf->num) { + case 0: + intf_sel &= ~MDP5_MDP_DISP_INTF_SEL_INTF0__MASK; + intf_sel |= MDP5_MDP_DISP_INTF_SEL_INTF0(intf->type); + break; + case 1: + intf_sel &= ~MDP5_MDP_DISP_INTF_SEL_INTF1__MASK; + intf_sel |= MDP5_MDP_DISP_INTF_SEL_INTF1(intf->type); + break; + case 2: + intf_sel &= ~MDP5_MDP_DISP_INTF_SEL_INTF2__MASK; + intf_sel |= MDP5_MDP_DISP_INTF_SEL_INTF2(intf->type); + break; + case 3: + intf_sel &= ~MDP5_MDP_DISP_INTF_SEL_INTF3__MASK; + intf_sel |= MDP5_MDP_DISP_INTF_SEL_INTF3(intf->type); + break; + default: + BUG(); + break; + } + + mdp5_write(mdp5_kms, REG_MDP5_MDP_DISP_INTF_SEL(0), intf_sel); + spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags); +} -int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, int intf) +static void set_ctl_op(struct mdp5_ctl *ctl, struct mdp5_interface *intf) { unsigned long flags; - static const enum mdp5_intfnum intfnum[] = { - INTF0, INTF1, INTF2, INTF3, - }; + u32 ctl_op = 0; + + if (!mdp5_cfg_intf_is_virtual(intf->type)) + ctl_op |= MDP5_CTL_OP_INTF_NUM(INTF0 + intf->num); + + switch (intf->type) { + case INTF_DSI: + if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND) + ctl_op |= MDP5_CTL_OP_CMD_MODE; + break; + + case INTF_WB: + if (intf->mode == MDP5_INTF_WB_MODE_LINE) + ctl_op |= MDP5_CTL_OP_MODE(MODE_WB_2_LINE); + break; + + default: + break; + } spin_lock_irqsave(&ctl->hw_lock, flags); - ctl_write(ctl, REG_MDP5_CTL_OP(ctl->id), - MDP5_CTL_OP_MODE(ctl->mode) | - MDP5_CTL_OP_INTF_NUM(intfnum[intf])); + ctl_write(ctl, REG_MDP5_CTL_OP(ctl->id), ctl_op); spin_unlock_irqrestore(&ctl->hw_lock, flags); +} + +int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, struct mdp5_interface *intf) +{ + struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm; + struct mdp5_kms *mdp5_kms = get_kms(ctl_mgr); + + memcpy(&ctl->pipeline.intf, intf, sizeof(*intf)); + + ctl->pipeline.start_mask = mdp_ctl_flush_mask_lm(ctl->lm) | + mdp_ctl_flush_mask_encoder(intf); + + /* Virtual interfaces need not set a display intf (e.g.: Writeback) */ + if (!mdp5_cfg_intf_is_virtual(intf->type)) + set_display_intf(mdp5_kms, intf); + + set_ctl_op(ctl, intf); return 0; } -int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, bool enable) +static bool start_signal_needed(struct mdp5_ctl *ctl) +{ + struct op_mode *pipeline = &ctl->pipeline; + + if (!pipeline->encoder_enabled || pipeline->start_mask != 0) + return false; + + switch (pipeline->intf.type) { + case INTF_WB: + return true; + case INTF_DSI: + return pipeline->intf.mode == MDP5_INTF_DSI_MODE_COMMAND; + default: + return false; + } +} + +/* + * send_start_signal() - Overlay Processor Start Signal + * + * For a given control operation (display pipeline), a START signal needs to be + * executed in order to kick off operation and activate all layers. + * e.g.: DSI command mode, Writeback + */ +static void send_start_signal(struct mdp5_ctl *ctl) +{ + unsigned long flags; + + spin_lock_irqsave(&ctl->hw_lock, flags); + ctl_write(ctl, REG_MDP5_CTL_START(ctl->id), 1); + spin_unlock_irqrestore(&ctl->hw_lock, flags); +} + +static void refill_start_mask(struct mdp5_ctl *ctl) +{ + struct op_mode *pipeline = &ctl->pipeline; + struct mdp5_interface *intf = &ctl->pipeline.intf; + + pipeline->start_mask = mdp_ctl_flush_mask_lm(ctl->lm); + + /* + * Writeback encoder needs to program & flush + * address registers for each page flip.. + */ + if (intf->type == INTF_WB) + pipeline->start_mask |= mdp_ctl_flush_mask_encoder(intf); +} + +/** + * mdp5_ctl_set_encoder_state() - set the encoder state + * + * @enable: true, when encoder is ready for data streaming; false, otherwise. + * + * Note: + * This encoder state is needed to trigger START signal (data path kickoff). + */ +int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl, bool enabled) +{ + if (WARN_ON(!ctl)) + return -EINVAL; + + ctl->pipeline.encoder_enabled = enabled; + DBG("intf_%d: %s", ctl->pipeline.intf.num, enabled ? "on" : "off"); + + if (start_signal_needed(ctl)) { + send_start_signal(ctl); + refill_start_mask(ctl); + } + + return 0; +} + +/* + * 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_set_cursor(struct mdp5_ctl *ctl, int cursor_id, bool enable) { struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm; unsigned long flags; u32 blend_cfg; - int lm; + int lm = ctl->lm; - lm = mdp5_crtc_get_lm(ctl->crtc); if (unlikely(WARN_ON(lm < 0))) { dev_err(ctl_mgr->dev->dev, "CTL %d cannot find LM: %d", ctl->id, lm); @@ -138,12 +290,12 @@ int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, bool 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) { unsigned long flags; @@ -157,37 +309,122 @@ int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg) ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, lm), blend_cfg); spin_unlock_irqrestore(&ctl->hw_lock, flags); + ctl->pending_ctl_trigger = mdp_ctl_flush_mask_lm(lm); + return 0; } +u32 mdp_ctl_flush_mask_encoder(struct mdp5_interface *intf) +{ + if (intf->type == INTF_WB) + return MDP5_CTL_FLUSH_WB; + + switch (intf->num) { + case 0: return MDP5_CTL_FLUSH_TIMING_0; + case 1: return MDP5_CTL_FLUSH_TIMING_1; + case 2: return MDP5_CTL_FLUSH_TIMING_2; + case 3: return MDP5_CTL_FLUSH_TIMING_3; + default: return 0; + } +} + +u32 mdp_ctl_flush_mask_cursor(int cursor_id) +{ + switch (cursor_id) { + case 0: return MDP5_CTL_FLUSH_CURSOR_0; + case 1: return MDP5_CTL_FLUSH_CURSOR_1; + default: return 0; + } +} + +u32 mdp_ctl_flush_mask_pipe(enum mdp5_pipe pipe) +{ + switch (pipe) { + case SSPP_VIG0: return MDP5_CTL_FLUSH_VIG0; + case SSPP_VIG1: return MDP5_CTL_FLUSH_VIG1; + case SSPP_VIG2: return MDP5_CTL_FLUSH_VIG2; + case SSPP_RGB0: return MDP5_CTL_FLUSH_RGB0; + case SSPP_RGB1: return MDP5_CTL_FLUSH_RGB1; + case SSPP_RGB2: return MDP5_CTL_FLUSH_RGB2; + case SSPP_DMA0: return MDP5_CTL_FLUSH_DMA0; + case SSPP_DMA1: return MDP5_CTL_FLUSH_DMA1; + case SSPP_VIG3: return MDP5_CTL_FLUSH_VIG3; + case SSPP_RGB3: return MDP5_CTL_FLUSH_RGB3; + default: return 0; + } +} + +u32 mdp_ctl_flush_mask_lm(int lm) +{ + switch (lm) { + case 0: return MDP5_CTL_FLUSH_LM0; + case 1: return MDP5_CTL_FLUSH_LM1; + case 2: return MDP5_CTL_FLUSH_LM2; + case 5: return MDP5_CTL_FLUSH_LM5; + default: return 0; + } +} + +static u32 fix_sw_flush(struct mdp5_ctl *ctl, u32 flush_mask) +{ + struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm; + u32 sw_mask = 0; +#define BIT_NEEDS_SW_FIX(bit) \ + (!(ctl_mgr->flush_hw_mask & bit) && (flush_mask & bit)) + + /* for some targets, cursor bit is the same as LM bit */ + if (BIT_NEEDS_SW_FIX(MDP5_CTL_FLUSH_CURSOR_0)) + sw_mask |= mdp_ctl_flush_mask_lm(ctl->lm); + + return sw_mask; +} + +/** + * mdp5_ctl_commit() - Register Flush + * + * The flush register is used to indicate several registers are all + * programmed, and are safe to update to the back copy of the double + * buffered registers. + * + * Some registers FLUSH bits are shared when the hardware does not have + * dedicated bits for them; handling these is the job of fix_sw_flush(). + * + * CTL registers need to be flushed in some circumstances; if that is the + * case, some trigger bits will be present in both flush mask and + * ctl->pending_ctl_trigger. + */ int 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; - if (flush_mask & MDP5_CTL_FLUSH_CURSOR_DUMMY) { - int lm = mdp5_crtc_get_lm(ctl->crtc); + pipeline->start_mask &= ~flush_mask; - if (unlikely(WARN_ON(lm < 0))) { - dev_err(ctl_mgr->dev->dev, "CTL %d cannot find LM: %d", - ctl->id, lm); - return -EINVAL; - } + VERB("flush_mask=%x, start_mask=%x, trigger=%x", flush_mask, + pipeline->start_mask, ctl->pending_ctl_trigger); - /* for current targets, cursor bit is the same as LM bit */ - flush_mask |= mdp_ctl_flush_mask_lm(lm); + if (ctl->pending_ctl_trigger & flush_mask) { + flush_mask |= MDP5_CTL_FLUSH_CTL; + ctl->pending_ctl_trigger = 0; } - spin_lock_irqsave(&ctl->hw_lock, flags); - ctl_write(ctl, REG_MDP5_CTL_FLUSH(ctl->id), flush_mask); - spin_unlock_irqrestore(&ctl->hw_lock, flags); + flush_mask |= fix_sw_flush(ctl, flush_mask); - return 0; -} + flush_mask &= ctl_mgr->flush_hw_mask; -u32 mdp5_ctl_get_flush(struct mdp5_ctl *ctl) -{ - return ctl->flush_mask; + if (flush_mask) { + spin_lock_irqsave(&ctl->hw_lock, flags); + ctl_write(ctl, REG_MDP5_CTL_FLUSH(ctl->id), flush_mask); + spin_unlock_irqrestore(&ctl->hw_lock, flags); + } + + if (start_signal_needed(ctl)) { + send_start_signal(ctl); + refill_start_mask(ctl); + } + + return 0; } void mdp5_ctl_release(struct mdp5_ctl *ctl) @@ -208,6 +445,11 @@ void mdp5_ctl_release(struct mdp5_ctl *ctl) 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 * @@ -235,8 +477,10 @@ struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctl_mgr, ctl = &ctl_mgr->ctls[c]; + ctl->lm = mdp5_crtc_get_lm(crtc); ctl->crtc = crtc; ctl->busy = true; + ctl->pending_ctl_trigger = 0; DBG("CTL %d allocated", ctl->id); unlock: @@ -267,7 +511,7 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, void __iomem *mmio_base, const struct mdp5_cfg_hw *hw_cfg) { struct mdp5_ctl_manager *ctl_mgr; - const struct mdp5_sub_block *ctl_cfg = &hw_cfg->ctl; + const struct mdp5_ctl_block *ctl_cfg = &hw_cfg->ctl; unsigned long flags; int c, ret; @@ -289,6 +533,7 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, ctl_mgr->dev = dev; ctl_mgr->nlm = hw_cfg->lm.count; ctl_mgr->nctl = ctl_cfg->count; + ctl_mgr->flush_hw_mask = ctl_cfg->flush_hw_mask; spin_lock_init(&ctl_mgr->pool_lock); /* initialize each CTL of the pool: */ @@ -303,9 +548,7 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, } ctl->ctlm = ctl_mgr; ctl->id = c; - ctl->mode = MODE_NONE; ctl->reg_offset = ctl_cfg->base[c]; - ctl->flush_mask = MDP5_CTL_FLUSH_CTL; ctl->busy = false; spin_lock_init(&ctl->hw_lock); } diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h index ad48788efeea..7a62000994a1 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h @@ -33,19 +33,13 @@ void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctlm); * 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); +int mdp5_ctl_get_ctl_id(struct mdp5_ctl *ctl); -int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, int intf); +struct mdp5_interface; +int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, struct mdp5_interface *intf); +int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl, bool enabled); -int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, bool enable); - -/* @blend_cfg: see LM blender config definition below */ -int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg); - -/* @flush_mask: see CTL flush masks definitions below */ -int mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask); -u32 mdp5_ctl_get_flush(struct mdp5_ctl *ctl); - -void mdp5_ctl_release(struct mdp5_ctl *ctl); +int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, int cursor_id, bool enable); /* * blend_cfg (LM blender config): @@ -72,51 +66,32 @@ static inline u32 mdp_ctl_blend_mask(enum mdp5_pipe pipe, } /* - * flush_mask (CTL flush masks): + * mdp5_ctl_blend() - Blend multiple layers on a Layer Mixer (LM) + * + * @blend_cfg: see LM blender config definition below * - * The following functions allow each DRM entity to get and store - * their own flush mask. - * Once stored, these masks will then be accessed through each DRM's - * interface and used by the caller of mdp5_ctl_commit() to specify - * which block(s) need to be flushed through @flush_mask parameter. + * 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_FLUSH_CURSOR_DUMMY 0x80000000 +/** + * mdp_ctl_flush_mask...() - Register FLUSH masks + * + * These masks are used to specify which block(s) need to be flushed + * through @flush_mask parameter in mdp5_ctl_commit(.., flush_mask). + */ +u32 mdp_ctl_flush_mask_lm(int lm); +u32 mdp_ctl_flush_mask_pipe(enum mdp5_pipe pipe); +u32 mdp_ctl_flush_mask_cursor(int cursor_id); +u32 mdp_ctl_flush_mask_encoder(struct mdp5_interface *intf); -static inline u32 mdp_ctl_flush_mask_cursor(int cursor_id) -{ - /* TODO: use id once multiple cursor support is present */ - (void)cursor_id; +/* @flush_mask: see CTL flush masks definitions below */ +int mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask); - return MDP5_CTL_FLUSH_CURSOR_DUMMY; -} +void mdp5_ctl_release(struct mdp5_ctl *ctl); -static inline u32 mdp_ctl_flush_mask_lm(int lm) -{ - switch (lm) { - case 0: return MDP5_CTL_FLUSH_LM0; - case 1: return MDP5_CTL_FLUSH_LM1; - case 2: return MDP5_CTL_FLUSH_LM2; - case 5: return MDP5_CTL_FLUSH_LM5; - default: return 0; - } -} -static inline u32 mdp_ctl_flush_mask_pipe(enum mdp5_pipe pipe) -{ - switch (pipe) { - case SSPP_VIG0: return MDP5_CTL_FLUSH_VIG0; - case SSPP_VIG1: return MDP5_CTL_FLUSH_VIG1; - case SSPP_VIG2: return MDP5_CTL_FLUSH_VIG2; - case SSPP_RGB0: return MDP5_CTL_FLUSH_RGB0; - case SSPP_RGB1: return MDP5_CTL_FLUSH_RGB1; - case SSPP_RGB2: return MDP5_CTL_FLUSH_RGB2; - case SSPP_DMA0: return MDP5_CTL_FLUSH_DMA0; - case SSPP_DMA1: return MDP5_CTL_FLUSH_DMA1; - case SSPP_VIG3: return MDP5_CTL_FLUSH_VIG3; - case SSPP_RGB3: return MDP5_CTL_FLUSH_RGB3; - default: return 0; - } -} #endif /* __MDP5_CTL_H__ */ diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c index af0e02fa4f48..1188f4bf1e60 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c @@ -23,8 +23,7 @@ struct mdp5_encoder { struct drm_encoder base; - int intf; - enum mdp5_intf intf_id; + struct mdp5_interface intf; spinlock_t intf_lock; /* protect REG_MDP5_INTF_* registers */ bool enabled; uint32_t bsc; @@ -126,7 +125,7 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder, struct mdp5_kms *mdp5_kms = get_kms(encoder); struct drm_device *dev = encoder->dev; struct drm_connector *connector; - int intf = mdp5_encoder->intf; + int intf = mdp5_encoder->intf.num; uint32_t dtv_hsync_skew, vsync_period, vsync_len, ctrl_pol; uint32_t display_v_start, display_v_end; uint32_t hsync_start_x, hsync_end_x; @@ -188,7 +187,7 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder, * DISPLAY_V_START = (VBP * HCYCLE) + HBP * DISPLAY_V_END = (VBP + VACTIVE) * HCYCLE - 1 - HFP */ - if (mdp5_encoder->intf_id == INTF_eDP) { + if (mdp5_encoder->intf.type == INTF_eDP) { display_v_start += mode->htotal - mode->hsync_start; display_v_end -= mode->hsync_start - mode->hdisplay; } @@ -218,21 +217,29 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder, mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(intf), 0x3); /* frame+line? */ spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags); + + mdp5_crtc_set_intf(encoder->crtc, &mdp5_encoder->intf); } 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); - int intf = mdp5_encoder->intf; + struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc); + int lm = mdp5_crtc_get_lm(encoder->crtc); + struct mdp5_interface *intf = &mdp5_encoder->intf; + int intfn = mdp5_encoder->intf.num; unsigned long flags; if (WARN_ON(!mdp5_encoder->enabled)) return; + mdp5_ctl_set_encoder_state(ctl, false); + spin_lock_irqsave(&mdp5_encoder->intf_lock, flags); - mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 0); + mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 0); spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags); + mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf)); /* * Wait for a vsync so we know the ENABLE=0 latched before @@ -242,7 +249,7 @@ static void mdp5_encoder_disable(struct drm_encoder *encoder) * the settings changes for the new modeset (like new * scanout buffer) don't latch properly.. */ - mdp_irq_wait(&mdp5_kms->base, intf2vblank(intf)); + mdp_irq_wait(&mdp5_kms->base, intf2vblank(lm, intf)); bs_set(mdp5_encoder, 0); @@ -253,19 +260,21 @@ 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); - int intf = mdp5_encoder->intf; + struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc); + struct mdp5_interface *intf = &mdp5_encoder->intf; + int intfn = mdp5_encoder->intf.num; unsigned long flags; if (WARN_ON(mdp5_encoder->enabled)) return; - mdp5_crtc_set_intf(encoder->crtc, mdp5_encoder->intf, - mdp5_encoder->intf_id); - bs_set(mdp5_encoder, 1); spin_lock_irqsave(&mdp5_encoder->intf_lock, flags); - mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 1); + mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 1); spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags); + mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf)); + + mdp5_ctl_set_encoder_state(ctl, true); mdp5_encoder->enabled = true; } @@ -277,12 +286,51 @@ static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = { .enable = mdp5_encoder_enable, }; +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_kms *mdp5_kms; + int intf_num; + u32 data = 0; + + if (!encoder || !slave_encoder) + return -EINVAL; + + mdp5_kms = get_kms(encoder); + intf_num = mdp5_encoder->intf.num; + + /* Switch slave encoder's TimingGen Sync mode, + * to use the master's enable signal for the slave encoder. + */ + if (intf_num == 1) + data |= MDP5_SPLIT_DPL_LOWER_INTF2_TG_SYNC; + else if (intf_num == 2) + data |= MDP5_SPLIT_DPL_LOWER_INTF1_TG_SYNC; + else + return -EINVAL; + + /* 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_SPLIT_DPL_UPPER, 0); + mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER, data); + mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1); + mdp5_disable(mdp5_kms); + + return 0; +} + /* initialize encoder */ -struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, int intf, - enum mdp5_intf intf_id) +struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, + struct mdp5_interface *intf) { struct drm_encoder *encoder = NULL; struct mdp5_encoder *mdp5_encoder; + int enc_type = (intf->type == INTF_DSI) ? + DRM_MODE_ENCODER_DSI : DRM_MODE_ENCODER_TMDS; int ret; mdp5_encoder = kzalloc(sizeof(*mdp5_encoder), GFP_KERNEL); @@ -291,14 +339,13 @@ struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, int intf, goto fail; } - mdp5_encoder->intf = intf; - mdp5_encoder->intf_id = intf_id; + memcpy(&mdp5_encoder->intf, intf, sizeof(mdp5_encoder->intf)); encoder = &mdp5_encoder->base; spin_lock_init(&mdp5_encoder->intf_lock); - drm_encoder_init(dev, encoder, &mdp5_encoder_funcs, - DRM_MODE_ENCODER_TMDS); + drm_encoder_init(dev, encoder, &mdp5_encoder_funcs, enc_type); + drm_encoder_helper_add(encoder, &mdp5_encoder_helper_funcs); bs_init(mdp5_encoder); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c index a9407105b9b7..33bd4c6160dd 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c @@ -23,7 +23,7 @@ void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask) { - mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_INTR_EN, irqmask); + mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_MDP_INTR_EN(0), irqmask); } static void mdp5_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus) @@ -35,8 +35,8 @@ void mdp5_irq_preinstall(struct msm_kms *kms) { struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); mdp5_enable(mdp5_kms); - mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, 0xffffffff); - mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000); + mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_CLEAR(0), 0xffffffff); + mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_EN(0), 0x00000000); mdp5_disable(mdp5_kms); } @@ -61,7 +61,7 @@ void mdp5_irq_uninstall(struct msm_kms *kms) { struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); mdp5_enable(mdp5_kms); - mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000); + mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_EN(0), 0x00000000); mdp5_disable(mdp5_kms); } @@ -73,8 +73,8 @@ static void mdp5_irq_mdp(struct mdp_kms *mdp_kms) unsigned int id; uint32_t status; - status = mdp5_read(mdp5_kms, REG_MDP5_INTR_STATUS); - mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, status); + status = mdp5_read(mdp5_kms, REG_MDP5_MDP_INTR_STATUS(0)); + mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_CLEAR(0), status); VERB("status=%08x", status); @@ -91,13 +91,13 @@ irqreturn_t mdp5_irq(struct msm_kms *kms) struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms); uint32_t intr; - intr = mdp5_read(mdp5_kms, REG_MDP5_HW_INTR_STATUS); + intr = mdp5_read(mdp5_kms, REG_MDSS_HW_INTR_STATUS); VERB("intr=%08x", intr); - if (intr & MDP5_HW_INTR_STATUS_INTR_MDP) { + if (intr & MDSS_HW_INTR_STATUS_INTR_MDP) { mdp5_irq_mdp(mdp_kms); - intr &= ~MDP5_HW_INTR_STATUS_INTR_MDP; + intr &= ~MDSS_HW_INTR_STATUS_INTR_MDP; } while (intr) { @@ -128,10 +128,10 @@ void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) * can register to get their irq's delivered */ -#define VALID_IRQS (MDP5_HW_INTR_STATUS_INTR_DSI0 | \ - MDP5_HW_INTR_STATUS_INTR_DSI1 | \ - MDP5_HW_INTR_STATUS_INTR_HDMI | \ - MDP5_HW_INTR_STATUS_INTR_EDP) +#define VALID_IRQS (MDSS_HW_INTR_STATUS_INTR_DSI0 | \ + MDSS_HW_INTR_STATUS_INTR_DSI1 | \ + MDSS_HW_INTR_STATUS_INTR_HDMI | \ + MDSS_HW_INTR_STATUS_INTR_EDP) static void mdp5_hw_mask_irq(struct irq_data *irqd) { diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index 92b61db5754c..dfa8beb9343a 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -58,7 +58,7 @@ static int mdp5_hw_init(struct msm_kms *kms) */ spin_lock_irqsave(&mdp5_kms->resource_lock, flags); - mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, 0); + mdp5_write(mdp5_kms, REG_MDP5_MDP_DISP_INTF_SEL(0), 0); spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags); mdp5_ctlm_hw_reset(mdp5_kms->ctlm); @@ -86,6 +86,18 @@ static long mdp5_round_pixclk(struct msm_kms *kms, unsigned long rate, return rate; } +static int mdp5_set_split_display(struct msm_kms *kms, + struct drm_encoder *encoder, + struct drm_encoder *slave_encoder, + bool is_cmd_mode) +{ + if (is_cmd_mode) + return mdp5_cmd_encoder_set_split_display(encoder, + slave_encoder); + else + return mdp5_encoder_set_split_display(encoder, slave_encoder); +} + static void mdp5_preclose(struct msm_kms *kms, struct drm_file *file) { struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); @@ -131,6 +143,7 @@ static const struct mdp_kms_funcs kms_funcs = { .complete_commit = mdp5_complete_commit, .get_format = mdp_get_format, .round_pixclk = mdp5_round_pixclk, + .set_split_display = mdp5_set_split_display, .preclose = mdp5_preclose, .destroy = mdp5_destroy, }, @@ -161,6 +174,134 @@ int mdp5_enable(struct mdp5_kms *mdp5_kms) 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) +{ + struct drm_device *dev = mdp5_kms->dev; + struct msm_drm_private *priv = dev->dev_private; + struct drm_encoder *encoder; + struct mdp5_interface intf = { + .num = intf_num, + .type = intf_type, + .mode = intf_mode, + }; + + if ((intf_type == INTF_DSI) && + (intf_mode == MDP5_INTF_DSI_MODE_COMMAND)) + encoder = mdp5_cmd_encoder_init(dev, &intf); + else + encoder = mdp5_encoder_init(dev, &intf); + + if (IS_ERR(encoder)) { + dev_err(dev->dev, "failed to construct encoder\n"); + return encoder; + } + + encoder->possible_crtcs = (1 << priv->num_crtcs) - 1; + priv->encoders[priv->num_encoders++] = encoder; + + return encoder; +} + +static int get_dsi_id_from_intf(const struct mdp5_cfg_hw *hw_cfg, int intf_num) +{ + const int intf_cnt = hw_cfg->intf.count; + const u32 *intfs = hw_cfg->intfs; + int id = 0, i; + + for (i = 0; i < intf_cnt; i++) { + if (intfs[i] == INTF_DSI) { + if (intf_num == i) + return id; + + id++; + } + } + + return -EINVAL; +} + +static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num) +{ + struct drm_device *dev = mdp5_kms->dev; + struct msm_drm_private *priv = dev->dev_private; + const struct mdp5_cfg_hw *hw_cfg = + mdp5_cfg_get_hw_config(mdp5_kms->cfg); + enum mdp5_intf_type intf_type = hw_cfg->intfs[intf_num]; + struct drm_encoder *encoder; + int ret = 0; + + switch (intf_type) { + case INTF_DISABLED: + break; + case INTF_eDP: + if (!priv->edp) + break; + + encoder = construct_encoder(mdp5_kms, INTF_eDP, intf_num, + MDP5_INTF_MODE_NONE); + if (IS_ERR(encoder)) { + ret = PTR_ERR(encoder); + break; + } + + ret = msm_edp_modeset_init(priv->edp, dev, encoder); + break; + case INTF_HDMI: + if (!priv->hdmi) + break; + + encoder = construct_encoder(mdp5_kms, INTF_HDMI, intf_num, + MDP5_INTF_MODE_NONE); + if (IS_ERR(encoder)) { + ret = PTR_ERR(encoder); + break; + } + + ret = hdmi_modeset_init(priv->hdmi, dev, encoder); + break; + case INTF_DSI: + { + int dsi_id = get_dsi_id_from_intf(hw_cfg, intf_num); + struct drm_encoder *dsi_encs[MSM_DSI_ENCODER_NUM]; + enum mdp5_intf_mode mode; + int i; + + if ((dsi_id >= ARRAY_SIZE(priv->dsi)) || (dsi_id < 0)) { + dev_err(dev->dev, "failed to find dsi from intf %d\n", + intf_num); + ret = -EINVAL; + break; + } + + if (!priv->dsi[dsi_id]) + 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); + break; + } + } + + ret = msm_dsi_modeset_init(priv->dsi[dsi_id], dev, dsi_encs); + break; + } + default: + dev_err(dev->dev, "unknown intf: %d\n", intf_type); + ret = -EINVAL; + break; + } + + return ret; +} + static int modeset_init(struct mdp5_kms *mdp5_kms) { static const enum mdp5_pipe crtcs[] = { @@ -171,7 +312,6 @@ static int modeset_init(struct mdp5_kms *mdp5_kms) }; struct drm_device *dev = mdp5_kms->dev; struct msm_drm_private *priv = dev->dev_private; - struct drm_encoder *encoder; const struct mdp5_cfg_hw *hw_cfg; int i, ret; @@ -222,44 +362,13 @@ static int modeset_init(struct mdp5_kms *mdp5_kms) } } - if (priv->hdmi) { - /* Construct encoder for HDMI: */ - encoder = mdp5_encoder_init(dev, 3, INTF_HDMI); - if (IS_ERR(encoder)) { - dev_err(dev->dev, "failed to construct encoder\n"); - ret = PTR_ERR(encoder); - goto fail; - } - - encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;; - priv->encoders[priv->num_encoders++] = encoder; - - ret = hdmi_modeset_init(priv->hdmi, dev, encoder); - if (ret) { - dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret); - goto fail; - } - } - - if (priv->edp) { - /* Construct encoder for eDP: */ - encoder = mdp5_encoder_init(dev, 0, INTF_eDP); - if (IS_ERR(encoder)) { - dev_err(dev->dev, "failed to construct eDP encoder\n"); - ret = PTR_ERR(encoder); - goto fail; - } - - encoder->possible_crtcs = (1 << priv->num_crtcs) - 1; - priv->encoders[priv->num_encoders++] = encoder; - - /* Construct bridge/connector for eDP: */ - ret = msm_edp_modeset_init(priv->edp, dev, encoder); - if (ret) { - dev_err(dev->dev, "failed to initialize eDP: %d\n", - ret); + /* Construct encoders and modeset initialize connector devices + * for each external display interface. + */ + for (i = 0; i < ARRAY_SIZE(hw_cfg->intfs); i++) { + ret = modeset_init_intf(mdp5_kms, i); + if (ret) goto fail; - } } return 0; @@ -274,11 +383,11 @@ static void read_hw_revision(struct mdp5_kms *mdp5_kms, uint32_t version; mdp5_enable(mdp5_kms); - version = mdp5_read(mdp5_kms, REG_MDP5_MDP_VERSION); + version = mdp5_read(mdp5_kms, REG_MDSS_HW_VERSION); mdp5_disable(mdp5_kms); - *major = FIELD(version, MDP5_MDP_VERSION_MAJOR); - *minor = FIELD(version, MDP5_MDP_VERSION_MINOR); + *major = FIELD(version, MDSS_HW_VERSION_MAJOR); + *minor = FIELD(version, MDSS_HW_VERSION_MINOR); DBG("MDP5 version v%d.%d", *major, *minor); } @@ -321,6 +430,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) mdp5_kms->dev = dev; + /* mdp5_kms->mmio actually represents the MDSS base address */ mdp5_kms->mmio = msm_ioremap(pdev, "mdp_phys", "MDP5"); if (IS_ERR(mdp5_kms->mmio)) { ret = PTR_ERR(mdp5_kms->mmio); @@ -403,8 +513,12 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) * we don't disable): */ mdp5_enable(mdp5_kms); - for (i = 0; i < config->hw->intf.count; i++) + for (i = 0; i < MDP5_INTF_NUM_MAX; i++) { + if (!config->hw->intf.base[i] || + mdp5_cfg_intf_is_virtual(config->hw->intfs[i])) + continue; mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(i), 0); + } mdp5_disable(mdp5_kms); mdelay(16); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h index 49d011e8835b..2c0de174cc09 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h @@ -54,7 +54,7 @@ struct mdp5_kms { /* * lock to protect access to global resources: ie., following register: - * - REG_MDP5_DISP_INTF_SEL + * - REG_MDP5_MDP_DISP_INTF_SEL */ spinlock_t resource_lock; @@ -94,6 +94,24 @@ struct mdp5_plane_state { #define to_mdp5_plane_state(x) \ container_of(x, struct mdp5_plane_state, base) +enum mdp5_intf_mode { + MDP5_INTF_MODE_NONE = 0, + + /* Modes used for DSI interface (INTF_DSI type): */ + MDP5_INTF_DSI_MODE_VIDEO, + MDP5_INTF_DSI_MODE_COMMAND, + + /* Modes used for WB interface (INTF_WB type): */ + MDP5_INTF_WB_MODE_BLOCK, + MDP5_INTF_WB_MODE_LINE, +}; + +struct mdp5_interface { + int num; /* display interface number */ + enum mdp5_intf_type type; + enum mdp5_intf_mode mode; +}; + static inline void mdp5_write(struct mdp5_kms *mdp5_kms, u32 reg, u32 data) { msm_writel(data, mdp5_kms->mmio + reg); @@ -130,9 +148,9 @@ static inline int pipe2nclients(enum mdp5_pipe pipe) } } -static inline uint32_t intf2err(int intf) +static inline uint32_t intf2err(int intf_num) { - switch (intf) { + switch (intf_num) { case 0: return MDP5_IRQ_INTF0_UNDER_RUN; case 1: return MDP5_IRQ_INTF1_UNDER_RUN; case 2: return MDP5_IRQ_INTF2_UNDER_RUN; @@ -141,9 +159,23 @@ static inline uint32_t intf2err(int intf) } } -static inline uint32_t intf2vblank(int intf) +#define GET_PING_PONG_ID(layer_mixer) ((layer_mixer == 5) ? 3 : layer_mixer) +static inline uint32_t intf2vblank(int lm, struct mdp5_interface *intf) { - switch (intf) { + /* + * In case of DSI Command Mode, the Ping Pong's read pointer IRQ + * acts as a Vblank signal. The Ping Pong buffer used is bound to + * layer mixer. + */ + + if ((intf->type == INTF_DSI) && + (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)) + return MDP5_IRQ_PING_PONG_0_RD_PTR << GET_PING_PONG_ID(lm); + + if (intf->type == INTF_WB) + return MDP5_IRQ_WB_2_DONE; + + switch (intf->num) { case 0: return MDP5_IRQ_INTF0_VSYNC; case 1: return MDP5_IRQ_INTF1_VSYNC; case 2: return MDP5_IRQ_INTF2_VSYNC; @@ -152,6 +184,11 @@ static inline uint32_t intf2vblank(int intf) } } +static inline uint32_t lm2ppdone(int lm) +{ + return MDP5_IRQ_PING_PONG_0_DONE << GET_PING_PONG_ID(lm); +} + int mdp5_disable(struct mdp5_kms *mdp5_kms); int mdp5_enable(struct mdp5_kms *mdp5_kms); @@ -197,13 +234,33 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev, 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, int intf, - enum mdp5_intf intf_id); +void mdp5_crtc_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf); struct drm_crtc *mdp5_crtc_init(struct drm_device *dev, struct drm_plane *plane, int id); -struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, int intf, - enum mdp5_intf intf_id); +struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, + struct mdp5_interface *intf); +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); +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) +{ + return ERR_PTR(-EINVAL); +} +static inline int mdp5_cmd_encoder_set_split_display( + struct drm_encoder *encoder, struct drm_encoder *slave_encoder) +{ + return -EINVAL; +} +#endif #endif /* __MDP5_KMS_H__ */ diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index 05cf9ab2a876..18a3d203b174 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -156,7 +156,8 @@ static const struct drm_plane_funcs mdp5_plane_funcs = { }; static int mdp5_plane_prepare_fb(struct drm_plane *plane, - struct drm_framebuffer *fb) + struct drm_framebuffer *fb, + const struct drm_plane_state *new_state) { struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); struct mdp5_kms *mdp5_kms = get_kms(plane); @@ -166,7 +167,8 @@ static int mdp5_plane_prepare_fb(struct drm_plane *plane, } static void mdp5_plane_cleanup_fb(struct drm_plane *plane, - struct drm_framebuffer *fb) + struct drm_framebuffer *fb, + const struct drm_plane_state *old_state) { struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); struct mdp5_kms *mdp5_kms = get_kms(plane); @@ -505,8 +507,8 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, spin_lock_irqsave(&mdp5_plane->pipe_lock, flags); mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe), - MDP5_PIPE_SRC_IMG_SIZE_WIDTH(src_w) | - MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(src_h)); + MDP5_PIPE_SRC_IMG_SIZE_WIDTH(fb->width) | + MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(fb->height)); mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_SIZE(pipe), MDP5_PIPE_SRC_SIZE_WIDTH(src_w) | diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c index 1f795af89680..16702aecf0df 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c @@ -43,7 +43,7 @@ * set. * * 2) mdp5_smp_configure(): - * As hw is programmed, before FLUSH, MDP5_SMP_ALLOC registers + * As hw is programmed, before FLUSH, MDP5_MDP_SMP_ALLOC registers * are configured for the union(pending, inuse) * * 3) mdp5_smp_commit(): @@ -74,7 +74,7 @@ struct mdp5_smp { spinlock_t state_lock; mdp5_smp_state_t state; /* to track smp allocation amongst pipes: */ - struct mdp5_client_smp_state client_state[CID_MAX]; + struct mdp5_client_smp_state client_state[MAX_CLIENTS]; }; static inline @@ -85,27 +85,31 @@ struct mdp5_kms *get_kms(struct mdp5_smp *smp) return to_mdp5_kms(to_mdp_kms(priv->kms)); } -static inline enum mdp5_client_id pipe2client(enum mdp5_pipe pipe, int plane) +static inline u32 pipe2client(enum mdp5_pipe pipe, int plane) { - WARN_ON(plane >= pipe2nclients(pipe)); - switch (pipe) { - case SSPP_VIG0: return CID_VIG0_Y + plane; - case SSPP_VIG1: return CID_VIG1_Y + plane; - case SSPP_VIG2: return CID_VIG2_Y + plane; - case SSPP_RGB0: return CID_RGB0; - case SSPP_RGB1: return CID_RGB1; - case SSPP_RGB2: return CID_RGB2; - case SSPP_DMA0: return CID_DMA0_Y + plane; - case SSPP_DMA1: return CID_DMA1_Y + plane; - case SSPP_VIG3: return CID_VIG3_Y + plane; - case SSPP_RGB3: return CID_RGB3; - default: return CID_UNUSED; - } +#define CID_UNUSED 0 + + if (WARN_ON(plane >= pipe2nclients(pipe))) + return CID_UNUSED; + + /* + * Note on SMP clients: + * For ViG pipes, fetch Y/Cr/Cb-components clients are always + * consecutive, and in that order. + * + * e.g.: + * if mdp5_cfg->smp.clients[SSPP_VIG0] = N, + * Y plane's client ID is N + * Cr plane's client ID is N + 1 + * Cb plane's client ID is N + 2 + */ + + return mdp5_cfg->smp.clients[pipe] + plane; } /* step #1: update # of blocks pending for the client: */ static int smp_request_block(struct mdp5_smp *smp, - enum mdp5_client_id cid, int nblks) + u32 cid, int nblks) { struct mdp5_kms *mdp5_kms = get_kms(smp); const struct mdp5_cfg_hw *hw_cfg; @@ -227,7 +231,7 @@ void mdp5_smp_release(struct mdp5_smp *smp, enum mdp5_pipe pipe) } static void update_smp_state(struct mdp5_smp *smp, - enum mdp5_client_id cid, mdp5_smp_state_t *assigned) + u32 cid, mdp5_smp_state_t *assigned) { struct mdp5_kms *mdp5_kms = get_kms(smp); int cnt = smp->blk_cnt; @@ -237,25 +241,25 @@ static void update_smp_state(struct mdp5_smp *smp, int idx = blk / 3; int fld = blk % 3; - val = mdp5_read(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(idx)); + val = mdp5_read(mdp5_kms, REG_MDP5_MDP_SMP_ALLOC_W_REG(0, idx)); switch (fld) { case 0: - val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK; - val |= MDP5_SMP_ALLOC_W_REG_CLIENT0(cid); + val &= ~MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__MASK; + val |= MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0(cid); break; case 1: - val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK; - val |= MDP5_SMP_ALLOC_W_REG_CLIENT1(cid); + val &= ~MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__MASK; + val |= MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1(cid); break; case 2: - val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK; - val |= MDP5_SMP_ALLOC_W_REG_CLIENT2(cid); + val &= ~MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__MASK; + val |= MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2(cid); break; } - mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(idx), val); - mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_R_REG(idx), val); + mdp5_write(mdp5_kms, REG_MDP5_MDP_SMP_ALLOC_W_REG(0, idx), val); + mdp5_write(mdp5_kms, REG_MDP5_MDP_SMP_ALLOC_R_REG(0, idx), val); } } @@ -267,7 +271,7 @@ void mdp5_smp_configure(struct mdp5_smp *smp, enum mdp5_pipe pipe) int i; for (i = 0; i < pipe2nclients(pipe); i++) { - enum mdp5_client_id cid = pipe2client(pipe, i); + u32 cid = pipe2client(pipe, i); struct mdp5_client_smp_state *ps = &smp->client_state[cid]; bitmap_or(assigned, ps->inuse, ps->pending, cnt); @@ -283,7 +287,7 @@ void mdp5_smp_commit(struct mdp5_smp *smp, enum mdp5_pipe pipe) int i; for (i = 0; i < pipe2nclients(pipe); i++) { - enum mdp5_client_id cid = pipe2client(pipe, i); + u32 cid = pipe2client(pipe, i); struct mdp5_client_smp_state *ps = &smp->client_state[cid]; /* |