diff options
Diffstat (limited to 'drivers/gpu/drm/msm/mdp')
21 files changed, 1255 insertions, 361 deletions
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h index a4a7f8c7122a..1d39174d91fb 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h @@ -8,16 +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 ( 647 bytes, from 2013-11-30 14:45:35) +- /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 ( 20136 bytes, from 2014-10-31 16:51:39) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1940 bytes, from 2014-10-31 16:51:39) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 23963 bytes, from 2014-10-31 16:51:46) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20908 bytes, from 2014-12-08 16:13:00) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2014-12-08 16:13:00) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 27208 bytes, from 2015-01-13 23:56:11) - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43) - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 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 ( 23613 bytes, from 2014-07-17 15:33:30) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 26848 bytes, from 2015-01-13 23:55:57) +- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 8253 bytes, from 2014-12-08 16:13:00) Copyright (C) 2013-2014 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) @@ -72,6 +73,18 @@ enum mdp4_cursor_format { CURSOR_XRGB = 2, }; +enum mdp4_frame_format { + FRAME_LINEAR = 0, + FRAME_TILE_ARGB_4X4 = 1, + FRAME_TILE_YCBCR_420 = 2, +}; + +enum mdp4_scale_unit { + SCALE_FIR = 0, + SCALE_MN_PHASE = 1, + SCALE_PIXEL_RPT = 2, +}; + enum mdp4_dma { DMA_P = 0, DMA_S = 1, @@ -637,6 +650,8 @@ static inline uint32_t REG_MDP4_PIPE_SRCP1_BASE(enum mdp4_pipe i0) { return 0x00 static inline uint32_t REG_MDP4_PIPE_SRCP2_BASE(enum mdp4_pipe i0) { return 0x00020018 + 0x10000*i0; } +static inline uint32_t REG_MDP4_PIPE_SRCP3_BASE(enum mdp4_pipe i0) { return 0x0002001c + 0x10000*i0; } + static inline uint32_t REG_MDP4_PIPE_SRC_STRIDE_A(enum mdp4_pipe i0) { return 0x00020040 + 0x10000*i0; } #define MDP4_PIPE_SRC_STRIDE_A_P0__MASK 0x0000ffff #define MDP4_PIPE_SRC_STRIDE_A_P0__SHIFT 0 @@ -720,7 +735,25 @@ static inline uint32_t MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT(uint32_t val) } #define MDP4_PIPE_SRC_FORMAT_UNPACK_TIGHT 0x00020000 #define MDP4_PIPE_SRC_FORMAT_UNPACK_ALIGN_MSB 0x00040000 +#define MDP4_PIPE_SRC_FORMAT_FETCH_PLANES__MASK 0x00180000 +#define MDP4_PIPE_SRC_FORMAT_FETCH_PLANES__SHIFT 19 +static inline uint32_t MDP4_PIPE_SRC_FORMAT_FETCH_PLANES(uint32_t val) +{ + return ((val) << MDP4_PIPE_SRC_FORMAT_FETCH_PLANES__SHIFT) & MDP4_PIPE_SRC_FORMAT_FETCH_PLANES__MASK; +} #define MDP4_PIPE_SRC_FORMAT_SOLID_FILL 0x00400000 +#define MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK 0x0c000000 +#define MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT 26 +static inline uint32_t MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP(enum mdp_chroma_samp_type val) +{ + return ((val) << MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT) & MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK; +} +#define MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT__MASK 0x60000000 +#define MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT__SHIFT 29 +static inline uint32_t MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT(enum mdp4_frame_format val) +{ + return ((val) << MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT__SHIFT) & MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT__MASK; +} static inline uint32_t REG_MDP4_PIPE_SRC_UNPACK(enum mdp4_pipe i0) { return 0x00020054 + 0x10000*i0; } #define MDP4_PIPE_SRC_UNPACK_ELEM0__MASK 0x000000ff @@ -751,6 +784,18 @@ static inline uint32_t MDP4_PIPE_SRC_UNPACK_ELEM3(uint32_t val) static inline uint32_t REG_MDP4_PIPE_OP_MODE(enum mdp4_pipe i0) { return 0x00020058 + 0x10000*i0; } #define MDP4_PIPE_OP_MODE_SCALEX_EN 0x00000001 #define MDP4_PIPE_OP_MODE_SCALEY_EN 0x00000002 +#define MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL__MASK 0x0000000c +#define MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL__SHIFT 2 +static inline uint32_t MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL(enum mdp4_scale_unit val) +{ + return ((val) << MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL__SHIFT) & MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL__MASK; +} +#define MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL__MASK 0x00000030 +#define MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL__SHIFT 4 +static inline uint32_t MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL(enum mdp4_scale_unit val) +{ + return ((val) << MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL__SHIFT) & MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL__MASK; +} #define MDP4_PIPE_OP_MODE_SRC_YCBCR 0x00000200 #define MDP4_PIPE_OP_MODE_DST_YCBCR 0x00000400 #define MDP4_PIPE_OP_MODE_CSC_EN 0x00000800 diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c index 3449213f1e76..73afa21822b4 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c @@ -140,26 +140,6 @@ static void mdp4_crtc_destroy(struct drm_crtc *crtc) kfree(mdp4_crtc); } -static void mdp4_crtc_dpms(struct drm_crtc *crtc, int mode) -{ - struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); - struct mdp4_kms *mdp4_kms = get_kms(crtc); - bool enabled = (mode == DRM_MODE_DPMS_ON); - - DBG("%s: mode=%d", mdp4_crtc->name, mode); - - if (enabled != mdp4_crtc->enabled) { - if (enabled) { - mdp4_enable(mdp4_kms); - mdp_irq_register(&mdp4_kms->base, &mdp4_crtc->err); - } else { - mdp_irq_unregister(&mdp4_kms->base, &mdp4_crtc->err); - mdp4_disable(mdp4_kms); - } - mdp4_crtc->enabled = enabled; - } -} - static bool mdp4_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -304,27 +284,38 @@ static void mdp4_crtc_mode_set_nofb(struct drm_crtc *crtc) } } -static void mdp4_crtc_prepare(struct drm_crtc *crtc) +static void mdp4_crtc_disable(struct drm_crtc *crtc) { struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); + struct mdp4_kms *mdp4_kms = get_kms(crtc); + DBG("%s", mdp4_crtc->name); - /* make sure we hold a ref to mdp clks while setting up mode: */ - drm_crtc_vblank_get(crtc); - mdp4_enable(get_kms(crtc)); - mdp4_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); + + if (WARN_ON(!mdp4_crtc->enabled)) + return; + + mdp_irq_unregister(&mdp4_kms->base, &mdp4_crtc->err); + mdp4_disable(mdp4_kms); + + mdp4_crtc->enabled = false; } -static void mdp4_crtc_commit(struct drm_crtc *crtc) +static void mdp4_crtc_enable(struct drm_crtc *crtc) { - mdp4_crtc_dpms(crtc, DRM_MODE_DPMS_ON); + struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); + struct mdp4_kms *mdp4_kms = get_kms(crtc); + + DBG("%s", mdp4_crtc->name); + + if (WARN_ON(mdp4_crtc->enabled)) + return; + + mdp4_enable(mdp4_kms); + mdp_irq_register(&mdp4_kms->base, &mdp4_crtc->err); + crtc_flush(crtc); - /* drop the ref to mdp clk's that we got in prepare: */ - mdp4_disable(get_kms(crtc)); - drm_crtc_vblank_put(crtc); -} -static void mdp4_crtc_load_lut(struct drm_crtc *crtc) -{ + mdp4_crtc->enabled = true; } static int mdp4_crtc_atomic_check(struct drm_crtc *crtc, @@ -508,14 +499,10 @@ static const struct drm_crtc_funcs mdp4_crtc_funcs = { }; static const struct drm_crtc_helper_funcs mdp4_crtc_helper_funcs = { - .dpms = mdp4_crtc_dpms, .mode_fixup = mdp4_crtc_mode_fixup, .mode_set_nofb = mdp4_crtc_mode_set_nofb, - .mode_set = drm_helper_crtc_mode_set, - .mode_set_base = drm_helper_crtc_mode_set_base, - .prepare = mdp4_crtc_prepare, - .commit = mdp4_crtc_commit, - .load_lut = mdp4_crtc_load_lut, + .disable = mdp4_crtc_disable, + .enable = mdp4_crtc_enable, .atomic_check = mdp4_crtc_atomic_check, .atomic_begin = mdp4_crtc_atomic_begin, .atomic_flush = mdp4_crtc_atomic_flush, diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c index c3878420180b..7896323b2631 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c @@ -94,61 +94,6 @@ static const struct drm_encoder_funcs mdp4_dtv_encoder_funcs = { .destroy = mdp4_dtv_encoder_destroy, }; -static void mdp4_dtv_encoder_dpms(struct drm_encoder *encoder, int mode) -{ - struct drm_device *dev = encoder->dev; - struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder); - struct mdp4_kms *mdp4_kms = get_kms(encoder); - bool enabled = (mode == DRM_MODE_DPMS_ON); - - DBG("mode=%d", mode); - - if (enabled == mdp4_dtv_encoder->enabled) - return; - - if (enabled) { - unsigned long pc = mdp4_dtv_encoder->pixclock; - int ret; - - bs_set(mdp4_dtv_encoder, 1); - - DBG("setting src_clk=%lu", pc); - - ret = clk_set_rate(mdp4_dtv_encoder->src_clk, pc); - if (ret) - dev_err(dev->dev, "failed to set src_clk to %lu: %d\n", pc, ret); - clk_prepare_enable(mdp4_dtv_encoder->src_clk); - ret = clk_prepare_enable(mdp4_dtv_encoder->hdmi_clk); - if (ret) - dev_err(dev->dev, "failed to enable hdmi_clk: %d\n", ret); - ret = clk_prepare_enable(mdp4_dtv_encoder->mdp_clk); - if (ret) - dev_err(dev->dev, "failed to enabled mdp_clk: %d\n", ret); - - mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 1); - } else { - mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 0); - - /* - * Wait for a vsync so we know the ENABLE=0 latched before - * the (connector) source of the vsync's gets disabled, - * otherwise we end up in a funny state if we re-enable - * before the disable latches, which results that some of - * the settings changes for the new modeset (like new - * scanout buffer) don't latch properly.. - */ - mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_EXTERNAL_VSYNC); - - clk_disable_unprepare(mdp4_dtv_encoder->src_clk); - clk_disable_unprepare(mdp4_dtv_encoder->hdmi_clk); - clk_disable_unprepare(mdp4_dtv_encoder->mdp_clk); - - bs_set(mdp4_dtv_encoder, 0); - } - - mdp4_dtv_encoder->enabled = enabled; -} - static bool mdp4_dtv_encoder_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -221,28 +166,78 @@ static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder, mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_VEND, 0); } -static void mdp4_dtv_encoder_prepare(struct drm_encoder *encoder) +static void mdp4_dtv_encoder_disable(struct drm_encoder *encoder) { - mdp4_dtv_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); + struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder); + struct mdp4_kms *mdp4_kms = get_kms(encoder); + + if (WARN_ON(!mdp4_dtv_encoder->enabled)) + return; + + mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 0); + + /* + * Wait for a vsync so we know the ENABLE=0 latched before + * the (connector) source of the vsync's gets disabled, + * otherwise we end up in a funny state if we re-enable + * before the disable latches, which results that some of + * the settings changes for the new modeset (like new + * scanout buffer) don't latch properly.. + */ + mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_EXTERNAL_VSYNC); + + clk_disable_unprepare(mdp4_dtv_encoder->src_clk); + clk_disable_unprepare(mdp4_dtv_encoder->hdmi_clk); + clk_disable_unprepare(mdp4_dtv_encoder->mdp_clk); + + bs_set(mdp4_dtv_encoder, 0); + + mdp4_dtv_encoder->enabled = false; } -static void mdp4_dtv_encoder_commit(struct drm_encoder *encoder) +static void mdp4_dtv_encoder_enable(struct drm_encoder *encoder) { + struct drm_device *dev = encoder->dev; + struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder); + struct mdp4_kms *mdp4_kms = get_kms(encoder); + unsigned long pc = mdp4_dtv_encoder->pixclock; + int ret; + + if (WARN_ON(mdp4_dtv_encoder->enabled)) + return; + mdp4_crtc_set_config(encoder->crtc, MDP4_DMA_CONFIG_R_BPC(BPC8) | MDP4_DMA_CONFIG_G_BPC(BPC8) | MDP4_DMA_CONFIG_B_BPC(BPC8) | MDP4_DMA_CONFIG_PACK(0x21)); mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV, 1); - mdp4_dtv_encoder_dpms(encoder, DRM_MODE_DPMS_ON); + + bs_set(mdp4_dtv_encoder, 1); + + DBG("setting src_clk=%lu", pc); + + ret = clk_set_rate(mdp4_dtv_encoder->src_clk, pc); + if (ret) + dev_err(dev->dev, "failed to set src_clk to %lu: %d\n", pc, ret); + clk_prepare_enable(mdp4_dtv_encoder->src_clk); + ret = clk_prepare_enable(mdp4_dtv_encoder->hdmi_clk); + if (ret) + dev_err(dev->dev, "failed to enable hdmi_clk: %d\n", ret); + ret = clk_prepare_enable(mdp4_dtv_encoder->mdp_clk); + if (ret) + dev_err(dev->dev, "failed to enabled mdp_clk: %d\n", ret); + + mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 1); + + mdp4_dtv_encoder->enabled = true; } static const struct drm_encoder_helper_funcs mdp4_dtv_encoder_helper_funcs = { - .dpms = mdp4_dtv_encoder_dpms, .mode_fixup = mdp4_dtv_encoder_mode_fixup, .mode_set = mdp4_dtv_encoder_mode_set, - .prepare = mdp4_dtv_encoder_prepare, - .commit = mdp4_dtv_encoder_commit, + .enable = mdp4_dtv_encoder_enable, + .disable = mdp4_dtv_encoder_disable, }; long mdp4_dtv_round_pixclk(struct drm_encoder *encoder, unsigned long rate) diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c index a62109e4ae0d..d847b9436194 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c @@ -125,6 +125,38 @@ out: return ret; } +static void mdp4_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state) +{ + struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); + int i, ncrtcs = state->dev->mode_config.num_crtc; + + mdp4_enable(mdp4_kms); + + /* see 119ecb7fd */ + for (i = 0; i < ncrtcs; i++) { + struct drm_crtc *crtc = state->crtcs[i]; + if (!crtc) + continue; + drm_crtc_vblank_get(crtc); + } +} + +static void mdp4_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state) +{ + struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); + int i, ncrtcs = state->dev->mode_config.num_crtc; + + /* see 119ecb7fd */ + for (i = 0; i < ncrtcs; i++) { + struct drm_crtc *crtc = state->crtcs[i]; + if (!crtc) + continue; + drm_crtc_vblank_put(crtc); + } + + mdp4_disable(mdp4_kms); +} + static long mdp4_round_pixclk(struct msm_kms *kms, unsigned long rate, struct drm_encoder *encoder) { @@ -161,6 +193,8 @@ static const struct mdp_kms_funcs kms_funcs = { .irq = mdp4_irq, .enable_vblank = mdp4_enable_vblank, .disable_vblank = mdp4_disable_vblank, + .prepare_commit = mdp4_prepare_commit, + .complete_commit = mdp4_complete_commit, .get_format = mdp_get_format, .round_pixclk = mdp4_round_pixclk, .preclose = mdp4_preclose, diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h index cbd77bc626d5..0a5c58bde7a9 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h @@ -175,14 +175,25 @@ 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) +{ + switch (pipe) { + case VG1: + case VG2: + case VG3: + case VG4: + return true; + default: + return false; + } +} + static inline uint32_t mdp4_get_formats(enum mdp4_pipe pipe_id, uint32_t *pixel_formats, uint32_t max_formats) { - /* TODO when we have YUV, we need to filter supported formats - * based on pipe_id.. - */ - return mdp_get_formats(pixel_formats, max_formats); + return mdp_get_formats(pixel_formats, max_formats, + !pipe_supports_yuv(pipe_id)); } void mdp4_plane_install_properties(struct drm_plane *plane, diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c index 41f6436754fc..60ec8222c9f6 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c @@ -259,77 +259,6 @@ static void setup_phy(struct drm_encoder *encoder) mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG0, lvds_phy_cfg0); } -static void mdp4_lcdc_encoder_dpms(struct drm_encoder *encoder, int mode) -{ - struct drm_device *dev = encoder->dev; - struct mdp4_lcdc_encoder *mdp4_lcdc_encoder = - to_mdp4_lcdc_encoder(encoder); - struct mdp4_kms *mdp4_kms = get_kms(encoder); - struct drm_panel *panel = mdp4_lcdc_encoder->panel; - bool enabled = (mode == DRM_MODE_DPMS_ON); - int i, ret; - - DBG("mode=%d", mode); - - if (enabled == mdp4_lcdc_encoder->enabled) - return; - - if (enabled) { - unsigned long pc = mdp4_lcdc_encoder->pixclock; - int ret; - - bs_set(mdp4_lcdc_encoder, 1); - - for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) { - ret = regulator_enable(mdp4_lcdc_encoder->regs[i]); - if (ret) - dev_err(dev->dev, "failed to enable regulator: %d\n", ret); - } - - DBG("setting lcdc_clk=%lu", pc); - ret = clk_set_rate(mdp4_lcdc_encoder->lcdc_clk, pc); - if (ret) - dev_err(dev->dev, "failed to configure lcdc_clk: %d\n", ret); - ret = clk_prepare_enable(mdp4_lcdc_encoder->lcdc_clk); - if (ret) - dev_err(dev->dev, "failed to enable lcdc_clk: %d\n", ret); - - if (panel) - drm_panel_enable(panel); - - setup_phy(encoder); - - mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 1); - } else { - mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0); - - if (panel) - drm_panel_disable(panel); - - /* - * Wait for a vsync so we know the ENABLE=0 latched before - * the (connector) source of the vsync's gets disabled, - * otherwise we end up in a funny state if we re-enable - * before the disable latches, which results that some of - * the settings changes for the new modeset (like new - * scanout buffer) don't latch properly.. - */ - mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_PRIMARY_VSYNC); - - clk_disable_unprepare(mdp4_lcdc_encoder->lcdc_clk); - - for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) { - ret = regulator_disable(mdp4_lcdc_encoder->regs[i]); - if (ret) - dev_err(dev->dev, "failed to disable regulator: %d\n", ret); - } - - bs_set(mdp4_lcdc_encoder, 0); - } - - mdp4_lcdc_encoder->enabled = enabled; -} - static bool mdp4_lcdc_encoder_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -403,13 +332,59 @@ static void mdp4_lcdc_encoder_mode_set(struct drm_encoder *encoder, mdp4_write(mdp4_kms, REG_MDP4_LCDC_ACTIVE_VEND, 0); } -static void mdp4_lcdc_encoder_prepare(struct drm_encoder *encoder) +static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder) { - mdp4_lcdc_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); + struct drm_device *dev = encoder->dev; + struct mdp4_lcdc_encoder *mdp4_lcdc_encoder = + to_mdp4_lcdc_encoder(encoder); + struct mdp4_kms *mdp4_kms = get_kms(encoder); + struct drm_panel *panel = mdp4_lcdc_encoder->panel; + int i, ret; + + if (WARN_ON(!mdp4_lcdc_encoder->enabled)) + return; + + mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0); + + if (panel) + drm_panel_disable(panel); + + /* + * Wait for a vsync so we know the ENABLE=0 latched before + * the (connector) source of the vsync's gets disabled, + * otherwise we end up in a funny state if we re-enable + * before the disable latches, which results that some of + * the settings changes for the new modeset (like new + * scanout buffer) don't latch properly.. + */ + mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_PRIMARY_VSYNC); + + clk_disable_unprepare(mdp4_lcdc_encoder->lcdc_clk); + + for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) { + ret = regulator_disable(mdp4_lcdc_encoder->regs[i]); + if (ret) + dev_err(dev->dev, "failed to disable regulator: %d\n", ret); + } + + bs_set(mdp4_lcdc_encoder, 0); + + mdp4_lcdc_encoder->enabled = false; } -static void mdp4_lcdc_encoder_commit(struct drm_encoder *encoder) +static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder) { + struct drm_device *dev = encoder->dev; + struct mdp4_lcdc_encoder *mdp4_lcdc_encoder = + to_mdp4_lcdc_encoder(encoder); + unsigned long pc = mdp4_lcdc_encoder->pixclock; + struct mdp4_kms *mdp4_kms = get_kms(encoder); + struct drm_panel *panel = mdp4_lcdc_encoder->panel; + int i, ret; + + if (WARN_ON(mdp4_lcdc_encoder->enabled)) + return; + /* TODO: hard-coded for 18bpp: */ mdp4_crtc_set_config(encoder->crtc, MDP4_DMA_CONFIG_R_BPC(BPC6) | @@ -420,15 +395,38 @@ static void mdp4_lcdc_encoder_commit(struct drm_encoder *encoder) MDP4_DMA_CONFIG_DEFLKR_EN | MDP4_DMA_CONFIG_DITHER_EN); mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV, 0); - mdp4_lcdc_encoder_dpms(encoder, DRM_MODE_DPMS_ON); + + bs_set(mdp4_lcdc_encoder, 1); + + for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) { + ret = regulator_enable(mdp4_lcdc_encoder->regs[i]); + if (ret) + dev_err(dev->dev, "failed to enable regulator: %d\n", ret); + } + + DBG("setting lcdc_clk=%lu", pc); + ret = clk_set_rate(mdp4_lcdc_encoder->lcdc_clk, pc); + if (ret) + dev_err(dev->dev, "failed to configure lcdc_clk: %d\n", ret); + ret = clk_prepare_enable(mdp4_lcdc_encoder->lcdc_clk); + if (ret) + dev_err(dev->dev, "failed to enable lcdc_clk: %d\n", ret); + + if (panel) + drm_panel_enable(panel); + + setup_phy(encoder); + + mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 1); + + mdp4_lcdc_encoder->enabled = true; } static const struct drm_encoder_helper_funcs mdp4_lcdc_encoder_helper_funcs = { - .dpms = mdp4_lcdc_encoder_dpms, .mode_fixup = mdp4_lcdc_encoder_mode_fixup, .mode_set = mdp4_lcdc_encoder_mode_set, - .prepare = mdp4_lcdc_encoder_prepare, - .commit = mdp4_lcdc_encoder_commit, + .disable = mdp4_lcdc_encoder_disable, + .enable = mdp4_lcdc_encoder_enable, }; long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate) diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c index 4ddc28e1275b..921185133d38 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c @@ -94,7 +94,7 @@ mdp4_lvds_connector_best_encoder(struct drm_connector *connector) } static const struct drm_connector_funcs mdp4_lvds_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = drm_atomic_helper_connector_dpms, .detect = mdp4_lvds_connector_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = mdp4_lvds_connector_destroy, diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c index 1e5ebe83647d..cde25009203a 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c @@ -17,6 +17,8 @@ #include "mdp4_kms.h" +#define DOWN_SCALE_MAX 8 +#define UP_SCALE_MAX 8 struct mdp4_plane { struct drm_plane base; @@ -136,10 +138,6 @@ static void mdp4_plane_set_scanout(struct drm_plane *plane, struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); struct mdp4_kms *mdp4_kms = get_kms(plane); enum mdp4_pipe pipe = mdp4_plane->pipe; - uint32_t iova = msm_framebuffer_iova(fb, mdp4_kms->id, 0); - - DBG("%s: set_scanout: %08x (%u)", mdp4_plane->name, - iova, fb->pitches[0]); mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_STRIDE_A(pipe), MDP4_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) | @@ -149,11 +147,45 @@ static void mdp4_plane_set_scanout(struct drm_plane *plane, MDP4_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) | MDP4_PIPE_SRC_STRIDE_B_P3(fb->pitches[3])); - mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP0_BASE(pipe), iova); + mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP0_BASE(pipe), + msm_framebuffer_iova(fb, mdp4_kms->id, 0)); + mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP1_BASE(pipe), + msm_framebuffer_iova(fb, mdp4_kms->id, 1)); + mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP2_BASE(pipe), + msm_framebuffer_iova(fb, mdp4_kms->id, 2)); + mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP3_BASE(pipe), + msm_framebuffer_iova(fb, mdp4_kms->id, 3)); plane->fb = fb; } +static void mdp4_write_csc_config(struct mdp4_kms *mdp4_kms, + enum mdp4_pipe pipe, struct csc_cfg *csc) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(csc->matrix); i++) { + mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_MV(pipe, i), + csc->matrix[i]); + } + + for (i = 0; i < ARRAY_SIZE(csc->post_bias) ; i++) { + mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_PRE_BV(pipe, i), + csc->pre_bias[i]); + + mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_POST_BV(pipe, i), + csc->post_bias[i]); + } + + for (i = 0; i < ARRAY_SIZE(csc->post_clamp) ; i++) { + mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_PRE_LV(pipe, i), + csc->pre_clamp[i]); + + mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_POST_LV(pipe, i), + csc->post_clamp[i]); + } +} + #define MDP4_VG_PHASE_STEP_DEFAULT 0x20000000 static int mdp4_plane_mode_set(struct drm_plane *plane, @@ -163,6 +195,7 @@ static int mdp4_plane_mode_set(struct drm_plane *plane, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { + struct drm_device *dev = plane->dev; struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); struct mdp4_kms *mdp4_kms = get_kms(plane); enum mdp4_pipe pipe = mdp4_plane->pipe; @@ -186,14 +219,59 @@ static int mdp4_plane_mode_set(struct drm_plane *plane, fb->base.id, src_x, src_y, src_w, src_h, crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h); + format = to_mdp_format(msm_framebuffer_format(fb)); + + if (src_w > (crtc_w * DOWN_SCALE_MAX)) { + dev_err(dev->dev, "Width down scaling exceeds limits!\n"); + return -ERANGE; + } + + if (src_h > (crtc_h * DOWN_SCALE_MAX)) { + dev_err(dev->dev, "Height down scaling exceeds limits!\n"); + return -ERANGE; + } + + if (crtc_w > (src_w * UP_SCALE_MAX)) { + dev_err(dev->dev, "Width up scaling exceeds limits!\n"); + return -ERANGE; + } + + if (crtc_h > (src_h * UP_SCALE_MAX)) { + dev_err(dev->dev, "Height up scaling exceeds limits!\n"); + return -ERANGE; + } + if (src_w != crtc_w) { + uint32_t sel_unit = SCALE_FIR; op_mode |= MDP4_PIPE_OP_MODE_SCALEX_EN; - /* TODO calc phasex_step */ + + if (MDP_FORMAT_IS_YUV(format)) { + if (crtc_w > src_w) + sel_unit = SCALE_PIXEL_RPT; + else if (crtc_w <= (src_w / 4)) + sel_unit = SCALE_MN_PHASE; + + op_mode |= MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL(sel_unit); + phasex_step = mult_frac(MDP4_VG_PHASE_STEP_DEFAULT, + src_w, crtc_w); + } } if (src_h != crtc_h) { + uint32_t sel_unit = SCALE_FIR; op_mode |= MDP4_PIPE_OP_MODE_SCALEY_EN; - /* TODO calc phasey_step */ + + if (MDP_FORMAT_IS_YUV(format)) { + + if (crtc_h > src_h) + sel_unit = SCALE_PIXEL_RPT; + else if (crtc_h <= (src_h / 4)) + sel_unit = SCALE_MN_PHASE; + + op_mode |= MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL(sel_unit); + phasey_step = mult_frac(MDP4_VG_PHASE_STEP_DEFAULT, + src_h, crtc_h); + } } mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_SIZE(pipe), @@ -214,8 +292,6 @@ static int mdp4_plane_mode_set(struct drm_plane *plane, mdp4_plane_set_scanout(plane, fb); - format = to_mdp_format(msm_framebuffer_format(fb)); - mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_FORMAT(pipe), MDP4_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) | MDP4_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) | @@ -224,6 +300,8 @@ static int mdp4_plane_mode_set(struct drm_plane *plane, COND(format->alpha_enable, MDP4_PIPE_SRC_FORMAT_ALPHA_ENABLE) | MDP4_PIPE_SRC_FORMAT_CPP(format->cpp - 1) | MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) | + MDP4_PIPE_SRC_FORMAT_FETCH_PLANES(format->fetch_type) | + MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample) | COND(format->unpack_tight, MDP4_PIPE_SRC_FORMAT_UNPACK_TIGHT)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_UNPACK(pipe), @@ -232,6 +310,14 @@ static int mdp4_plane_mode_set(struct drm_plane *plane, MDP4_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) | MDP4_PIPE_SRC_UNPACK_ELEM3(format->unpack[3])); + if (MDP_FORMAT_IS_YUV(format)) { + struct csc_cfg *csc = mdp_get_default_csc_cfg(CSC_YUV2RGB); + + op_mode |= MDP4_PIPE_OP_MODE_SRC_YCBCR; + op_mode |= MDP4_PIPE_OP_MODE_CSC_EN; + mdp4_write_csc_config(mdp4_kms, pipe, csc); + } + mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(pipe), op_mode); mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEX_STEP(pipe), phasex_step); mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEY_STEP(pipe), phasey_step); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h index e87ef5512cb0..09b4a25eb553 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h @@ -8,18 +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 ( 647 bytes, from 2013-11-30 14:45:35) +- /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 ( 20136 bytes, from 2014-10-31 16:51:39) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1940 bytes, from 2014-10-31 16:51:39) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 23963 bytes, from 2014-10-31 16:51:46) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20908 bytes, from 2014-12-08 16:13:00) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2014-12-08 16:13:00) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 27208 bytes, from 2015-01-13 23:56:11) - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43) - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 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 ( 23613 bytes, from 2014-07-17 15:33:30) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 26848 bytes, from 2015-01-13 23:55:57) +- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 8253 bytes, from 2014-12-08 16:13:00) -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 @@ -88,13 +89,6 @@ enum mdp5_pack_3d { PACK_3D_COL_INT = 3, }; -enum mdp5_chroma_samp_type { - CHROMA_RGB = 0, - CHROMA_H2V1 = 1, - CHROMA_H1V2 = 2, - CHROMA_420 = 3, -}; - enum mdp5_scale_filter { SCALE_FILTER_NEAREST = 0, SCALE_FILTER_BIL = 1, @@ -135,6 +129,17 @@ enum mdp5_client_id { CID_MAX = 23, }; +enum mdp5_cursor_format { + CURSOR_FMT_ARGB8888 = 0, + CURSOR_FMT_ARGB1555 = 2, + CURSOR_FMT_ARGB4444 = 4, +}; + +enum mdp5_cursor_alpha { + CURSOR_ALPHA_CONST = 0, + CURSOR_ALPHA_PER_PIXEL = 2, +}; + enum mdp5_igc_type { IGC_VIG = 0, IGC_RGB = 1, @@ -142,6 +147,11 @@ enum mdp5_igc_type { IGC_DSPP = 3, }; +enum mdp5_data_format { + DATA_FORMAT_RGB = 0, + 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 @@ -463,12 +473,143 @@ static inline uint32_t __offset_PIPE(enum mdp5_pipe idx) } static inline uint32_t REG_MDP5_PIPE(enum mdp5_pipe i0) { return 0x00000000 + __offset_PIPE(i0); } +static inline uint32_t REG_MDP5_PIPE_OP_MODE(enum mdp5_pipe i0) { return 0x00000200 + __offset_PIPE(i0); } +#define MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT__MASK 0x00080000 +#define MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT__SHIFT 19 +static inline uint32_t MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT(enum mdp5_data_format val) +{ + return ((val) << MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT__SHIFT) & MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT__MASK; +} +#define MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT__MASK 0x00040000 +#define MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT__SHIFT 18 +static inline uint32_t MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT(enum mdp5_data_format val) +{ + return ((val) << MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT__SHIFT) & MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT__MASK; +} +#define MDP5_PIPE_OP_MODE_CSC_1_EN 0x00020000 + static inline uint32_t REG_MDP5_PIPE_HIST_CTL_BASE(enum mdp5_pipe i0) { return 0x000002c4 + __offset_PIPE(i0); } static inline uint32_t REG_MDP5_PIPE_HIST_LUT_BASE(enum mdp5_pipe i0) { return 0x000002f0 + __offset_PIPE(i0); } static inline uint32_t REG_MDP5_PIPE_HIST_LUT_SWAP(enum mdp5_pipe i0) { return 0x00000300 + __offset_PIPE(i0); } +static inline uint32_t REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_0(enum mdp5_pipe i0) { return 0x00000320 + __offset_PIPE(i0); } +#define MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11__MASK 0x00001fff +#define MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11__SHIFT 0 +static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11(uint32_t val) +{ + return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11__MASK; +} +#define MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12__MASK 0x1fff0000 +#define MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12__SHIFT 16 +static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12(uint32_t val) +{ + return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_1(enum mdp5_pipe i0) { return 0x00000324 + __offset_PIPE(i0); } +#define MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13__MASK 0x00001fff +#define MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13__SHIFT 0 +static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13(uint32_t val) +{ + return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13__MASK; +} +#define MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21__MASK 0x1fff0000 +#define MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21__SHIFT 16 +static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21(uint32_t val) +{ + return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_2(enum mdp5_pipe i0) { return 0x00000328 + __offset_PIPE(i0); } +#define MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22__MASK 0x00001fff +#define MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22__SHIFT 0 +static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22(uint32_t val) +{ + return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22__MASK; +} +#define MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23__MASK 0x1fff0000 +#define MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23__SHIFT 16 +static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23(uint32_t val) +{ + return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_3(enum mdp5_pipe i0) { return 0x0000032c + __offset_PIPE(i0); } +#define MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31__MASK 0x00001fff +#define MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31__SHIFT 0 +static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31(uint32_t val) +{ + return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31__MASK; +} +#define MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32__MASK 0x1fff0000 +#define MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32__SHIFT 16 +static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32(uint32_t val) +{ + return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_4(enum mdp5_pipe i0) { return 0x00000330 + __offset_PIPE(i0); } +#define MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33__MASK 0x00001fff +#define MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33__SHIFT 0 +static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33(uint32_t val) +{ + return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_CSC_1_PRE_CLAMP(enum mdp5_pipe i0, uint32_t i1) { return 0x00000334 + __offset_PIPE(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP5_PIPE_CSC_1_PRE_CLAMP_REG(enum mdp5_pipe i0, uint32_t i1) { return 0x00000334 + __offset_PIPE(i0) + 0x4*i1; } +#define MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH__MASK 0x000000ff +#define MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH__SHIFT 0 +static inline uint32_t MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH(uint32_t val) +{ + return ((val) << MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH__SHIFT) & MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH__MASK; +} +#define MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW__MASK 0x0000ff00 +#define MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW__SHIFT 8 +static inline uint32_t MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW(uint32_t val) +{ + return ((val) << MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW__SHIFT) & MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_CSC_1_POST_CLAMP(enum mdp5_pipe i0, uint32_t i1) { return 0x00000340 + __offset_PIPE(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP5_PIPE_CSC_1_POST_CLAMP_REG(enum mdp5_pipe i0, uint32_t i1) { return 0x00000340 + __offset_PIPE(i0) + 0x4*i1; } +#define MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH__MASK 0x000000ff +#define MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH__SHIFT 0 +static inline uint32_t MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH(uint32_t val) +{ + return ((val) << MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH__SHIFT) & MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH__MASK; +} +#define MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW__MASK 0x0000ff00 +#define MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW__SHIFT 8 +static inline uint32_t MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW(uint32_t val) +{ + return ((val) << MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW__SHIFT) & MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_CSC_1_PRE_BIAS(enum mdp5_pipe i0, uint32_t i1) { return 0x0000034c + __offset_PIPE(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP5_PIPE_CSC_1_PRE_BIAS_REG(enum mdp5_pipe i0, uint32_t i1) { return 0x0000034c + __offset_PIPE(i0) + 0x4*i1; } +#define MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE__MASK 0x000001ff +#define MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE__SHIFT 0 +static inline uint32_t MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE(uint32_t val) +{ + return ((val) << MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE__SHIFT) & MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_CSC_1_POST_BIAS(enum mdp5_pipe i0, uint32_t i1) { return 0x00000358 + __offset_PIPE(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP5_PIPE_CSC_1_POST_BIAS_REG(enum mdp5_pipe i0, uint32_t i1) { return 0x00000358 + __offset_PIPE(i0) + 0x4*i1; } +#define MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE__MASK 0x000001ff +#define MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE__SHIFT 0 +static inline uint32_t MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE(uint32_t val) +{ + return ((val) << MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE__SHIFT) & MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE__MASK; +} + static inline uint32_t REG_MDP5_PIPE_SRC_SIZE(enum mdp5_pipe i0) { return 0x00000000 + __offset_PIPE(i0); } #define MDP5_PIPE_SRC_SIZE_HEIGHT__MASK 0xffff0000 #define MDP5_PIPE_SRC_SIZE_HEIGHT__SHIFT 16 @@ -618,15 +759,15 @@ 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 0x00780000 +#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(uint32_t val) +static inline uint32_t MDP5_PIPE_SRC_FORMAT_NUM_PLANES(enum mdp_sspp_fetch_type val) { return ((val) << MDP5_PIPE_SRC_FORMAT_NUM_PLANES__SHIFT) & MDP5_PIPE_SRC_FORMAT_NUM_PLANES__MASK; } #define MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK 0x01800000 #define MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT 23 -static inline uint32_t MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(enum mdp5_chroma_samp_type val) +static inline uint32_t MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(enum mdp_chroma_samp_type val) { return ((val) << MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT) & MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK; } @@ -753,6 +894,10 @@ static inline uint32_t REG_MDP5_PIPE_SCALE_PHASE_STEP_X(enum mdp5_pipe i0) { ret static inline uint32_t REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(enum mdp5_pipe i0) { return 0x00000214 + __offset_PIPE(i0); } +static inline uint32_t REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(enum mdp5_pipe i0) { return 0x00000218 + __offset_PIPE(i0); } + +static inline uint32_t REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(enum mdp5_pipe i0) { return 0x0000021c + __offset_PIPE(i0); } + static inline uint32_t REG_MDP5_PIPE_SCALE_INIT_PHASE_X(enum mdp5_pipe i0) { return 0x00000220 + __offset_PIPE(i0); } static inline uint32_t REG_MDP5_PIPE_SCALE_INIT_PHASE_Y(enum mdp5_pipe i0) { return 0x00000224 + __offset_PIPE(i0); } @@ -839,20 +984,88 @@ static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH0(uint32_t i0, uint32_t i 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_CURSOR_IMG_SIZE(uint32_t i0) { return 0x000000e0 + __offset_LM(i0); } +#define MDP5_LM_CURSOR_IMG_SIZE_SRC_W__MASK 0x0000ffff +#define MDP5_LM_CURSOR_IMG_SIZE_SRC_W__SHIFT 0 +static inline uint32_t MDP5_LM_CURSOR_IMG_SIZE_SRC_W(uint32_t val) +{ + return ((val) << MDP5_LM_CURSOR_IMG_SIZE_SRC_W__SHIFT) & MDP5_LM_CURSOR_IMG_SIZE_SRC_W__MASK; +} +#define MDP5_LM_CURSOR_IMG_SIZE_SRC_H__MASK 0xffff0000 +#define MDP5_LM_CURSOR_IMG_SIZE_SRC_H__SHIFT 16 +static inline uint32_t MDP5_LM_CURSOR_IMG_SIZE_SRC_H(uint32_t val) +{ + return ((val) << MDP5_LM_CURSOR_IMG_SIZE_SRC_H__SHIFT) & MDP5_LM_CURSOR_IMG_SIZE_SRC_H__MASK; +} static inline uint32_t REG_MDP5_LM_CURSOR_SIZE(uint32_t i0) { return 0x000000e4 + __offset_LM(i0); } +#define MDP5_LM_CURSOR_SIZE_ROI_W__MASK 0x0000ffff +#define MDP5_LM_CURSOR_SIZE_ROI_W__SHIFT 0 +static inline uint32_t MDP5_LM_CURSOR_SIZE_ROI_W(uint32_t val) +{ + return ((val) << MDP5_LM_CURSOR_SIZE_ROI_W__SHIFT) & MDP5_LM_CURSOR_SIZE_ROI_W__MASK; +} +#define MDP5_LM_CURSOR_SIZE_ROI_H__MASK 0xffff0000 +#define MDP5_LM_CURSOR_SIZE_ROI_H__SHIFT 16 +static inline uint32_t MDP5_LM_CURSOR_SIZE_ROI_H(uint32_t val) +{ + return ((val) << MDP5_LM_CURSOR_SIZE_ROI_H__SHIFT) & MDP5_LM_CURSOR_SIZE_ROI_H__MASK; +} static inline uint32_t REG_MDP5_LM_CURSOR_XY(uint32_t i0) { return 0x000000e8 + __offset_LM(i0); } +#define MDP5_LM_CURSOR_XY_SRC_X__MASK 0x0000ffff +#define MDP5_LM_CURSOR_XY_SRC_X__SHIFT 0 +static inline uint32_t MDP5_LM_CURSOR_XY_SRC_X(uint32_t val) +{ + return ((val) << MDP5_LM_CURSOR_XY_SRC_X__SHIFT) & MDP5_LM_CURSOR_XY_SRC_X__MASK; +} +#define MDP5_LM_CURSOR_XY_SRC_Y__MASK 0xffff0000 +#define MDP5_LM_CURSOR_XY_SRC_Y__SHIFT 16 +static inline uint32_t MDP5_LM_CURSOR_XY_SRC_Y(uint32_t val) +{ + return ((val) << MDP5_LM_CURSOR_XY_SRC_Y__SHIFT) & MDP5_LM_CURSOR_XY_SRC_Y__MASK; +} static inline uint32_t REG_MDP5_LM_CURSOR_STRIDE(uint32_t i0) { return 0x000000dc + __offset_LM(i0); } +#define MDP5_LM_CURSOR_STRIDE_STRIDE__MASK 0x0000ffff +#define MDP5_LM_CURSOR_STRIDE_STRIDE__SHIFT 0 +static inline uint32_t MDP5_LM_CURSOR_STRIDE_STRIDE(uint32_t val) +{ + return ((val) << MDP5_LM_CURSOR_STRIDE_STRIDE__SHIFT) & MDP5_LM_CURSOR_STRIDE_STRIDE__MASK; +} static inline uint32_t REG_MDP5_LM_CURSOR_FORMAT(uint32_t i0) { return 0x000000ec + __offset_LM(i0); } +#define MDP5_LM_CURSOR_FORMAT_FORMAT__MASK 0x00000007 +#define MDP5_LM_CURSOR_FORMAT_FORMAT__SHIFT 0 +static inline uint32_t MDP5_LM_CURSOR_FORMAT_FORMAT(enum mdp5_cursor_format val) +{ + return ((val) << MDP5_LM_CURSOR_FORMAT_FORMAT__SHIFT) & MDP5_LM_CURSOR_FORMAT_FORMAT__MASK; +} static inline uint32_t REG_MDP5_LM_CURSOR_BASE_ADDR(uint32_t i0) { return 0x000000f0 + __offset_LM(i0); } static inline uint32_t REG_MDP5_LM_CURSOR_START_XY(uint32_t i0) { return 0x000000f4 + __offset_LM(i0); } +#define MDP5_LM_CURSOR_START_XY_X_START__MASK 0x0000ffff +#define MDP5_LM_CURSOR_START_XY_X_START__SHIFT 0 +static inline uint32_t MDP5_LM_CURSOR_START_XY_X_START(uint32_t val) +{ + return ((val) << MDP5_LM_CURSOR_START_XY_X_START__SHIFT) & MDP5_LM_CURSOR_START_XY_X_START__MASK; +} +#define MDP5_LM_CURSOR_START_XY_Y_START__MASK 0xffff0000 +#define MDP5_LM_CURSOR_START_XY_Y_START__SHIFT 16 +static inline uint32_t MDP5_LM_CURSOR_START_XY_Y_START(uint32_t val) +{ + return ((val) << MDP5_LM_CURSOR_START_XY_Y_START__SHIFT) & MDP5_LM_CURSOR_START_XY_Y_START__MASK; +} static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_CONFIG(uint32_t i0) { return 0x000000f8 + __offset_LM(i0); } +#define MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_EN 0x00000001 +#define MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL__MASK 0x00000006 +#define MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL__SHIFT 1 +static inline uint32_t MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL(enum mdp5_cursor_alpha val) +{ + return ((val) << MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL__SHIFT) & MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL__MASK; +} +#define MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_TRANSP_EN 0x00000008 static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_PARAM(uint32_t i0) { return 0x000000fc + __offset_LM(i0); } diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index f021f960a8a2..46fac545dc2b 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -24,6 +24,9 @@ #include "drm_crtc_helper.h" #include "drm_flip_work.h" +#define CURSOR_WIDTH 64 +#define CURSOR_HEIGHT 64 + #define SSPP_MAX (SSPP_RGB3 + 1) /* TODO: Add SSPP_MAX in mdp5.xml.h */ struct mdp5_crtc { @@ -47,8 +50,21 @@ struct mdp5_crtc { #define PENDING_FLIP 0x2 atomic_t pending; + /* for unref'ing cursor bo's after scanout completes: */ + struct drm_flip_work unref_cursor_work; + struct mdp_irq vblank; struct mdp_irq err; + + struct { + /* protect REG_MDP5_LM_CURSOR* registers and cursor scanout_bo*/ + spinlock_t lock; + + /* current cursor being scanned out: */ + struct drm_gem_object *scanout_bo; + uint32_t width; + uint32_t height; + } cursor; }; #define to_mdp5_crtc(x) container_of(x, struct mdp5_crtc, base) @@ -129,37 +145,26 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file) } } +static void unref_cursor_worker(struct drm_flip_work *work, void *val) +{ + struct mdp5_crtc *mdp5_crtc = + container_of(work, struct mdp5_crtc, unref_cursor_work); + struct mdp5_kms *mdp5_kms = get_kms(&mdp5_crtc->base); + + msm_gem_put_iova(val, mdp5_kms->id); + drm_gem_object_unreference_unlocked(val); +} + static void mdp5_crtc_destroy(struct drm_crtc *crtc) { struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); drm_crtc_cleanup(crtc); + drm_flip_work_cleanup(&mdp5_crtc->unref_cursor_work); kfree(mdp5_crtc); } -static void mdp5_crtc_dpms(struct drm_crtc *crtc, int mode) -{ - struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); - struct mdp5_kms *mdp5_kms = get_kms(crtc); - bool enabled = (mode == DRM_MODE_DPMS_ON); - - DBG("%s: mode=%d", mdp5_crtc->name, mode); - - if (enabled != mdp5_crtc->enabled) { - if (enabled) { - mdp5_enable(mdp5_kms); - mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err); - } else { - /* set STAGE_UNUSED for all layers */ - mdp5_ctl_blend(mdp5_crtc->ctl, mdp5_crtc->lm, 0x00000000); - mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->err); - mdp5_disable(mdp5_kms); - } - mdp5_crtc->enabled = enabled; - } -} - static bool mdp5_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -256,27 +261,41 @@ static void mdp5_crtc_mode_set_nofb(struct drm_crtc *crtc) spin_unlock_irqrestore(&mdp5_crtc->lm_lock, flags); } -static void mdp5_crtc_prepare(struct drm_crtc *crtc) +static void mdp5_crtc_disable(struct drm_crtc *crtc) { struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + struct mdp5_kms *mdp5_kms = get_kms(crtc); + DBG("%s", mdp5_crtc->name); - /* make sure we hold a ref to mdp clks while setting up mode: */ - mdp5_enable(get_kms(crtc)); - mdp5_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); + + if (WARN_ON(!mdp5_crtc->enabled)) + return; + + /* set STAGE_UNUSED for all layers */ + mdp5_ctl_blend(mdp5_crtc->ctl, mdp5_crtc->lm, 0x00000000); + + mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->err); + mdp5_disable(mdp5_kms); + + mdp5_crtc->enabled = false; } -static void mdp5_crtc_commit(struct drm_crtc *crtc) +static void mdp5_crtc_enable(struct drm_crtc *crtc) { struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + struct mdp5_kms *mdp5_kms = get_kms(crtc); + DBG("%s", mdp5_crtc->name); - mdp5_crtc_dpms(crtc, DRM_MODE_DPMS_ON); + + if (WARN_ON(mdp5_crtc->enabled)) + return; + + mdp5_enable(mdp5_kms); + mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err); + crtc_flush_all(crtc); - /* drop the ref to mdp clk's that we got in prepare: */ - mdp5_disable(get_kms(crtc)); -} -static void mdp5_crtc_load_lut(struct drm_crtc *crtc) -{ + mdp5_crtc->enabled = true; } struct plane_state { @@ -384,6 +403,132 @@ static int mdp5_crtc_set_property(struct drm_crtc *crtc, return -EINVAL; } +static int mdp5_crtc_cursor_set(struct drm_crtc *crtc, + struct drm_file *file, uint32_t handle, + uint32_t width, uint32_t height) +{ + 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; + 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); + unsigned long flags; + + if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) { + dev_err(dev->dev, "bad cursor size: %dx%d\n", width, height); + return -EINVAL; + } + + if (NULL == mdp5_crtc->ctl) + return -EINVAL; + + if (!handle) { + DBG("Cursor off"); + return mdp5_ctl_set_cursor(mdp5_crtc->ctl, false); + } + + cursor_bo = drm_gem_object_lookup(dev, file, handle); + if (!cursor_bo) + return -ENOENT; + + ret = msm_gem_get_iova(cursor_bo, mdp5_kms->id, &cursor_addr); + if (ret) + return -EINVAL; + + lm = mdp5_crtc->lm; + drm_fb_get_bpp_depth(DRM_FORMAT_ARGB8888, &depth, &bpp); + stride = width * (bpp >> 3); + + spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags); + old_bo = mdp5_crtc->cursor.scanout_bo; + + mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_STRIDE(lm), stride); + mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_FORMAT(lm), + MDP5_LM_CURSOR_FORMAT_FORMAT(CURSOR_FMT_ARGB8888)); + mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_IMG_SIZE(lm), + MDP5_LM_CURSOR_IMG_SIZE_SRC_H(height) | + MDP5_LM_CURSOR_IMG_SIZE_SRC_W(width)); + mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(lm), + MDP5_LM_CURSOR_SIZE_ROI_H(height) | + MDP5_LM_CURSOR_SIZE_ROI_W(width)); + mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BASE_ADDR(lm), cursor_addr); + + + blendcfg = MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_EN; + blendcfg |= MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_TRANSP_EN; + blendcfg |= MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL(cur_alpha); + mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BLEND_CONFIG(lm), blendcfg); + + mdp5_crtc->cursor.scanout_bo = cursor_bo; + mdp5_crtc->cursor.width = width; + mdp5_crtc->cursor.height = height; + spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags); + + ret = mdp5_ctl_set_cursor(mdp5_crtc->ctl, true); + if (ret) + goto end; + + flush_mask |= mdp5_ctl_get_flush(mdp5_crtc->ctl); + crtc_flush(crtc, flush_mask); + +end: + if (old_bo) { + drm_flip_work_queue(&mdp5_crtc->unref_cursor_work, old_bo); + /* enable vblank to complete cursor work: */ + request_pending(crtc, PENDING_CURSOR); + } + return ret; +} + +static int mdp5_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) +{ + struct mdp5_kms *mdp5_kms = get_kms(crtc); + struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0); + uint32_t xres = crtc->mode.hdisplay; + uint32_t yres = crtc->mode.vdisplay; + uint32_t roi_w; + uint32_t roi_h; + unsigned long flags; + + x = (x > 0) ? x : 0; + y = (y > 0) ? y : 0; + + /* + * Cursor Region Of Interest (ROI) is a plane read from cursor + * buffer to render. The ROI region is determined by the visiblity of + * the cursor point. In the default Cursor image the cursor point will + * be at the top left of the cursor image, unless it is specified + * otherwise using hotspot feature. + * + * If the cursor point reaches the right (xres - x < cursor.width) or + * bottom (yres - y < cursor.height) boundary of the screen, then ROI + * width and ROI height need to be evaluated to crop the cursor image + * accordingly. + * (xres-x) will be new cursor width when x > (xres - cursor.width) + * (yres-y) will be new cursor height when y > (yres - cursor.height) + */ + roi_w = min(mdp5_crtc->cursor.width, xres - x); + roi_h = min(mdp5_crtc->cursor.height, yres - y); + + spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags); + mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(mdp5_crtc->lm), + MDP5_LM_CURSOR_SIZE_ROI_H(roi_h) | + MDP5_LM_CURSOR_SIZE_ROI_W(roi_w)); + mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_START_XY(mdp5_crtc->lm), + MDP5_LM_CURSOR_START_XY_Y_START(y) | + MDP5_LM_CURSOR_START_XY_X_START(x)); + spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags); + + crtc_flush(crtc, flush_mask); + + return 0; +} + static const struct drm_crtc_funcs mdp5_crtc_funcs = { .set_config = drm_atomic_helper_set_config, .destroy = mdp5_crtc_destroy, @@ -392,17 +537,15 @@ static const struct drm_crtc_funcs mdp5_crtc_funcs = { .reset = drm_atomic_helper_crtc_reset, .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .cursor_set = mdp5_crtc_cursor_set, + .cursor_move = mdp5_crtc_cursor_move, }; static const struct drm_crtc_helper_funcs mdp5_crtc_helper_funcs = { - .dpms = mdp5_crtc_dpms, .mode_fixup = mdp5_crtc_mode_fixup, .mode_set_nofb = mdp5_crtc_mode_set_nofb, - .mode_set = drm_helper_crtc_mode_set, - .mode_set_base = drm_helper_crtc_mode_set_base, - .prepare = mdp5_crtc_prepare, - .commit = mdp5_crtc_commit, - .load_lut = mdp5_crtc_load_lut, + .prepare = mdp5_crtc_disable, + .commit = mdp5_crtc_enable, .atomic_check = mdp5_crtc_atomic_check, .atomic_begin = mdp5_crtc_atomic_begin, .atomic_flush = mdp5_crtc_atomic_flush, @@ -412,6 +555,7 @@ static void mdp5_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus) { struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc, vblank); struct drm_crtc *crtc = &mdp5_crtc->base; + struct msm_drm_private *priv = crtc->dev->dev_private; unsigned pending; mdp_irq_unregister(&get_kms(crtc)->base, &mdp5_crtc->vblank); @@ -421,6 +565,9 @@ static void mdp5_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus) if (pending & PENDING_FLIP) { complete_flip(crtc, NULL); } + + if (pending & PENDING_CURSOR) + drm_flip_work_commit(&mdp5_crtc->unref_cursor_work, priv->wq); } static void mdp5_crtc_err_irq(struct mdp_irq *irq, uint32_t irqstatus) @@ -520,6 +667,7 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev, mdp5_crtc->lm = GET_LM_ID(id); spin_lock_init(&mdp5_crtc->lm_lock); + spin_lock_init(&mdp5_crtc->cursor.lock); mdp5_crtc->vblank.irq = mdp5_crtc_vblank_irq; mdp5_crtc->err.irq = mdp5_crtc_err_irq; @@ -528,6 +676,10 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev, pipe2name(mdp5_plane_pipe(plane)), id); drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp5_crtc_funcs); + + drm_flip_work_init(&mdp5_crtc->unref_cursor_work, + "unref cursor", unref_cursor_worker); + drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs); plane->crtc = crtc; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c index dea4505ac963..151129032d16 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c @@ -95,7 +95,7 @@ u32 ctl_read(struct mdp5_ctl *ctl, u32 reg) } -int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, enum mdp5_intf intf) +int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, int intf) { unsigned long flags; static const enum mdp5_intfnum intfnum[] = { diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h index 1018519b6af2..ad48788efeea 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h @@ -34,7 +34,7 @@ void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctlm); */ struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctlm, struct drm_crtc *crtc); -int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, enum mdp5_intf intf); +int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, int intf); int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, bool enable); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c index 0254bfdeb92f..d6a14bb99988 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * @@ -110,45 +111,6 @@ static const struct drm_encoder_funcs mdp5_encoder_funcs = { .destroy = mdp5_encoder_destroy, }; -static void mdp5_encoder_dpms(struct drm_encoder *encoder, int mode) -{ - struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder); - struct mdp5_kms *mdp5_kms = get_kms(encoder); - int intf = mdp5_encoder->intf; - bool enabled = (mode == DRM_MODE_DPMS_ON); - unsigned long flags; - - DBG("mode=%d", mode); - - if (enabled == mdp5_encoder->enabled) - return; - - if (enabled) { - 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); - spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags); - } else { - spin_lock_irqsave(&mdp5_encoder->intf_lock, flags); - mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 0); - spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags); - - /* - * Wait for a vsync so we know the ENABLE=0 latched before - * the (connector) source of the vsync's gets disabled, - * otherwise we end up in a funny state if we re-enable - * before the disable latches, which results that some of - * the settings changes for the new modeset (like new - * scanout buffer) don't latch properly.. - */ - mdp_irq_wait(&mdp5_kms->base, intf2vblank(intf)); - - bs_set(mdp5_encoder, 0); - } - - mdp5_encoder->enabled = enabled; -} - static bool mdp5_encoder_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -162,11 +124,13 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder, { struct mdp5_encoder *mdp5_encoder = to_mdp5_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; uint32_t dtv_hsync_skew, vsync_period, vsync_len, ctrl_pol; uint32_t display_v_start, display_v_end; uint32_t hsync_start_x, hsync_end_x; - uint32_t format; + uint32_t format = 0x2100; unsigned long flags; mode = adjusted_mode; @@ -188,7 +152,28 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder, /* probably need to get DATA_EN polarity from panel.. */ dtv_hsync_skew = 0; /* get this from panel? */ - format = 0x213f; /* get this from panel? */ + + /* Get color format from panel, default is 8bpc */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->encoder == encoder) { + switch (connector->display_info.bpc) { + case 4: + format |= 0; + break; + case 5: + format |= 0x15; + break; + case 6: + format |= 0x2A; + break; + case 8: + default: + format |= 0x3F; + break; + } + break; + } + } hsync_start_x = (mode->htotal - mode->hsync_start); hsync_end_x = mode->htotal - (mode->hsync_start - mode->hdisplay) - 1; @@ -198,6 +183,16 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder, display_v_start = (mode->vtotal - mode->vsync_start) * mode->htotal + dtv_hsync_skew; display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + dtv_hsync_skew - 1; + /* + * For edp only: + * DISPLAY_V_START = (VBP * HCYCLE) + HBP + * DISPLAY_V_END = (VBP + VACTIVE) * HCYCLE - 1 - HFP + */ + if (mdp5_encoder->intf_id == INTF_eDP) { + display_v_start += mode->htotal - mode->hsync_start; + display_v_end -= mode->hsync_start - mode->hdisplay; + } + spin_lock_irqsave(&mdp5_encoder->intf_lock, flags); mdp5_write(mdp5_kms, REG_MDP5_INTF_HSYNC_CTL(intf), @@ -225,25 +220,61 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder, spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags); } -static void mdp5_encoder_prepare(struct drm_encoder *encoder) +static void mdp5_encoder_disable(struct drm_encoder *encoder) { - mdp5_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); + struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder); + struct mdp5_kms *mdp5_kms = get_kms(encoder); + int intf = mdp5_encoder->intf; + unsigned long flags; + + if (WARN_ON(!mdp5_encoder->enabled)) + return; + + spin_lock_irqsave(&mdp5_encoder->intf_lock, flags); + mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 0); + spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags); + + /* + * Wait for a vsync so we know the ENABLE=0 latched before + * the (connector) source of the vsync's gets disabled, + * otherwise we end up in a funny state if we re-enable + * before the disable latches, which results that some of + * the settings changes for the new modeset (like new + * scanout buffer) don't latch properly.. + */ + mdp_irq_wait(&mdp5_kms->base, intf2vblank(intf)); + + bs_set(mdp5_encoder, 0); + + mdp5_encoder->enabled = false; } -static void mdp5_encoder_commit(struct drm_encoder *encoder) +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; + unsigned long flags; + + if (WARN_ON(mdp5_encoder->enabled)) + return; + mdp5_crtc_set_intf(encoder->crtc, mdp5_encoder->intf, mdp5_encoder->intf_id); - mdp5_encoder_dpms(encoder, DRM_MODE_DPMS_ON); + + 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); + spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags); + + mdp5_encoder->enabled = false; } static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = { - .dpms = mdp5_encoder_dpms, .mode_fixup = mdp5_encoder_mode_fixup, .mode_set = mdp5_encoder_mode_set, - .prepare = mdp5_encoder_prepare, - .commit = mdp5_encoder_commit, + .prepare = mdp5_encoder_disable, + .commit = mdp5_encoder_enable, }; /* initialize encoder */ diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index 9f01a4f21af2..92b61db5754c 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -68,6 +68,18 @@ static int mdp5_hw_init(struct msm_kms *kms) return 0; } +static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state) +{ + struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); + mdp5_enable(mdp5_kms); +} + +static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state) +{ + struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); + mdp5_disable(mdp5_kms); +} + static long mdp5_round_pixclk(struct msm_kms *kms, unsigned long rate, struct drm_encoder *encoder) { @@ -115,6 +127,8 @@ static const struct mdp_kms_funcs kms_funcs = { .irq = mdp5_irq, .enable_vblank = mdp5_enable_vblank, .disable_vblank = mdp5_disable_vblank, + .prepare_commit = mdp5_prepare_commit, + .complete_commit = mdp5_complete_commit, .get_format = mdp_get_format, .round_pixclk = mdp5_round_pixclk, .preclose = mdp5_preclose, @@ -208,19 +222,18 @@ static int modeset_init(struct mdp5_kms *mdp5_kms) } } - /* 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; - } + 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; + encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;; + priv->encoders[priv->num_encoders++] = encoder; - /* Construct bridge/connector for HDMI: */ - if (priv->hdmi) { ret = hdmi_modeset_init(priv->hdmi, dev, encoder); if (ret) { dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret); @@ -228,6 +241,27 @@ static int modeset_init(struct mdp5_kms *mdp5_kms) } } + 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); + goto fail; + } + } + return 0; fail: diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h index dd69c77c0d64..49d011e8835b 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h @@ -165,14 +165,25 @@ 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) { - /* TODO when we have YUV, we need to filter supported formats - * based on pipe id.. - */ - return mdp_get_formats(pixel_formats, max_formats); + return mdp_get_formats(pixel_formats, max_formats, + !pipe_supports_yuv(pipe)); } void mdp5_plane_install_properties(struct drm_plane *plane, diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index 26e5fdea6594..05cf9ab2a876 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -18,8 +18,6 @@ #include "mdp5_kms.h" -#define MAX_PLANE 4 - struct mdp5_plane { struct drm_plane base; const char *name; @@ -113,6 +111,7 @@ static void mdp5_plane_reset(struct drm_plane *plane) } else { mdp5_state->zpos = 1 + drm_plane_index(plane); } + mdp5_state->base.plane = plane; plane->state = &mdp5_state->base; } @@ -277,6 +276,155 @@ static void set_scanout_locked(struct drm_plane *plane, plane->fb = fb; } +/* Note: mdp5_plane->pipe_lock must be locked */ +static void csc_disable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe) +{ + uint32_t value = mdp5_read(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe)) & + ~MDP5_PIPE_OP_MODE_CSC_1_EN; + + mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), value); +} + +/* Note: mdp5_plane->pipe_lock must be locked */ +static void csc_enable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe, + struct csc_cfg *csc) +{ + uint32_t i, mode = 0; /* RGB, no CSC */ + uint32_t *matrix; + + if (unlikely(!csc)) + return; + + if ((csc->type == CSC_YUV2RGB) || (CSC_YUV2YUV == csc->type)) + mode |= MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT(DATA_FORMAT_YUV); + if ((csc->type == CSC_RGB2YUV) || (CSC_YUV2YUV == csc->type)) + mode |= MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT(DATA_FORMAT_YUV); + mode |= MDP5_PIPE_OP_MODE_CSC_1_EN; + mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), mode); + + matrix = csc->matrix; + mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_0(pipe), + MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11(matrix[0]) | + MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12(matrix[1])); + mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_1(pipe), + MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13(matrix[2]) | + MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21(matrix[3])); + mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_2(pipe), + MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22(matrix[4]) | + MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23(matrix[5])); + mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_3(pipe), + MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31(matrix[6]) | + MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32(matrix[7])); + mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_4(pipe), + MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33(matrix[8])); + + for (i = 0; i < ARRAY_SIZE(csc->pre_bias); i++) { + uint32_t *pre_clamp = csc->pre_clamp; + uint32_t *post_clamp = csc->post_clamp; + + mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_CLAMP(pipe, i), + MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH(pre_clamp[2*i+1]) | + MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW(pre_clamp[2*i])); + + mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_CLAMP(pipe, i), + MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH(post_clamp[2*i+1]) | + MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW(post_clamp[2*i])); + + mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_BIAS(pipe, i), + MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE(csc->pre_bias[i])); + + mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_BIAS(pipe, i), + MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE(csc->post_bias[i])); + } +} + +#define PHASE_STEP_SHIFT 21 +#define DOWN_SCALE_RATIO_MAX 32 /* 2^(26-21) */ + +static int calc_phase_step(uint32_t src, uint32_t dst, uint32_t *out_phase) +{ + uint32_t unit; + + if (src == 0 || dst == 0) + return -EINVAL; + + /* + * PHASE_STEP_X/Y is coded on 26 bits (25:0), + * where 2^21 represents the unity "1" in fixed-point hardware design. + * This leaves 5 bits for the integer part (downscale case): + * -> maximum downscale ratio = 0b1_1111 = 31 + */ + if (src > (dst * DOWN_SCALE_RATIO_MAX)) + return -EOVERFLOW; + + unit = 1 << PHASE_STEP_SHIFT; + *out_phase = mult_frac(unit, src, dst); + + return 0; +} + +static int calc_scalex_steps(uint32_t pixel_format, uint32_t src, uint32_t dest, + uint32_t phasex_steps[2]) +{ + uint32_t phasex_step; + unsigned int hsub; + int ret; + + ret = calc_phase_step(src, dest, &phasex_step); + if (ret) + return ret; + + hsub = drm_format_horz_chroma_subsampling(pixel_format); + + phasex_steps[0] = phasex_step; + phasex_steps[1] = phasex_step / hsub; + + return 0; +} + +static int calc_scaley_steps(uint32_t pixel_format, uint32_t src, uint32_t dest, + uint32_t phasey_steps[2]) +{ + uint32_t phasey_step; + unsigned int vsub; + int ret; + + ret = calc_phase_step(src, dest, &phasey_step); + if (ret) + return ret; + + vsub = drm_format_vert_chroma_subsampling(pixel_format); + + phasey_steps[0] = phasey_step; + phasey_steps[1] = phasey_step / vsub; + + return 0; +} + +static uint32_t get_scalex_config(uint32_t src, uint32_t dest) +{ + uint32_t filter; + + filter = (src <= dest) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN; + + 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); +} + static int mdp5_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, @@ -286,11 +434,14 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, { struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 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; - uint32_t phasex_step = 0, phasey_step = 0; + /* below array -> index 0: comp 0/3 ; index 1: comp 1/2 */ + uint32_t phasex_step[2] = {0,}, phasey_step[2] = {0,}; uint32_t hdecm = 0, vdecm = 0; + uint32_t pix_format; unsigned long flags; int ret; @@ -300,6 +451,9 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, if (WARN_ON(nplanes > pipe2nclients(pipe))) return -EINVAL; + format = to_mdp_format(msm_framebuffer_format(fb)); + pix_format = format->base.pixel_format; + /* src values are in Q16 fixed point, convert to integer: */ src_x = src_x >> 16; src_y = src_y >> 16; @@ -324,14 +478,28 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, */ mdp5_smp_configure(mdp5_kms->smp, pipe); - if (src_w != crtc_w) { - config |= MDP5_PIPE_SCALE_CONFIG_SCALEX_EN; - /* TODO calc phasex_step, hdecm */ + /* SCALE is used to both scale and up-sample chroma components */ + + 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) { - config |= MDP5_PIPE_SCALE_CONFIG_SCALEY_EN; - /* TODO calc phasey_step, vdecm */ + 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); } spin_lock_irqsave(&mdp5_plane->pipe_lock, flags); @@ -356,8 +524,6 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, MDP5_PIPE_OUT_XY_X(crtc_x) | MDP5_PIPE_OUT_XY_Y(crtc_y)); - format = to_mdp_format(msm_framebuffer_format(fb)); - mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_FORMAT(pipe), MDP5_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) | MDP5_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) | @@ -367,8 +533,8 @@ 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(nplanes - 1) | - MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(CHROMA_RGB)); + MDP5_PIPE_SRC_FORMAT_NUM_PLANES(format->fetch_type) | + MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample)); mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe), MDP5_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) | @@ -382,18 +548,24 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, /* not using secure mode: */ mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0); - mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe), phasex_step); - mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe), phasey_step); + mdp5_write(mdp5_kms, REG_MDP5_PIPE_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), - MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(SCALE_FILTER_NEAREST) | - MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(SCALE_FILTER_NEAREST) | - MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(SCALE_FILTER_NEAREST) | - MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(SCALE_FILTER_NEAREST) | - MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(SCALE_FILTER_NEAREST) | - MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(SCALE_FILTER_NEAREST)); + 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); set_scanout_locked(plane, fb); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c index bf551885e019..1f795af89680 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c @@ -119,9 +119,10 @@ static int smp_request_block(struct mdp5_smp *smp, spin_lock_irqsave(&smp->state_lock, flags); - nblks -= reserved; - if (reserved) + if (reserved) { + nblks = max(0, nblks - reserved); DBG("%d MMBs allocated (%d reserved)", nblks, reserved); + } avail = cnt - bitmap_weight(smp->state, cnt); if (nblks > avail) { diff --git a/drivers/gpu/drm/msm/mdp/mdp_common.xml.h b/drivers/gpu/drm/msm/mdp/mdp_common.xml.h index 64c1afd6030a..a1d35f162c7f 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_common.xml.h +++ b/drivers/gpu/drm/msm/mdp/mdp_common.xml.h @@ -8,18 +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 ( 647 bytes, from 2013-11-30 14:45:35) +- /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 ( 17996 bytes, from 2013-12-01 19:10:31) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2013-11-30 15:00:52) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2014-06-25 12:55:02) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20908 bytes, from 2014-12-08 16:13:00) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2014-12-08 16:13:00) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 27208 bytes, from 2015-01-13 23:56:11) - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43) - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1544 bytes, from 2013-08-16 19:17:05) +- /home/robclark/src/freedreno/envytools/rnndb/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 ( 23613 bytes, from 2014-06-25 12:53:44) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 26848 bytes, from 2015-01-13 23:55:57) +- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 8253 bytes, from 2014-12-08 16:13:00) -Copyright (C) 2013 by the following authors: +Copyright (C) 2013-2014 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) Permission is hereby granted, free of charge, to any person obtaining @@ -44,6 +45,19 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +enum mdp_chroma_samp_type { + CHROMA_RGB = 0, + CHROMA_H2V1 = 1, + CHROMA_H1V2 = 2, + CHROMA_420 = 3, +}; + +enum mdp_sspp_fetch_type { + MDP_PLANE_INTERLEAVED = 0, + MDP_PLANE_PLANAR = 1, + MDP_PLANE_PSEUDO_PLANAR = 2, +}; + enum mdp_mixer_stage_id { STAGE_UNUSED = 0, STAGE_BASE = 1, diff --git a/drivers/gpu/drm/msm/mdp/mdp_format.c b/drivers/gpu/drm/msm/mdp/mdp_format.c index e0a6ffbe6ab4..f683433b6727 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_format.c +++ b/drivers/gpu/drm/msm/mdp/mdp_format.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * @@ -19,7 +20,58 @@ #include "msm_drv.h" #include "mdp_kms.h" -#define FMT(name, a, r, g, b, e0, e1, e2, e3, alpha, tight, c, cnt) { \ +static struct csc_cfg csc_convert[CSC_MAX] = { + [CSC_RGB2RGB] = { + .type = CSC_RGB2RGB, + .matrix = { + 0x0200, 0x0000, 0x0000, + 0x0000, 0x0200, 0x0000, + 0x0000, 0x0000, 0x0200 + }, + .pre_bias = { 0x0, 0x0, 0x0 }, + .post_bias = { 0x0, 0x0, 0x0 }, + .pre_clamp = { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff }, + .post_clamp = { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff }, + }, + [CSC_YUV2RGB] = { + .type = CSC_YUV2RGB, + .matrix = { + 0x0254, 0x0000, 0x0331, + 0x0254, 0xff37, 0xfe60, + 0x0254, 0x0409, 0x0000 + }, + .pre_bias = { 0xfff0, 0xff80, 0xff80 }, + .post_bias = { 0x00, 0x00, 0x00 }, + .pre_clamp = { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, + .post_clamp = { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, + }, + [CSC_RGB2YUV] = { + .type = CSC_RGB2YUV, + .matrix = { + 0x0083, 0x0102, 0x0032, + 0x1fb5, 0x1f6c, 0x00e1, + 0x00e1, 0x1f45, 0x1fdc + }, + .pre_bias = { 0x00, 0x00, 0x00 }, + .post_bias = { 0x10, 0x80, 0x80 }, + .pre_clamp = { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, + .post_clamp = { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0 }, + }, + [CSC_YUV2YUV] = { + .type = CSC_YUV2YUV, + .matrix = { + 0x0200, 0x0000, 0x0000, + 0x0000, 0x0200, 0x0000, + 0x0000, 0x0000, 0x0200 + }, + .pre_bias = { 0x00, 0x00, 0x00 }, + .post_bias = { 0x00, 0x00, 0x00 }, + .pre_clamp = { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, + .post_clamp = { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, + }, +}; + +#define FMT(name, a, r, g, b, e0, e1, e2, e3, alpha, tight, c, cnt, fp, cs) { \ .base = { .pixel_format = DRM_FORMAT_ ## name }, \ .bpc_a = BPC ## a ## A, \ .bpc_r = BPC ## r, \ @@ -30,21 +82,46 @@ .unpack_tight = tight, \ .cpp = c, \ .unpack_count = cnt, \ - } + .fetch_type = fp, \ + .chroma_sample = cs \ +} #define BPC0A 0 +/* + * Note: Keep RGB formats 1st, followed by YUV formats to avoid breaking + * mdp_get_rgb_formats()'s implementation. + */ static const struct mdp_format formats[] = { - /* name a r g b e0 e1 e2 e3 alpha tight cpp cnt */ - FMT(ARGB8888, 8, 8, 8, 8, 1, 0, 2, 3, true, true, 4, 4), - FMT(XRGB8888, 8, 8, 8, 8, 1, 0, 2, 3, false, true, 4, 4), - FMT(RGB888, 0, 8, 8, 8, 1, 0, 2, 0, false, true, 3, 3), - FMT(BGR888, 0, 8, 8, 8, 2, 0, 1, 0, false, true, 3, 3), - FMT(RGB565, 0, 5, 6, 5, 1, 0, 2, 0, false, true, 2, 3), - FMT(BGR565, 0, 5, 6, 5, 2, 0, 1, 0, false, true, 2, 3), + /* 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), + FMT(XRGB8888, 8, 8, 8, 8, 1, 0, 2, 3, false, true, 4, 4, + MDP_PLANE_INTERLEAVED, CHROMA_RGB), + FMT(RGB888, 0, 8, 8, 8, 1, 0, 2, 0, false, true, 3, 3, + MDP_PLANE_INTERLEAVED, CHROMA_RGB), + FMT(BGR888, 0, 8, 8, 8, 2, 0, 1, 0, false, true, 3, 3, + MDP_PLANE_INTERLEAVED, CHROMA_RGB), + FMT(RGB565, 0, 5, 6, 5, 1, 0, 2, 0, false, true, 2, 3, + MDP_PLANE_INTERLEAVED, CHROMA_RGB), + FMT(BGR565, 0, 5, 6, 5, 2, 0, 1, 0, false, true, 2, 3, + MDP_PLANE_INTERLEAVED, CHROMA_RGB), + + /* --- RGB formats above / YUV formats below this line --- */ + + FMT(NV12, 0, 8, 8, 8, 1, 2, 0, 0, false, true, 2, 2, + MDP_PLANE_PSEUDO_PLANAR, CHROMA_420), + FMT(NV21, 0, 8, 8, 8, 2, 1, 0, 0, false, true, 2, 2, + MDP_PLANE_PSEUDO_PLANAR, CHROMA_420), }; -uint32_t mdp_get_formats(uint32_t *pixel_formats, uint32_t max_formats) +/* + * Note: + * @rgb_only must be set to true, when requesting + * supported formats for RGB pipes. + */ +uint32_t mdp_get_formats(uint32_t *pixel_formats, uint32_t max_formats, + bool rgb_only) { uint32_t i; for (i = 0; i < ARRAY_SIZE(formats); i++) { @@ -53,6 +130,9 @@ uint32_t mdp_get_formats(uint32_t *pixel_formats, uint32_t max_formats) if (i == max_formats) break; + if (rgb_only && MDP_FORMAT_IS_YUV(f)) + break; + pixel_formats[i] = f->base.pixel_format; } @@ -69,3 +149,11 @@ const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format) } return NULL; } + +struct csc_cfg *mdp_get_default_csc_cfg(enum csc_type type) +{ + if (unlikely(WARN_ON(type >= CSC_MAX))) + return NULL; + + return &csc_convert[type]; +} diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.c b/drivers/gpu/drm/msm/mdp/mdp_kms.c index 2a731722d840..1988c243f437 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp_kms.c @@ -34,7 +34,7 @@ static void update_irq(struct mdp_kms *mdp_kms) struct mdp_irq *irq; uint32_t irqmask = mdp_kms->vblank_mask; - BUG_ON(!spin_is_locked(&list_lock)); + assert_spin_locked(&list_lock); list_for_each_entry(irq, &mdp_kms->irq_list, node) irqmask |= irq->irqmask; diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.h b/drivers/gpu/drm/msm/mdp/mdp_kms.h index b268ce95d394..5ae4039d68e4 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp_kms.h @@ -88,10 +88,32 @@ struct mdp_format { uint8_t unpack[4]; bool alpha_enable, unpack_tight; uint8_t cpp, unpack_count; + enum mdp_sspp_fetch_type fetch_type; + enum mdp_chroma_samp_type chroma_sample; }; #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) -uint32_t mdp_get_formats(uint32_t *formats, uint32_t max_formats); +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); +enum csc_type { + CSC_RGB2RGB = 0, + CSC_YUV2RGB, + CSC_RGB2YUV, + CSC_YUV2YUV, + CSC_MAX +}; + +struct csc_cfg { + enum csc_type type; + uint32_t matrix[9]; + uint32_t pre_bias[3]; + uint32_t post_bias[3]; + uint32_t pre_clamp[6]; + uint32_t post_clamp[6]; +}; + +struct csc_cfg *mdp_get_default_csc_cfg(enum csc_type); + #endif /* __MDP_KMS_H__ */ |