1*dbf21777SIcenowy Zheng // SPDX-License-Identifier: GPL-2.0-only 2*dbf21777SIcenowy Zheng /* 3*dbf21777SIcenowy Zheng * Copyright (C) 2025 Icenowy Zheng <uwu@icenowy.me> 4*dbf21777SIcenowy Zheng */ 5*dbf21777SIcenowy Zheng 6*dbf21777SIcenowy Zheng #include <linux/regmap.h> 7*dbf21777SIcenowy Zheng 8*dbf21777SIcenowy Zheng #include <drm/drm_atomic.h> 9*dbf21777SIcenowy Zheng #include <drm/drm_atomic_helper.h> 10*dbf21777SIcenowy Zheng #include <drm/drm_crtc.h> 11*dbf21777SIcenowy Zheng #include <drm/drm_fourcc.h> 12*dbf21777SIcenowy Zheng #include <drm/drm_framebuffer.h> 13*dbf21777SIcenowy Zheng #include <drm/drm_gem_atomic_helper.h> 14*dbf21777SIcenowy Zheng #include <drm/drm_modeset_helper_vtables.h> 15*dbf21777SIcenowy Zheng #include <drm/drm_plane.h> 16*dbf21777SIcenowy Zheng #include <drm/drm_print.h> 17*dbf21777SIcenowy Zheng 18*dbf21777SIcenowy Zheng #include "vs_crtc.h" 19*dbf21777SIcenowy Zheng #include "vs_plane.h" 20*dbf21777SIcenowy Zheng #include "vs_dc.h" 21*dbf21777SIcenowy Zheng #include "vs_primary_plane_regs.h" 22*dbf21777SIcenowy Zheng 23*dbf21777SIcenowy Zheng static int vs_primary_plane_atomic_check(struct drm_plane *plane, 24*dbf21777SIcenowy Zheng struct drm_atomic_state *state) 25*dbf21777SIcenowy Zheng { 26*dbf21777SIcenowy Zheng struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, 27*dbf21777SIcenowy Zheng plane); 28*dbf21777SIcenowy Zheng struct drm_crtc *crtc = new_plane_state->crtc; 29*dbf21777SIcenowy Zheng struct drm_crtc_state *crtc_state; 30*dbf21777SIcenowy Zheng 31*dbf21777SIcenowy Zheng if (!crtc) 32*dbf21777SIcenowy Zheng return 0; 33*dbf21777SIcenowy Zheng 34*dbf21777SIcenowy Zheng crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 35*dbf21777SIcenowy Zheng if (WARN_ON(!crtc_state)) 36*dbf21777SIcenowy Zheng return -EINVAL; 37*dbf21777SIcenowy Zheng 38*dbf21777SIcenowy Zheng return drm_atomic_helper_check_plane_state(new_plane_state, 39*dbf21777SIcenowy Zheng crtc_state, 40*dbf21777SIcenowy Zheng DRM_PLANE_NO_SCALING, 41*dbf21777SIcenowy Zheng DRM_PLANE_NO_SCALING, 42*dbf21777SIcenowy Zheng false, true); 43*dbf21777SIcenowy Zheng } 44*dbf21777SIcenowy Zheng 45*dbf21777SIcenowy Zheng static void vs_primary_plane_commit(struct vs_dc *dc, unsigned int output) 46*dbf21777SIcenowy Zheng { 47*dbf21777SIcenowy Zheng regmap_set_bits(dc->regs, VSDC_FB_CONFIG_EX(output), 48*dbf21777SIcenowy Zheng VSDC_FB_CONFIG_EX_COMMIT); 49*dbf21777SIcenowy Zheng } 50*dbf21777SIcenowy Zheng 51*dbf21777SIcenowy Zheng static void vs_primary_plane_atomic_enable(struct drm_plane *plane, 52*dbf21777SIcenowy Zheng struct drm_atomic_state *atomic_state) 53*dbf21777SIcenowy Zheng { 54*dbf21777SIcenowy Zheng struct drm_plane_state *state = drm_atomic_get_new_plane_state(atomic_state, 55*dbf21777SIcenowy Zheng plane); 56*dbf21777SIcenowy Zheng struct drm_crtc *crtc = state->crtc; 57*dbf21777SIcenowy Zheng struct vs_crtc *vcrtc = drm_crtc_to_vs_crtc(crtc); 58*dbf21777SIcenowy Zheng unsigned int output = vcrtc->id; 59*dbf21777SIcenowy Zheng struct vs_dc *dc = vcrtc->dc; 60*dbf21777SIcenowy Zheng 61*dbf21777SIcenowy Zheng regmap_set_bits(dc->regs, VSDC_FB_CONFIG_EX(output), 62*dbf21777SIcenowy Zheng VSDC_FB_CONFIG_EX_FB_EN); 63*dbf21777SIcenowy Zheng regmap_update_bits(dc->regs, VSDC_FB_CONFIG_EX(output), 64*dbf21777SIcenowy Zheng VSDC_FB_CONFIG_EX_DISPLAY_ID_MASK, 65*dbf21777SIcenowy Zheng VSDC_FB_CONFIG_EX_DISPLAY_ID(output)); 66*dbf21777SIcenowy Zheng 67*dbf21777SIcenowy Zheng vs_primary_plane_commit(dc, output); 68*dbf21777SIcenowy Zheng } 69*dbf21777SIcenowy Zheng 70*dbf21777SIcenowy Zheng static void vs_primary_plane_atomic_disable(struct drm_plane *plane, 71*dbf21777SIcenowy Zheng struct drm_atomic_state *atomic_state) 72*dbf21777SIcenowy Zheng { 73*dbf21777SIcenowy Zheng struct drm_plane_state *state = drm_atomic_get_old_plane_state(atomic_state, 74*dbf21777SIcenowy Zheng plane); 75*dbf21777SIcenowy Zheng struct drm_crtc *crtc = state->crtc; 76*dbf21777SIcenowy Zheng struct vs_crtc *vcrtc = drm_crtc_to_vs_crtc(crtc); 77*dbf21777SIcenowy Zheng unsigned int output = vcrtc->id; 78*dbf21777SIcenowy Zheng struct vs_dc *dc = vcrtc->dc; 79*dbf21777SIcenowy Zheng 80*dbf21777SIcenowy Zheng regmap_set_bits(dc->regs, VSDC_FB_CONFIG_EX(output), 81*dbf21777SIcenowy Zheng VSDC_FB_CONFIG_EX_FB_EN); 82*dbf21777SIcenowy Zheng 83*dbf21777SIcenowy Zheng vs_primary_plane_commit(dc, output); 84*dbf21777SIcenowy Zheng } 85*dbf21777SIcenowy Zheng 86*dbf21777SIcenowy Zheng static void vs_primary_plane_atomic_update(struct drm_plane *plane, 87*dbf21777SIcenowy Zheng struct drm_atomic_state *atomic_state) 88*dbf21777SIcenowy Zheng { 89*dbf21777SIcenowy Zheng struct drm_plane_state *state = drm_atomic_get_new_plane_state(atomic_state, 90*dbf21777SIcenowy Zheng plane); 91*dbf21777SIcenowy Zheng struct drm_framebuffer *fb = state->fb; 92*dbf21777SIcenowy Zheng struct drm_crtc *crtc = state->crtc; 93*dbf21777SIcenowy Zheng struct vs_dc *dc; 94*dbf21777SIcenowy Zheng struct vs_crtc *vcrtc; 95*dbf21777SIcenowy Zheng struct vs_format fmt; 96*dbf21777SIcenowy Zheng unsigned int output; 97*dbf21777SIcenowy Zheng dma_addr_t dma_addr; 98*dbf21777SIcenowy Zheng 99*dbf21777SIcenowy Zheng if (!state->visible) { 100*dbf21777SIcenowy Zheng vs_primary_plane_atomic_disable(plane, atomic_state); 101*dbf21777SIcenowy Zheng return; 102*dbf21777SIcenowy Zheng } 103*dbf21777SIcenowy Zheng 104*dbf21777SIcenowy Zheng vcrtc = drm_crtc_to_vs_crtc(crtc); 105*dbf21777SIcenowy Zheng output = vcrtc->id; 106*dbf21777SIcenowy Zheng dc = vcrtc->dc; 107*dbf21777SIcenowy Zheng 108*dbf21777SIcenowy Zheng drm_format_to_vs_format(state->fb->format->format, &fmt); 109*dbf21777SIcenowy Zheng 110*dbf21777SIcenowy Zheng regmap_update_bits(dc->regs, VSDC_FB_CONFIG(output), 111*dbf21777SIcenowy Zheng VSDC_FB_CONFIG_FMT_MASK, 112*dbf21777SIcenowy Zheng VSDC_FB_CONFIG_FMT(fmt.color)); 113*dbf21777SIcenowy Zheng regmap_update_bits(dc->regs, VSDC_FB_CONFIG(output), 114*dbf21777SIcenowy Zheng VSDC_FB_CONFIG_SWIZZLE_MASK, 115*dbf21777SIcenowy Zheng VSDC_FB_CONFIG_SWIZZLE(fmt.swizzle)); 116*dbf21777SIcenowy Zheng regmap_assign_bits(dc->regs, VSDC_FB_CONFIG(output), 117*dbf21777SIcenowy Zheng VSDC_FB_CONFIG_UV_SWIZZLE_EN, fmt.uv_swizzle); 118*dbf21777SIcenowy Zheng 119*dbf21777SIcenowy Zheng dma_addr = vs_fb_get_dma_addr(fb, &state->src); 120*dbf21777SIcenowy Zheng 121*dbf21777SIcenowy Zheng regmap_write(dc->regs, VSDC_FB_ADDRESS(output), 122*dbf21777SIcenowy Zheng lower_32_bits(dma_addr)); 123*dbf21777SIcenowy Zheng regmap_write(dc->regs, VSDC_FB_STRIDE(output), 124*dbf21777SIcenowy Zheng fb->pitches[0]); 125*dbf21777SIcenowy Zheng 126*dbf21777SIcenowy Zheng regmap_write(dc->regs, VSDC_FB_TOP_LEFT(output), 127*dbf21777SIcenowy Zheng VSDC_MAKE_PLANE_POS(state->crtc_x, state->crtc_y)); 128*dbf21777SIcenowy Zheng regmap_write(dc->regs, VSDC_FB_BOTTOM_RIGHT(output), 129*dbf21777SIcenowy Zheng VSDC_MAKE_PLANE_POS(state->crtc_x + state->crtc_w, 130*dbf21777SIcenowy Zheng state->crtc_y + state->crtc_h)); 131*dbf21777SIcenowy Zheng regmap_write(dc->regs, VSDC_FB_SIZE(output), 132*dbf21777SIcenowy Zheng VSDC_MAKE_PLANE_SIZE(state->crtc_w, state->crtc_h)); 133*dbf21777SIcenowy Zheng 134*dbf21777SIcenowy Zheng regmap_write(dc->regs, VSDC_FB_BLEND_CONFIG(output), 135*dbf21777SIcenowy Zheng VSDC_FB_BLEND_CONFIG_BLEND_DISABLE); 136*dbf21777SIcenowy Zheng 137*dbf21777SIcenowy Zheng vs_primary_plane_commit(dc, output); 138*dbf21777SIcenowy Zheng } 139*dbf21777SIcenowy Zheng 140*dbf21777SIcenowy Zheng static const struct drm_plane_helper_funcs vs_primary_plane_helper_funcs = { 141*dbf21777SIcenowy Zheng .atomic_check = vs_primary_plane_atomic_check, 142*dbf21777SIcenowy Zheng .atomic_update = vs_primary_plane_atomic_update, 143*dbf21777SIcenowy Zheng .atomic_enable = vs_primary_plane_atomic_enable, 144*dbf21777SIcenowy Zheng .atomic_disable = vs_primary_plane_atomic_disable, 145*dbf21777SIcenowy Zheng }; 146*dbf21777SIcenowy Zheng 147*dbf21777SIcenowy Zheng static const struct drm_plane_funcs vs_primary_plane_funcs = { 148*dbf21777SIcenowy Zheng .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 149*dbf21777SIcenowy Zheng .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 150*dbf21777SIcenowy Zheng .disable_plane = drm_atomic_helper_disable_plane, 151*dbf21777SIcenowy Zheng .reset = drm_atomic_helper_plane_reset, 152*dbf21777SIcenowy Zheng .update_plane = drm_atomic_helper_update_plane, 153*dbf21777SIcenowy Zheng }; 154*dbf21777SIcenowy Zheng 155*dbf21777SIcenowy Zheng struct drm_plane *vs_primary_plane_init(struct drm_device *drm_dev, struct vs_dc *dc) 156*dbf21777SIcenowy Zheng { 157*dbf21777SIcenowy Zheng struct drm_plane *plane; 158*dbf21777SIcenowy Zheng 159*dbf21777SIcenowy Zheng plane = drmm_universal_plane_alloc(drm_dev, struct drm_plane, dev, 0, 160*dbf21777SIcenowy Zheng &vs_primary_plane_funcs, 161*dbf21777SIcenowy Zheng dc->identity.formats->array, 162*dbf21777SIcenowy Zheng dc->identity.formats->num, 163*dbf21777SIcenowy Zheng NULL, 164*dbf21777SIcenowy Zheng DRM_PLANE_TYPE_PRIMARY, 165*dbf21777SIcenowy Zheng NULL); 166*dbf21777SIcenowy Zheng 167*dbf21777SIcenowy Zheng if (IS_ERR(plane)) 168*dbf21777SIcenowy Zheng return plane; 169*dbf21777SIcenowy Zheng 170*dbf21777SIcenowy Zheng drm_plane_helper_add(plane, &vs_primary_plane_helper_funcs); 171*dbf21777SIcenowy Zheng 172*dbf21777SIcenowy Zheng return plane; 173*dbf21777SIcenowy Zheng } 174