1*711a3b87SLiu Ying // SPDX-License-Identifier: GPL-2.0+ 2*711a3b87SLiu Ying /* 3*711a3b87SLiu Ying * Copyright 2024 NXP 4*711a3b87SLiu Ying */ 5*711a3b87SLiu Ying 6*711a3b87SLiu Ying #include <linux/container_of.h> 7*711a3b87SLiu Ying 8*711a3b87SLiu Ying #include <drm/drm_atomic.h> 9*711a3b87SLiu Ying #include <drm/drm_atomic_helper.h> 10*711a3b87SLiu Ying #include <drm/drm_atomic_state_helper.h> 11*711a3b87SLiu Ying #include <drm/drm_crtc.h> 12*711a3b87SLiu Ying #include <drm/drm_drv.h> 13*711a3b87SLiu Ying #include <drm/drm_fb_dma_helper.h> 14*711a3b87SLiu Ying #include <drm/drm_fourcc.h> 15*711a3b87SLiu Ying #include <drm/drm_framebuffer.h> 16*711a3b87SLiu Ying #include <drm/drm_gem_atomic_helper.h> 17*711a3b87SLiu Ying #include <drm/drm_plane_helper.h> 18*711a3b87SLiu Ying #include <drm/drm_print.h> 19*711a3b87SLiu Ying 20*711a3b87SLiu Ying #include "dc-drv.h" 21*711a3b87SLiu Ying #include "dc-fu.h" 22*711a3b87SLiu Ying #include "dc-kms.h" 23*711a3b87SLiu Ying 24*711a3b87SLiu Ying #define DC_PLANE_MAX_PITCH 0x10000 25*711a3b87SLiu Ying #define DC_PLANE_MAX_PIX_CNT 8192 26*711a3b87SLiu Ying 27*711a3b87SLiu Ying #define dc_plane_dbg(plane, fmt, ...) \ 28*711a3b87SLiu Ying do { \ 29*711a3b87SLiu Ying struct drm_plane *_plane = (plane); \ 30*711a3b87SLiu Ying drm_dbg_kms(_plane->dev, "[PLANE:%d:%s] " fmt, \ 31*711a3b87SLiu Ying _plane->base.id, _plane->name, ##__VA_ARGS__); \ 32*711a3b87SLiu Ying } while (0) 33*711a3b87SLiu Ying 34*711a3b87SLiu Ying static const uint32_t dc_plane_formats[] = { 35*711a3b87SLiu Ying DRM_FORMAT_XRGB8888, 36*711a3b87SLiu Ying }; 37*711a3b87SLiu Ying 38*711a3b87SLiu Ying static const struct drm_plane_funcs dc_plane_funcs = { 39*711a3b87SLiu Ying .update_plane = drm_atomic_helper_update_plane, 40*711a3b87SLiu Ying .disable_plane = drm_atomic_helper_disable_plane, 41*711a3b87SLiu Ying .destroy = drm_plane_cleanup, 42*711a3b87SLiu Ying .reset = drm_atomic_helper_plane_reset, 43*711a3b87SLiu Ying .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 44*711a3b87SLiu Ying .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 45*711a3b87SLiu Ying }; 46*711a3b87SLiu Ying 47*711a3b87SLiu Ying static inline struct dc_plane *to_dc_plane(struct drm_plane *plane) 48*711a3b87SLiu Ying { 49*711a3b87SLiu Ying return container_of(plane, struct dc_plane, base); 50*711a3b87SLiu Ying } 51*711a3b87SLiu Ying 52*711a3b87SLiu Ying static int dc_plane_check_max_source_resolution(struct drm_plane_state *state) 53*711a3b87SLiu Ying { 54*711a3b87SLiu Ying int src_h = drm_rect_height(&state->src) >> 16; 55*711a3b87SLiu Ying int src_w = drm_rect_width(&state->src) >> 16; 56*711a3b87SLiu Ying 57*711a3b87SLiu Ying if (src_w > DC_PLANE_MAX_PIX_CNT || src_h > DC_PLANE_MAX_PIX_CNT) { 58*711a3b87SLiu Ying dc_plane_dbg(state->plane, "invalid source resolution\n"); 59*711a3b87SLiu Ying return -EINVAL; 60*711a3b87SLiu Ying } 61*711a3b87SLiu Ying 62*711a3b87SLiu Ying return 0; 63*711a3b87SLiu Ying } 64*711a3b87SLiu Ying 65*711a3b87SLiu Ying static int dc_plane_check_fb(struct drm_plane_state *state) 66*711a3b87SLiu Ying { 67*711a3b87SLiu Ying struct drm_framebuffer *fb = state->fb; 68*711a3b87SLiu Ying dma_addr_t baseaddr = drm_fb_dma_get_gem_addr(fb, state, 0); 69*711a3b87SLiu Ying 70*711a3b87SLiu Ying /* base address alignment */ 71*711a3b87SLiu Ying if (baseaddr & 0x3) { 72*711a3b87SLiu Ying dc_plane_dbg(state->plane, "fb bad baddr alignment\n"); 73*711a3b87SLiu Ying return -EINVAL; 74*711a3b87SLiu Ying } 75*711a3b87SLiu Ying 76*711a3b87SLiu Ying /* pitches[0] range */ 77*711a3b87SLiu Ying if (fb->pitches[0] > DC_PLANE_MAX_PITCH) { 78*711a3b87SLiu Ying dc_plane_dbg(state->plane, "fb pitches[0] is out of range\n"); 79*711a3b87SLiu Ying return -EINVAL; 80*711a3b87SLiu Ying } 81*711a3b87SLiu Ying 82*711a3b87SLiu Ying /* pitches[0] alignment */ 83*711a3b87SLiu Ying if (fb->pitches[0] & 0x3) { 84*711a3b87SLiu Ying dc_plane_dbg(state->plane, "fb bad pitches[0] alignment\n"); 85*711a3b87SLiu Ying return -EINVAL; 86*711a3b87SLiu Ying } 87*711a3b87SLiu Ying 88*711a3b87SLiu Ying return 0; 89*711a3b87SLiu Ying } 90*711a3b87SLiu Ying 91*711a3b87SLiu Ying static int 92*711a3b87SLiu Ying dc_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) 93*711a3b87SLiu Ying { 94*711a3b87SLiu Ying struct drm_plane_state *plane_state = 95*711a3b87SLiu Ying drm_atomic_get_new_plane_state(state, plane); 96*711a3b87SLiu Ying struct drm_crtc_state *crtc_state; 97*711a3b87SLiu Ying int ret; 98*711a3b87SLiu Ying 99*711a3b87SLiu Ying /* ok to disable */ 100*711a3b87SLiu Ying if (!plane_state->fb) 101*711a3b87SLiu Ying return 0; 102*711a3b87SLiu Ying 103*711a3b87SLiu Ying if (!plane_state->crtc) { 104*711a3b87SLiu Ying dc_plane_dbg(plane, "no CRTC in plane state\n"); 105*711a3b87SLiu Ying return -EINVAL; 106*711a3b87SLiu Ying } 107*711a3b87SLiu Ying 108*711a3b87SLiu Ying crtc_state = 109*711a3b87SLiu Ying drm_atomic_get_existing_crtc_state(state, plane_state->crtc); 110*711a3b87SLiu Ying if (WARN_ON(!crtc_state)) 111*711a3b87SLiu Ying return -EINVAL; 112*711a3b87SLiu Ying 113*711a3b87SLiu Ying ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state, 114*711a3b87SLiu Ying DRM_PLANE_NO_SCALING, 115*711a3b87SLiu Ying DRM_PLANE_NO_SCALING, 116*711a3b87SLiu Ying true, false); 117*711a3b87SLiu Ying if (ret) { 118*711a3b87SLiu Ying dc_plane_dbg(plane, "failed to check plane state: %d\n", ret); 119*711a3b87SLiu Ying return ret; 120*711a3b87SLiu Ying } 121*711a3b87SLiu Ying 122*711a3b87SLiu Ying ret = dc_plane_check_max_source_resolution(plane_state); 123*711a3b87SLiu Ying if (ret) 124*711a3b87SLiu Ying return ret; 125*711a3b87SLiu Ying 126*711a3b87SLiu Ying return dc_plane_check_fb(plane_state); 127*711a3b87SLiu Ying } 128*711a3b87SLiu Ying 129*711a3b87SLiu Ying static void 130*711a3b87SLiu Ying dc_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state) 131*711a3b87SLiu Ying { 132*711a3b87SLiu Ying struct drm_plane_state *new_state = 133*711a3b87SLiu Ying drm_atomic_get_new_plane_state(state, plane); 134*711a3b87SLiu Ying struct dc_plane *dplane = to_dc_plane(plane); 135*711a3b87SLiu Ying struct drm_framebuffer *fb = new_state->fb; 136*711a3b87SLiu Ying const struct dc_fu_ops *fu_ops; 137*711a3b87SLiu Ying struct dc_lb *lb = dplane->lb; 138*711a3b87SLiu Ying struct dc_fu *fu = dplane->fu; 139*711a3b87SLiu Ying dma_addr_t baseaddr; 140*711a3b87SLiu Ying int src_w, src_h; 141*711a3b87SLiu Ying int idx; 142*711a3b87SLiu Ying 143*711a3b87SLiu Ying if (!drm_dev_enter(plane->dev, &idx)) 144*711a3b87SLiu Ying return; 145*711a3b87SLiu Ying 146*711a3b87SLiu Ying src_w = drm_rect_width(&new_state->src) >> 16; 147*711a3b87SLiu Ying src_h = drm_rect_height(&new_state->src) >> 16; 148*711a3b87SLiu Ying 149*711a3b87SLiu Ying baseaddr = drm_fb_dma_get_gem_addr(fb, new_state, 0); 150*711a3b87SLiu Ying 151*711a3b87SLiu Ying fu_ops = dc_fu_get_ops(dplane->fu); 152*711a3b87SLiu Ying 153*711a3b87SLiu Ying fu_ops->set_layerblend(fu, lb); 154*711a3b87SLiu Ying fu_ops->set_burstlength(fu, baseaddr); 155*711a3b87SLiu Ying fu_ops->set_src_stride(fu, DC_FETCHUNIT_FRAC0, fb->pitches[0]); 156*711a3b87SLiu Ying fu_ops->set_src_buf_dimensions(fu, DC_FETCHUNIT_FRAC0, src_w, src_h); 157*711a3b87SLiu Ying fu_ops->set_fmt(fu, DC_FETCHUNIT_FRAC0, fb->format); 158*711a3b87SLiu Ying fu_ops->set_framedimensions(fu, src_w, src_h); 159*711a3b87SLiu Ying fu_ops->set_baseaddress(fu, DC_FETCHUNIT_FRAC0, baseaddr); 160*711a3b87SLiu Ying fu_ops->enable_src_buf(fu, DC_FETCHUNIT_FRAC0); 161*711a3b87SLiu Ying 162*711a3b87SLiu Ying dc_plane_dbg(plane, "uses %s\n", fu_ops->get_name(fu)); 163*711a3b87SLiu Ying 164*711a3b87SLiu Ying dc_lb_pec_dynamic_prim_sel(lb, dc_cf_get_link_id(dplane->cf)); 165*711a3b87SLiu Ying dc_lb_pec_dynamic_sec_sel(lb, fu_ops->get_link_id(fu)); 166*711a3b87SLiu Ying dc_lb_mode(lb, LB_BLEND); 167*711a3b87SLiu Ying dc_lb_position(lb, new_state->dst.x1, new_state->dst.y1); 168*711a3b87SLiu Ying dc_lb_pec_clken(lb, CLKEN_AUTOMATIC); 169*711a3b87SLiu Ying 170*711a3b87SLiu Ying dc_plane_dbg(plane, "uses LayerBlend%d\n", dc_lb_get_id(lb)); 171*711a3b87SLiu Ying 172*711a3b87SLiu Ying /* set ExtDst's source to LayerBlend */ 173*711a3b87SLiu Ying dc_ed_pec_src_sel(dplane->ed, dc_lb_get_link_id(lb)); 174*711a3b87SLiu Ying 175*711a3b87SLiu Ying drm_dev_exit(idx); 176*711a3b87SLiu Ying } 177*711a3b87SLiu Ying 178*711a3b87SLiu Ying static void dc_plane_atomic_disable(struct drm_plane *plane, 179*711a3b87SLiu Ying struct drm_atomic_state *state) 180*711a3b87SLiu Ying { 181*711a3b87SLiu Ying struct dc_plane *dplane = to_dc_plane(plane); 182*711a3b87SLiu Ying const struct dc_fu_ops *fu_ops; 183*711a3b87SLiu Ying int idx; 184*711a3b87SLiu Ying 185*711a3b87SLiu Ying if (!drm_dev_enter(plane->dev, &idx)) 186*711a3b87SLiu Ying return; 187*711a3b87SLiu Ying 188*711a3b87SLiu Ying /* disable fetchunit in shadow */ 189*711a3b87SLiu Ying fu_ops = dc_fu_get_ops(dplane->fu); 190*711a3b87SLiu Ying fu_ops->disable_src_buf(dplane->fu, DC_FETCHUNIT_FRAC0); 191*711a3b87SLiu Ying 192*711a3b87SLiu Ying /* set ExtDst's source to ConstFrame */ 193*711a3b87SLiu Ying dc_ed_pec_src_sel(dplane->ed, dc_cf_get_link_id(dplane->cf)); 194*711a3b87SLiu Ying 195*711a3b87SLiu Ying drm_dev_exit(idx); 196*711a3b87SLiu Ying } 197*711a3b87SLiu Ying 198*711a3b87SLiu Ying static const struct drm_plane_helper_funcs dc_plane_helper_funcs = { 199*711a3b87SLiu Ying .atomic_check = dc_plane_atomic_check, 200*711a3b87SLiu Ying .atomic_update = dc_plane_atomic_update, 201*711a3b87SLiu Ying .atomic_disable = dc_plane_atomic_disable, 202*711a3b87SLiu Ying }; 203*711a3b87SLiu Ying 204*711a3b87SLiu Ying int dc_plane_init(struct dc_drm_device *dc_drm, struct dc_plane *dc_plane) 205*711a3b87SLiu Ying { 206*711a3b87SLiu Ying struct drm_plane *plane = &dc_plane->base; 207*711a3b87SLiu Ying int ret; 208*711a3b87SLiu Ying 209*711a3b87SLiu Ying ret = drm_universal_plane_init(&dc_drm->base, plane, 0, &dc_plane_funcs, 210*711a3b87SLiu Ying dc_plane_formats, 211*711a3b87SLiu Ying ARRAY_SIZE(dc_plane_formats), 212*711a3b87SLiu Ying NULL, DRM_PLANE_TYPE_PRIMARY, NULL); 213*711a3b87SLiu Ying if (ret) 214*711a3b87SLiu Ying return ret; 215*711a3b87SLiu Ying 216*711a3b87SLiu Ying drm_plane_helper_add(plane, &dc_plane_helper_funcs); 217*711a3b87SLiu Ying 218*711a3b87SLiu Ying dc_plane->fu = dc_drm->pe->fu_disp[plane->index]; 219*711a3b87SLiu Ying dc_plane->cf = dc_drm->pe->cf_cont[plane->index]; 220*711a3b87SLiu Ying dc_plane->lb = dc_drm->pe->lb[plane->index]; 221*711a3b87SLiu Ying dc_plane->ed = dc_drm->pe->ed_cont[plane->index]; 222*711a3b87SLiu Ying 223*711a3b87SLiu Ying return 0; 224*711a3b87SLiu Ying } 225