diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-12-25 11:48:26 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-12-25 11:48:26 -0800 |
commit | 4971f090aa7f6ce5daa094ce4334f6618f93a7eb (patch) | |
tree | 45d75782b7dedbec76a3ab82d2769f7707668071 /drivers/gpu/drm/meson/meson_plane.c | |
parent | c76cd634eb5bfd497617ea224a54a03b545c8c4d (diff) | |
parent | 2a3c83f5fe0770d13bbb71b23674886ff4111f44 (diff) |
Merge tag 'drm-next-2018-12-14' of git://anongit.freedesktop.org/drm/drm
Pull drm updates from Dave Airlie:
"Core:
- shared fencing staging removal
- drop transactional atomic helpers and move helpers to new location
- DP/MST atomic cleanup
- Leasing cleanups and drop EXPORT_SYMBOL
- Convert drivers to atomic helpers and generic fbdev.
- removed deprecated obj_ref/unref in favour of get/put
- Improve dumb callback documentation
- MODESET_LOCK_BEGIN/END helpers
panels:
- CDTech panels, Banana Pi Panel, DLC1010GIG,
- Olimex LCD-O-LinuXino, Samsung S6D16D0, Truly NT35597 WQXGA,
- Himax HX8357D, simulated RTSM AEMv8.
- GPD Win2 panel
- AUO G101EVN010
vgem:
- render node support
ttm:
- move global init out of drivers
- fix LRU handling for ghost objects
- Support for simultaneous submissions to multiple engines
scheduler:
- timeout/fault handling changes to help GPU recovery
- helpers for hw with preemption support
i915:
- Scaler/Watermark fixes
- DP MST + powerwell fixes
- PSR fixes
- Break long get/put shmemfs pages
- Icelake fixes
- Icelake DSI video mode enablement
- Engine workaround improvements
amdgpu:
- freesync support
- GPU reset enabled on CI, VI, SOC15 dGPUs
- ABM support in DC
- KFD support for vega12/polaris12
- SDMA paging queue on vega
- More amdkfd code sharing
- DCC scanout on GFX9
- DC kerneldoc
- Updated SMU firmware for GFX8 chips
- XGMI PSP + hive reset support
- GPU reset
- DC trace support
- Powerplay updates for newer Polaris
- Cursor plane update fast path
- kfd dma-buf support
virtio-gpu:
- add EDID support
vmwgfx:
- pageflip with damage support
nouveau:
- Initial Turing TU104/TU106 modesetting support
msm:
- a2xx gpu support for apq8060 and imx5
- a2xx gpummu support
- mdp4 display support for apq8060
- DPU fixes and cleanups
- enhanced profiling support
- debug object naming interface
- get_iova/page pinning decoupling
tegra:
- Tegra194 host1x, VIC and display support enabled
- Audio over HDMI for Tegra186 and Tegra194
exynos:
- DMA/IOMMU refactoring
- plane alpha + blend mode support
- Color format fixes for mixer driver
rcar-du:
- R8A7744 and R8A77470 support
- R8A77965 LVDS support
imx:
- fbdev emulation fix
- multi-tiled scalling fixes
- SPDX identifiers
rockchip
- dw_hdmi support
- dw-mipi-dsi + dual dsi support
- mailbox read size fix
qxl:
- fix cursor pinning
vc4:
- YUV support (scaling + cursor)
v3d:
- enable TFU (Texture Formatting Unit)
mali-dp:
- add support for linear tiled formats
sun4i:
- Display Engine 3 support
- H6 DE3 mixer 0 support
- H6 display engine support
- dw-hdmi support
- H6 HDMI phy support
- implicit fence waiting
- BGRX8888 support
meson:
- Overlay plane support
- implicit fence waiting
- HDMI 1.4 4k modes
bridge:
- i2c fixes for sii902x"
* tag 'drm-next-2018-12-14' of git://anongit.freedesktop.org/drm/drm: (1403 commits)
drm/amd/display: Add fast path for cursor plane updates
drm/amdgpu: Enable GPU recovery by default for CI
drm/amd/display: Fix duplicating scaling/underscan connector state
drm/amd/display: Fix unintialized max_bpc state values
Revert "drm/amd/display: Set RMX_ASPECT as default"
drm/amdgpu: Fix stub function name
drm/msm/dpu: Fix clock issue after bind failure
drm/msm/dpu: Clean up dpu_media_info.h static inline functions
drm/msm/dpu: Further cleanups for static inline functions
drm/msm/dpu: Cleanup the debugfs functions
drm/msm/dpu: Remove dpu_irq and unused functions
drm/msm: Make irq_postinstall optional
drm/msm/dpu: Cleanup callers of dpu_hw_blk_init
drm/msm/dpu: Remove unused functions
drm/msm/dpu: Remove dpu_crtc_is_enabled()
drm/msm/dpu: Remove dpu_crtc_get_mixer_height
drm/msm/dpu: Remove dpu_dbg
drm/msm: dpu: Remove crtc_lock
drm/msm: dpu: Remove vblank_requested flag from dpu_crtc
drm/msm: dpu: Separate crtc assignment from vblank enable
...
Diffstat (limited to 'drivers/gpu/drm/meson/meson_plane.c')
-rw-r--r-- | drivers/gpu/drm/meson/meson_plane.c | 199 |
1 files changed, 176 insertions, 23 deletions
diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index 12c80dfcff59..6119a0224278 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c @@ -24,6 +24,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/bitfield.h> #include <linux/platform_device.h> #include <drm/drmP.h> #include <drm/drm_atomic.h> @@ -31,6 +32,7 @@ #include <drm/drm_plane_helper.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_fb_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_rect.h> #include "meson_plane.h" @@ -39,12 +41,51 @@ #include "meson_canvas.h" #include "meson_registers.h" +/* OSD_SCI_WH_M1 */ +#define SCI_WH_M1_W(w) FIELD_PREP(GENMASK(28, 16), w) +#define SCI_WH_M1_H(h) FIELD_PREP(GENMASK(12, 0), h) + +/* OSD_SCO_H_START_END */ +/* OSD_SCO_V_START_END */ +#define SCO_HV_START(start) FIELD_PREP(GENMASK(27, 16), start) +#define SCO_HV_END(end) FIELD_PREP(GENMASK(11, 0), end) + +/* OSD_SC_CTRL0 */ +#define SC_CTRL0_PATH_EN BIT(3) +#define SC_CTRL0_SEL_OSD1 BIT(2) + +/* OSD_VSC_CTRL0 */ +#define VSC_BANK_LEN(value) FIELD_PREP(GENMASK(2, 0), value) +#define VSC_TOP_INI_RCV_NUM(value) FIELD_PREP(GENMASK(6, 3), value) +#define VSC_TOP_RPT_L0_NUM(value) FIELD_PREP(GENMASK(9, 8), value) +#define VSC_BOT_INI_RCV_NUM(value) FIELD_PREP(GENMASK(14, 11), value) +#define VSC_BOT_RPT_L0_NUM(value) FIELD_PREP(GENMASK(17, 16), value) +#define VSC_PROG_INTERLACE BIT(23) +#define VSC_VERTICAL_SCALER_EN BIT(24) + +/* OSD_VSC_INI_PHASE */ +#define VSC_INI_PHASE_BOT(bottom) FIELD_PREP(GENMASK(31, 16), bottom) +#define VSC_INI_PHASE_TOP(top) FIELD_PREP(GENMASK(15, 0), top) + +/* OSD_HSC_CTRL0 */ +#define HSC_BANK_LENGTH(value) FIELD_PREP(GENMASK(2, 0), value) +#define HSC_INI_RCV_NUM0(value) FIELD_PREP(GENMASK(6, 3), value) +#define HSC_RPT_P0_NUM0(value) FIELD_PREP(GENMASK(9, 8), value) +#define HSC_HORIZ_SCALER_EN BIT(22) + +/* VPP_OSD_VSC_PHASE_STEP */ +/* VPP_OSD_HSC_PHASE_STEP */ +#define SC_PHASE_STEP(value) FIELD_PREP(GENMASK(27, 0), value) + struct meson_plane { struct drm_plane base; struct meson_drm *priv; + bool enabled; }; #define to_meson_plane(x) container_of(x, struct meson_plane, base) +#define FRAC_16_16(mult, div) (((mult) << 16) / (div)) + static int meson_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { @@ -57,10 +98,15 @@ static int meson_plane_atomic_check(struct drm_plane *plane, if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); + /* + * Only allow : + * - Upscaling up to 5x, vertical and horizontal + * - Final coordinates must match crtc size + */ return drm_atomic_helper_check_plane_state(state, crtc_state, + FRAC_16_16(1, 5), DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, - true, true); + false, true); } /* Takes a fixed 16.16 number and converts it to integer. */ @@ -74,22 +120,20 @@ static void meson_plane_atomic_update(struct drm_plane *plane, { struct meson_plane *meson_plane = to_meson_plane(plane); struct drm_plane_state *state = plane->state; - struct drm_framebuffer *fb = state->fb; + struct drm_rect dest = drm_plane_state_dest(state); struct meson_drm *priv = meson_plane->priv; + struct drm_framebuffer *fb = state->fb; struct drm_gem_cma_object *gem; - struct drm_rect src = { - .x1 = (state->src_x), - .y1 = (state->src_y), - .x2 = (state->src_x + state->src_w), - .y2 = (state->src_y + state->src_h), - }; - struct drm_rect dest = { - .x1 = state->crtc_x, - .y1 = state->crtc_y, - .x2 = state->crtc_x + state->crtc_w, - .y2 = state->crtc_y + state->crtc_h, - }; unsigned long flags; + int vsc_ini_rcv_num, vsc_ini_rpt_p0_num; + int vsc_bot_rcv_num, vsc_bot_rpt_p0_num; + int hsc_ini_rcv_num, hsc_ini_rpt_p0_num; + int hf_phase_step, vf_phase_step; + int src_w, src_h, dst_w, dst_h; + int bot_ini_phase; + int hf_bank_len; + int vf_bank_len; + u8 canvas_id_osd1; /* * Update Coordinates @@ -104,8 +148,13 @@ static void meson_plane_atomic_update(struct drm_plane *plane, (0xFF << OSD_GLOBAL_ALPHA_SHIFT) | OSD_BLK0_ENABLE; + if (priv->canvas) + canvas_id_osd1 = priv->canvas_id_osd1; + else + canvas_id_osd1 = MESON_CANVAS_ID_OSD1; + /* Set up BLK0 to point to the right canvas */ - priv->viu.osd1_blk0_cfg[0] = ((MESON_CANVAS_ID_OSD1 << OSD_CANVAS_SEL) | + priv->viu.osd1_blk0_cfg[0] = ((canvas_id_osd1 << OSD_CANVAS_SEL) | OSD_ENDIANNESS_LE); /* On GXBB, Use the old non-HDR RGB2YUV converter */ @@ -137,23 +186,115 @@ static void meson_plane_atomic_update(struct drm_plane *plane, break; }; + /* Default scaler parameters */ + vsc_bot_rcv_num = 0; + vsc_bot_rpt_p0_num = 0; + hf_bank_len = 4; + vf_bank_len = 4; + if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) { - priv->viu.osd1_interlace = true; + vsc_bot_rcv_num = 6; + vsc_bot_rpt_p0_num = 2; + } + + hsc_ini_rcv_num = hf_bank_len; + vsc_ini_rcv_num = vf_bank_len; + hsc_ini_rpt_p0_num = (hf_bank_len / 2) - 1; + vsc_ini_rpt_p0_num = (vf_bank_len / 2) - 1; + + src_w = fixed16_to_int(state->src_w); + src_h = fixed16_to_int(state->src_h); + dst_w = state->crtc_w; + dst_h = state->crtc_h; + /* + * When the output is interlaced, the OSD must switch between + * each field using the INTERLACE_SEL_ODD (0) of VIU_OSD1_BLK0_CFG_W0 + * at each vsync. + * But the vertical scaler can provide such funtionnality if + * is configured for 2:1 scaling with interlace options enabled. + */ + if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) { dest.y1 /= 2; dest.y2 /= 2; - } else - priv->viu.osd1_interlace = false; + dst_h /= 2; + } + + hf_phase_step = ((src_w << 18) / dst_w) << 6; + vf_phase_step = (src_h << 20) / dst_h; + + if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) + bot_ini_phase = ((vf_phase_step / 2) >> 4); + else + bot_ini_phase = 0; + + vf_phase_step = (vf_phase_step << 4); + + /* In interlaced mode, scaler is always active */ + if (src_h != dst_h || src_w != dst_w) { + priv->viu.osd_sc_i_wh_m1 = SCI_WH_M1_W(src_w - 1) | + SCI_WH_M1_H(src_h - 1); + priv->viu.osd_sc_o_h_start_end = SCO_HV_START(dest.x1) | + SCO_HV_END(dest.x2 - 1); + priv->viu.osd_sc_o_v_start_end = SCO_HV_START(dest.y1) | + SCO_HV_END(dest.y2 - 1); + /* Enable OSD Scaler */ + priv->viu.osd_sc_ctrl0 = SC_CTRL0_PATH_EN | SC_CTRL0_SEL_OSD1; + } else { + priv->viu.osd_sc_i_wh_m1 = 0; + priv->viu.osd_sc_o_h_start_end = 0; + priv->viu.osd_sc_o_v_start_end = 0; + priv->viu.osd_sc_ctrl0 = 0; + } + + /* In interlaced mode, vertical scaler is always active */ + if (src_h != dst_h) { + priv->viu.osd_sc_v_ctrl0 = + VSC_BANK_LEN(vf_bank_len) | + VSC_TOP_INI_RCV_NUM(vsc_ini_rcv_num) | + VSC_TOP_RPT_L0_NUM(vsc_ini_rpt_p0_num) | + VSC_VERTICAL_SCALER_EN; + + if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) + priv->viu.osd_sc_v_ctrl0 |= + VSC_BOT_INI_RCV_NUM(vsc_bot_rcv_num) | + VSC_BOT_RPT_L0_NUM(vsc_bot_rpt_p0_num) | + VSC_PROG_INTERLACE; + + priv->viu.osd_sc_v_phase_step = SC_PHASE_STEP(vf_phase_step); + priv->viu.osd_sc_v_ini_phase = VSC_INI_PHASE_BOT(bot_ini_phase); + } else { + priv->viu.osd_sc_v_ctrl0 = 0; + priv->viu.osd_sc_v_phase_step = 0; + priv->viu.osd_sc_v_ini_phase = 0; + } + + /* Horizontal scaler is only used if width does not match */ + if (src_w != dst_w) { + priv->viu.osd_sc_h_ctrl0 = + HSC_BANK_LENGTH(hf_bank_len) | + HSC_INI_RCV_NUM0(hsc_ini_rcv_num) | + HSC_RPT_P0_NUM0(hsc_ini_rpt_p0_num) | + HSC_HORIZ_SCALER_EN; + priv->viu.osd_sc_h_phase_step = SC_PHASE_STEP(hf_phase_step); + priv->viu.osd_sc_h_ini_phase = 0; + } else { + priv->viu.osd_sc_h_ctrl0 = 0; + priv->viu.osd_sc_h_phase_step = 0; + priv->viu.osd_sc_h_ini_phase = 0; + } /* * The format of these registers is (x2 << 16 | x1), * where x2 is exclusive. * e.g. +30x1920 would be (1919 << 16) | 30 */ - priv->viu.osd1_blk0_cfg[1] = ((fixed16_to_int(src.x2) - 1) << 16) | - fixed16_to_int(src.x1); - priv->viu.osd1_blk0_cfg[2] = ((fixed16_to_int(src.y2) - 1) << 16) | - fixed16_to_int(src.y1); + priv->viu.osd1_blk0_cfg[1] = + ((fixed16_to_int(state->src.x2) - 1) << 16) | + fixed16_to_int(state->src.x1); + priv->viu.osd1_blk0_cfg[2] = + ((fixed16_to_int(state->src.y2) - 1) << 16) | + fixed16_to_int(state->src.y1); priv->viu.osd1_blk0_cfg[3] = ((dest.x2 - 1) << 16) | dest.x1; priv->viu.osd1_blk0_cfg[4] = ((dest.y2 - 1) << 16) | dest.y1; @@ -164,6 +305,15 @@ static void meson_plane_atomic_update(struct drm_plane *plane, priv->viu.osd1_stride = fb->pitches[0]; priv->viu.osd1_height = fb->height; + if (!meson_plane->enabled) { + /* Reset OSD1 before enabling it on GXL+ SoCs */ + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || + meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + meson_viu_osd1_reset(priv); + + meson_plane->enabled = true; + } + spin_unlock_irqrestore(&priv->drm->event_lock, flags); } @@ -177,12 +327,15 @@ static void meson_plane_atomic_disable(struct drm_plane *plane, writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0, priv->io_base + _REG(VPP_MISC)); + meson_plane->enabled = false; + } static const struct drm_plane_helper_funcs meson_plane_helper_funcs = { .atomic_check = meson_plane_atomic_check, .atomic_disable = meson_plane_atomic_disable, .atomic_update = meson_plane_atomic_update, + .prepare_fb = drm_gem_fb_prepare_fb, }; static const struct drm_plane_funcs meson_plane_funcs = { |