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 35766cc6b1SStefan Schake static struct vc4_ctm_state *to_vc4_ctm_state(struct drm_private_state *priv) 36766cc6b1SStefan Schake { 37766cc6b1SStefan Schake return container_of(priv, struct vc4_ctm_state, base); 38766cc6b1SStefan Schake } 39766cc6b1SStefan Schake 404686da83SBoris Brezillon struct vc4_load_tracker_state { 414686da83SBoris Brezillon struct drm_private_state base; 424686da83SBoris Brezillon u64 hvs_load; 434686da83SBoris Brezillon u64 membus_load; 444686da83SBoris Brezillon }; 454686da83SBoris Brezillon 464686da83SBoris Brezillon static struct vc4_load_tracker_state * 474686da83SBoris Brezillon to_vc4_load_tracker_state(struct drm_private_state *priv) 484686da83SBoris Brezillon { 494686da83SBoris Brezillon return container_of(priv, struct vc4_load_tracker_state, base); 504686da83SBoris Brezillon } 514686da83SBoris Brezillon 52766cc6b1SStefan Schake static struct vc4_ctm_state *vc4_get_ctm_state(struct drm_atomic_state *state, 53766cc6b1SStefan Schake struct drm_private_obj *manager) 54766cc6b1SStefan Schake { 55766cc6b1SStefan Schake struct drm_device *dev = state->dev; 5688e08589SMaxime Ripard struct vc4_dev *vc4 = to_vc4_dev(dev); 57766cc6b1SStefan Schake struct drm_private_state *priv_state; 58766cc6b1SStefan Schake int ret; 59766cc6b1SStefan Schake 60766cc6b1SStefan Schake ret = drm_modeset_lock(&vc4->ctm_state_lock, state->acquire_ctx); 61766cc6b1SStefan Schake if (ret) 62766cc6b1SStefan Schake return ERR_PTR(ret); 63766cc6b1SStefan Schake 64766cc6b1SStefan Schake priv_state = drm_atomic_get_private_obj_state(state, manager); 65766cc6b1SStefan Schake if (IS_ERR(priv_state)) 66766cc6b1SStefan Schake return ERR_CAST(priv_state); 67766cc6b1SStefan Schake 68766cc6b1SStefan Schake return to_vc4_ctm_state(priv_state); 69766cc6b1SStefan Schake } 70766cc6b1SStefan Schake 71766cc6b1SStefan Schake static struct drm_private_state * 72766cc6b1SStefan Schake vc4_ctm_duplicate_state(struct drm_private_obj *obj) 73766cc6b1SStefan Schake { 74766cc6b1SStefan Schake struct vc4_ctm_state *state; 75766cc6b1SStefan Schake 76766cc6b1SStefan Schake state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL); 77766cc6b1SStefan Schake if (!state) 78766cc6b1SStefan Schake return NULL; 79766cc6b1SStefan Schake 80766cc6b1SStefan Schake __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); 81766cc6b1SStefan Schake 82766cc6b1SStefan Schake return &state->base; 83766cc6b1SStefan Schake } 84766cc6b1SStefan Schake 85766cc6b1SStefan Schake static void vc4_ctm_destroy_state(struct drm_private_obj *obj, 86766cc6b1SStefan Schake struct drm_private_state *state) 87766cc6b1SStefan Schake { 88766cc6b1SStefan Schake struct vc4_ctm_state *ctm_state = to_vc4_ctm_state(state); 89766cc6b1SStefan Schake 90766cc6b1SStefan Schake kfree(ctm_state); 91766cc6b1SStefan Schake } 92766cc6b1SStefan Schake 93766cc6b1SStefan Schake static const struct drm_private_state_funcs vc4_ctm_state_funcs = { 94766cc6b1SStefan Schake .atomic_duplicate_state = vc4_ctm_duplicate_state, 95766cc6b1SStefan Schake .atomic_destroy_state = vc4_ctm_destroy_state, 96766cc6b1SStefan Schake }; 97766cc6b1SStefan Schake 98dcda7c28SMaxime Ripard static void vc4_ctm_obj_fini(struct drm_device *dev, void *unused) 99dcda7c28SMaxime Ripard { 100dcda7c28SMaxime Ripard struct vc4_dev *vc4 = to_vc4_dev(dev); 101dcda7c28SMaxime Ripard 102dcda7c28SMaxime Ripard drm_atomic_private_obj_fini(&vc4->ctm_manager); 103dcda7c28SMaxime Ripard } 104dcda7c28SMaxime Ripard 105dcda7c28SMaxime Ripard static int vc4_ctm_obj_init(struct vc4_dev *vc4) 106dcda7c28SMaxime Ripard { 107dcda7c28SMaxime Ripard struct vc4_ctm_state *ctm_state; 108dcda7c28SMaxime Ripard 109dcda7c28SMaxime Ripard drm_modeset_lock_init(&vc4->ctm_state_lock); 110dcda7c28SMaxime Ripard 111dcda7c28SMaxime Ripard ctm_state = kzalloc(sizeof(*ctm_state), GFP_KERNEL); 112dcda7c28SMaxime Ripard if (!ctm_state) 113dcda7c28SMaxime Ripard return -ENOMEM; 114dcda7c28SMaxime Ripard 115dcda7c28SMaxime Ripard drm_atomic_private_obj_init(&vc4->base, &vc4->ctm_manager, &ctm_state->base, 116dcda7c28SMaxime Ripard &vc4_ctm_state_funcs); 117dcda7c28SMaxime Ripard 1183c354ed1SMaxime Ripard return drmm_add_action_or_reset(&vc4->base, vc4_ctm_obj_fini, NULL); 119dcda7c28SMaxime Ripard } 120dcda7c28SMaxime Ripard 121766cc6b1SStefan Schake /* Converts a DRM S31.32 value to the HW S0.9 format. */ 122766cc6b1SStefan Schake static u16 vc4_ctm_s31_32_to_s0_9(u64 in) 123766cc6b1SStefan Schake { 124766cc6b1SStefan Schake u16 r; 125766cc6b1SStefan Schake 126766cc6b1SStefan Schake /* Sign bit. */ 127766cc6b1SStefan Schake r = in & BIT_ULL(63) ? BIT(9) : 0; 128766cc6b1SStefan Schake 129766cc6b1SStefan Schake if ((in & GENMASK_ULL(62, 32)) > 0) { 130766cc6b1SStefan Schake /* We have zero integer bits so we can only saturate here. */ 131766cc6b1SStefan Schake r |= GENMASK(8, 0); 132766cc6b1SStefan Schake } else { 133766cc6b1SStefan Schake /* Otherwise take the 9 most important fractional bits. */ 134766cc6b1SStefan Schake r |= (in >> 23) & GENMASK(8, 0); 135766cc6b1SStefan Schake } 136766cc6b1SStefan Schake 137766cc6b1SStefan Schake return r; 138766cc6b1SStefan Schake } 139766cc6b1SStefan Schake 140766cc6b1SStefan Schake static void 141766cc6b1SStefan Schake vc4_ctm_commit(struct vc4_dev *vc4, struct drm_atomic_state *state) 142766cc6b1SStefan Schake { 143766cc6b1SStefan Schake struct vc4_ctm_state *ctm_state = to_vc4_ctm_state(vc4->ctm_manager.state); 144766cc6b1SStefan Schake struct drm_color_ctm *ctm = ctm_state->ctm; 145766cc6b1SStefan Schake 146766cc6b1SStefan Schake if (ctm_state->fifo) { 147766cc6b1SStefan Schake HVS_WRITE(SCALER_OLEDCOEF2, 148766cc6b1SStefan Schake VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[0]), 149766cc6b1SStefan Schake SCALER_OLEDCOEF2_R_TO_R) | 150766cc6b1SStefan Schake VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[3]), 151766cc6b1SStefan Schake SCALER_OLEDCOEF2_R_TO_G) | 152766cc6b1SStefan Schake VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[6]), 153766cc6b1SStefan Schake SCALER_OLEDCOEF2_R_TO_B)); 154766cc6b1SStefan Schake HVS_WRITE(SCALER_OLEDCOEF1, 155766cc6b1SStefan Schake VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[1]), 156766cc6b1SStefan Schake SCALER_OLEDCOEF1_G_TO_R) | 157766cc6b1SStefan Schake VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[4]), 158766cc6b1SStefan Schake SCALER_OLEDCOEF1_G_TO_G) | 159766cc6b1SStefan Schake VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[7]), 160766cc6b1SStefan Schake SCALER_OLEDCOEF1_G_TO_B)); 161766cc6b1SStefan Schake HVS_WRITE(SCALER_OLEDCOEF0, 162766cc6b1SStefan Schake VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[2]), 163766cc6b1SStefan Schake SCALER_OLEDCOEF0_B_TO_R) | 164766cc6b1SStefan Schake VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[5]), 165766cc6b1SStefan Schake SCALER_OLEDCOEF0_B_TO_G) | 166766cc6b1SStefan Schake VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[8]), 167766cc6b1SStefan Schake SCALER_OLEDCOEF0_B_TO_B)); 168766cc6b1SStefan Schake } 169766cc6b1SStefan Schake 170766cc6b1SStefan Schake HVS_WRITE(SCALER_OLEDOFFS, 171766cc6b1SStefan Schake VC4_SET_FIELD(ctm_state->fifo, SCALER_OLEDOFFS_DISPFIFO)); 172766cc6b1SStefan Schake } 173c8b75bcaSEric Anholt 17487ebcd42SMaxime Ripard static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4, 17587ebcd42SMaxime Ripard struct drm_atomic_state *state) 17687ebcd42SMaxime Ripard { 17787ebcd42SMaxime Ripard struct drm_crtc_state *crtc_state; 17887ebcd42SMaxime Ripard struct drm_crtc *crtc; 17987ebcd42SMaxime Ripard unsigned int i; 18087ebcd42SMaxime Ripard 18187ebcd42SMaxime Ripard for_each_new_crtc_in_state(state, crtc, crtc_state, i) { 18287ebcd42SMaxime Ripard struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); 18387ebcd42SMaxime Ripard u32 dispctrl; 18487ebcd42SMaxime Ripard u32 dsp3_mux; 18587ebcd42SMaxime Ripard 18687ebcd42SMaxime Ripard if (!crtc_state->active) 18787ebcd42SMaxime Ripard continue; 18887ebcd42SMaxime Ripard 18987ebcd42SMaxime Ripard if (vc4_state->assigned_channel != 2) 19087ebcd42SMaxime Ripard continue; 19187ebcd42SMaxime Ripard 19287ebcd42SMaxime Ripard /* 19387ebcd42SMaxime Ripard * SCALER_DISPCTRL_DSP3 = X, where X < 2 means 'connect DSP3 to 19487ebcd42SMaxime Ripard * FIFO X'. 19587ebcd42SMaxime Ripard * SCALER_DISPCTRL_DSP3 = 3 means 'disable DSP 3'. 19687ebcd42SMaxime Ripard * 19787ebcd42SMaxime Ripard * DSP3 is connected to FIFO2 unless the transposer is 19887ebcd42SMaxime Ripard * enabled. In this case, FIFO 2 is directly accessed by the 19987ebcd42SMaxime Ripard * TXP IP, and we need to disable the FIFO2 -> pixelvalve1 20087ebcd42SMaxime Ripard * route. 20187ebcd42SMaxime Ripard */ 20287ebcd42SMaxime Ripard if (vc4_state->feed_txp) 20387ebcd42SMaxime Ripard dsp3_mux = VC4_SET_FIELD(3, SCALER_DISPCTRL_DSP3_MUX); 20487ebcd42SMaxime Ripard else 20587ebcd42SMaxime Ripard dsp3_mux = VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX); 20687ebcd42SMaxime Ripard 20787ebcd42SMaxime Ripard dispctrl = HVS_READ(SCALER_DISPCTRL) & 20887ebcd42SMaxime Ripard ~SCALER_DISPCTRL_DSP3_MUX_MASK; 20987ebcd42SMaxime Ripard HVS_WRITE(SCALER_DISPCTRL, dispctrl | dsp3_mux); 21087ebcd42SMaxime Ripard } 21187ebcd42SMaxime Ripard } 21287ebcd42SMaxime Ripard 21387ebcd42SMaxime Ripard static void vc5_hvs_pv_muxing_commit(struct vc4_dev *vc4, 21487ebcd42SMaxime Ripard struct drm_atomic_state *state) 21587ebcd42SMaxime Ripard { 21687ebcd42SMaxime Ripard struct drm_crtc_state *crtc_state; 21787ebcd42SMaxime Ripard struct drm_crtc *crtc; 21887ebcd42SMaxime Ripard unsigned char dsp2_mux = 0; 21987ebcd42SMaxime Ripard unsigned char dsp3_mux = 3; 22087ebcd42SMaxime Ripard unsigned char dsp4_mux = 3; 22187ebcd42SMaxime Ripard unsigned char dsp5_mux = 3; 22287ebcd42SMaxime Ripard unsigned int i; 22387ebcd42SMaxime Ripard u32 reg; 22487ebcd42SMaxime Ripard 22587ebcd42SMaxime Ripard for_each_new_crtc_in_state(state, crtc, crtc_state, i) { 22687ebcd42SMaxime Ripard struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); 22787ebcd42SMaxime Ripard struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); 22887ebcd42SMaxime Ripard 22987ebcd42SMaxime Ripard if (!crtc_state->active) 23087ebcd42SMaxime Ripard continue; 23187ebcd42SMaxime Ripard 23287ebcd42SMaxime Ripard switch (vc4_crtc->data->hvs_output) { 23387ebcd42SMaxime Ripard case 2: 23487ebcd42SMaxime Ripard dsp2_mux = (vc4_state->assigned_channel == 2) ? 0 : 1; 23587ebcd42SMaxime Ripard break; 23687ebcd42SMaxime Ripard 23787ebcd42SMaxime Ripard case 3: 23887ebcd42SMaxime Ripard dsp3_mux = vc4_state->assigned_channel; 23987ebcd42SMaxime Ripard break; 24087ebcd42SMaxime Ripard 24187ebcd42SMaxime Ripard case 4: 24287ebcd42SMaxime Ripard dsp4_mux = vc4_state->assigned_channel; 24387ebcd42SMaxime Ripard break; 24487ebcd42SMaxime Ripard 24587ebcd42SMaxime Ripard case 5: 24687ebcd42SMaxime Ripard dsp5_mux = vc4_state->assigned_channel; 24787ebcd42SMaxime Ripard break; 24887ebcd42SMaxime Ripard 24987ebcd42SMaxime Ripard default: 25087ebcd42SMaxime Ripard break; 25187ebcd42SMaxime Ripard } 25287ebcd42SMaxime Ripard } 25387ebcd42SMaxime Ripard 25487ebcd42SMaxime Ripard reg = HVS_READ(SCALER_DISPECTRL); 25587ebcd42SMaxime Ripard HVS_WRITE(SCALER_DISPECTRL, 25687ebcd42SMaxime Ripard (reg & ~SCALER_DISPECTRL_DSP2_MUX_MASK) | 25787ebcd42SMaxime Ripard VC4_SET_FIELD(dsp2_mux, SCALER_DISPECTRL_DSP2_MUX)); 25887ebcd42SMaxime Ripard 25987ebcd42SMaxime Ripard reg = HVS_READ(SCALER_DISPCTRL); 26087ebcd42SMaxime Ripard HVS_WRITE(SCALER_DISPCTRL, 26187ebcd42SMaxime Ripard (reg & ~SCALER_DISPCTRL_DSP3_MUX_MASK) | 26287ebcd42SMaxime Ripard VC4_SET_FIELD(dsp3_mux, SCALER_DISPCTRL_DSP3_MUX)); 26387ebcd42SMaxime Ripard 26487ebcd42SMaxime Ripard reg = HVS_READ(SCALER_DISPEOLN); 26587ebcd42SMaxime Ripard HVS_WRITE(SCALER_DISPEOLN, 26687ebcd42SMaxime Ripard (reg & ~SCALER_DISPEOLN_DSP4_MUX_MASK) | 26787ebcd42SMaxime Ripard VC4_SET_FIELD(dsp4_mux, SCALER_DISPEOLN_DSP4_MUX)); 26887ebcd42SMaxime Ripard 26987ebcd42SMaxime Ripard reg = HVS_READ(SCALER_DISPDITHER); 27087ebcd42SMaxime Ripard HVS_WRITE(SCALER_DISPDITHER, 27187ebcd42SMaxime Ripard (reg & ~SCALER_DISPDITHER_DSP5_MUX_MASK) | 27287ebcd42SMaxime Ripard VC4_SET_FIELD(dsp5_mux, SCALER_DISPDITHER_DSP5_MUX)); 27387ebcd42SMaxime Ripard } 27487ebcd42SMaxime Ripard 275b501baccSEric Anholt static void 276cf1b372eSEric Anholt vc4_atomic_complete_commit(struct drm_atomic_state *state) 277b501baccSEric Anholt { 278b501baccSEric Anholt struct drm_device *dev = state->dev; 279b501baccSEric Anholt struct vc4_dev *vc4 = to_vc4_dev(dev); 280d7d96c00SMaxime Ripard struct vc4_hvs *hvs = vc4->hvs; 28159635667SMaxime Ripard struct drm_crtc_state *new_crtc_state; 28259635667SMaxime Ripard struct drm_crtc *crtc; 283531a1b62SBoris Brezillon int i; 284531a1b62SBoris Brezillon 28559635667SMaxime Ripard for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { 28687ebcd42SMaxime Ripard struct vc4_crtc_state *vc4_crtc_state; 28759635667SMaxime Ripard 28859635667SMaxime Ripard if (!new_crtc_state->commit) 289531a1b62SBoris Brezillon continue; 290531a1b62SBoris Brezillon 29187ebcd42SMaxime Ripard vc4_crtc_state = to_vc4_crtc_state(new_crtc_state); 29287ebcd42SMaxime Ripard vc4_hvs_mask_underrun(dev, vc4_crtc_state->assigned_channel); 293531a1b62SBoris Brezillon } 294b501baccSEric Anholt 295d7d96c00SMaxime Ripard if (vc4->hvs->hvs5) 296d7d96c00SMaxime Ripard clk_set_min_rate(hvs->core_clk, 500000000); 297d7d96c00SMaxime Ripard 29834c8ea40SBoris Brezillon drm_atomic_helper_wait_for_fences(dev, state, false); 29934c8ea40SBoris Brezillon 30034c8ea40SBoris Brezillon drm_atomic_helper_wait_for_dependencies(state); 30134c8ea40SBoris Brezillon 302b501baccSEric Anholt drm_atomic_helper_commit_modeset_disables(dev, state); 303b501baccSEric Anholt 304766cc6b1SStefan Schake vc4_ctm_commit(vc4, state); 305766cc6b1SStefan Schake 30687ebcd42SMaxime Ripard if (vc4->hvs->hvs5) 30787ebcd42SMaxime Ripard vc5_hvs_pv_muxing_commit(vc4, state); 30887ebcd42SMaxime Ripard else 30987ebcd42SMaxime Ripard vc4_hvs_pv_muxing_commit(vc4, state); 31087ebcd42SMaxime Ripard 3112b58e98dSLiu Ying drm_atomic_helper_commit_planes(dev, state, 0); 312b501baccSEric Anholt 313b501baccSEric Anholt drm_atomic_helper_commit_modeset_enables(dev, state); 314b501baccSEric Anholt 3151ebe99a7SBoris Brezillon drm_atomic_helper_fake_vblank(state); 3161ebe99a7SBoris Brezillon 31734c8ea40SBoris Brezillon drm_atomic_helper_commit_hw_done(state); 31834c8ea40SBoris Brezillon 319184d3cf4SBoris Brezillon drm_atomic_helper_wait_for_flip_done(dev, state); 320b501baccSEric Anholt 321b501baccSEric Anholt drm_atomic_helper_cleanup_planes(dev, state); 322b501baccSEric Anholt 32334c8ea40SBoris Brezillon drm_atomic_helper_commit_cleanup_done(state); 32434c8ea40SBoris Brezillon 325d7d96c00SMaxime Ripard if (vc4->hvs->hvs5) 326d7d96c00SMaxime Ripard clk_set_min_rate(hvs->core_clk, 0); 327d7d96c00SMaxime Ripard 3280853695cSChris Wilson drm_atomic_state_put(state); 329b501baccSEric Anholt 330b501baccSEric Anholt up(&vc4->async_modeset); 331b501baccSEric Anholt } 332b501baccSEric Anholt 333cf1b372eSEric Anholt static void commit_work(struct work_struct *work) 334b501baccSEric Anholt { 335cf1b372eSEric Anholt struct drm_atomic_state *state = container_of(work, 336cf1b372eSEric Anholt struct drm_atomic_state, 337cf1b372eSEric Anholt commit_work); 338cf1b372eSEric Anholt vc4_atomic_complete_commit(state); 339b501baccSEric Anholt } 340b501baccSEric Anholt 341b501baccSEric Anholt /** 342b501baccSEric Anholt * vc4_atomic_commit - commit validated state object 343b501baccSEric Anholt * @dev: DRM device 344b501baccSEric Anholt * @state: the driver state object 345eb63961bSMaarten Lankhorst * @nonblock: nonblocking commit 346b501baccSEric Anholt * 347b501baccSEric Anholt * This function commits a with drm_atomic_helper_check() pre-validated state 348b501baccSEric Anholt * object. This can still fail when e.g. the framebuffer reservation fails. For 349b501baccSEric Anholt * now this doesn't implement asynchronous commits. 350b501baccSEric Anholt * 351b501baccSEric Anholt * RETURNS 352b501baccSEric Anholt * Zero for success or -errno. 353b501baccSEric Anholt */ 354b501baccSEric Anholt static int vc4_atomic_commit(struct drm_device *dev, 355b501baccSEric Anholt struct drm_atomic_state *state, 356eb63961bSMaarten Lankhorst bool nonblock) 357b501baccSEric Anholt { 358b501baccSEric Anholt struct vc4_dev *vc4 = to_vc4_dev(dev); 359b501baccSEric Anholt int ret; 360b501baccSEric Anholt 361539c320bSGustavo Padovan if (state->async_update) { 362539c320bSGustavo Padovan ret = down_interruptible(&vc4->async_modeset); 363539c320bSGustavo Padovan if (ret) 364539c320bSGustavo Padovan return ret; 365539c320bSGustavo Padovan 366539c320bSGustavo Padovan ret = drm_atomic_helper_prepare_planes(dev, state); 367539c320bSGustavo Padovan if (ret) { 368539c320bSGustavo Padovan up(&vc4->async_modeset); 369539c320bSGustavo Padovan return ret; 370539c320bSGustavo Padovan } 371539c320bSGustavo Padovan 372539c320bSGustavo Padovan drm_atomic_helper_async_commit(dev, state); 373539c320bSGustavo Padovan 374539c320bSGustavo Padovan drm_atomic_helper_cleanup_planes(dev, state); 375539c320bSGustavo Padovan 376539c320bSGustavo Padovan up(&vc4->async_modeset); 377539c320bSGustavo Padovan 378539c320bSGustavo Padovan return 0; 379539c320bSGustavo Padovan } 380539c320bSGustavo Padovan 381fcc86cb4SBoris Brezillon /* We know for sure we don't want an async update here. Set 382fcc86cb4SBoris Brezillon * state->legacy_cursor_update to false to prevent 383fcc86cb4SBoris Brezillon * drm_atomic_helper_setup_commit() from auto-completing 384fcc86cb4SBoris Brezillon * commit->flip_done. 385fcc86cb4SBoris Brezillon */ 386fcc86cb4SBoris Brezillon state->legacy_cursor_update = false; 38734c8ea40SBoris Brezillon ret = drm_atomic_helper_setup_commit(state, nonblock); 38834c8ea40SBoris Brezillon if (ret) 38934c8ea40SBoris Brezillon return ret; 39026fc78f6SDerek Foreman 391cf1b372eSEric Anholt INIT_WORK(&state->commit_work, commit_work); 392cf1b372eSEric Anholt 393b501baccSEric Anholt ret = down_interruptible(&vc4->async_modeset); 394cf1b372eSEric Anholt if (ret) 395b501baccSEric Anholt return ret; 396b501baccSEric Anholt 397b501baccSEric Anholt ret = drm_atomic_helper_prepare_planes(dev, state); 398b501baccSEric Anholt if (ret) { 399b501baccSEric Anholt up(&vc4->async_modeset); 400b501baccSEric Anholt return ret; 401b501baccSEric Anholt } 402b501baccSEric Anholt 40353ad0694SEric Anholt if (!nonblock) { 40453ad0694SEric Anholt ret = drm_atomic_helper_wait_for_fences(dev, state, true); 40553ad0694SEric Anholt if (ret) { 40653ad0694SEric Anholt drm_atomic_helper_cleanup_planes(dev, state); 40753ad0694SEric Anholt up(&vc4->async_modeset); 40853ad0694SEric Anholt return ret; 40953ad0694SEric Anholt } 41053ad0694SEric Anholt } 41153ad0694SEric Anholt 412b501baccSEric Anholt /* 413b501baccSEric Anholt * This is the point of no return - everything below never fails except 414b501baccSEric Anholt * when the hw goes bonghits. Which means we can commit the new state on 415b501baccSEric Anholt * the software side now. 416b501baccSEric Anholt */ 417b501baccSEric Anholt 418d68bc0e7SMaarten Lankhorst BUG_ON(drm_atomic_helper_swap_state(state, false) < 0); 419b501baccSEric Anholt 420b501baccSEric Anholt /* 421b501baccSEric Anholt * Everything below can be run asynchronously without the need to grab 422b501baccSEric Anholt * any modeset locks at all under one condition: It must be guaranteed 423b501baccSEric Anholt * that the asynchronous work has either been cancelled (if the driver 424b501baccSEric Anholt * supports it, which at least requires that the framebuffers get 425b501baccSEric Anholt * cleaned up with drm_atomic_helper_cleanup_planes()) or completed 426b501baccSEric Anholt * before the new state gets committed on the software side with 427b501baccSEric Anholt * drm_atomic_helper_swap_state(). 428b501baccSEric Anholt * 429b501baccSEric Anholt * This scheme allows new atomic state updates to be prepared and 430b501baccSEric Anholt * checked in parallel to the asynchronous completion of the previous 431b501baccSEric Anholt * update. Which is important since compositors need to figure out the 432b501baccSEric Anholt * composition of the next frame right after having submitted the 433b501baccSEric Anholt * current layout. 434b501baccSEric Anholt */ 435b501baccSEric Anholt 4360853695cSChris Wilson drm_atomic_state_get(state); 437cf1b372eSEric Anholt if (nonblock) 438cf1b372eSEric Anholt queue_work(system_unbound_wq, &state->commit_work); 439cf1b372eSEric Anholt else 440cf1b372eSEric Anholt vc4_atomic_complete_commit(state); 441b501baccSEric Anholt 442b501baccSEric Anholt return 0; 443b501baccSEric Anholt } 444b501baccSEric Anholt 44583753117SEric Anholt static struct drm_framebuffer *vc4_fb_create(struct drm_device *dev, 44683753117SEric Anholt struct drm_file *file_priv, 44783753117SEric Anholt const struct drm_mode_fb_cmd2 *mode_cmd) 44883753117SEric Anholt { 44983753117SEric Anholt struct drm_mode_fb_cmd2 mode_cmd_local; 45083753117SEric Anholt 45183753117SEric Anholt /* If the user didn't specify a modifier, use the 45283753117SEric Anholt * vc4_set_tiling_ioctl() state for the BO. 45383753117SEric Anholt */ 45483753117SEric Anholt if (!(mode_cmd->flags & DRM_MODE_FB_MODIFIERS)) { 45583753117SEric Anholt struct drm_gem_object *gem_obj; 45683753117SEric Anholt struct vc4_bo *bo; 45783753117SEric Anholt 45883753117SEric Anholt gem_obj = drm_gem_object_lookup(file_priv, 45983753117SEric Anholt mode_cmd->handles[0]); 46083753117SEric Anholt if (!gem_obj) { 461fb95992aSEric Anholt DRM_DEBUG("Failed to look up GEM BO %d\n", 46283753117SEric Anholt mode_cmd->handles[0]); 46383753117SEric Anholt return ERR_PTR(-ENOENT); 46483753117SEric Anholt } 46583753117SEric Anholt bo = to_vc4_bo(gem_obj); 46683753117SEric Anholt 46783753117SEric Anholt mode_cmd_local = *mode_cmd; 46883753117SEric Anholt 46983753117SEric Anholt if (bo->t_format) { 47083753117SEric Anholt mode_cmd_local.modifier[0] = 47183753117SEric Anholt DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED; 47283753117SEric Anholt } else { 47383753117SEric Anholt mode_cmd_local.modifier[0] = DRM_FORMAT_MOD_NONE; 47483753117SEric Anholt } 47583753117SEric Anholt 476f7a8cd30SEmil Velikov drm_gem_object_put(gem_obj); 47783753117SEric Anholt 47883753117SEric Anholt mode_cmd = &mode_cmd_local; 47983753117SEric Anholt } 48083753117SEric Anholt 4819762477cSNoralf Trønnes return drm_gem_fb_create(dev, file_priv, mode_cmd); 48283753117SEric Anholt } 48383753117SEric Anholt 484766cc6b1SStefan Schake /* Our CTM has some peculiar limitations: we can only enable it for one CRTC 485766cc6b1SStefan Schake * at a time and the HW only supports S0.9 scalars. To account for the latter, 486766cc6b1SStefan Schake * we don't allow userland to set a CTM that we have no hope of approximating. 487766cc6b1SStefan Schake */ 488766cc6b1SStefan Schake static int 489766cc6b1SStefan Schake vc4_ctm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) 490766cc6b1SStefan Schake { 491766cc6b1SStefan Schake struct vc4_dev *vc4 = to_vc4_dev(dev); 492766cc6b1SStefan Schake struct vc4_ctm_state *ctm_state = NULL; 493766cc6b1SStefan Schake struct drm_crtc *crtc; 494766cc6b1SStefan Schake struct drm_crtc_state *old_crtc_state, *new_crtc_state; 495766cc6b1SStefan Schake struct drm_color_ctm *ctm; 496766cc6b1SStefan Schake int i; 497766cc6b1SStefan Schake 498766cc6b1SStefan Schake for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { 499766cc6b1SStefan Schake /* CTM is being disabled. */ 500766cc6b1SStefan Schake if (!new_crtc_state->ctm && old_crtc_state->ctm) { 501766cc6b1SStefan Schake ctm_state = vc4_get_ctm_state(state, &vc4->ctm_manager); 502766cc6b1SStefan Schake if (IS_ERR(ctm_state)) 503766cc6b1SStefan Schake return PTR_ERR(ctm_state); 504766cc6b1SStefan Schake ctm_state->fifo = 0; 505766cc6b1SStefan Schake } 506766cc6b1SStefan Schake } 507766cc6b1SStefan Schake 508766cc6b1SStefan Schake for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { 509766cc6b1SStefan Schake if (new_crtc_state->ctm == old_crtc_state->ctm) 510766cc6b1SStefan Schake continue; 511766cc6b1SStefan Schake 512766cc6b1SStefan Schake if (!ctm_state) { 513766cc6b1SStefan Schake ctm_state = vc4_get_ctm_state(state, &vc4->ctm_manager); 514766cc6b1SStefan Schake if (IS_ERR(ctm_state)) 515766cc6b1SStefan Schake return PTR_ERR(ctm_state); 516766cc6b1SStefan Schake } 517766cc6b1SStefan Schake 518766cc6b1SStefan Schake /* CTM is being enabled or the matrix changed. */ 519766cc6b1SStefan Schake if (new_crtc_state->ctm) { 52087ebcd42SMaxime Ripard struct vc4_crtc_state *vc4_crtc_state = 52187ebcd42SMaxime Ripard to_vc4_crtc_state(new_crtc_state); 52287ebcd42SMaxime Ripard 523766cc6b1SStefan Schake /* fifo is 1-based since 0 disables CTM. */ 52487ebcd42SMaxime Ripard int fifo = vc4_crtc_state->assigned_channel + 1; 525766cc6b1SStefan Schake 526766cc6b1SStefan Schake /* Check userland isn't trying to turn on CTM for more 527766cc6b1SStefan Schake * than one CRTC at a time. 528766cc6b1SStefan Schake */ 529766cc6b1SStefan Schake if (ctm_state->fifo && ctm_state->fifo != fifo) { 530766cc6b1SStefan Schake DRM_DEBUG_DRIVER("Too many CTM configured\n"); 531766cc6b1SStefan Schake return -EINVAL; 532766cc6b1SStefan Schake } 533766cc6b1SStefan Schake 534766cc6b1SStefan Schake /* Check we can approximate the specified CTM. 535766cc6b1SStefan Schake * We disallow scalars |c| > 1.0 since the HW has 536766cc6b1SStefan Schake * no integer bits. 537766cc6b1SStefan Schake */ 538766cc6b1SStefan Schake ctm = new_crtc_state->ctm->data; 539766cc6b1SStefan Schake for (i = 0; i < ARRAY_SIZE(ctm->matrix); i++) { 540766cc6b1SStefan Schake u64 val = ctm->matrix[i]; 541766cc6b1SStefan Schake 542766cc6b1SStefan Schake val &= ~BIT_ULL(63); 543766cc6b1SStefan Schake if (val > BIT_ULL(32)) 544766cc6b1SStefan Schake return -EINVAL; 545766cc6b1SStefan Schake } 546766cc6b1SStefan Schake 547766cc6b1SStefan Schake ctm_state->fifo = fifo; 548766cc6b1SStefan Schake ctm_state->ctm = ctm; 549766cc6b1SStefan Schake } 550766cc6b1SStefan Schake } 551766cc6b1SStefan Schake 552766cc6b1SStefan Schake return 0; 553766cc6b1SStefan Schake } 554766cc6b1SStefan Schake 5554686da83SBoris Brezillon static int vc4_load_tracker_atomic_check(struct drm_atomic_state *state) 5564686da83SBoris Brezillon { 5574686da83SBoris Brezillon struct drm_plane_state *old_plane_state, *new_plane_state; 5584686da83SBoris Brezillon struct vc4_dev *vc4 = to_vc4_dev(state->dev); 5594686da83SBoris Brezillon struct vc4_load_tracker_state *load_state; 5604686da83SBoris Brezillon struct drm_private_state *priv_state; 5614686da83SBoris Brezillon struct drm_plane *plane; 5624686da83SBoris Brezillon int i; 5634686da83SBoris Brezillon 564f437bc1eSMaxime Ripard if (!vc4->load_tracker_available) 565f437bc1eSMaxime Ripard return 0; 566f437bc1eSMaxime Ripard 5674686da83SBoris Brezillon priv_state = drm_atomic_get_private_obj_state(state, 5684686da83SBoris Brezillon &vc4->load_tracker); 5694686da83SBoris Brezillon if (IS_ERR(priv_state)) 5704686da83SBoris Brezillon return PTR_ERR(priv_state); 5714686da83SBoris Brezillon 5724686da83SBoris Brezillon load_state = to_vc4_load_tracker_state(priv_state); 5734686da83SBoris Brezillon for_each_oldnew_plane_in_state(state, plane, old_plane_state, 5744686da83SBoris Brezillon new_plane_state, i) { 5754686da83SBoris Brezillon struct vc4_plane_state *vc4_plane_state; 5764686da83SBoris Brezillon 5774686da83SBoris Brezillon if (old_plane_state->fb && old_plane_state->crtc) { 5784686da83SBoris Brezillon vc4_plane_state = to_vc4_plane_state(old_plane_state); 5794686da83SBoris Brezillon load_state->membus_load -= vc4_plane_state->membus_load; 5804686da83SBoris Brezillon load_state->hvs_load -= vc4_plane_state->hvs_load; 5814686da83SBoris Brezillon } 5824686da83SBoris Brezillon 5834686da83SBoris Brezillon if (new_plane_state->fb && new_plane_state->crtc) { 5844686da83SBoris Brezillon vc4_plane_state = to_vc4_plane_state(new_plane_state); 5854686da83SBoris Brezillon load_state->membus_load += vc4_plane_state->membus_load; 5864686da83SBoris Brezillon load_state->hvs_load += vc4_plane_state->hvs_load; 5874686da83SBoris Brezillon } 5884686da83SBoris Brezillon } 5894686da83SBoris Brezillon 5906b5c029dSPaul Kocialkowski /* Don't check the load when the tracker is disabled. */ 5916b5c029dSPaul Kocialkowski if (!vc4->load_tracker_enabled) 5926b5c029dSPaul Kocialkowski return 0; 5936b5c029dSPaul Kocialkowski 5944686da83SBoris Brezillon /* The absolute limit is 2Gbyte/sec, but let's take a margin to let 5954686da83SBoris Brezillon * the system work when other blocks are accessing the memory. 5964686da83SBoris Brezillon */ 5974686da83SBoris Brezillon if (load_state->membus_load > SZ_1G + SZ_512M) 5984686da83SBoris Brezillon return -ENOSPC; 5994686da83SBoris Brezillon 6004686da83SBoris Brezillon /* HVS clock is supposed to run @ 250Mhz, let's take a margin and 6014686da83SBoris Brezillon * consider the maximum number of cycles is 240M. 6024686da83SBoris Brezillon */ 6034686da83SBoris Brezillon if (load_state->hvs_load > 240000000ULL) 6044686da83SBoris Brezillon return -ENOSPC; 6054686da83SBoris Brezillon 6064686da83SBoris Brezillon return 0; 6074686da83SBoris Brezillon } 6084686da83SBoris Brezillon 6094686da83SBoris Brezillon static struct drm_private_state * 6104686da83SBoris Brezillon vc4_load_tracker_duplicate_state(struct drm_private_obj *obj) 6114686da83SBoris Brezillon { 6124686da83SBoris Brezillon struct vc4_load_tracker_state *state; 6134686da83SBoris Brezillon 6144686da83SBoris Brezillon state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL); 6154686da83SBoris Brezillon if (!state) 6164686da83SBoris Brezillon return NULL; 6174686da83SBoris Brezillon 6184686da83SBoris Brezillon __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); 6194686da83SBoris Brezillon 6204686da83SBoris Brezillon return &state->base; 6214686da83SBoris Brezillon } 6224686da83SBoris Brezillon 6234686da83SBoris Brezillon static void vc4_load_tracker_destroy_state(struct drm_private_obj *obj, 6244686da83SBoris Brezillon struct drm_private_state *state) 6254686da83SBoris Brezillon { 6264686da83SBoris Brezillon struct vc4_load_tracker_state *load_state; 6274686da83SBoris Brezillon 6284686da83SBoris Brezillon load_state = to_vc4_load_tracker_state(state); 6294686da83SBoris Brezillon kfree(load_state); 6304686da83SBoris Brezillon } 6314686da83SBoris Brezillon 6324686da83SBoris Brezillon static const struct drm_private_state_funcs vc4_load_tracker_state_funcs = { 6334686da83SBoris Brezillon .atomic_duplicate_state = vc4_load_tracker_duplicate_state, 6344686da83SBoris Brezillon .atomic_destroy_state = vc4_load_tracker_destroy_state, 6354686da83SBoris Brezillon }; 6364686da83SBoris Brezillon 637dcda7c28SMaxime Ripard static void vc4_load_tracker_obj_fini(struct drm_device *dev, void *unused) 638dcda7c28SMaxime Ripard { 639dcda7c28SMaxime Ripard struct vc4_dev *vc4 = to_vc4_dev(dev); 640dcda7c28SMaxime Ripard 641dcda7c28SMaxime Ripard if (!vc4->load_tracker_available) 642dcda7c28SMaxime Ripard return; 643dcda7c28SMaxime Ripard 644dcda7c28SMaxime Ripard drm_atomic_private_obj_fini(&vc4->load_tracker); 645dcda7c28SMaxime Ripard } 646dcda7c28SMaxime Ripard 647dcda7c28SMaxime Ripard static int vc4_load_tracker_obj_init(struct vc4_dev *vc4) 648dcda7c28SMaxime Ripard { 649dcda7c28SMaxime Ripard struct vc4_load_tracker_state *load_state; 650dcda7c28SMaxime Ripard 651dcda7c28SMaxime Ripard if (!vc4->load_tracker_available) 652dcda7c28SMaxime Ripard return 0; 653dcda7c28SMaxime Ripard 654dcda7c28SMaxime Ripard load_state = kzalloc(sizeof(*load_state), GFP_KERNEL); 655dcda7c28SMaxime Ripard if (!load_state) 656dcda7c28SMaxime Ripard return -ENOMEM; 657dcda7c28SMaxime Ripard 658dcda7c28SMaxime Ripard drm_atomic_private_obj_init(&vc4->base, &vc4->load_tracker, 659dcda7c28SMaxime Ripard &load_state->base, 660dcda7c28SMaxime Ripard &vc4_load_tracker_state_funcs); 661dcda7c28SMaxime Ripard 6623c354ed1SMaxime Ripard return drmm_add_action_or_reset(&vc4->base, vc4_load_tracker_obj_fini, NULL); 663dcda7c28SMaxime Ripard } 664dcda7c28SMaxime Ripard 665a72b0458SMaxime Ripard static int vc4_pv_muxing_atomic_check(struct drm_device *dev, 666a72b0458SMaxime Ripard struct drm_atomic_state *state) 667766cc6b1SStefan Schake { 668a9661f27SMaxime Ripard unsigned long unassigned_channels = GENMASK(HVS_NUM_CHANNELS - 1, 0); 6698ba0b6d1SMaxime Ripard struct drm_crtc_state *old_crtc_state, *new_crtc_state; 67087ebcd42SMaxime Ripard struct drm_crtc *crtc; 671a72b0458SMaxime Ripard unsigned int i; 67287ebcd42SMaxime Ripard 673089d8341SMaxime Ripard /* 674089d8341SMaxime Ripard * Since the HVS FIFOs are shared across all the pixelvalves and 675089d8341SMaxime Ripard * the TXP (and thus all the CRTCs), we need to pull the current 676089d8341SMaxime Ripard * state of all the enabled CRTCs so that an update to a single 677089d8341SMaxime Ripard * CRTC still keeps the previous FIFOs enabled and assigned to 678089d8341SMaxime Ripard * the same CRTCs, instead of evaluating only the CRTC being 679089d8341SMaxime Ripard * modified. 680089d8341SMaxime Ripard */ 681089d8341SMaxime Ripard list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 6828ba0b6d1SMaxime Ripard struct drm_crtc_state *crtc_state; 6838ba0b6d1SMaxime Ripard 684089d8341SMaxime Ripard if (!crtc->state->enable) 685089d8341SMaxime Ripard continue; 686089d8341SMaxime Ripard 687089d8341SMaxime Ripard crtc_state = drm_atomic_get_crtc_state(state, crtc); 688089d8341SMaxime Ripard if (IS_ERR(crtc_state)) 689089d8341SMaxime Ripard return PTR_ERR(crtc_state); 690089d8341SMaxime Ripard } 691089d8341SMaxime Ripard 6928ba0b6d1SMaxime Ripard for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { 6938ba0b6d1SMaxime Ripard struct vc4_crtc_state *new_vc4_crtc_state = 6948ba0b6d1SMaxime Ripard to_vc4_crtc_state(new_crtc_state); 69587ebcd42SMaxime Ripard struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); 69687ebcd42SMaxime Ripard unsigned int matching_channels; 69787ebcd42SMaxime Ripard 6988ba0b6d1SMaxime Ripard if (old_crtc_state->enable && !new_crtc_state->enable) 6998ba0b6d1SMaxime Ripard new_vc4_crtc_state->assigned_channel = VC4_HVS_CHANNEL_DISABLED; 7008ba0b6d1SMaxime Ripard 7018ba0b6d1SMaxime Ripard if (!new_crtc_state->enable) 70287ebcd42SMaxime Ripard continue; 70387ebcd42SMaxime Ripard 7048ba0b6d1SMaxime Ripard if (new_vc4_crtc_state->assigned_channel != VC4_HVS_CHANNEL_DISABLED) { 7058ba0b6d1SMaxime Ripard unassigned_channels &= ~BIT(new_vc4_crtc_state->assigned_channel); 7068ba0b6d1SMaxime Ripard continue; 7078ba0b6d1SMaxime Ripard } 7088ba0b6d1SMaxime Ripard 70987ebcd42SMaxime Ripard /* 71087ebcd42SMaxime Ripard * The problem we have to solve here is that we have 71187ebcd42SMaxime Ripard * up to 7 encoders, connected to up to 6 CRTCs. 71287ebcd42SMaxime Ripard * 71387ebcd42SMaxime Ripard * Those CRTCs, depending on the instance, can be 71487ebcd42SMaxime Ripard * routed to 1, 2 or 3 HVS FIFOs, and we need to set 71587ebcd42SMaxime Ripard * the change the muxing between FIFOs and outputs in 71687ebcd42SMaxime Ripard * the HVS accordingly. 71787ebcd42SMaxime Ripard * 71887ebcd42SMaxime Ripard * It would be pretty hard to come up with an 71987ebcd42SMaxime Ripard * algorithm that would generically solve 72087ebcd42SMaxime Ripard * this. However, the current routing trees we support 72187ebcd42SMaxime Ripard * allow us to simplify a bit the problem. 72287ebcd42SMaxime Ripard * 72387ebcd42SMaxime Ripard * Indeed, with the current supported layouts, if we 72487ebcd42SMaxime Ripard * try to assign in the ascending crtc index order the 72587ebcd42SMaxime Ripard * FIFOs, we can't fall into the situation where an 72687ebcd42SMaxime Ripard * earlier CRTC that had multiple routes is assigned 72787ebcd42SMaxime Ripard * one that was the only option for a later CRTC. 72887ebcd42SMaxime Ripard * 72987ebcd42SMaxime Ripard * If the layout changes and doesn't give us that in 73087ebcd42SMaxime Ripard * the future, we will need to have something smarter, 73187ebcd42SMaxime Ripard * but it works so far. 73287ebcd42SMaxime Ripard */ 73387ebcd42SMaxime Ripard matching_channels = unassigned_channels & vc4_crtc->data->hvs_available_channels; 73487ebcd42SMaxime Ripard if (matching_channels) { 73587ebcd42SMaxime Ripard unsigned int channel = ffs(matching_channels) - 1; 73687ebcd42SMaxime Ripard 7378ba0b6d1SMaxime Ripard new_vc4_crtc_state->assigned_channel = channel; 73887ebcd42SMaxime Ripard unassigned_channels &= ~BIT(channel); 73987ebcd42SMaxime Ripard } else { 74087ebcd42SMaxime Ripard return -EINVAL; 74187ebcd42SMaxime Ripard } 74287ebcd42SMaxime Ripard } 743766cc6b1SStefan Schake 744a72b0458SMaxime Ripard return 0; 745a72b0458SMaxime Ripard } 746a72b0458SMaxime Ripard 747a72b0458SMaxime Ripard static int 748a72b0458SMaxime Ripard vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) 749a72b0458SMaxime Ripard { 750a72b0458SMaxime Ripard int ret; 751a72b0458SMaxime Ripard 752a72b0458SMaxime Ripard ret = vc4_pv_muxing_atomic_check(dev, state); 753a72b0458SMaxime Ripard if (ret) 754a72b0458SMaxime Ripard return ret; 755a72b0458SMaxime Ripard 756766cc6b1SStefan Schake ret = vc4_ctm_atomic_check(dev, state); 757766cc6b1SStefan Schake if (ret < 0) 758766cc6b1SStefan Schake return ret; 759766cc6b1SStefan Schake 7604686da83SBoris Brezillon ret = drm_atomic_helper_check(dev, state); 7614686da83SBoris Brezillon if (ret) 7624686da83SBoris Brezillon return ret; 7634686da83SBoris Brezillon 7644686da83SBoris Brezillon return vc4_load_tracker_atomic_check(state); 765766cc6b1SStefan Schake } 766766cc6b1SStefan Schake 767c8b75bcaSEric Anholt static const struct drm_mode_config_funcs vc4_mode_funcs = { 768766cc6b1SStefan Schake .atomic_check = vc4_atomic_check, 769b501baccSEric Anholt .atomic_commit = vc4_atomic_commit, 77083753117SEric Anholt .fb_create = vc4_fb_create, 771c8b75bcaSEric Anholt }; 772c8b75bcaSEric Anholt 773c8b75bcaSEric Anholt int vc4_kms_load(struct drm_device *dev) 774c8b75bcaSEric Anholt { 77548666d56SDerek Foreman struct vc4_dev *vc4 = to_vc4_dev(dev); 776f437bc1eSMaxime Ripard bool is_vc5 = of_device_is_compatible(dev->dev->of_node, 777f437bc1eSMaxime Ripard "brcm,bcm2711-vc5"); 778c8b75bcaSEric Anholt int ret; 779c8b75bcaSEric Anholt 780f437bc1eSMaxime Ripard if (!is_vc5) { 781f437bc1eSMaxime Ripard vc4->load_tracker_available = true; 782f437bc1eSMaxime Ripard 783f437bc1eSMaxime Ripard /* Start with the load tracker enabled. Can be 784f437bc1eSMaxime Ripard * disabled through the debugfs load_tracker file. 7856b5c029dSPaul Kocialkowski */ 7866b5c029dSPaul Kocialkowski vc4->load_tracker_enabled = true; 787f437bc1eSMaxime Ripard } 7886b5c029dSPaul Kocialkowski 789b501baccSEric Anholt sema_init(&vc4->async_modeset, 1); 790b501baccSEric Anholt 7917d2818f5SMario Kleiner /* Set support for vblank irq fast disable, before drm_vblank_init() */ 7927d2818f5SMario Kleiner dev->vblank_disable_immediate = true; 7937d2818f5SMario Kleiner 794ffc26740SEric Anholt dev->irq_enabled = true; 795c8b75bcaSEric Anholt ret = drm_vblank_init(dev, dev->mode_config.num_crtc); 796c8b75bcaSEric Anholt if (ret < 0) { 797c8b75bcaSEric Anholt dev_err(dev->dev, "failed to initialize vblank\n"); 798c8b75bcaSEric Anholt return ret; 799c8b75bcaSEric Anholt } 800c8b75bcaSEric Anholt 801f437bc1eSMaxime Ripard if (is_vc5) { 802f437bc1eSMaxime Ripard dev->mode_config.max_width = 7680; 803f437bc1eSMaxime Ripard dev->mode_config.max_height = 7680; 804f437bc1eSMaxime Ripard } else { 805c8b75bcaSEric Anholt dev->mode_config.max_width = 2048; 806c8b75bcaSEric Anholt dev->mode_config.max_height = 2048; 807f437bc1eSMaxime Ripard } 808f437bc1eSMaxime Ripard 809c8b75bcaSEric Anholt dev->mode_config.funcs = &vc4_mode_funcs; 810c8b75bcaSEric Anholt dev->mode_config.preferred_depth = 24; 811b501baccSEric Anholt dev->mode_config.async_page_flip = true; 812423ad7b3SDaniel Stone dev->mode_config.allow_fb_modifiers = true; 813b501baccSEric Anholt 814dcda7c28SMaxime Ripard ret = vc4_ctm_obj_init(vc4); 815dcda7c28SMaxime Ripard if (ret) 816dcda7c28SMaxime Ripard return ret; 817766cc6b1SStefan Schake 818dcda7c28SMaxime Ripard ret = vc4_load_tracker_obj_init(vc4); 819dcda7c28SMaxime Ripard if (ret) 820dcda7c28SMaxime Ripard return ret; 8214686da83SBoris Brezillon 822c8b75bcaSEric Anholt drm_mode_config_reset(dev); 823c8b75bcaSEric Anholt 824c8b75bcaSEric Anholt drm_kms_helper_poll_init(dev); 825c8b75bcaSEric Anholt 826c8b75bcaSEric Anholt return 0; 827c8b75bcaSEric Anholt } 828