1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2c8b75bcaSEric Anholt /* 3c8b75bcaSEric Anholt * Copyright (C) 2015 Broadcom 4c8b75bcaSEric Anholt */ 5c8b75bcaSEric Anholt 6c8b75bcaSEric Anholt /** 7c8b75bcaSEric Anholt * DOC: VC4 KMS 8c8b75bcaSEric Anholt * 9c8b75bcaSEric Anholt * This is the general code for implementing KMS mode setting that 10c8b75bcaSEric Anholt * doesn't clearly associate with any of the other objects (plane, 11c8b75bcaSEric Anholt * crtc, HDMI encoder). 12c8b75bcaSEric Anholt */ 13c8b75bcaSEric Anholt 14d7d96c00SMaxime Ripard #include <linux/clk.h> 15d7d96c00SMaxime Ripard 16b7e8e25bSMasahiro Yamada #include <drm/drm_atomic.h> 17b7e8e25bSMasahiro Yamada #include <drm/drm_atomic_helper.h> 18fd6d6d80SSam Ravnborg #include <drm/drm_crtc.h> 199762477cSNoralf Trønnes #include <drm/drm_gem_framebuffer_helper.h> 20fcd70cd3SDaniel Vetter #include <drm/drm_plane_helper.h> 21fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h> 22fd6d6d80SSam Ravnborg #include <drm/drm_vblank.h> 23fd6d6d80SSam Ravnborg 24c8b75bcaSEric Anholt #include "vc4_drv.h" 25766cc6b1SStefan Schake #include "vc4_regs.h" 26766cc6b1SStefan Schake 27a9661f27SMaxime Ripard #define HVS_NUM_CHANNELS 3 28a9661f27SMaxime Ripard 29766cc6b1SStefan Schake struct vc4_ctm_state { 30766cc6b1SStefan Schake struct drm_private_state base; 31766cc6b1SStefan Schake struct drm_color_ctm *ctm; 32766cc6b1SStefan Schake int fifo; 33766cc6b1SStefan Schake }; 34766cc6b1SStefan Schake 35220f125cSMaxime Ripard static struct vc4_ctm_state * 36220f125cSMaxime Ripard to_vc4_ctm_state(const struct drm_private_state *priv) 37766cc6b1SStefan Schake { 38766cc6b1SStefan Schake return container_of(priv, struct vc4_ctm_state, base); 39766cc6b1SStefan Schake } 40766cc6b1SStefan Schake 41f2df84e0SMaxime Ripard struct vc4_hvs_state { 42f2df84e0SMaxime Ripard struct drm_private_state base; 4316e10105SMaxime Ripard unsigned long core_clock_rate; 449ec03d7fSMaxime Ripard 459ec03d7fSMaxime Ripard struct { 469ec03d7fSMaxime Ripard unsigned in_use: 1; 4716e10105SMaxime Ripard unsigned long fifo_load; 489ec03d7fSMaxime Ripard struct drm_crtc_commit *pending_commit; 499ec03d7fSMaxime Ripard } fifo_state[HVS_NUM_CHANNELS]; 50f2df84e0SMaxime Ripard }; 51f2df84e0SMaxime Ripard 52f2df84e0SMaxime Ripard static struct vc4_hvs_state * 53220f125cSMaxime Ripard to_vc4_hvs_state(const struct drm_private_state *priv) 54f2df84e0SMaxime Ripard { 55f2df84e0SMaxime Ripard return container_of(priv, struct vc4_hvs_state, base); 56f2df84e0SMaxime Ripard } 57f2df84e0SMaxime Ripard 584686da83SBoris Brezillon struct vc4_load_tracker_state { 594686da83SBoris Brezillon struct drm_private_state base; 604686da83SBoris Brezillon u64 hvs_load; 614686da83SBoris Brezillon u64 membus_load; 624686da83SBoris Brezillon }; 634686da83SBoris Brezillon 644686da83SBoris Brezillon static struct vc4_load_tracker_state * 65220f125cSMaxime Ripard to_vc4_load_tracker_state(const struct drm_private_state *priv) 664686da83SBoris Brezillon { 674686da83SBoris Brezillon return container_of(priv, struct vc4_load_tracker_state, base); 684686da83SBoris Brezillon } 694686da83SBoris Brezillon 70766cc6b1SStefan Schake static struct vc4_ctm_state *vc4_get_ctm_state(struct drm_atomic_state *state, 71766cc6b1SStefan Schake struct drm_private_obj *manager) 72766cc6b1SStefan Schake { 73766cc6b1SStefan Schake struct drm_device *dev = state->dev; 7488e08589SMaxime Ripard struct vc4_dev *vc4 = to_vc4_dev(dev); 75766cc6b1SStefan Schake struct drm_private_state *priv_state; 76766cc6b1SStefan Schake int ret; 77766cc6b1SStefan Schake 78766cc6b1SStefan Schake ret = drm_modeset_lock(&vc4->ctm_state_lock, state->acquire_ctx); 79766cc6b1SStefan Schake if (ret) 80766cc6b1SStefan Schake return ERR_PTR(ret); 81766cc6b1SStefan Schake 82766cc6b1SStefan Schake priv_state = drm_atomic_get_private_obj_state(state, manager); 83766cc6b1SStefan Schake if (IS_ERR(priv_state)) 84766cc6b1SStefan Schake return ERR_CAST(priv_state); 85766cc6b1SStefan Schake 86766cc6b1SStefan Schake return to_vc4_ctm_state(priv_state); 87766cc6b1SStefan Schake } 88766cc6b1SStefan Schake 89766cc6b1SStefan Schake static struct drm_private_state * 90766cc6b1SStefan Schake vc4_ctm_duplicate_state(struct drm_private_obj *obj) 91766cc6b1SStefan Schake { 92766cc6b1SStefan Schake struct vc4_ctm_state *state; 93766cc6b1SStefan Schake 94766cc6b1SStefan Schake state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL); 95766cc6b1SStefan Schake if (!state) 96766cc6b1SStefan Schake return NULL; 97766cc6b1SStefan Schake 98766cc6b1SStefan Schake __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); 99766cc6b1SStefan Schake 100766cc6b1SStefan Schake return &state->base; 101766cc6b1SStefan Schake } 102766cc6b1SStefan Schake 103766cc6b1SStefan Schake static void vc4_ctm_destroy_state(struct drm_private_obj *obj, 104766cc6b1SStefan Schake struct drm_private_state *state) 105766cc6b1SStefan Schake { 106766cc6b1SStefan Schake struct vc4_ctm_state *ctm_state = to_vc4_ctm_state(state); 107766cc6b1SStefan Schake 108766cc6b1SStefan Schake kfree(ctm_state); 109766cc6b1SStefan Schake } 110766cc6b1SStefan Schake 111766cc6b1SStefan Schake static const struct drm_private_state_funcs vc4_ctm_state_funcs = { 112766cc6b1SStefan Schake .atomic_duplicate_state = vc4_ctm_duplicate_state, 113766cc6b1SStefan Schake .atomic_destroy_state = vc4_ctm_destroy_state, 114766cc6b1SStefan Schake }; 115766cc6b1SStefan Schake 116dcda7c28SMaxime Ripard static void vc4_ctm_obj_fini(struct drm_device *dev, void *unused) 117dcda7c28SMaxime Ripard { 118dcda7c28SMaxime Ripard struct vc4_dev *vc4 = to_vc4_dev(dev); 119dcda7c28SMaxime Ripard 120dcda7c28SMaxime Ripard drm_atomic_private_obj_fini(&vc4->ctm_manager); 121dcda7c28SMaxime Ripard } 122dcda7c28SMaxime Ripard 123dcda7c28SMaxime Ripard static int vc4_ctm_obj_init(struct vc4_dev *vc4) 124dcda7c28SMaxime Ripard { 125dcda7c28SMaxime Ripard struct vc4_ctm_state *ctm_state; 126dcda7c28SMaxime Ripard 127dcda7c28SMaxime Ripard drm_modeset_lock_init(&vc4->ctm_state_lock); 128dcda7c28SMaxime Ripard 129dcda7c28SMaxime Ripard ctm_state = kzalloc(sizeof(*ctm_state), GFP_KERNEL); 130dcda7c28SMaxime Ripard if (!ctm_state) 131dcda7c28SMaxime Ripard return -ENOMEM; 132dcda7c28SMaxime Ripard 133dcda7c28SMaxime Ripard drm_atomic_private_obj_init(&vc4->base, &vc4->ctm_manager, &ctm_state->base, 134dcda7c28SMaxime Ripard &vc4_ctm_state_funcs); 135dcda7c28SMaxime Ripard 1363c354ed1SMaxime Ripard return drmm_add_action_or_reset(&vc4->base, vc4_ctm_obj_fini, NULL); 137dcda7c28SMaxime Ripard } 138dcda7c28SMaxime Ripard 139766cc6b1SStefan Schake /* Converts a DRM S31.32 value to the HW S0.9 format. */ 140766cc6b1SStefan Schake static u16 vc4_ctm_s31_32_to_s0_9(u64 in) 141766cc6b1SStefan Schake { 142766cc6b1SStefan Schake u16 r; 143766cc6b1SStefan Schake 144766cc6b1SStefan Schake /* Sign bit. */ 145766cc6b1SStefan Schake r = in & BIT_ULL(63) ? BIT(9) : 0; 146766cc6b1SStefan Schake 147766cc6b1SStefan Schake if ((in & GENMASK_ULL(62, 32)) > 0) { 148766cc6b1SStefan Schake /* We have zero integer bits so we can only saturate here. */ 149766cc6b1SStefan Schake r |= GENMASK(8, 0); 150766cc6b1SStefan Schake } else { 151766cc6b1SStefan Schake /* Otherwise take the 9 most important fractional bits. */ 152766cc6b1SStefan Schake r |= (in >> 23) & GENMASK(8, 0); 153766cc6b1SStefan Schake } 154766cc6b1SStefan Schake 155766cc6b1SStefan Schake return r; 156766cc6b1SStefan Schake } 157766cc6b1SStefan Schake 158766cc6b1SStefan Schake static void 159766cc6b1SStefan Schake vc4_ctm_commit(struct vc4_dev *vc4, struct drm_atomic_state *state) 160766cc6b1SStefan Schake { 1613454f01aSMaxime Ripard struct vc4_hvs *hvs = vc4->hvs; 162766cc6b1SStefan Schake struct vc4_ctm_state *ctm_state = to_vc4_ctm_state(vc4->ctm_manager.state); 163766cc6b1SStefan Schake struct drm_color_ctm *ctm = ctm_state->ctm; 164766cc6b1SStefan Schake 165766cc6b1SStefan Schake if (ctm_state->fifo) { 166766cc6b1SStefan Schake HVS_WRITE(SCALER_OLEDCOEF2, 167766cc6b1SStefan Schake VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[0]), 168766cc6b1SStefan Schake SCALER_OLEDCOEF2_R_TO_R) | 169766cc6b1SStefan Schake VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[3]), 170766cc6b1SStefan Schake SCALER_OLEDCOEF2_R_TO_G) | 171766cc6b1SStefan Schake VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[6]), 172766cc6b1SStefan Schake SCALER_OLEDCOEF2_R_TO_B)); 173766cc6b1SStefan Schake HVS_WRITE(SCALER_OLEDCOEF1, 174766cc6b1SStefan Schake VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[1]), 175766cc6b1SStefan Schake SCALER_OLEDCOEF1_G_TO_R) | 176766cc6b1SStefan Schake VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[4]), 177766cc6b1SStefan Schake SCALER_OLEDCOEF1_G_TO_G) | 178766cc6b1SStefan Schake VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[7]), 179766cc6b1SStefan Schake SCALER_OLEDCOEF1_G_TO_B)); 180766cc6b1SStefan Schake HVS_WRITE(SCALER_OLEDCOEF0, 181766cc6b1SStefan Schake VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[2]), 182766cc6b1SStefan Schake SCALER_OLEDCOEF0_B_TO_R) | 183766cc6b1SStefan Schake VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[5]), 184766cc6b1SStefan Schake SCALER_OLEDCOEF0_B_TO_G) | 185766cc6b1SStefan Schake VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[8]), 186766cc6b1SStefan Schake SCALER_OLEDCOEF0_B_TO_B)); 187766cc6b1SStefan Schake } 188766cc6b1SStefan Schake 189766cc6b1SStefan Schake HVS_WRITE(SCALER_OLEDOFFS, 190766cc6b1SStefan Schake VC4_SET_FIELD(ctm_state->fifo, SCALER_OLEDOFFS_DISPFIFO)); 191766cc6b1SStefan Schake } 192c8b75bcaSEric Anholt 193f2df84e0SMaxime Ripard static struct vc4_hvs_state * 1949ec03d7fSMaxime Ripard vc4_hvs_get_new_global_state(struct drm_atomic_state *state) 1959ec03d7fSMaxime Ripard { 1969ec03d7fSMaxime Ripard struct vc4_dev *vc4 = to_vc4_dev(state->dev); 1979ec03d7fSMaxime Ripard struct drm_private_state *priv_state; 1989ec03d7fSMaxime Ripard 1999ec03d7fSMaxime Ripard priv_state = drm_atomic_get_new_private_obj_state(state, &vc4->hvs_channels); 2009ec03d7fSMaxime Ripard if (IS_ERR(priv_state)) 2019ec03d7fSMaxime Ripard return ERR_CAST(priv_state); 2029ec03d7fSMaxime Ripard 2039ec03d7fSMaxime Ripard return to_vc4_hvs_state(priv_state); 2049ec03d7fSMaxime Ripard } 2059ec03d7fSMaxime Ripard 2069ec03d7fSMaxime Ripard static struct vc4_hvs_state * 2079ec03d7fSMaxime Ripard vc4_hvs_get_old_global_state(struct drm_atomic_state *state) 2089ec03d7fSMaxime Ripard { 2099ec03d7fSMaxime Ripard struct vc4_dev *vc4 = to_vc4_dev(state->dev); 2109ec03d7fSMaxime Ripard struct drm_private_state *priv_state; 2119ec03d7fSMaxime Ripard 2129ec03d7fSMaxime Ripard priv_state = drm_atomic_get_old_private_obj_state(state, &vc4->hvs_channels); 2139ec03d7fSMaxime Ripard if (IS_ERR(priv_state)) 2149ec03d7fSMaxime Ripard return ERR_CAST(priv_state); 2159ec03d7fSMaxime Ripard 2169ec03d7fSMaxime Ripard return to_vc4_hvs_state(priv_state); 2179ec03d7fSMaxime Ripard } 2189ec03d7fSMaxime Ripard 2199ec03d7fSMaxime Ripard static struct vc4_hvs_state * 220f2df84e0SMaxime Ripard vc4_hvs_get_global_state(struct drm_atomic_state *state) 221f2df84e0SMaxime Ripard { 222f2df84e0SMaxime Ripard struct vc4_dev *vc4 = to_vc4_dev(state->dev); 223f2df84e0SMaxime Ripard struct drm_private_state *priv_state; 224f2df84e0SMaxime Ripard 225f2df84e0SMaxime Ripard priv_state = drm_atomic_get_private_obj_state(state, &vc4->hvs_channels); 226f2df84e0SMaxime Ripard if (IS_ERR(priv_state)) 227f2df84e0SMaxime Ripard return ERR_CAST(priv_state); 228f2df84e0SMaxime Ripard 229f2df84e0SMaxime Ripard return to_vc4_hvs_state(priv_state); 230f2df84e0SMaxime Ripard } 231f2df84e0SMaxime Ripard 23287ebcd42SMaxime Ripard static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4, 23387ebcd42SMaxime Ripard struct drm_atomic_state *state) 23487ebcd42SMaxime Ripard { 2353454f01aSMaxime Ripard struct vc4_hvs *hvs = vc4->hvs; 23687ebcd42SMaxime Ripard struct drm_crtc_state *crtc_state; 23787ebcd42SMaxime Ripard struct drm_crtc *crtc; 23887ebcd42SMaxime Ripard unsigned int i; 23987ebcd42SMaxime Ripard 24087ebcd42SMaxime Ripard for_each_new_crtc_in_state(state, crtc, crtc_state, i) { 241a16c6640SMaxime Ripard struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); 24287ebcd42SMaxime Ripard struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); 24387ebcd42SMaxime Ripard u32 dispctrl; 24487ebcd42SMaxime Ripard u32 dsp3_mux; 24587ebcd42SMaxime Ripard 24687ebcd42SMaxime Ripard if (!crtc_state->active) 24787ebcd42SMaxime Ripard continue; 24887ebcd42SMaxime Ripard 24987ebcd42SMaxime Ripard if (vc4_state->assigned_channel != 2) 25087ebcd42SMaxime Ripard continue; 25187ebcd42SMaxime Ripard 25287ebcd42SMaxime Ripard /* 25387ebcd42SMaxime Ripard * SCALER_DISPCTRL_DSP3 = X, where X < 2 means 'connect DSP3 to 25487ebcd42SMaxime Ripard * FIFO X'. 25587ebcd42SMaxime Ripard * SCALER_DISPCTRL_DSP3 = 3 means 'disable DSP 3'. 25687ebcd42SMaxime Ripard * 25787ebcd42SMaxime Ripard * DSP3 is connected to FIFO2 unless the transposer is 25887ebcd42SMaxime Ripard * enabled. In this case, FIFO 2 is directly accessed by the 25987ebcd42SMaxime Ripard * TXP IP, and we need to disable the FIFO2 -> pixelvalve1 26087ebcd42SMaxime Ripard * route. 26187ebcd42SMaxime Ripard */ 262a16c6640SMaxime Ripard if (vc4_crtc->feeds_txp) 26387ebcd42SMaxime Ripard dsp3_mux = VC4_SET_FIELD(3, SCALER_DISPCTRL_DSP3_MUX); 26487ebcd42SMaxime Ripard else 26587ebcd42SMaxime Ripard dsp3_mux = VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX); 26687ebcd42SMaxime Ripard 26787ebcd42SMaxime Ripard dispctrl = HVS_READ(SCALER_DISPCTRL) & 26887ebcd42SMaxime Ripard ~SCALER_DISPCTRL_DSP3_MUX_MASK; 26987ebcd42SMaxime Ripard HVS_WRITE(SCALER_DISPCTRL, dispctrl | dsp3_mux); 27087ebcd42SMaxime Ripard } 27187ebcd42SMaxime Ripard } 27287ebcd42SMaxime Ripard 27387ebcd42SMaxime Ripard static void vc5_hvs_pv_muxing_commit(struct vc4_dev *vc4, 27487ebcd42SMaxime Ripard struct drm_atomic_state *state) 27587ebcd42SMaxime Ripard { 2763454f01aSMaxime Ripard struct vc4_hvs *hvs = vc4->hvs; 27787ebcd42SMaxime Ripard struct drm_crtc_state *crtc_state; 27887ebcd42SMaxime Ripard struct drm_crtc *crtc; 2792820526dSMaxime Ripard unsigned char mux; 28087ebcd42SMaxime Ripard unsigned int i; 28187ebcd42SMaxime Ripard u32 reg; 28287ebcd42SMaxime Ripard 28387ebcd42SMaxime Ripard for_each_new_crtc_in_state(state, crtc, crtc_state, i) { 28487ebcd42SMaxime Ripard struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); 28587ebcd42SMaxime Ripard struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); 286f47d37a9SMaxime Ripard unsigned int channel = vc4_state->assigned_channel; 28787ebcd42SMaxime Ripard 2882820526dSMaxime Ripard if (!vc4_state->update_muxing) 28987ebcd42SMaxime Ripard continue; 29087ebcd42SMaxime Ripard 29187ebcd42SMaxime Ripard switch (vc4_crtc->data->hvs_output) { 29287ebcd42SMaxime Ripard case 2: 293457e5184SMaxime Ripard drm_WARN_ON(&vc4->base, 294457e5184SMaxime Ripard VC4_GET_FIELD(HVS_READ(SCALER_DISPCTRL), 295457e5184SMaxime Ripard SCALER_DISPCTRL_DSP3_MUX) == channel); 296457e5184SMaxime Ripard 297f47d37a9SMaxime Ripard mux = (channel == 2) ? 0 : 1; 2982820526dSMaxime Ripard reg = HVS_READ(SCALER_DISPECTRL); 2992820526dSMaxime Ripard HVS_WRITE(SCALER_DISPECTRL, 3002820526dSMaxime Ripard (reg & ~SCALER_DISPECTRL_DSP2_MUX_MASK) | 3012820526dSMaxime Ripard VC4_SET_FIELD(mux, SCALER_DISPECTRL_DSP2_MUX)); 30287ebcd42SMaxime Ripard break; 30387ebcd42SMaxime Ripard 30487ebcd42SMaxime Ripard case 3: 305f47d37a9SMaxime Ripard if (channel == VC4_HVS_CHANNEL_DISABLED) 3062820526dSMaxime Ripard mux = 3; 3072820526dSMaxime Ripard else 308f47d37a9SMaxime Ripard mux = channel; 3092820526dSMaxime Ripard 3102820526dSMaxime Ripard reg = HVS_READ(SCALER_DISPCTRL); 3112820526dSMaxime Ripard HVS_WRITE(SCALER_DISPCTRL, 3122820526dSMaxime Ripard (reg & ~SCALER_DISPCTRL_DSP3_MUX_MASK) | 3132820526dSMaxime Ripard VC4_SET_FIELD(mux, SCALER_DISPCTRL_DSP3_MUX)); 31487ebcd42SMaxime Ripard break; 31587ebcd42SMaxime Ripard 31687ebcd42SMaxime Ripard case 4: 317f47d37a9SMaxime Ripard if (channel == VC4_HVS_CHANNEL_DISABLED) 3182820526dSMaxime Ripard mux = 3; 3192820526dSMaxime Ripard else 320f47d37a9SMaxime Ripard mux = channel; 3212820526dSMaxime Ripard 3222820526dSMaxime Ripard reg = HVS_READ(SCALER_DISPEOLN); 3232820526dSMaxime Ripard HVS_WRITE(SCALER_DISPEOLN, 3242820526dSMaxime Ripard (reg & ~SCALER_DISPEOLN_DSP4_MUX_MASK) | 3252820526dSMaxime Ripard VC4_SET_FIELD(mux, SCALER_DISPEOLN_DSP4_MUX)); 3262820526dSMaxime Ripard 32787ebcd42SMaxime Ripard break; 32887ebcd42SMaxime Ripard 32987ebcd42SMaxime Ripard case 5: 330f47d37a9SMaxime Ripard if (channel == VC4_HVS_CHANNEL_DISABLED) 3312820526dSMaxime Ripard mux = 3; 3322820526dSMaxime Ripard else 333f47d37a9SMaxime Ripard mux = channel; 3342820526dSMaxime Ripard 3352820526dSMaxime Ripard reg = HVS_READ(SCALER_DISPDITHER); 3362820526dSMaxime Ripard HVS_WRITE(SCALER_DISPDITHER, 3372820526dSMaxime Ripard (reg & ~SCALER_DISPDITHER_DSP5_MUX_MASK) | 3382820526dSMaxime Ripard VC4_SET_FIELD(mux, SCALER_DISPDITHER_DSP5_MUX)); 33987ebcd42SMaxime Ripard break; 34087ebcd42SMaxime Ripard 34187ebcd42SMaxime Ripard default: 34287ebcd42SMaxime Ripard break; 34387ebcd42SMaxime Ripard } 34487ebcd42SMaxime Ripard } 34587ebcd42SMaxime Ripard } 34687ebcd42SMaxime Ripard 347f3c420feSMaxime Ripard static void vc4_atomic_commit_tail(struct drm_atomic_state *state) 348b501baccSEric Anholt { 349b501baccSEric Anholt struct drm_device *dev = state->dev; 350b501baccSEric Anholt struct vc4_dev *vc4 = to_vc4_dev(dev); 351d7d96c00SMaxime Ripard struct vc4_hvs *hvs = vc4->hvs; 35259635667SMaxime Ripard struct drm_crtc_state *new_crtc_state; 35316e10105SMaxime Ripard struct vc4_hvs_state *new_hvs_state; 35459635667SMaxime Ripard struct drm_crtc *crtc; 3559ec03d7fSMaxime Ripard struct vc4_hvs_state *old_hvs_state; 3566052a311SMaxime Ripard unsigned int channel; 357531a1b62SBoris Brezillon int i; 358531a1b62SBoris Brezillon 35916e10105SMaxime Ripard old_hvs_state = vc4_hvs_get_old_global_state(state); 36099b03ca6SDaniel Vetter if (WARN_ON(IS_ERR(old_hvs_state))) 36116e10105SMaxime Ripard return; 36216e10105SMaxime Ripard 36316e10105SMaxime Ripard new_hvs_state = vc4_hvs_get_new_global_state(state); 36499b03ca6SDaniel Vetter if (WARN_ON(IS_ERR(new_hvs_state))) 36516e10105SMaxime Ripard return; 36616e10105SMaxime Ripard 36759635667SMaxime Ripard for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { 36887ebcd42SMaxime Ripard struct vc4_crtc_state *vc4_crtc_state; 36959635667SMaxime Ripard 37059635667SMaxime Ripard if (!new_crtc_state->commit) 371531a1b62SBoris Brezillon continue; 372531a1b62SBoris Brezillon 37387ebcd42SMaxime Ripard vc4_crtc_state = to_vc4_crtc_state(new_crtc_state); 3743454f01aSMaxime Ripard vc4_hvs_mask_underrun(hvs, vc4_crtc_state->assigned_channel); 375531a1b62SBoris Brezillon } 376b501baccSEric Anholt 3776052a311SMaxime Ripard for (channel = 0; channel < HVS_NUM_CHANNELS; channel++) { 378049cfff8SMaxime Ripard struct drm_crtc_commit *commit; 379b99c2c95SMaxime Ripard int ret; 3809ec03d7fSMaxime Ripard 3819ec03d7fSMaxime Ripard if (!old_hvs_state->fifo_state[channel].in_use) 3829ec03d7fSMaxime Ripard continue; 3839ec03d7fSMaxime Ripard 384049cfff8SMaxime Ripard commit = old_hvs_state->fifo_state[channel].pending_commit; 385049cfff8SMaxime Ripard if (!commit) 386049cfff8SMaxime Ripard continue; 387049cfff8SMaxime Ripard 388049cfff8SMaxime Ripard ret = drm_crtc_commit_wait(commit); 389b99c2c95SMaxime Ripard if (ret) 390b99c2c95SMaxime Ripard drm_err(dev, "Timed out waiting for commit\n"); 391049cfff8SMaxime Ripard 392049cfff8SMaxime Ripard drm_crtc_commit_put(commit); 393d134c5ffSMaxime Ripard old_hvs_state->fifo_state[channel].pending_commit = NULL; 3949ec03d7fSMaxime Ripard } 3959ec03d7fSMaxime Ripard 396*1cbc91ebSMaxime Ripard if (vc4->is_vc5) { 397748acfc9SMaxime Ripard unsigned long state_rate = max(old_hvs_state->core_clock_rate, 398244a36e5SMaxime Ripard new_hvs_state->core_clock_rate); 399748acfc9SMaxime Ripard unsigned long core_rate = max_t(unsigned long, 400748acfc9SMaxime Ripard 500000000, state_rate); 401244a36e5SMaxime Ripard 4025b6ef06eSMaxime Ripard drm_dbg(dev, "Raising the core clock at %lu Hz\n", core_rate); 4035b6ef06eSMaxime Ripard 4045b6ef06eSMaxime Ripard /* 4055b6ef06eSMaxime Ripard * Do a temporary request on the core clock during the 4065b6ef06eSMaxime Ripard * modeset. 4075b6ef06eSMaxime Ripard */ 408244a36e5SMaxime Ripard clk_set_min_rate(hvs->core_clk, core_rate); 409244a36e5SMaxime Ripard } 4105b6ef06eSMaxime Ripard 411b501baccSEric Anholt drm_atomic_helper_commit_modeset_disables(dev, state); 412b501baccSEric Anholt 413766cc6b1SStefan Schake vc4_ctm_commit(vc4, state); 414766cc6b1SStefan Schake 415*1cbc91ebSMaxime Ripard if (vc4->is_vc5) 41687ebcd42SMaxime Ripard vc5_hvs_pv_muxing_commit(vc4, state); 41787ebcd42SMaxime Ripard else 41887ebcd42SMaxime Ripard vc4_hvs_pv_muxing_commit(vc4, state); 41987ebcd42SMaxime Ripard 420d65661acSMaxime Ripard drm_atomic_helper_commit_planes(dev, state, 421d65661acSMaxime Ripard DRM_PLANE_COMMIT_ACTIVE_ONLY); 422b501baccSEric Anholt 423b501baccSEric Anholt drm_atomic_helper_commit_modeset_enables(dev, state); 424b501baccSEric Anholt 4251ebe99a7SBoris Brezillon drm_atomic_helper_fake_vblank(state); 4261ebe99a7SBoris Brezillon 42734c8ea40SBoris Brezillon drm_atomic_helper_commit_hw_done(state); 42834c8ea40SBoris Brezillon 429184d3cf4SBoris Brezillon drm_atomic_helper_wait_for_flip_done(dev, state); 430b501baccSEric Anholt 431b501baccSEric Anholt drm_atomic_helper_cleanup_planes(dev, state); 432b501baccSEric Anholt 433*1cbc91ebSMaxime Ripard if (vc4->is_vc5) { 43416e10105SMaxime Ripard drm_dbg(dev, "Running the core clock at %lu Hz\n", 43516e10105SMaxime Ripard new_hvs_state->core_clock_rate); 43616e10105SMaxime Ripard 4375b6ef06eSMaxime Ripard /* 4385b6ef06eSMaxime Ripard * Request a clock rate based on the current HVS 4395b6ef06eSMaxime Ripard * requirements. 4405b6ef06eSMaxime Ripard */ 44116e10105SMaxime Ripard clk_set_min_rate(hvs->core_clk, new_hvs_state->core_clock_rate); 4423870b54eSMaxime Ripard 4433870b54eSMaxime Ripard drm_dbg(dev, "Core clock actual rate: %lu Hz\n", 4443870b54eSMaxime Ripard clk_get_rate(hvs->core_clk)); 44516e10105SMaxime Ripard } 446b501baccSEric Anholt } 447b501baccSEric Anholt 4489ec03d7fSMaxime Ripard static int vc4_atomic_commit_setup(struct drm_atomic_state *state) 4499ec03d7fSMaxime Ripard { 4509ec03d7fSMaxime Ripard struct drm_crtc_state *crtc_state; 4519ec03d7fSMaxime Ripard struct vc4_hvs_state *hvs_state; 4529ec03d7fSMaxime Ripard struct drm_crtc *crtc; 4539ec03d7fSMaxime Ripard unsigned int i; 4549ec03d7fSMaxime Ripard 4559ec03d7fSMaxime Ripard hvs_state = vc4_hvs_get_new_global_state(state); 456f9277679SMaxime Ripard if (WARN_ON(IS_ERR(hvs_state))) 457f9277679SMaxime Ripard return PTR_ERR(hvs_state); 4589ec03d7fSMaxime Ripard 4599ec03d7fSMaxime Ripard for_each_new_crtc_in_state(state, crtc, crtc_state, i) { 4609ec03d7fSMaxime Ripard struct vc4_crtc_state *vc4_crtc_state = 4619ec03d7fSMaxime Ripard to_vc4_crtc_state(crtc_state); 4629ec03d7fSMaxime Ripard unsigned int channel = 4639ec03d7fSMaxime Ripard vc4_crtc_state->assigned_channel; 4649ec03d7fSMaxime Ripard 4659ec03d7fSMaxime Ripard if (channel == VC4_HVS_CHANNEL_DISABLED) 4669ec03d7fSMaxime Ripard continue; 4679ec03d7fSMaxime Ripard 4689ec03d7fSMaxime Ripard if (!hvs_state->fifo_state[channel].in_use) 4699ec03d7fSMaxime Ripard continue; 4709ec03d7fSMaxime Ripard 4719ec03d7fSMaxime Ripard hvs_state->fifo_state[channel].pending_commit = 4729ec03d7fSMaxime Ripard drm_crtc_commit_get(crtc_state->commit); 4739ec03d7fSMaxime Ripard } 4749ec03d7fSMaxime Ripard 4759ec03d7fSMaxime Ripard return 0; 4769ec03d7fSMaxime Ripard } 4779ec03d7fSMaxime Ripard 47883753117SEric Anholt static struct drm_framebuffer *vc4_fb_create(struct drm_device *dev, 47983753117SEric Anholt struct drm_file *file_priv, 48083753117SEric Anholt const struct drm_mode_fb_cmd2 *mode_cmd) 48183753117SEric Anholt { 48283753117SEric Anholt struct drm_mode_fb_cmd2 mode_cmd_local; 48383753117SEric Anholt 48483753117SEric Anholt /* If the user didn't specify a modifier, use the 48583753117SEric Anholt * vc4_set_tiling_ioctl() state for the BO. 48683753117SEric Anholt */ 48783753117SEric Anholt if (!(mode_cmd->flags & DRM_MODE_FB_MODIFIERS)) { 48883753117SEric Anholt struct drm_gem_object *gem_obj; 48983753117SEric Anholt struct vc4_bo *bo; 49083753117SEric Anholt 49183753117SEric Anholt gem_obj = drm_gem_object_lookup(file_priv, 49283753117SEric Anholt mode_cmd->handles[0]); 49383753117SEric Anholt if (!gem_obj) { 494fb95992aSEric Anholt DRM_DEBUG("Failed to look up GEM BO %d\n", 49583753117SEric Anholt mode_cmd->handles[0]); 49683753117SEric Anholt return ERR_PTR(-ENOENT); 49783753117SEric Anholt } 49883753117SEric Anholt bo = to_vc4_bo(gem_obj); 49983753117SEric Anholt 50083753117SEric Anholt mode_cmd_local = *mode_cmd; 50183753117SEric Anholt 50283753117SEric Anholt if (bo->t_format) { 50383753117SEric Anholt mode_cmd_local.modifier[0] = 50483753117SEric Anholt DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED; 50583753117SEric Anholt } else { 50683753117SEric Anholt mode_cmd_local.modifier[0] = DRM_FORMAT_MOD_NONE; 50783753117SEric Anholt } 50883753117SEric Anholt 509f7a8cd30SEmil Velikov drm_gem_object_put(gem_obj); 51083753117SEric Anholt 51183753117SEric Anholt mode_cmd = &mode_cmd_local; 51283753117SEric Anholt } 51383753117SEric Anholt 5149762477cSNoralf Trønnes return drm_gem_fb_create(dev, file_priv, mode_cmd); 51583753117SEric Anholt } 51683753117SEric Anholt 517766cc6b1SStefan Schake /* Our CTM has some peculiar limitations: we can only enable it for one CRTC 518766cc6b1SStefan Schake * at a time and the HW only supports S0.9 scalars. To account for the latter, 519766cc6b1SStefan Schake * we don't allow userland to set a CTM that we have no hope of approximating. 520766cc6b1SStefan Schake */ 521766cc6b1SStefan Schake static int 522766cc6b1SStefan Schake vc4_ctm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) 523766cc6b1SStefan Schake { 524766cc6b1SStefan Schake struct vc4_dev *vc4 = to_vc4_dev(dev); 525766cc6b1SStefan Schake struct vc4_ctm_state *ctm_state = NULL; 526766cc6b1SStefan Schake struct drm_crtc *crtc; 527766cc6b1SStefan Schake struct drm_crtc_state *old_crtc_state, *new_crtc_state; 528766cc6b1SStefan Schake struct drm_color_ctm *ctm; 529766cc6b1SStefan Schake int i; 530766cc6b1SStefan Schake 531766cc6b1SStefan Schake for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { 532766cc6b1SStefan Schake /* CTM is being disabled. */ 533766cc6b1SStefan Schake if (!new_crtc_state->ctm && old_crtc_state->ctm) { 534766cc6b1SStefan Schake ctm_state = vc4_get_ctm_state(state, &vc4->ctm_manager); 535766cc6b1SStefan Schake if (IS_ERR(ctm_state)) 536766cc6b1SStefan Schake return PTR_ERR(ctm_state); 537766cc6b1SStefan Schake ctm_state->fifo = 0; 538766cc6b1SStefan Schake } 539766cc6b1SStefan Schake } 540766cc6b1SStefan Schake 541766cc6b1SStefan Schake for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { 542766cc6b1SStefan Schake if (new_crtc_state->ctm == old_crtc_state->ctm) 543766cc6b1SStefan Schake continue; 544766cc6b1SStefan Schake 545766cc6b1SStefan Schake if (!ctm_state) { 546766cc6b1SStefan Schake ctm_state = vc4_get_ctm_state(state, &vc4->ctm_manager); 547766cc6b1SStefan Schake if (IS_ERR(ctm_state)) 548766cc6b1SStefan Schake return PTR_ERR(ctm_state); 549766cc6b1SStefan Schake } 550766cc6b1SStefan Schake 551766cc6b1SStefan Schake /* CTM is being enabled or the matrix changed. */ 552766cc6b1SStefan Schake if (new_crtc_state->ctm) { 55387ebcd42SMaxime Ripard struct vc4_crtc_state *vc4_crtc_state = 55487ebcd42SMaxime Ripard to_vc4_crtc_state(new_crtc_state); 55587ebcd42SMaxime Ripard 556766cc6b1SStefan Schake /* fifo is 1-based since 0 disables CTM. */ 55787ebcd42SMaxime Ripard int fifo = vc4_crtc_state->assigned_channel + 1; 558766cc6b1SStefan Schake 559766cc6b1SStefan Schake /* Check userland isn't trying to turn on CTM for more 560766cc6b1SStefan Schake * than one CRTC at a time. 561766cc6b1SStefan Schake */ 562766cc6b1SStefan Schake if (ctm_state->fifo && ctm_state->fifo != fifo) { 563766cc6b1SStefan Schake DRM_DEBUG_DRIVER("Too many CTM configured\n"); 564766cc6b1SStefan Schake return -EINVAL; 565766cc6b1SStefan Schake } 566766cc6b1SStefan Schake 567766cc6b1SStefan Schake /* Check we can approximate the specified CTM. 568766cc6b1SStefan Schake * We disallow scalars |c| > 1.0 since the HW has 569766cc6b1SStefan Schake * no integer bits. 570766cc6b1SStefan Schake */ 571766cc6b1SStefan Schake ctm = new_crtc_state->ctm->data; 572766cc6b1SStefan Schake for (i = 0; i < ARRAY_SIZE(ctm->matrix); i++) { 573766cc6b1SStefan Schake u64 val = ctm->matrix[i]; 574766cc6b1SStefan Schake 575766cc6b1SStefan Schake val &= ~BIT_ULL(63); 576766cc6b1SStefan Schake if (val > BIT_ULL(32)) 577766cc6b1SStefan Schake return -EINVAL; 578766cc6b1SStefan Schake } 579766cc6b1SStefan Schake 580766cc6b1SStefan Schake ctm_state->fifo = fifo; 581766cc6b1SStefan Schake ctm_state->ctm = ctm; 582766cc6b1SStefan Schake } 583766cc6b1SStefan Schake } 584766cc6b1SStefan Schake 585766cc6b1SStefan Schake return 0; 586766cc6b1SStefan Schake } 587766cc6b1SStefan Schake 5884686da83SBoris Brezillon static int vc4_load_tracker_atomic_check(struct drm_atomic_state *state) 5894686da83SBoris Brezillon { 5904686da83SBoris Brezillon struct drm_plane_state *old_plane_state, *new_plane_state; 5914686da83SBoris Brezillon struct vc4_dev *vc4 = to_vc4_dev(state->dev); 5924686da83SBoris Brezillon struct vc4_load_tracker_state *load_state; 5934686da83SBoris Brezillon struct drm_private_state *priv_state; 5944686da83SBoris Brezillon struct drm_plane *plane; 5954686da83SBoris Brezillon int i; 5964686da83SBoris Brezillon 5974686da83SBoris Brezillon priv_state = drm_atomic_get_private_obj_state(state, 5984686da83SBoris Brezillon &vc4->load_tracker); 5994686da83SBoris Brezillon if (IS_ERR(priv_state)) 6004686da83SBoris Brezillon return PTR_ERR(priv_state); 6014686da83SBoris Brezillon 6024686da83SBoris Brezillon load_state = to_vc4_load_tracker_state(priv_state); 6034686da83SBoris Brezillon for_each_oldnew_plane_in_state(state, plane, old_plane_state, 6044686da83SBoris Brezillon new_plane_state, i) { 6054686da83SBoris Brezillon struct vc4_plane_state *vc4_plane_state; 6064686da83SBoris Brezillon 6074686da83SBoris Brezillon if (old_plane_state->fb && old_plane_state->crtc) { 6084686da83SBoris Brezillon vc4_plane_state = to_vc4_plane_state(old_plane_state); 6094686da83SBoris Brezillon load_state->membus_load -= vc4_plane_state->membus_load; 6104686da83SBoris Brezillon load_state->hvs_load -= vc4_plane_state->hvs_load; 6114686da83SBoris Brezillon } 6124686da83SBoris Brezillon 6134686da83SBoris Brezillon if (new_plane_state->fb && new_plane_state->crtc) { 6144686da83SBoris Brezillon vc4_plane_state = to_vc4_plane_state(new_plane_state); 6154686da83SBoris Brezillon load_state->membus_load += vc4_plane_state->membus_load; 6164686da83SBoris Brezillon load_state->hvs_load += vc4_plane_state->hvs_load; 6174686da83SBoris Brezillon } 6184686da83SBoris Brezillon } 6194686da83SBoris Brezillon 6206b5c029dSPaul Kocialkowski /* Don't check the load when the tracker is disabled. */ 6216b5c029dSPaul Kocialkowski if (!vc4->load_tracker_enabled) 6226b5c029dSPaul Kocialkowski return 0; 6236b5c029dSPaul Kocialkowski 6244686da83SBoris Brezillon /* The absolute limit is 2Gbyte/sec, but let's take a margin to let 6254686da83SBoris Brezillon * the system work when other blocks are accessing the memory. 6264686da83SBoris Brezillon */ 6274686da83SBoris Brezillon if (load_state->membus_load > SZ_1G + SZ_512M) 6284686da83SBoris Brezillon return -ENOSPC; 6294686da83SBoris Brezillon 6304686da83SBoris Brezillon /* HVS clock is supposed to run @ 250Mhz, let's take a margin and 6314686da83SBoris Brezillon * consider the maximum number of cycles is 240M. 6324686da83SBoris Brezillon */ 6334686da83SBoris Brezillon if (load_state->hvs_load > 240000000ULL) 6344686da83SBoris Brezillon return -ENOSPC; 6354686da83SBoris Brezillon 6364686da83SBoris Brezillon return 0; 6374686da83SBoris Brezillon } 6384686da83SBoris Brezillon 6394686da83SBoris Brezillon static struct drm_private_state * 6404686da83SBoris Brezillon vc4_load_tracker_duplicate_state(struct drm_private_obj *obj) 6414686da83SBoris Brezillon { 6424686da83SBoris Brezillon struct vc4_load_tracker_state *state; 6434686da83SBoris Brezillon 6444686da83SBoris Brezillon state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL); 6454686da83SBoris Brezillon if (!state) 6464686da83SBoris Brezillon return NULL; 6474686da83SBoris Brezillon 6484686da83SBoris Brezillon __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); 6494686da83SBoris Brezillon 6504686da83SBoris Brezillon return &state->base; 6514686da83SBoris Brezillon } 6524686da83SBoris Brezillon 6534686da83SBoris Brezillon static void vc4_load_tracker_destroy_state(struct drm_private_obj *obj, 6544686da83SBoris Brezillon struct drm_private_state *state) 6554686da83SBoris Brezillon { 6564686da83SBoris Brezillon struct vc4_load_tracker_state *load_state; 6574686da83SBoris Brezillon 6584686da83SBoris Brezillon load_state = to_vc4_load_tracker_state(state); 6594686da83SBoris Brezillon kfree(load_state); 6604686da83SBoris Brezillon } 6614686da83SBoris Brezillon 6624686da83SBoris Brezillon static const struct drm_private_state_funcs vc4_load_tracker_state_funcs = { 6634686da83SBoris Brezillon .atomic_duplicate_state = vc4_load_tracker_duplicate_state, 6644686da83SBoris Brezillon .atomic_destroy_state = vc4_load_tracker_destroy_state, 6654686da83SBoris Brezillon }; 6664686da83SBoris Brezillon 667dcda7c28SMaxime Ripard static void vc4_load_tracker_obj_fini(struct drm_device *dev, void *unused) 668dcda7c28SMaxime Ripard { 669dcda7c28SMaxime Ripard struct vc4_dev *vc4 = to_vc4_dev(dev); 670dcda7c28SMaxime Ripard 671dcda7c28SMaxime Ripard drm_atomic_private_obj_fini(&vc4->load_tracker); 672dcda7c28SMaxime Ripard } 673dcda7c28SMaxime Ripard 674dcda7c28SMaxime Ripard static int vc4_load_tracker_obj_init(struct vc4_dev *vc4) 675dcda7c28SMaxime Ripard { 676dcda7c28SMaxime Ripard struct vc4_load_tracker_state *load_state; 677dcda7c28SMaxime Ripard 678dcda7c28SMaxime Ripard load_state = kzalloc(sizeof(*load_state), GFP_KERNEL); 679dcda7c28SMaxime Ripard if (!load_state) 680dcda7c28SMaxime Ripard return -ENOMEM; 681dcda7c28SMaxime Ripard 682dcda7c28SMaxime Ripard drm_atomic_private_obj_init(&vc4->base, &vc4->load_tracker, 683dcda7c28SMaxime Ripard &load_state->base, 684dcda7c28SMaxime Ripard &vc4_load_tracker_state_funcs); 685dcda7c28SMaxime Ripard 6863c354ed1SMaxime Ripard return drmm_add_action_or_reset(&vc4->base, vc4_load_tracker_obj_fini, NULL); 687dcda7c28SMaxime Ripard } 688dcda7c28SMaxime Ripard 689f2df84e0SMaxime Ripard static struct drm_private_state * 690f2df84e0SMaxime Ripard vc4_hvs_channels_duplicate_state(struct drm_private_obj *obj) 691f2df84e0SMaxime Ripard { 692f2df84e0SMaxime Ripard struct vc4_hvs_state *old_state = to_vc4_hvs_state(obj->state); 693f2df84e0SMaxime Ripard struct vc4_hvs_state *state; 6949ec03d7fSMaxime Ripard unsigned int i; 695f2df84e0SMaxime Ripard 696f2df84e0SMaxime Ripard state = kzalloc(sizeof(*state), GFP_KERNEL); 697f2df84e0SMaxime Ripard if (!state) 698f2df84e0SMaxime Ripard return NULL; 699f2df84e0SMaxime Ripard 700f2df84e0SMaxime Ripard __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); 701f2df84e0SMaxime Ripard 7029ec03d7fSMaxime Ripard for (i = 0; i < HVS_NUM_CHANNELS; i++) { 7039ec03d7fSMaxime Ripard state->fifo_state[i].in_use = old_state->fifo_state[i].in_use; 70416e10105SMaxime Ripard state->fifo_state[i].fifo_load = old_state->fifo_state[i].fifo_load; 7059ec03d7fSMaxime Ripard } 7069ec03d7fSMaxime Ripard 70716e10105SMaxime Ripard state->core_clock_rate = old_state->core_clock_rate; 70816e10105SMaxime Ripard 709f2df84e0SMaxime Ripard return &state->base; 710f2df84e0SMaxime Ripard } 711f2df84e0SMaxime Ripard 712f2df84e0SMaxime Ripard static void vc4_hvs_channels_destroy_state(struct drm_private_obj *obj, 713f2df84e0SMaxime Ripard struct drm_private_state *state) 714f2df84e0SMaxime Ripard { 715f2df84e0SMaxime Ripard struct vc4_hvs_state *hvs_state = to_vc4_hvs_state(state); 7169ec03d7fSMaxime Ripard unsigned int i; 7179ec03d7fSMaxime Ripard 7189ec03d7fSMaxime Ripard for (i = 0; i < HVS_NUM_CHANNELS; i++) { 7199ec03d7fSMaxime Ripard if (!hvs_state->fifo_state[i].pending_commit) 7209ec03d7fSMaxime Ripard continue; 7219ec03d7fSMaxime Ripard 7229ec03d7fSMaxime Ripard drm_crtc_commit_put(hvs_state->fifo_state[i].pending_commit); 7239ec03d7fSMaxime Ripard } 724f2df84e0SMaxime Ripard 725f2df84e0SMaxime Ripard kfree(hvs_state); 726f2df84e0SMaxime Ripard } 727f2df84e0SMaxime Ripard 72866bfe59dSMaxime Ripard static void vc4_hvs_channels_print_state(struct drm_printer *p, 72966bfe59dSMaxime Ripard const struct drm_private_state *state) 73066bfe59dSMaxime Ripard { 73166bfe59dSMaxime Ripard struct vc4_hvs_state *hvs_state = to_vc4_hvs_state(state); 73266bfe59dSMaxime Ripard unsigned int i; 73366bfe59dSMaxime Ripard 73466bfe59dSMaxime Ripard drm_printf(p, "HVS State\n"); 73566bfe59dSMaxime Ripard drm_printf(p, "\tCore Clock Rate: %lu\n", hvs_state->core_clock_rate); 73666bfe59dSMaxime Ripard 73766bfe59dSMaxime Ripard for (i = 0; i < HVS_NUM_CHANNELS; i++) { 73866bfe59dSMaxime Ripard drm_printf(p, "\tChannel %d\n", i); 73966bfe59dSMaxime Ripard drm_printf(p, "\t\tin use=%d\n", hvs_state->fifo_state[i].in_use); 74066bfe59dSMaxime Ripard drm_printf(p, "\t\tload=%lu\n", hvs_state->fifo_state[i].fifo_load); 74166bfe59dSMaxime Ripard } 74266bfe59dSMaxime Ripard } 74366bfe59dSMaxime Ripard 744f2df84e0SMaxime Ripard static const struct drm_private_state_funcs vc4_hvs_state_funcs = { 745f2df84e0SMaxime Ripard .atomic_duplicate_state = vc4_hvs_channels_duplicate_state, 746f2df84e0SMaxime Ripard .atomic_destroy_state = vc4_hvs_channels_destroy_state, 74766bfe59dSMaxime Ripard .atomic_print_state = vc4_hvs_channels_print_state, 748f2df84e0SMaxime Ripard }; 749f2df84e0SMaxime Ripard 750f2df84e0SMaxime Ripard static void vc4_hvs_channels_obj_fini(struct drm_device *dev, void *unused) 751f2df84e0SMaxime Ripard { 752f2df84e0SMaxime Ripard struct vc4_dev *vc4 = to_vc4_dev(dev); 753f2df84e0SMaxime Ripard 754f2df84e0SMaxime Ripard drm_atomic_private_obj_fini(&vc4->hvs_channels); 755f2df84e0SMaxime Ripard } 756f2df84e0SMaxime Ripard 757f2df84e0SMaxime Ripard static int vc4_hvs_channels_obj_init(struct vc4_dev *vc4) 758f2df84e0SMaxime Ripard { 759f2df84e0SMaxime Ripard struct vc4_hvs_state *state; 760f2df84e0SMaxime Ripard 761f2df84e0SMaxime Ripard state = kzalloc(sizeof(*state), GFP_KERNEL); 762f2df84e0SMaxime Ripard if (!state) 763f2df84e0SMaxime Ripard return -ENOMEM; 764f2df84e0SMaxime Ripard 765f2df84e0SMaxime Ripard drm_atomic_private_obj_init(&vc4->base, &vc4->hvs_channels, 766f2df84e0SMaxime Ripard &state->base, 767f2df84e0SMaxime Ripard &vc4_hvs_state_funcs); 768f2df84e0SMaxime Ripard 769f2df84e0SMaxime Ripard return drmm_add_action_or_reset(&vc4->base, vc4_hvs_channels_obj_fini, NULL); 770f2df84e0SMaxime Ripard } 771f2df84e0SMaxime Ripard 772b5dbc4d3SMaxime Ripard /* 773b5dbc4d3SMaxime Ripard * The BCM2711 HVS has up to 7 outputs connected to the pixelvalves and 774b5dbc4d3SMaxime Ripard * the TXP (and therefore all the CRTCs found on that platform). 775b5dbc4d3SMaxime Ripard * 776b5dbc4d3SMaxime Ripard * The naive (and our initial) implementation would just iterate over 777b5dbc4d3SMaxime Ripard * all the active CRTCs, try to find a suitable FIFO, and then remove it 778b5dbc4d3SMaxime Ripard * from the pool of available FIFOs. However, there are a few corner 779b5dbc4d3SMaxime Ripard * cases that need to be considered: 780b5dbc4d3SMaxime Ripard * 781b5dbc4d3SMaxime Ripard * - When running in a dual-display setup (so with two CRTCs involved), 782b5dbc4d3SMaxime Ripard * we can update the state of a single CRTC (for example by changing 783b5dbc4d3SMaxime Ripard * its mode using xrandr under X11) without affecting the other. In 784b5dbc4d3SMaxime Ripard * this case, the other CRTC wouldn't be in the state at all, so we 785b5dbc4d3SMaxime Ripard * need to consider all the running CRTCs in the DRM device to assign 786b5dbc4d3SMaxime Ripard * a FIFO, not just the one in the state. 787b5dbc4d3SMaxime Ripard * 788f2df84e0SMaxime Ripard * - To fix the above, we can't use drm_atomic_get_crtc_state on all 789f2df84e0SMaxime Ripard * enabled CRTCs to pull their CRTC state into the global state, since 790f2df84e0SMaxime Ripard * a page flip would start considering their vblank to complete. Since 791f2df84e0SMaxime Ripard * we don't have a guarantee that they are actually active, that 792f2df84e0SMaxime Ripard * vblank might never happen, and shouldn't even be considered if we 793f2df84e0SMaxime Ripard * want to do a page flip on a single CRTC. That can be tested by 794f2df84e0SMaxime Ripard * doing a modetest -v first on HDMI1 and then on HDMI0. 795f2df84e0SMaxime Ripard * 796b5dbc4d3SMaxime Ripard * - Since we need the pixelvalve to be disabled and enabled back when 797b5dbc4d3SMaxime Ripard * the FIFO is changed, we should keep the FIFO assigned for as long 798b5dbc4d3SMaxime Ripard * as the CRTC is enabled, only considering it free again once that 799b5dbc4d3SMaxime Ripard * CRTC has been disabled. This can be tested by booting X11 on a 800b5dbc4d3SMaxime Ripard * single display, and changing the resolution down and then back up. 801b5dbc4d3SMaxime Ripard */ 802a72b0458SMaxime Ripard static int vc4_pv_muxing_atomic_check(struct drm_device *dev, 803a72b0458SMaxime Ripard struct drm_atomic_state *state) 804766cc6b1SStefan Schake { 805f2df84e0SMaxime Ripard struct vc4_hvs_state *hvs_new_state; 8068ba0b6d1SMaxime Ripard struct drm_crtc_state *old_crtc_state, *new_crtc_state; 80787ebcd42SMaxime Ripard struct drm_crtc *crtc; 80803b03efeSMaxime Ripard unsigned int unassigned_channels = 0; 809a72b0458SMaxime Ripard unsigned int i; 81087ebcd42SMaxime Ripard 811f2df84e0SMaxime Ripard hvs_new_state = vc4_hvs_get_global_state(state); 812f9277679SMaxime Ripard if (IS_ERR(hvs_new_state)) 813f9277679SMaxime Ripard return PTR_ERR(hvs_new_state); 814089d8341SMaxime Ripard 81503b03efeSMaxime Ripard for (i = 0; i < ARRAY_SIZE(hvs_new_state->fifo_state); i++) 81603b03efeSMaxime Ripard if (!hvs_new_state->fifo_state[i].in_use) 81703b03efeSMaxime Ripard unassigned_channels |= BIT(i); 81803b03efeSMaxime Ripard 8198ba0b6d1SMaxime Ripard for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { 820f2df84e0SMaxime Ripard struct vc4_crtc_state *old_vc4_crtc_state = 821f2df84e0SMaxime Ripard to_vc4_crtc_state(old_crtc_state); 8228ba0b6d1SMaxime Ripard struct vc4_crtc_state *new_vc4_crtc_state = 8238ba0b6d1SMaxime Ripard to_vc4_crtc_state(new_crtc_state); 82487ebcd42SMaxime Ripard struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); 82587ebcd42SMaxime Ripard unsigned int matching_channels; 826d62a8ed7SMaxime Ripard unsigned int channel; 82787ebcd42SMaxime Ripard 8283870b54eSMaxime Ripard drm_dbg(dev, "%s: Trying to find a channel.\n", crtc->name); 8293870b54eSMaxime Ripard 8302820526dSMaxime Ripard /* Nothing to do here, let's skip it */ 8313870b54eSMaxime Ripard if (old_crtc_state->enable == new_crtc_state->enable) { 8323870b54eSMaxime Ripard if (new_crtc_state->enable) 8333870b54eSMaxime Ripard drm_dbg(dev, "%s: Already enabled, reusing channel %d.\n", 8343870b54eSMaxime Ripard crtc->name, new_vc4_crtc_state->assigned_channel); 8353870b54eSMaxime Ripard else 8363870b54eSMaxime Ripard drm_dbg(dev, "%s: Disabled, ignoring.\n", crtc->name); 8373870b54eSMaxime Ripard 8382820526dSMaxime Ripard continue; 8393870b54eSMaxime Ripard } 8402820526dSMaxime Ripard 8412820526dSMaxime Ripard /* Muxing will need to be modified, mark it as such */ 8422820526dSMaxime Ripard new_vc4_crtc_state->update_muxing = true; 8432820526dSMaxime Ripard 8442820526dSMaxime Ripard /* If we're disabling our CRTC, we put back our channel */ 8452820526dSMaxime Ripard if (!new_crtc_state->enable) { 8469ec03d7fSMaxime Ripard channel = old_vc4_crtc_state->assigned_channel; 8473870b54eSMaxime Ripard 8483870b54eSMaxime Ripard drm_dbg(dev, "%s: Disabling, Freeing channel %d\n", 8493870b54eSMaxime Ripard crtc->name, channel); 8503870b54eSMaxime Ripard 8519ec03d7fSMaxime Ripard hvs_new_state->fifo_state[channel].in_use = false; 8528ba0b6d1SMaxime Ripard new_vc4_crtc_state->assigned_channel = VC4_HVS_CHANNEL_DISABLED; 8532820526dSMaxime Ripard continue; 854f2df84e0SMaxime Ripard } 8558ba0b6d1SMaxime Ripard 85687ebcd42SMaxime Ripard /* 85787ebcd42SMaxime Ripard * The problem we have to solve here is that we have 85887ebcd42SMaxime Ripard * up to 7 encoders, connected to up to 6 CRTCs. 85987ebcd42SMaxime Ripard * 86087ebcd42SMaxime Ripard * Those CRTCs, depending on the instance, can be 86187ebcd42SMaxime Ripard * routed to 1, 2 or 3 HVS FIFOs, and we need to set 86287ebcd42SMaxime Ripard * the change the muxing between FIFOs and outputs in 86387ebcd42SMaxime Ripard * the HVS accordingly. 86487ebcd42SMaxime Ripard * 86587ebcd42SMaxime Ripard * It would be pretty hard to come up with an 86687ebcd42SMaxime Ripard * algorithm that would generically solve 86787ebcd42SMaxime Ripard * this. However, the current routing trees we support 86887ebcd42SMaxime Ripard * allow us to simplify a bit the problem. 86987ebcd42SMaxime Ripard * 87087ebcd42SMaxime Ripard * Indeed, with the current supported layouts, if we 87187ebcd42SMaxime Ripard * try to assign in the ascending crtc index order the 87287ebcd42SMaxime Ripard * FIFOs, we can't fall into the situation where an 87387ebcd42SMaxime Ripard * earlier CRTC that had multiple routes is assigned 87487ebcd42SMaxime Ripard * one that was the only option for a later CRTC. 87587ebcd42SMaxime Ripard * 87687ebcd42SMaxime Ripard * If the layout changes and doesn't give us that in 87787ebcd42SMaxime Ripard * the future, we will need to have something smarter, 87887ebcd42SMaxime Ripard * but it works so far. 87987ebcd42SMaxime Ripard */ 88003b03efeSMaxime Ripard matching_channels = unassigned_channels & vc4_crtc->data->hvs_available_channels; 881d62a8ed7SMaxime Ripard if (!matching_channels) 882d62a8ed7SMaxime Ripard return -EINVAL; 88387ebcd42SMaxime Ripard 884d62a8ed7SMaxime Ripard channel = ffs(matching_channels) - 1; 8853870b54eSMaxime Ripard 8863870b54eSMaxime Ripard drm_dbg(dev, "Assigned HVS channel %d to CRTC %s\n", channel, crtc->name); 8878ba0b6d1SMaxime Ripard new_vc4_crtc_state->assigned_channel = channel; 88803b03efeSMaxime Ripard unassigned_channels &= ~BIT(channel); 8899ec03d7fSMaxime Ripard hvs_new_state->fifo_state[channel].in_use = true; 89087ebcd42SMaxime Ripard } 891766cc6b1SStefan Schake 892a72b0458SMaxime Ripard return 0; 893a72b0458SMaxime Ripard } 894a72b0458SMaxime Ripard 895a72b0458SMaxime Ripard static int 89616e10105SMaxime Ripard vc4_core_clock_atomic_check(struct drm_atomic_state *state) 89716e10105SMaxime Ripard { 89816e10105SMaxime Ripard struct vc4_dev *vc4 = to_vc4_dev(state->dev); 89916e10105SMaxime Ripard struct drm_private_state *priv_state; 90016e10105SMaxime Ripard struct vc4_hvs_state *hvs_new_state; 90116e10105SMaxime Ripard struct vc4_load_tracker_state *load_state; 90216e10105SMaxime Ripard struct drm_crtc_state *old_crtc_state, *new_crtc_state; 90316e10105SMaxime Ripard struct drm_crtc *crtc; 90416e10105SMaxime Ripard unsigned int num_outputs; 90516e10105SMaxime Ripard unsigned long pixel_rate; 90616e10105SMaxime Ripard unsigned long cob_rate; 90716e10105SMaxime Ripard unsigned int i; 90816e10105SMaxime Ripard 90916e10105SMaxime Ripard priv_state = drm_atomic_get_private_obj_state(state, 91016e10105SMaxime Ripard &vc4->load_tracker); 91116e10105SMaxime Ripard if (IS_ERR(priv_state)) 91216e10105SMaxime Ripard return PTR_ERR(priv_state); 91316e10105SMaxime Ripard 91416e10105SMaxime Ripard load_state = to_vc4_load_tracker_state(priv_state); 91516e10105SMaxime Ripard 91616e10105SMaxime Ripard hvs_new_state = vc4_hvs_get_global_state(state); 91799b03ca6SDaniel Vetter if (IS_ERR(hvs_new_state)) 91899b03ca6SDaniel Vetter return PTR_ERR(hvs_new_state); 91916e10105SMaxime Ripard 92016e10105SMaxime Ripard for_each_oldnew_crtc_in_state(state, crtc, 92116e10105SMaxime Ripard old_crtc_state, 92216e10105SMaxime Ripard new_crtc_state, 92316e10105SMaxime Ripard i) { 92416e10105SMaxime Ripard if (old_crtc_state->active) { 92516e10105SMaxime Ripard struct vc4_crtc_state *old_vc4_state = 92616e10105SMaxime Ripard to_vc4_crtc_state(old_crtc_state); 92716e10105SMaxime Ripard unsigned int channel = old_vc4_state->assigned_channel; 92816e10105SMaxime Ripard 92916e10105SMaxime Ripard hvs_new_state->fifo_state[channel].fifo_load = 0; 93016e10105SMaxime Ripard } 93116e10105SMaxime Ripard 93216e10105SMaxime Ripard if (new_crtc_state->active) { 93316e10105SMaxime Ripard struct vc4_crtc_state *new_vc4_state = 93416e10105SMaxime Ripard to_vc4_crtc_state(new_crtc_state); 93516e10105SMaxime Ripard unsigned int channel = new_vc4_state->assigned_channel; 93616e10105SMaxime Ripard 93716e10105SMaxime Ripard hvs_new_state->fifo_state[channel].fifo_load = 93816e10105SMaxime Ripard new_vc4_state->hvs_load; 93916e10105SMaxime Ripard } 94016e10105SMaxime Ripard } 94116e10105SMaxime Ripard 94216e10105SMaxime Ripard cob_rate = 0; 94316e10105SMaxime Ripard num_outputs = 0; 94416e10105SMaxime Ripard for (i = 0; i < HVS_NUM_CHANNELS; i++) { 94516e10105SMaxime Ripard if (!hvs_new_state->fifo_state[i].in_use) 94616e10105SMaxime Ripard continue; 94716e10105SMaxime Ripard 94816e10105SMaxime Ripard num_outputs++; 94916e10105SMaxime Ripard cob_rate += hvs_new_state->fifo_state[i].fifo_load; 95016e10105SMaxime Ripard } 95116e10105SMaxime Ripard 95216e10105SMaxime Ripard pixel_rate = load_state->hvs_load; 95316e10105SMaxime Ripard if (num_outputs > 1) { 95416e10105SMaxime Ripard pixel_rate = (pixel_rate * 40) / 100; 95516e10105SMaxime Ripard } else { 95616e10105SMaxime Ripard pixel_rate = (pixel_rate * 60) / 100; 95716e10105SMaxime Ripard } 95816e10105SMaxime Ripard 95916e10105SMaxime Ripard hvs_new_state->core_clock_rate = max(cob_rate, pixel_rate); 96016e10105SMaxime Ripard 96116e10105SMaxime Ripard return 0; 96216e10105SMaxime Ripard } 96316e10105SMaxime Ripard 96416e10105SMaxime Ripard 96516e10105SMaxime Ripard static int 966a72b0458SMaxime Ripard vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) 967a72b0458SMaxime Ripard { 968a72b0458SMaxime Ripard int ret; 969a72b0458SMaxime Ripard 970a72b0458SMaxime Ripard ret = vc4_pv_muxing_atomic_check(dev, state); 971a72b0458SMaxime Ripard if (ret) 972a72b0458SMaxime Ripard return ret; 973a72b0458SMaxime Ripard 974766cc6b1SStefan Schake ret = vc4_ctm_atomic_check(dev, state); 975766cc6b1SStefan Schake if (ret < 0) 976766cc6b1SStefan Schake return ret; 977766cc6b1SStefan Schake 9784686da83SBoris Brezillon ret = drm_atomic_helper_check(dev, state); 9794686da83SBoris Brezillon if (ret) 9804686da83SBoris Brezillon return ret; 9814686da83SBoris Brezillon 98216e10105SMaxime Ripard ret = vc4_load_tracker_atomic_check(state); 98316e10105SMaxime Ripard if (ret) 98416e10105SMaxime Ripard return ret; 98516e10105SMaxime Ripard 98616e10105SMaxime Ripard return vc4_core_clock_atomic_check(state); 987766cc6b1SStefan Schake } 988766cc6b1SStefan Schake 9899ec03d7fSMaxime Ripard static struct drm_mode_config_helper_funcs vc4_mode_config_helpers = { 9909ec03d7fSMaxime Ripard .atomic_commit_setup = vc4_atomic_commit_setup, 991f3c420feSMaxime Ripard .atomic_commit_tail = vc4_atomic_commit_tail, 9929ec03d7fSMaxime Ripard }; 9939ec03d7fSMaxime Ripard 994c8b75bcaSEric Anholt static const struct drm_mode_config_funcs vc4_mode_funcs = { 995766cc6b1SStefan Schake .atomic_check = vc4_atomic_check, 996f3c420feSMaxime Ripard .atomic_commit = drm_atomic_helper_commit, 99783753117SEric Anholt .fb_create = vc4_fb_create, 998c8b75bcaSEric Anholt }; 999c8b75bcaSEric Anholt 1000c8b75bcaSEric Anholt int vc4_kms_load(struct drm_device *dev) 1001c8b75bcaSEric Anholt { 100248666d56SDerek Foreman struct vc4_dev *vc4 = to_vc4_dev(dev); 1003c8b75bcaSEric Anholt int ret; 1004c8b75bcaSEric Anholt 10057f817159SMaxime Ripard /* 10067f817159SMaxime Ripard * The limits enforced by the load tracker aren't relevant for 10077f817159SMaxime Ripard * the BCM2711, but the load tracker computations are used for 10087f817159SMaxime Ripard * the core clock rate calculation. 10097f817159SMaxime Ripard */ 1010*1cbc91ebSMaxime Ripard if (!vc4->is_vc5) { 1011f437bc1eSMaxime Ripard /* Start with the load tracker enabled. Can be 1012f437bc1eSMaxime Ripard * disabled through the debugfs load_tracker file. 10136b5c029dSPaul Kocialkowski */ 10146b5c029dSPaul Kocialkowski vc4->load_tracker_enabled = true; 1015f437bc1eSMaxime Ripard } 10166b5c029dSPaul Kocialkowski 10177d2818f5SMario Kleiner /* Set support for vblank irq fast disable, before drm_vblank_init() */ 10187d2818f5SMario Kleiner dev->vblank_disable_immediate = true; 10197d2818f5SMario Kleiner 1020c8b75bcaSEric Anholt ret = drm_vblank_init(dev, dev->mode_config.num_crtc); 1021c8b75bcaSEric Anholt if (ret < 0) { 1022c8b75bcaSEric Anholt dev_err(dev->dev, "failed to initialize vblank\n"); 1023c8b75bcaSEric Anholt return ret; 1024c8b75bcaSEric Anholt } 1025c8b75bcaSEric Anholt 1026*1cbc91ebSMaxime Ripard if (vc4->is_vc5) { 1027f437bc1eSMaxime Ripard dev->mode_config.max_width = 7680; 1028f437bc1eSMaxime Ripard dev->mode_config.max_height = 7680; 1029f437bc1eSMaxime Ripard } else { 1030c8b75bcaSEric Anholt dev->mode_config.max_width = 2048; 1031c8b75bcaSEric Anholt dev->mode_config.max_height = 2048; 1032f437bc1eSMaxime Ripard } 1033f437bc1eSMaxime Ripard 1034c8b75bcaSEric Anholt dev->mode_config.funcs = &vc4_mode_funcs; 10359ec03d7fSMaxime Ripard dev->mode_config.helper_private = &vc4_mode_config_helpers; 1036c8b75bcaSEric Anholt dev->mode_config.preferred_depth = 24; 1037b501baccSEric Anholt dev->mode_config.async_page_flip = true; 1038b501baccSEric Anholt 1039dcda7c28SMaxime Ripard ret = vc4_ctm_obj_init(vc4); 1040dcda7c28SMaxime Ripard if (ret) 1041dcda7c28SMaxime Ripard return ret; 1042766cc6b1SStefan Schake 1043dcda7c28SMaxime Ripard ret = vc4_load_tracker_obj_init(vc4); 1044dcda7c28SMaxime Ripard if (ret) 1045dcda7c28SMaxime Ripard return ret; 10464686da83SBoris Brezillon 1047f2df84e0SMaxime Ripard ret = vc4_hvs_channels_obj_init(vc4); 1048f2df84e0SMaxime Ripard if (ret) 1049f2df84e0SMaxime Ripard return ret; 1050f2df84e0SMaxime Ripard 1051c8b75bcaSEric Anholt drm_mode_config_reset(dev); 1052c8b75bcaSEric Anholt 1053c8b75bcaSEric Anholt drm_kms_helper_poll_init(dev); 1054c8b75bcaSEric Anholt 1055c8b75bcaSEric Anholt return 0; 1056c8b75bcaSEric Anholt } 1057