1379bc100SJani Nikula /*
2379bc100SJani Nikula * Copyright © 2018 Intel Corporation
3379bc100SJani Nikula *
4379bc100SJani Nikula * Permission is hereby granted, free of charge, to any person obtaining a
5379bc100SJani Nikula * copy of this software and associated documentation files (the "Software"),
6379bc100SJani Nikula * to deal in the Software without restriction, including without limitation
7379bc100SJani Nikula * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8379bc100SJani Nikula * and/or sell copies of the Software, and to permit persons to whom the
9379bc100SJani Nikula * Software is furnished to do so, subject to the following conditions:
10379bc100SJani Nikula *
11379bc100SJani Nikula * The above copyright notice and this permission notice (including the next
12379bc100SJani Nikula * paragraph) shall be included in all copies or substantial portions of the
13379bc100SJani Nikula * Software.
14379bc100SJani Nikula *
15379bc100SJani Nikula * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16379bc100SJani Nikula * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17379bc100SJani Nikula * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18379bc100SJani Nikula * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19379bc100SJani Nikula * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20379bc100SJani Nikula * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21379bc100SJani Nikula * DEALINGS IN THE SOFTWARE.
22379bc100SJani Nikula *
23379bc100SJani Nikula * Authors:
24379bc100SJani Nikula * Madhav Chauhan <madhav.chauhan@intel.com>
25379bc100SJani Nikula * Jani Nikula <jani.nikula@intel.com>
26379bc100SJani Nikula */
27379bc100SJani Nikula
282a64b147SThomas Zimmermann #include <drm/display/drm_dsc_helper.h>
29379bc100SJani Nikula #include <drm/drm_atomic_helper.h>
308466a141SImre Deak #include <drm/drm_fixed.h>
31379bc100SJani Nikula #include <drm/drm_mipi_dsi.h>
32379bc100SJani Nikula
33801543b2SJani Nikula #include "i915_reg.h"
34617ed6c2SJani Nikula #include "icl_dsi.h"
353c0deb14SJani Nikula #include "icl_dsi_regs.h"
36379bc100SJani Nikula #include "intel_atomic.h"
376cc42fbeSJani Nikula #include "intel_backlight.h"
38a9b4c16dSJani Nikula #include "intel_backlight_regs.h"
39379bc100SJani Nikula #include "intel_combo_phy.h"
40d0864ee4SMatt Roper #include "intel_combo_phy_regs.h"
41379bc100SJani Nikula #include "intel_connector.h"
427c53e628SJani Nikula #include "intel_crtc.h"
43379bc100SJani Nikula #include "intel_ddi.h"
447785ae0bSVille Syrjälä #include "intel_de.h"
45379bc100SJani Nikula #include "intel_dsi.h"
46aebdd742SJani Nikula #include "intel_dsi_vbt.h"
47379bc100SJani Nikula #include "intel_panel.h"
482b68392eSJani Nikula #include "intel_vdsc.h"
49c3f05948SJani Nikula #include "intel_vdsc_regs.h"
50714b1cdbSDave Airlie #include "skl_scaler.h"
5146d12f91SDave Airlie #include "skl_universal_plane.h"
52379bc100SJani Nikula
header_credits_available(struct drm_i915_private * dev_priv,enum transcoder dsi_trans)5381b55ef1SJani Nikula static int header_credits_available(struct drm_i915_private *dev_priv,
54379bc100SJani Nikula enum transcoder dsi_trans)
55379bc100SJani Nikula {
561c63f6dfSJani Nikula return (intel_de_read(dev_priv, DSI_CMD_TXCTL(dsi_trans)) & FREE_HEADER_CREDIT_MASK)
57379bc100SJani Nikula >> FREE_HEADER_CREDIT_SHIFT;
58379bc100SJani Nikula }
59379bc100SJani Nikula
payload_credits_available(struct drm_i915_private * dev_priv,enum transcoder dsi_trans)6081b55ef1SJani Nikula static int payload_credits_available(struct drm_i915_private *dev_priv,
61379bc100SJani Nikula enum transcoder dsi_trans)
62379bc100SJani Nikula {
631c63f6dfSJani Nikula return (intel_de_read(dev_priv, DSI_CMD_TXCTL(dsi_trans)) & FREE_PLOAD_CREDIT_MASK)
64379bc100SJani Nikula >> FREE_PLOAD_CREDIT_SHIFT;
65379bc100SJani Nikula }
66379bc100SJani Nikula
wait_for_header_credits(struct drm_i915_private * dev_priv,enum transcoder dsi_trans,int hdr_credit)6743315f86SLee Shawn C static bool wait_for_header_credits(struct drm_i915_private *dev_priv,
6843315f86SLee Shawn C enum transcoder dsi_trans, int hdr_credit)
69379bc100SJani Nikula {
70379bc100SJani Nikula if (wait_for_us(header_credits_available(dev_priv, dsi_trans) >=
7143315f86SLee Shawn C hdr_credit, 100)) {
72b5280cd0SWambui Karuga drm_err(&dev_priv->drm, "DSI header credits not released\n");
7343315f86SLee Shawn C return false;
74379bc100SJani Nikula }
75379bc100SJani Nikula
7643315f86SLee Shawn C return true;
7743315f86SLee Shawn C }
7843315f86SLee Shawn C
wait_for_payload_credits(struct drm_i915_private * dev_priv,enum transcoder dsi_trans,int payld_credit)7943315f86SLee Shawn C static bool wait_for_payload_credits(struct drm_i915_private *dev_priv,
8043315f86SLee Shawn C enum transcoder dsi_trans, int payld_credit)
81379bc100SJani Nikula {
82379bc100SJani Nikula if (wait_for_us(payload_credits_available(dev_priv, dsi_trans) >=
8343315f86SLee Shawn C payld_credit, 100)) {
84b5280cd0SWambui Karuga drm_err(&dev_priv->drm, "DSI payload credits not released\n");
8543315f86SLee Shawn C return false;
8643315f86SLee Shawn C }
8743315f86SLee Shawn C
8843315f86SLee Shawn C return true;
89379bc100SJani Nikula }
90379bc100SJani Nikula
dsi_port_to_transcoder(enum port port)91379bc100SJani Nikula static enum transcoder dsi_port_to_transcoder(enum port port)
92379bc100SJani Nikula {
93379bc100SJani Nikula if (port == PORT_A)
94379bc100SJani Nikula return TRANSCODER_DSI_0;
95379bc100SJani Nikula else
96379bc100SJani Nikula return TRANSCODER_DSI_1;
97379bc100SJani Nikula }
98379bc100SJani Nikula
wait_for_cmds_dispatched_to_panel(struct intel_encoder * encoder)99379bc100SJani Nikula static void wait_for_cmds_dispatched_to_panel(struct intel_encoder *encoder)
100379bc100SJani Nikula {
101379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
102b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
103379bc100SJani Nikula struct mipi_dsi_device *dsi;
104379bc100SJani Nikula enum port port;
105379bc100SJani Nikula enum transcoder dsi_trans;
106379bc100SJani Nikula int ret;
107379bc100SJani Nikula
108379bc100SJani Nikula /* wait for header/payload credits to be released */
109379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
110379bc100SJani Nikula dsi_trans = dsi_port_to_transcoder(port);
11143315f86SLee Shawn C wait_for_header_credits(dev_priv, dsi_trans, MAX_HEADER_CREDIT);
11243315f86SLee Shawn C wait_for_payload_credits(dev_priv, dsi_trans, MAX_PLOAD_CREDIT);
113379bc100SJani Nikula }
114379bc100SJani Nikula
115379bc100SJani Nikula /* send nop DCS command */
116379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
117379bc100SJani Nikula dsi = intel_dsi->dsi_hosts[port]->device;
118379bc100SJani Nikula dsi->mode_flags |= MIPI_DSI_MODE_LPM;
119379bc100SJani Nikula dsi->channel = 0;
120379bc100SJani Nikula ret = mipi_dsi_dcs_nop(dsi);
121379bc100SJani Nikula if (ret < 0)
122b5280cd0SWambui Karuga drm_err(&dev_priv->drm,
123b5280cd0SWambui Karuga "error sending DCS NOP command\n");
124379bc100SJani Nikula }
125379bc100SJani Nikula
126379bc100SJani Nikula /* wait for header credits to be released */
127379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
128379bc100SJani Nikula dsi_trans = dsi_port_to_transcoder(port);
12943315f86SLee Shawn C wait_for_header_credits(dev_priv, dsi_trans, MAX_HEADER_CREDIT);
130379bc100SJani Nikula }
131379bc100SJani Nikula
132379bc100SJani Nikula /* wait for LP TX in progress bit to be cleared */
133379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
134379bc100SJani Nikula dsi_trans = dsi_port_to_transcoder(port);
1351c63f6dfSJani Nikula if (wait_for_us(!(intel_de_read(dev_priv, DSI_LP_MSG(dsi_trans)) &
136379bc100SJani Nikula LPTX_IN_PROGRESS), 20))
137b5280cd0SWambui Karuga drm_err(&dev_priv->drm, "LPTX bit not cleared\n");
138379bc100SJani Nikula }
139379bc100SJani Nikula }
140379bc100SJani Nikula
dsi_send_pkt_payld(struct intel_dsi_host * host,const struct mipi_dsi_packet * packet)141207ea507SJani Nikula static int dsi_send_pkt_payld(struct intel_dsi_host *host,
142207ea507SJani Nikula const struct mipi_dsi_packet *packet)
143379bc100SJani Nikula {
144379bc100SJani Nikula struct intel_dsi *intel_dsi = host->intel_dsi;
145207ea507SJani Nikula struct drm_i915_private *i915 = to_i915(intel_dsi->base.base.dev);
146379bc100SJani Nikula enum transcoder dsi_trans = dsi_port_to_transcoder(host->port);
147207ea507SJani Nikula const u8 *data = packet->payload;
148207ea507SJani Nikula u32 len = packet->payload_length;
149379bc100SJani Nikula int i, j;
150379bc100SJani Nikula
151207ea507SJani Nikula /* payload queue can accept *256 bytes*, check limit */
152207ea507SJani Nikula if (len > MAX_PLOAD_CREDIT * 4) {
153207ea507SJani Nikula drm_err(&i915->drm, "payload size exceeds max queue limit\n");
154207ea507SJani Nikula return -EINVAL;
155207ea507SJani Nikula }
156207ea507SJani Nikula
157379bc100SJani Nikula for (i = 0; i < len; i += 4) {
158379bc100SJani Nikula u32 tmp = 0;
159379bc100SJani Nikula
160207ea507SJani Nikula if (!wait_for_payload_credits(i915, dsi_trans, 1))
161207ea507SJani Nikula return -EBUSY;
162379bc100SJani Nikula
163379bc100SJani Nikula for (j = 0; j < min_t(u32, len - i, 4); j++)
164379bc100SJani Nikula tmp |= *data++ << 8 * j;
165379bc100SJani Nikula
166207ea507SJani Nikula intel_de_write(i915, DSI_CMD_TXPYLD(dsi_trans), tmp);
167379bc100SJani Nikula }
168379bc100SJani Nikula
169207ea507SJani Nikula return 0;
170379bc100SJani Nikula }
171379bc100SJani Nikula
dsi_send_pkt_hdr(struct intel_dsi_host * host,const struct mipi_dsi_packet * packet,bool enable_lpdt)172379bc100SJani Nikula static int dsi_send_pkt_hdr(struct intel_dsi_host *host,
1733e2947cdSJani Nikula const struct mipi_dsi_packet *packet,
1743e2947cdSJani Nikula bool enable_lpdt)
175379bc100SJani Nikula {
176379bc100SJani Nikula struct intel_dsi *intel_dsi = host->intel_dsi;
177379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
178379bc100SJani Nikula enum transcoder dsi_trans = dsi_port_to_transcoder(host->port);
179379bc100SJani Nikula u32 tmp;
180379bc100SJani Nikula
18143315f86SLee Shawn C if (!wait_for_header_credits(dev_priv, dsi_trans, 1))
182b90acd09SJani Nikula return -EBUSY;
183379bc100SJani Nikula
1841c63f6dfSJani Nikula tmp = intel_de_read(dev_priv, DSI_CMD_TXHDR(dsi_trans));
185379bc100SJani Nikula
1863e2947cdSJani Nikula if (packet->payload)
187379bc100SJani Nikula tmp |= PAYLOAD_PRESENT;
188379bc100SJani Nikula else
189379bc100SJani Nikula tmp &= ~PAYLOAD_PRESENT;
190379bc100SJani Nikula
191379bc100SJani Nikula tmp &= ~VBLANK_FENCE;
192379bc100SJani Nikula
193379bc100SJani Nikula if (enable_lpdt)
194379bc100SJani Nikula tmp |= LP_DATA_TRANSFER;
19538a1b50cSWilliam Tseng else
19638a1b50cSWilliam Tseng tmp &= ~LP_DATA_TRANSFER;
197379bc100SJani Nikula
198379bc100SJani Nikula tmp &= ~(PARAM_WC_MASK | VC_MASK | DT_MASK);
1993e2947cdSJani Nikula tmp |= ((packet->header[0] & VC_MASK) << VC_SHIFT);
2003e2947cdSJani Nikula tmp |= ((packet->header[0] & DT_MASK) << DT_SHIFT);
2013e2947cdSJani Nikula tmp |= (packet->header[1] << PARAM_WC_LOWER_SHIFT);
2023e2947cdSJani Nikula tmp |= (packet->header[2] << PARAM_WC_UPPER_SHIFT);
2031c63f6dfSJani Nikula intel_de_write(dev_priv, DSI_CMD_TXHDR(dsi_trans), tmp);
204379bc100SJani Nikula
205379bc100SJani Nikula return 0;
206379bc100SJani Nikula }
207379bc100SJani Nikula
icl_dsi_frame_update(struct intel_crtc_state * crtc_state)20826fb0d55SVandita Kulkarni void icl_dsi_frame_update(struct intel_crtc_state *crtc_state)
20926fb0d55SVandita Kulkarni {
21026fb0d55SVandita Kulkarni struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
21126fb0d55SVandita Kulkarni struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
2121a45d681SAndrzej Hajda u32 mode_flags;
21326fb0d55SVandita Kulkarni enum port port;
21426fb0d55SVandita Kulkarni
21526fb0d55SVandita Kulkarni mode_flags = crtc_state->mode_flags;
21626fb0d55SVandita Kulkarni
21726fb0d55SVandita Kulkarni /*
21826fb0d55SVandita Kulkarni * case 1 also covers dual link
21926fb0d55SVandita Kulkarni * In case of dual link, frame update should be set on
22026fb0d55SVandita Kulkarni * DSI_0
22126fb0d55SVandita Kulkarni */
22226fb0d55SVandita Kulkarni if (mode_flags & I915_MODE_FLAG_DSI_USE_TE0)
22326fb0d55SVandita Kulkarni port = PORT_A;
22426fb0d55SVandita Kulkarni else if (mode_flags & I915_MODE_FLAG_DSI_USE_TE1)
22526fb0d55SVandita Kulkarni port = PORT_B;
22626fb0d55SVandita Kulkarni else
22726fb0d55SVandita Kulkarni return;
22826fb0d55SVandita Kulkarni
2291a45d681SAndrzej Hajda intel_de_rmw(dev_priv, DSI_CMD_FRMCTL(port), 0, DSI_FRAME_UPDATE_REQUEST);
23026fb0d55SVandita Kulkarni }
23126fb0d55SVandita Kulkarni
dsi_program_swing_and_deemphasis(struct intel_encoder * encoder)232379bc100SJani Nikula static void dsi_program_swing_and_deemphasis(struct intel_encoder *encoder)
233379bc100SJani Nikula {
234379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
235b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
236dc867bc7SMatt Roper enum phy phy;
2371a45d681SAndrzej Hajda u32 tmp, mask, val;
238379bc100SJani Nikula int lane;
239379bc100SJani Nikula
240dc867bc7SMatt Roper for_each_dsi_phy(phy, intel_dsi->phys) {
241379bc100SJani Nikula /*
242379bc100SJani Nikula * Program voltage swing and pre-emphasis level values as per
243379bc100SJani Nikula * table in BSPEC under DDI buffer programing
244379bc100SJani Nikula */
2451a45d681SAndrzej Hajda mask = SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK;
2461a45d681SAndrzej Hajda val = SCALING_MODE_SEL(0x2) | TAP2_DISABLE | TAP3_DISABLE |
2471a45d681SAndrzej Hajda RTERM_SELECT(0x6);
248e6908588SVille Syrjälä tmp = intel_de_read(dev_priv, ICL_PORT_TX_DW5_LN(0, phy));
2491a45d681SAndrzej Hajda tmp &= ~mask;
2501a45d681SAndrzej Hajda tmp |= val;
2511c63f6dfSJani Nikula intel_de_write(dev_priv, ICL_PORT_TX_DW5_GRP(phy), tmp);
2521a45d681SAndrzej Hajda intel_de_rmw(dev_priv, ICL_PORT_TX_DW5_AUX(phy), mask, val);
253379bc100SJani Nikula
2541a45d681SAndrzej Hajda mask = SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK |
2551a45d681SAndrzej Hajda RCOMP_SCALAR_MASK;
2561a45d681SAndrzej Hajda val = SWING_SEL_UPPER(0x2) | SWING_SEL_LOWER(0x2) |
2571a45d681SAndrzej Hajda RCOMP_SCALAR(0x98);
258e6908588SVille Syrjälä tmp = intel_de_read(dev_priv, ICL_PORT_TX_DW2_LN(0, phy));
2591a45d681SAndrzej Hajda tmp &= ~mask;
2601a45d681SAndrzej Hajda tmp |= val;
2611c63f6dfSJani Nikula intel_de_write(dev_priv, ICL_PORT_TX_DW2_GRP(phy), tmp);
2621a45d681SAndrzej Hajda intel_de_rmw(dev_priv, ICL_PORT_TX_DW2_AUX(phy), mask, val);
263379bc100SJani Nikula
2641a45d681SAndrzej Hajda mask = POST_CURSOR_1_MASK | POST_CURSOR_2_MASK |
2651a45d681SAndrzej Hajda CURSOR_COEFF_MASK;
2661a45d681SAndrzej Hajda val = POST_CURSOR_1(0x0) | POST_CURSOR_2(0x0) |
2671a45d681SAndrzej Hajda CURSOR_COEFF(0x3f);
2681a45d681SAndrzej Hajda intel_de_rmw(dev_priv, ICL_PORT_TX_DW4_AUX(phy), mask, val);
269379bc100SJani Nikula
270379bc100SJani Nikula /* Bspec: must not use GRP register for write */
2711a45d681SAndrzej Hajda for (lane = 0; lane <= 3; lane++)
2721a45d681SAndrzej Hajda intel_de_rmw(dev_priv, ICL_PORT_TX_DW4_LN(lane, phy),
2731a45d681SAndrzej Hajda mask, val);
274379bc100SJani Nikula }
275379bc100SJani Nikula }
276379bc100SJani Nikula
configure_dual_link_mode(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config)277379bc100SJani Nikula static void configure_dual_link_mode(struct intel_encoder *encoder,
278379bc100SJani Nikula const struct intel_crtc_state *pipe_config)
279379bc100SJani Nikula {
280379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
281b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
2821a62dd98SJani Nikula i915_reg_t dss_ctl1_reg, dss_ctl2_reg;
283379bc100SJani Nikula u32 dss_ctl1;
284379bc100SJani Nikula
2851a62dd98SJani Nikula /* FIXME: Move all DSS handling to intel_vdsc.c */
2861a62dd98SJani Nikula if (DISPLAY_VER(dev_priv) >= 12) {
2871a62dd98SJani Nikula struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
2881a62dd98SJani Nikula
2891a62dd98SJani Nikula dss_ctl1_reg = ICL_PIPE_DSS_CTL1(crtc->pipe);
2901a62dd98SJani Nikula dss_ctl2_reg = ICL_PIPE_DSS_CTL2(crtc->pipe);
2911a62dd98SJani Nikula } else {
2921a62dd98SJani Nikula dss_ctl1_reg = DSS_CTL1;
2931a62dd98SJani Nikula dss_ctl2_reg = DSS_CTL2;
2941a62dd98SJani Nikula }
2951a62dd98SJani Nikula
2961a62dd98SJani Nikula dss_ctl1 = intel_de_read(dev_priv, dss_ctl1_reg);
297379bc100SJani Nikula dss_ctl1 |= SPLITTER_ENABLE;
298379bc100SJani Nikula dss_ctl1 &= ~OVERLAP_PIXELS_MASK;
299379bc100SJani Nikula dss_ctl1 |= OVERLAP_PIXELS(intel_dsi->pixel_overlap);
300379bc100SJani Nikula
301379bc100SJani Nikula if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
302379bc100SJani Nikula const struct drm_display_mode *adjusted_mode =
3031326a92cSMaarten Lankhorst &pipe_config->hw.adjusted_mode;
304379bc100SJani Nikula u16 hactive = adjusted_mode->crtc_hdisplay;
305379bc100SJani Nikula u16 dl_buffer_depth;
306379bc100SJani Nikula
307379bc100SJani Nikula dss_ctl1 &= ~DUAL_LINK_MODE_INTERLEAVE;
308379bc100SJani Nikula dl_buffer_depth = hactive / 2 + intel_dsi->pixel_overlap;
309379bc100SJani Nikula
310379bc100SJani Nikula if (dl_buffer_depth > MAX_DL_BUFFER_TARGET_DEPTH)
311b5280cd0SWambui Karuga drm_err(&dev_priv->drm,
312b5280cd0SWambui Karuga "DL buffer depth exceed max value\n");
313379bc100SJani Nikula
314379bc100SJani Nikula dss_ctl1 &= ~LEFT_DL_BUF_TARGET_DEPTH_MASK;
315379bc100SJani Nikula dss_ctl1 |= LEFT_DL_BUF_TARGET_DEPTH(dl_buffer_depth);
3161a62dd98SJani Nikula intel_de_rmw(dev_priv, dss_ctl2_reg, RIGHT_DL_BUF_TARGET_DEPTH_MASK,
3171a45d681SAndrzej Hajda RIGHT_DL_BUF_TARGET_DEPTH(dl_buffer_depth));
318379bc100SJani Nikula } else {
319379bc100SJani Nikula /* Interleave */
320379bc100SJani Nikula dss_ctl1 |= DUAL_LINK_MODE_INTERLEAVE;
321379bc100SJani Nikula }
322379bc100SJani Nikula
3231a62dd98SJani Nikula intel_de_write(dev_priv, dss_ctl1_reg, dss_ctl1);
324379bc100SJani Nikula }
325379bc100SJani Nikula
32654ed6902SJani Nikula /* aka DSI 8X clock */
afe_clk(struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state)32704865139SJani Nikula static int afe_clk(struct intel_encoder *encoder,
32804865139SJani Nikula const struct intel_crtc_state *crtc_state)
32954ed6902SJani Nikula {
330b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
33154ed6902SJani Nikula int bpp;
33254ed6902SJani Nikula
33304865139SJani Nikula if (crtc_state->dsc.compression_enable)
3348466a141SImre Deak bpp = fxp_q4_to_int(crtc_state->dsc.compressed_bpp_x16);
33504865139SJani Nikula else
33654ed6902SJani Nikula bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
33754ed6902SJani Nikula
33854ed6902SJani Nikula return DIV_ROUND_CLOSEST(intel_dsi->pclk * bpp, intel_dsi->lane_count);
33954ed6902SJani Nikula }
34054ed6902SJani Nikula
gen11_dsi_program_esc_clk_div(struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state)34104865139SJani Nikula static void gen11_dsi_program_esc_clk_div(struct intel_encoder *encoder,
34204865139SJani Nikula const struct intel_crtc_state *crtc_state)
343379bc100SJani Nikula {
344379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
345b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
346379bc100SJani Nikula enum port port;
34754ed6902SJani Nikula int afe_clk_khz;
348510b2814SMika Kahola int theo_word_clk, act_word_clk;
349510b2814SMika Kahola u32 esc_clk_div_m, esc_clk_div_m_phy;
350379bc100SJani Nikula
35104865139SJani Nikula afe_clk_khz = afe_clk(encoder, crtc_state);
352510b2814SMika Kahola
353510b2814SMika Kahola if (IS_ALDERLAKE_S(dev_priv) || IS_ALDERLAKE_P(dev_priv)) {
354510b2814SMika Kahola theo_word_clk = DIV_ROUND_UP(afe_clk_khz, 8 * DSI_MAX_ESC_CLK);
355510b2814SMika Kahola act_word_clk = max(3, theo_word_clk + (theo_word_clk + 1) % 2);
356510b2814SMika Kahola esc_clk_div_m = act_word_clk * 8;
357510b2814SMika Kahola esc_clk_div_m_phy = (act_word_clk - 1) / 2;
358510b2814SMika Kahola } else {
359379bc100SJani Nikula esc_clk_div_m = DIV_ROUND_UP(afe_clk_khz, DSI_MAX_ESC_CLK);
360510b2814SMika Kahola }
361379bc100SJani Nikula
362379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
3631c63f6dfSJani Nikula intel_de_write(dev_priv, ICL_DSI_ESC_CLK_DIV(port),
364379bc100SJani Nikula esc_clk_div_m & ICL_ESC_CLK_DIV_MASK);
3651c63f6dfSJani Nikula intel_de_posting_read(dev_priv, ICL_DSI_ESC_CLK_DIV(port));
366379bc100SJani Nikula }
367379bc100SJani Nikula
368379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
3691c63f6dfSJani Nikula intel_de_write(dev_priv, ICL_DPHY_ESC_CLK_DIV(port),
370379bc100SJani Nikula esc_clk_div_m & ICL_ESC_CLK_DIV_MASK);
3711c63f6dfSJani Nikula intel_de_posting_read(dev_priv, ICL_DPHY_ESC_CLK_DIV(port));
372379bc100SJani Nikula }
373510b2814SMika Kahola
374510b2814SMika Kahola if (IS_ALDERLAKE_S(dev_priv) || IS_ALDERLAKE_P(dev_priv)) {
375510b2814SMika Kahola for_each_dsi_port(port, intel_dsi->ports) {
376510b2814SMika Kahola intel_de_write(dev_priv, ADL_MIPIO_DW(port, 8),
377510b2814SMika Kahola esc_clk_div_m_phy & TX_ESC_CLK_DIV_PHY);
378510b2814SMika Kahola intel_de_posting_read(dev_priv, ADL_MIPIO_DW(port, 8));
379510b2814SMika Kahola }
380510b2814SMika Kahola }
381379bc100SJani Nikula }
382379bc100SJani Nikula
get_dsi_io_power_domains(struct drm_i915_private * dev_priv,struct intel_dsi * intel_dsi)383379bc100SJani Nikula static void get_dsi_io_power_domains(struct drm_i915_private *dev_priv,
384379bc100SJani Nikula struct intel_dsi *intel_dsi)
385379bc100SJani Nikula {
386379bc100SJani Nikula enum port port;
387379bc100SJani Nikula
388379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
3893dbe5e11SPankaj Bharadiya drm_WARN_ON(&dev_priv->drm, intel_dsi->io_wakeref[port]);
390379bc100SJani Nikula intel_dsi->io_wakeref[port] =
391379bc100SJani Nikula intel_display_power_get(dev_priv,
392379bc100SJani Nikula port == PORT_A ?
3930ba2661dSImre Deak POWER_DOMAIN_PORT_DDI_IO_A :
3940ba2661dSImre Deak POWER_DOMAIN_PORT_DDI_IO_B);
395379bc100SJani Nikula }
396379bc100SJani Nikula }
397379bc100SJani Nikula
gen11_dsi_enable_io_power(struct intel_encoder * encoder)398379bc100SJani Nikula static void gen11_dsi_enable_io_power(struct intel_encoder *encoder)
399379bc100SJani Nikula {
400379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
401b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
402379bc100SJani Nikula enum port port;
403379bc100SJani Nikula
4041a45d681SAndrzej Hajda for_each_dsi_port(port, intel_dsi->ports)
4051a45d681SAndrzej Hajda intel_de_rmw(dev_priv, ICL_DSI_IO_MODECTL(port),
4061a45d681SAndrzej Hajda 0, COMBO_PHY_MODE_DSI);
407379bc100SJani Nikula
408379bc100SJani Nikula get_dsi_io_power_domains(dev_priv, intel_dsi);
409379bc100SJani Nikula }
410379bc100SJani Nikula
gen11_dsi_power_up_lanes(struct intel_encoder * encoder)411379bc100SJani Nikula static void gen11_dsi_power_up_lanes(struct intel_encoder *encoder)
412379bc100SJani Nikula {
413379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
414b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
415dc867bc7SMatt Roper enum phy phy;
416379bc100SJani Nikula
417dc867bc7SMatt Roper for_each_dsi_phy(phy, intel_dsi->phys)
418dc867bc7SMatt Roper intel_combo_phy_power_up_lanes(dev_priv, phy, true,
419379bc100SJani Nikula intel_dsi->lane_count, false);
420379bc100SJani Nikula }
421379bc100SJani Nikula
gen11_dsi_config_phy_lanes_sequence(struct intel_encoder * encoder)422379bc100SJani Nikula static void gen11_dsi_config_phy_lanes_sequence(struct intel_encoder *encoder)
423379bc100SJani Nikula {
424379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
425b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
426dc867bc7SMatt Roper enum phy phy;
427379bc100SJani Nikula u32 tmp;
428379bc100SJani Nikula int lane;
429379bc100SJani Nikula
430379bc100SJani Nikula /* Step 4b(i) set loadgen select for transmit and aux lanes */
431dc867bc7SMatt Roper for_each_dsi_phy(phy, intel_dsi->phys) {
4321a45d681SAndrzej Hajda intel_de_rmw(dev_priv, ICL_PORT_TX_DW4_AUX(phy), LOADGEN_SELECT, 0);
4331a45d681SAndrzej Hajda for (lane = 0; lane <= 3; lane++)
4341a45d681SAndrzej Hajda intel_de_rmw(dev_priv, ICL_PORT_TX_DW4_LN(lane, phy),
4351a45d681SAndrzej Hajda LOADGEN_SELECT, lane != 2 ? LOADGEN_SELECT : 0);
436379bc100SJani Nikula }
437379bc100SJani Nikula
438379bc100SJani Nikula /* Step 4b(ii) set latency optimization for transmit and aux lanes */
439dc867bc7SMatt Roper for_each_dsi_phy(phy, intel_dsi->phys) {
4401a45d681SAndrzej Hajda intel_de_rmw(dev_priv, ICL_PORT_TX_DW2_AUX(phy),
4411a45d681SAndrzej Hajda FRC_LATENCY_OPTIM_MASK, FRC_LATENCY_OPTIM_VAL(0x5));
442e6908588SVille Syrjälä tmp = intel_de_read(dev_priv, ICL_PORT_TX_DW2_LN(0, phy));
443379bc100SJani Nikula tmp &= ~FRC_LATENCY_OPTIM_MASK;
444379bc100SJani Nikula tmp |= FRC_LATENCY_OPTIM_VAL(0x5);
4451c63f6dfSJani Nikula intel_de_write(dev_priv, ICL_PORT_TX_DW2_GRP(phy), tmp);
4466a7bafe8SVandita Kulkarni
447960e9836SVandita Kulkarni /* For EHL, TGL, set latency optimization for PCS_DW1 lanes */
4480c65dc06SDnyaneshwar Bhadane if (IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv) ||
4490c65dc06SDnyaneshwar Bhadane (DISPLAY_VER(dev_priv) >= 12)) {
4501a45d681SAndrzej Hajda intel_de_rmw(dev_priv, ICL_PORT_PCS_DW1_AUX(phy),
4511a45d681SAndrzej Hajda LATENCY_OPTIM_MASK, LATENCY_OPTIM_VAL(0));
4526a7bafe8SVandita Kulkarni
4531c63f6dfSJani Nikula tmp = intel_de_read(dev_priv,
454e6908588SVille Syrjälä ICL_PORT_PCS_DW1_LN(0, phy));
4556a7bafe8SVandita Kulkarni tmp &= ~LATENCY_OPTIM_MASK;
4566a7bafe8SVandita Kulkarni tmp |= LATENCY_OPTIM_VAL(0x1);
4571c63f6dfSJani Nikula intel_de_write(dev_priv, ICL_PORT_PCS_DW1_GRP(phy),
4581c63f6dfSJani Nikula tmp);
4596a7bafe8SVandita Kulkarni }
460379bc100SJani Nikula }
461379bc100SJani Nikula
462379bc100SJani Nikula }
463379bc100SJani Nikula
gen11_dsi_voltage_swing_program_seq(struct intel_encoder * encoder)464379bc100SJani Nikula static void gen11_dsi_voltage_swing_program_seq(struct intel_encoder *encoder)
465379bc100SJani Nikula {
466379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
467b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
468379bc100SJani Nikula u32 tmp;
469dc867bc7SMatt Roper enum phy phy;
470379bc100SJani Nikula
471379bc100SJani Nikula /* clear common keeper enable bit */
472dc867bc7SMatt Roper for_each_dsi_phy(phy, intel_dsi->phys) {
473e6908588SVille Syrjälä tmp = intel_de_read(dev_priv, ICL_PORT_PCS_DW1_LN(0, phy));
474379bc100SJani Nikula tmp &= ~COMMON_KEEPER_EN;
4751c63f6dfSJani Nikula intel_de_write(dev_priv, ICL_PORT_PCS_DW1_GRP(phy), tmp);
4761a45d681SAndrzej Hajda intel_de_rmw(dev_priv, ICL_PORT_PCS_DW1_AUX(phy), COMMON_KEEPER_EN, 0);
477379bc100SJani Nikula }
478379bc100SJani Nikula
479379bc100SJani Nikula /*
480379bc100SJani Nikula * Set SUS Clock Config bitfield to 11b
481379bc100SJani Nikula * Note: loadgen select program is done
482379bc100SJani Nikula * as part of lane phy sequence configuration
483379bc100SJani Nikula */
4841a45d681SAndrzej Hajda for_each_dsi_phy(phy, intel_dsi->phys)
4851a45d681SAndrzej Hajda intel_de_rmw(dev_priv, ICL_PORT_CL_DW5(phy), 0, SUS_CLOCK_CONFIG);
486379bc100SJani Nikula
487379bc100SJani Nikula /* Clear training enable to change swing values */
488dc867bc7SMatt Roper for_each_dsi_phy(phy, intel_dsi->phys) {
489e6908588SVille Syrjälä tmp = intel_de_read(dev_priv, ICL_PORT_TX_DW5_LN(0, phy));
490379bc100SJani Nikula tmp &= ~TX_TRAINING_EN;
4911c63f6dfSJani Nikula intel_de_write(dev_priv, ICL_PORT_TX_DW5_GRP(phy), tmp);
4921a45d681SAndrzej Hajda intel_de_rmw(dev_priv, ICL_PORT_TX_DW5_AUX(phy), TX_TRAINING_EN, 0);
493379bc100SJani Nikula }
494379bc100SJani Nikula
495379bc100SJani Nikula /* Program swing and de-emphasis */
496379bc100SJani Nikula dsi_program_swing_and_deemphasis(encoder);
497379bc100SJani Nikula
498379bc100SJani Nikula /* Set training enable to trigger update */
499dc867bc7SMatt Roper for_each_dsi_phy(phy, intel_dsi->phys) {
500e6908588SVille Syrjälä tmp = intel_de_read(dev_priv, ICL_PORT_TX_DW5_LN(0, phy));
501379bc100SJani Nikula tmp |= TX_TRAINING_EN;
5021c63f6dfSJani Nikula intel_de_write(dev_priv, ICL_PORT_TX_DW5_GRP(phy), tmp);
5031a45d681SAndrzej Hajda intel_de_rmw(dev_priv, ICL_PORT_TX_DW5_AUX(phy), 0, TX_TRAINING_EN);
504379bc100SJani Nikula }
505379bc100SJani Nikula }
506379bc100SJani Nikula
gen11_dsi_enable_ddi_buffer(struct intel_encoder * encoder)507379bc100SJani Nikula static void gen11_dsi_enable_ddi_buffer(struct intel_encoder *encoder)
508379bc100SJani Nikula {
509379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
510b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
511379bc100SJani Nikula enum port port;
512379bc100SJani Nikula
513379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
5141a45d681SAndrzej Hajda intel_de_rmw(dev_priv, DDI_BUF_CTL(port), 0, DDI_BUF_CTL_ENABLE);
515379bc100SJani Nikula
5161c63f6dfSJani Nikula if (wait_for_us(!(intel_de_read(dev_priv, DDI_BUF_CTL(port)) &
517379bc100SJani Nikula DDI_BUF_IS_IDLE),
518379bc100SJani Nikula 500))
519b5280cd0SWambui Karuga drm_err(&dev_priv->drm, "DDI port:%c buffer idle\n",
520b5280cd0SWambui Karuga port_name(port));
521379bc100SJani Nikula }
522379bc100SJani Nikula }
523379bc100SJani Nikula
52404865139SJani Nikula static void
gen11_dsi_setup_dphy_timings(struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state)52504865139SJani Nikula gen11_dsi_setup_dphy_timings(struct intel_encoder *encoder,
52604865139SJani Nikula const struct intel_crtc_state *crtc_state)
527379bc100SJani Nikula {
528379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
529b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
530379bc100SJani Nikula enum port port;
531dc867bc7SMatt Roper enum phy phy;
532379bc100SJani Nikula
533379bc100SJani Nikula /* Program DPHY clock lanes timings */
534d4121327SVille Syrjälä for_each_dsi_port(port, intel_dsi->ports)
5351c63f6dfSJani Nikula intel_de_write(dev_priv, DPHY_CLK_TIMING_PARAM(port),
5361c63f6dfSJani Nikula intel_dsi->dphy_reg);
537379bc100SJani Nikula
538379bc100SJani Nikula /* Program DPHY data lanes timings */
539d4121327SVille Syrjälä for_each_dsi_port(port, intel_dsi->ports)
5401c63f6dfSJani Nikula intel_de_write(dev_priv, DPHY_DATA_TIMING_PARAM(port),
541379bc100SJani Nikula intel_dsi->dphy_data_lane_reg);
542379bc100SJani Nikula
543379bc100SJani Nikula /*
544379bc100SJani Nikula * If DSI link operating at or below an 800 MHz,
545379bc100SJani Nikula * TA_SURE should be override and programmed to
546379bc100SJani Nikula * a value '0' inside TA_PARAM_REGISTERS otherwise
547379bc100SJani Nikula * leave all fields at HW default values.
548379bc100SJani Nikula */
54993e7e61eSLucas De Marchi if (DISPLAY_VER(dev_priv) == 11) {
55004865139SJani Nikula if (afe_clk(encoder, crtc_state) <= 800000) {
551d4121327SVille Syrjälä for_each_dsi_port(port, intel_dsi->ports)
5521a45d681SAndrzej Hajda intel_de_rmw(dev_priv, DPHY_TA_TIMING_PARAM(port),
5531a45d681SAndrzej Hajda TA_SURE_MASK,
5541a45d681SAndrzej Hajda TA_SURE_OVERRIDE | TA_SURE(0));
555379bc100SJani Nikula }
5567b864f95SVandita Kulkarni }
557683d672cSJosé Roberto de Souza
5580c65dc06SDnyaneshwar Bhadane if (IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) {
5591a45d681SAndrzej Hajda for_each_dsi_phy(phy, intel_dsi->phys)
5601a45d681SAndrzej Hajda intel_de_rmw(dev_priv, ICL_DPHY_CHKN(phy),
5611a45d681SAndrzej Hajda 0, ICL_DPHY_CHKN_AFE_OVER_PPI_STRAP);
562683d672cSJosé Roberto de Souza }
563379bc100SJani Nikula }
564379bc100SJani Nikula
565d4121327SVille Syrjälä static void
gen11_dsi_setup_timings(struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state)566d4121327SVille Syrjälä gen11_dsi_setup_timings(struct intel_encoder *encoder,
567d4121327SVille Syrjälä const struct intel_crtc_state *crtc_state)
568d4121327SVille Syrjälä {
569d4121327SVille Syrjälä struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
570d4121327SVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
571d4121327SVille Syrjälä enum port port;
572d4121327SVille Syrjälä
573d4121327SVille Syrjälä /* Program T-INIT master registers */
574d4121327SVille Syrjälä for_each_dsi_port(port, intel_dsi->ports)
575d4121327SVille Syrjälä intel_de_rmw(dev_priv, ICL_DSI_T_INIT_MASTER(port),
576d4121327SVille Syrjälä DSI_T_INIT_MASTER_MASK, intel_dsi->init_count);
577d4121327SVille Syrjälä
578d4121327SVille Syrjälä /* shadow register inside display core */
579d4121327SVille Syrjälä for_each_dsi_port(port, intel_dsi->ports)
580d4121327SVille Syrjälä intel_de_write(dev_priv, DSI_CLK_TIMING_PARAM(port),
581d4121327SVille Syrjälä intel_dsi->dphy_reg);
582d4121327SVille Syrjälä
583d4121327SVille Syrjälä /* shadow register inside display core */
584d4121327SVille Syrjälä for_each_dsi_port(port, intel_dsi->ports)
585d4121327SVille Syrjälä intel_de_write(dev_priv, DSI_DATA_TIMING_PARAM(port),
586d4121327SVille Syrjälä intel_dsi->dphy_data_lane_reg);
587d4121327SVille Syrjälä
588d4121327SVille Syrjälä /* shadow register inside display core */
589d4121327SVille Syrjälä if (DISPLAY_VER(dev_priv) == 11) {
590d4121327SVille Syrjälä if (afe_clk(encoder, crtc_state) <= 800000) {
591d4121327SVille Syrjälä for_each_dsi_port(port, intel_dsi->ports) {
592d4121327SVille Syrjälä intel_de_rmw(dev_priv, DSI_TA_TIMING_PARAM(port),
593d4121327SVille Syrjälä TA_SURE_MASK,
594d4121327SVille Syrjälä TA_SURE_OVERRIDE | TA_SURE(0));
595d4121327SVille Syrjälä }
596d4121327SVille Syrjälä }
597d4121327SVille Syrjälä }
598d4121327SVille Syrjälä }
599d4121327SVille Syrjälä
gen11_dsi_gate_clocks(struct intel_encoder * encoder)600379bc100SJani Nikula static void gen11_dsi_gate_clocks(struct intel_encoder *encoder)
601379bc100SJani Nikula {
602379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
603b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
604379bc100SJani Nikula u32 tmp;
605befa372bSMatt Roper enum phy phy;
606379bc100SJani Nikula
60736d225f3SJani Nikula mutex_lock(&dev_priv->display.dpll.lock);
6081c63f6dfSJani Nikula tmp = intel_de_read(dev_priv, ICL_DPCLKA_CFGCR0);
609dc867bc7SMatt Roper for_each_dsi_phy(phy, intel_dsi->phys)
610befa372bSMatt Roper tmp |= ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy);
611379bc100SJani Nikula
6121c63f6dfSJani Nikula intel_de_write(dev_priv, ICL_DPCLKA_CFGCR0, tmp);
61336d225f3SJani Nikula mutex_unlock(&dev_priv->display.dpll.lock);
614379bc100SJani Nikula }
615379bc100SJani Nikula
gen11_dsi_ungate_clocks(struct intel_encoder * encoder)616379bc100SJani Nikula static void gen11_dsi_ungate_clocks(struct intel_encoder *encoder)
617379bc100SJani Nikula {
618379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
619b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
620379bc100SJani Nikula u32 tmp;
621befa372bSMatt Roper enum phy phy;
622379bc100SJani Nikula
62336d225f3SJani Nikula mutex_lock(&dev_priv->display.dpll.lock);
6241c63f6dfSJani Nikula tmp = intel_de_read(dev_priv, ICL_DPCLKA_CFGCR0);
625dc867bc7SMatt Roper for_each_dsi_phy(phy, intel_dsi->phys)
626befa372bSMatt Roper tmp &= ~ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy);
627379bc100SJani Nikula
6281c63f6dfSJani Nikula intel_de_write(dev_priv, ICL_DPCLKA_CFGCR0, tmp);
62936d225f3SJani Nikula mutex_unlock(&dev_priv->display.dpll.lock);
630379bc100SJani Nikula }
631379bc100SJani Nikula
gen11_dsi_is_clock_enabled(struct intel_encoder * encoder)6320fbd8694SVille Syrjälä static bool gen11_dsi_is_clock_enabled(struct intel_encoder *encoder)
6330fbd8694SVille Syrjälä {
6340fbd8694SVille Syrjälä struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
6350fbd8694SVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
6360fbd8694SVille Syrjälä bool clock_enabled = false;
6370fbd8694SVille Syrjälä enum phy phy;
6380fbd8694SVille Syrjälä u32 tmp;
6390fbd8694SVille Syrjälä
6400fbd8694SVille Syrjälä tmp = intel_de_read(dev_priv, ICL_DPCLKA_CFGCR0);
6410fbd8694SVille Syrjälä
6420fbd8694SVille Syrjälä for_each_dsi_phy(phy, intel_dsi->phys) {
6430fbd8694SVille Syrjälä if (!(tmp & ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)))
6440fbd8694SVille Syrjälä clock_enabled = true;
6450fbd8694SVille Syrjälä }
6460fbd8694SVille Syrjälä
6470fbd8694SVille Syrjälä return clock_enabled;
6480fbd8694SVille Syrjälä }
6490fbd8694SVille Syrjälä
gen11_dsi_map_pll(struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state)650379bc100SJani Nikula static void gen11_dsi_map_pll(struct intel_encoder *encoder,
651379bc100SJani Nikula const struct intel_crtc_state *crtc_state)
652379bc100SJani Nikula {
653379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
654b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
655379bc100SJani Nikula struct intel_shared_dpll *pll = crtc_state->shared_dpll;
656befa372bSMatt Roper enum phy phy;
657379bc100SJani Nikula u32 val;
658379bc100SJani Nikula
65936d225f3SJani Nikula mutex_lock(&dev_priv->display.dpll.lock);
660379bc100SJani Nikula
6611c63f6dfSJani Nikula val = intel_de_read(dev_priv, ICL_DPCLKA_CFGCR0);
662dc867bc7SMatt Roper for_each_dsi_phy(phy, intel_dsi->phys) {
663befa372bSMatt Roper val &= ~ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy);
664befa372bSMatt Roper val |= ICL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy);
665379bc100SJani Nikula }
6661c63f6dfSJani Nikula intel_de_write(dev_priv, ICL_DPCLKA_CFGCR0, val);
667379bc100SJani Nikula
668dc867bc7SMatt Roper for_each_dsi_phy(phy, intel_dsi->phys) {
669befa372bSMatt Roper val &= ~ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy);
670379bc100SJani Nikula }
6711c63f6dfSJani Nikula intel_de_write(dev_priv, ICL_DPCLKA_CFGCR0, val);
672379bc100SJani Nikula
6731c63f6dfSJani Nikula intel_de_posting_read(dev_priv, ICL_DPCLKA_CFGCR0);
674379bc100SJani Nikula
67536d225f3SJani Nikula mutex_unlock(&dev_priv->display.dpll.lock);
676379bc100SJani Nikula }
677379bc100SJani Nikula
678379bc100SJani Nikula static void
gen11_dsi_configure_transcoder(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config)679379bc100SJani Nikula gen11_dsi_configure_transcoder(struct intel_encoder *encoder,
680379bc100SJani Nikula const struct intel_crtc_state *pipe_config)
681379bc100SJani Nikula {
682379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
683b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
684f15f01a7SVille Syrjälä struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
685f15f01a7SVille Syrjälä enum pipe pipe = crtc->pipe;
686379bc100SJani Nikula u32 tmp;
687379bc100SJani Nikula enum port port;
688379bc100SJani Nikula enum transcoder dsi_trans;
689379bc100SJani Nikula
690379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
691379bc100SJani Nikula dsi_trans = dsi_port_to_transcoder(port);
6921c63f6dfSJani Nikula tmp = intel_de_read(dev_priv, DSI_TRANS_FUNC_CONF(dsi_trans));
693379bc100SJani Nikula
694379bc100SJani Nikula if (intel_dsi->eotp_pkt)
695379bc100SJani Nikula tmp &= ~EOTP_DISABLED;
696379bc100SJani Nikula else
697379bc100SJani Nikula tmp |= EOTP_DISABLED;
698379bc100SJani Nikula
699379bc100SJani Nikula /* enable link calibration if freq > 1.5Gbps */
70004865139SJani Nikula if (afe_clk(encoder, pipe_config) >= 1500 * 1000) {
701379bc100SJani Nikula tmp &= ~LINK_CALIBRATION_MASK;
702379bc100SJani Nikula tmp |= CALIBRATION_ENABLED_INITIAL_ONLY;
703379bc100SJani Nikula }
704379bc100SJani Nikula
705379bc100SJani Nikula /* configure continuous clock */
706379bc100SJani Nikula tmp &= ~CONTINUOUS_CLK_MASK;
707379bc100SJani Nikula if (intel_dsi->clock_stop)
708379bc100SJani Nikula tmp |= CLK_ENTER_LP_AFTER_DATA;
709379bc100SJani Nikula else
710379bc100SJani Nikula tmp |= CLK_HS_CONTINUOUS;
711379bc100SJani Nikula
712379bc100SJani Nikula /* configure buffer threshold limit to minimum */
713379bc100SJani Nikula tmp &= ~PIX_BUF_THRESHOLD_MASK;
714379bc100SJani Nikula tmp |= PIX_BUF_THRESHOLD_1_4;
715379bc100SJani Nikula
716379bc100SJani Nikula /* set virtual channel to '0' */
717379bc100SJani Nikula tmp &= ~PIX_VIRT_CHAN_MASK;
718379bc100SJani Nikula tmp |= PIX_VIRT_CHAN(0);
719379bc100SJani Nikula
720379bc100SJani Nikula /* program BGR transmission */
721379bc100SJani Nikula if (intel_dsi->bgr_enabled)
722379bc100SJani Nikula tmp |= BGR_TRANSMISSION;
723379bc100SJani Nikula
724379bc100SJani Nikula /* select pixel format */
725379bc100SJani Nikula tmp &= ~PIX_FMT_MASK;
72638b89881SJani Nikula if (pipe_config->dsc.compression_enable) {
72738b89881SJani Nikula tmp |= PIX_FMT_COMPRESSED;
72838b89881SJani Nikula } else {
729379bc100SJani Nikula switch (intel_dsi->pixel_format) {
730379bc100SJani Nikula default:
731379bc100SJani Nikula MISSING_CASE(intel_dsi->pixel_format);
732df561f66SGustavo A. R. Silva fallthrough;
733379bc100SJani Nikula case MIPI_DSI_FMT_RGB565:
734379bc100SJani Nikula tmp |= PIX_FMT_RGB565;
735379bc100SJani Nikula break;
736379bc100SJani Nikula case MIPI_DSI_FMT_RGB666_PACKED:
737379bc100SJani Nikula tmp |= PIX_FMT_RGB666_PACKED;
738379bc100SJani Nikula break;
739379bc100SJani Nikula case MIPI_DSI_FMT_RGB666:
740379bc100SJani Nikula tmp |= PIX_FMT_RGB666_LOOSE;
741379bc100SJani Nikula break;
742379bc100SJani Nikula case MIPI_DSI_FMT_RGB888:
743379bc100SJani Nikula tmp |= PIX_FMT_RGB888;
744379bc100SJani Nikula break;
745379bc100SJani Nikula }
74638b89881SJani Nikula }
747379bc100SJani Nikula
748005e9537SMatt Roper if (DISPLAY_VER(dev_priv) >= 12) {
74932d38e6cSVandita Kulkarni if (is_vid_mode(intel_dsi))
75032d38e6cSVandita Kulkarni tmp |= BLANKING_PACKET_ENABLE;
75132d38e6cSVandita Kulkarni }
75232d38e6cSVandita Kulkarni
753379bc100SJani Nikula /* program DSI operation mode */
754379bc100SJani Nikula if (is_vid_mode(intel_dsi)) {
755379bc100SJani Nikula tmp &= ~OP_MODE_MASK;
7568f0991ccSJani Nikula switch (intel_dsi->video_mode) {
757379bc100SJani Nikula default:
7588f0991ccSJani Nikula MISSING_CASE(intel_dsi->video_mode);
759df561f66SGustavo A. R. Silva fallthrough;
7608f0991ccSJani Nikula case NON_BURST_SYNC_EVENTS:
761379bc100SJani Nikula tmp |= VIDEO_MODE_SYNC_EVENT;
762379bc100SJani Nikula break;
7638f0991ccSJani Nikula case NON_BURST_SYNC_PULSE:
764379bc100SJani Nikula tmp |= VIDEO_MODE_SYNC_PULSE;
765379bc100SJani Nikula break;
766379bc100SJani Nikula }
767b4b95b05SVandita Kulkarni } else {
768b4b95b05SVandita Kulkarni /*
769b4b95b05SVandita Kulkarni * FIXME: Retrieve this info from VBT.
770b4b95b05SVandita Kulkarni * As per the spec when dsi transcoder is operating
771b4b95b05SVandita Kulkarni * in TE GATE mode, TE comes from GPIO
772b4b95b05SVandita Kulkarni * which is UTIL PIN for DSI 0.
773b4b95b05SVandita Kulkarni * Also this GPIO would not be used for other
774b4b95b05SVandita Kulkarni * purposes is an assumption.
775b4b95b05SVandita Kulkarni */
776b4b95b05SVandita Kulkarni tmp &= ~OP_MODE_MASK;
777b4b95b05SVandita Kulkarni tmp |= CMD_MODE_TE_GATE;
778b4b95b05SVandita Kulkarni tmp |= TE_SOURCE_GPIO;
779379bc100SJani Nikula }
780379bc100SJani Nikula
7811c63f6dfSJani Nikula intel_de_write(dev_priv, DSI_TRANS_FUNC_CONF(dsi_trans), tmp);
782379bc100SJani Nikula }
783379bc100SJani Nikula
784379bc100SJani Nikula /* enable port sync mode if dual link */
785379bc100SJani Nikula if (intel_dsi->dual_link) {
786379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
787379bc100SJani Nikula dsi_trans = dsi_port_to_transcoder(port);
78876f1b2b1SJani Nikula intel_de_rmw(dev_priv,
78976f1b2b1SJani Nikula TRANS_DDI_FUNC_CTL2(dev_priv, dsi_trans),
7901a45d681SAndrzej Hajda 0, PORT_SYNC_MODE_ENABLE);
791379bc100SJani Nikula }
792379bc100SJani Nikula
793379bc100SJani Nikula /* configure stream splitting */
794379bc100SJani Nikula configure_dual_link_mode(encoder, pipe_config);
795379bc100SJani Nikula }
796379bc100SJani Nikula
797379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
798379bc100SJani Nikula dsi_trans = dsi_port_to_transcoder(port);
799379bc100SJani Nikula
800379bc100SJani Nikula /* select data lane width */
801b092d6adSJani Nikula tmp = intel_de_read(dev_priv,
802b092d6adSJani Nikula TRANS_DDI_FUNC_CTL(dev_priv, dsi_trans));
803379bc100SJani Nikula tmp &= ~DDI_PORT_WIDTH_MASK;
804379bc100SJani Nikula tmp |= DDI_PORT_WIDTH(intel_dsi->lane_count);
805379bc100SJani Nikula
806379bc100SJani Nikula /* select input pipe */
807379bc100SJani Nikula tmp &= ~TRANS_DDI_EDP_INPUT_MASK;
808379bc100SJani Nikula switch (pipe) {
809379bc100SJani Nikula default:
810379bc100SJani Nikula MISSING_CASE(pipe);
811df561f66SGustavo A. R. Silva fallthrough;
812379bc100SJani Nikula case PIPE_A:
813379bc100SJani Nikula tmp |= TRANS_DDI_EDP_INPUT_A_ON;
814379bc100SJani Nikula break;
815379bc100SJani Nikula case PIPE_B:
816379bc100SJani Nikula tmp |= TRANS_DDI_EDP_INPUT_B_ONOFF;
817379bc100SJani Nikula break;
818379bc100SJani Nikula case PIPE_C:
819379bc100SJani Nikula tmp |= TRANS_DDI_EDP_INPUT_C_ONOFF;
820379bc100SJani Nikula break;
8214d89adc7SJosé Roberto de Souza case PIPE_D:
8224d89adc7SJosé Roberto de Souza tmp |= TRANS_DDI_EDP_INPUT_D_ONOFF;
8234d89adc7SJosé Roberto de Souza break;
824379bc100SJani Nikula }
825379bc100SJani Nikula
826379bc100SJani Nikula /* enable DDI buffer */
827379bc100SJani Nikula tmp |= TRANS_DDI_FUNC_ENABLE;
828b092d6adSJani Nikula intel_de_write(dev_priv,
829b092d6adSJani Nikula TRANS_DDI_FUNC_CTL(dev_priv, dsi_trans), tmp);
830379bc100SJani Nikula }
831379bc100SJani Nikula
832379bc100SJani Nikula /* wait for link ready */
833379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
834379bc100SJani Nikula dsi_trans = dsi_port_to_transcoder(port);
8351c63f6dfSJani Nikula if (wait_for_us((intel_de_read(dev_priv, DSI_TRANS_FUNC_CONF(dsi_trans)) &
836379bc100SJani Nikula LINK_READY), 2500))
837b5280cd0SWambui Karuga drm_err(&dev_priv->drm, "DSI link not ready\n");
838379bc100SJani Nikula }
839379bc100SJani Nikula }
840379bc100SJani Nikula
841379bc100SJani Nikula static void
gen11_dsi_set_transcoder_timings(struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state)842379bc100SJani Nikula gen11_dsi_set_transcoder_timings(struct intel_encoder *encoder,
84353693f02SJani Nikula const struct intel_crtc_state *crtc_state)
844379bc100SJani Nikula {
845379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
846b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
847379bc100SJani Nikula const struct drm_display_mode *adjusted_mode =
84853693f02SJani Nikula &crtc_state->hw.adjusted_mode;
849379bc100SJani Nikula enum port port;
850379bc100SJani Nikula enum transcoder dsi_trans;
851379bc100SJani Nikula /* horizontal timings */
852379bc100SJani Nikula u16 htotal, hactive, hsync_start, hsync_end, hsync_size;
8530cc35a9cSYueHaibing u16 hback_porch;
854379bc100SJani Nikula /* vertical timings */
855379bc100SJani Nikula u16 vtotal, vactive, vsync_start, vsync_end, vsync_shift;
85653693f02SJani Nikula int mul = 1, div = 1;
85753693f02SJani Nikula
85853693f02SJani Nikula /*
85953693f02SJani Nikula * Adjust horizontal timings (htotal, hsync_start, hsync_end) to account
86053693f02SJani Nikula * for slower link speed if DSC is enabled.
86153693f02SJani Nikula *
86253693f02SJani Nikula * The compression frequency ratio is the ratio between compressed and
86353693f02SJani Nikula * non-compressed link speeds, and simplifies down to the ratio between
86453693f02SJani Nikula * compressed and non-compressed bpp.
86553693f02SJani Nikula */
86653693f02SJani Nikula if (crtc_state->dsc.compression_enable) {
8678466a141SImre Deak mul = fxp_q4_to_int(crtc_state->dsc.compressed_bpp_x16);
86853693f02SJani Nikula div = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
86953693f02SJani Nikula }
870379bc100SJani Nikula
871379bc100SJani Nikula hactive = adjusted_mode->crtc_hdisplay;
872b9277832SVandita Kulkarni
873b9277832SVandita Kulkarni if (is_vid_mode(intel_dsi))
87453693f02SJani Nikula htotal = DIV_ROUND_UP(adjusted_mode->crtc_htotal * mul, div);
875b9277832SVandita Kulkarni else
876b9277832SVandita Kulkarni htotal = DIV_ROUND_UP((hactive + 160) * mul, div);
877b9277832SVandita Kulkarni
87853693f02SJani Nikula hsync_start = DIV_ROUND_UP(adjusted_mode->crtc_hsync_start * mul, div);
87953693f02SJani Nikula hsync_end = DIV_ROUND_UP(adjusted_mode->crtc_hsync_end * mul, div);
880379bc100SJani Nikula hsync_size = hsync_end - hsync_start;
881379bc100SJani Nikula hback_porch = (adjusted_mode->crtc_htotal -
882379bc100SJani Nikula adjusted_mode->crtc_hsync_end);
883379bc100SJani Nikula vactive = adjusted_mode->crtc_vdisplay;
884b9277832SVandita Kulkarni
885b9277832SVandita Kulkarni if (is_vid_mode(intel_dsi)) {
886379bc100SJani Nikula vtotal = adjusted_mode->crtc_vtotal;
887b9277832SVandita Kulkarni } else {
888b9277832SVandita Kulkarni int bpp, line_time_us, byte_clk_period_ns;
889b9277832SVandita Kulkarni
890b9277832SVandita Kulkarni if (crtc_state->dsc.compression_enable)
8918466a141SImre Deak bpp = fxp_q4_to_int(crtc_state->dsc.compressed_bpp_x16);
892b9277832SVandita Kulkarni else
893b9277832SVandita Kulkarni bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
894b9277832SVandita Kulkarni
895b9277832SVandita Kulkarni byte_clk_period_ns = 1000000 / afe_clk(encoder, crtc_state);
896b9277832SVandita Kulkarni line_time_us = (htotal * (bpp / 8) * byte_clk_period_ns) / (1000 * intel_dsi->lane_count);
897b9277832SVandita Kulkarni vtotal = vactive + DIV_ROUND_UP(400, line_time_us);
898b9277832SVandita Kulkarni }
899379bc100SJani Nikula vsync_start = adjusted_mode->crtc_vsync_start;
900379bc100SJani Nikula vsync_end = adjusted_mode->crtc_vsync_end;
901379bc100SJani Nikula vsync_shift = hsync_start - htotal / 2;
902379bc100SJani Nikula
903379bc100SJani Nikula if (intel_dsi->dual_link) {
904379bc100SJani Nikula hactive /= 2;
905379bc100SJani Nikula if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
906379bc100SJani Nikula hactive += intel_dsi->pixel_overlap;
907379bc100SJani Nikula htotal /= 2;
908379bc100SJani Nikula }
909379bc100SJani Nikula
910379bc100SJani Nikula /* minimum hactive as per bspec: 256 pixels */
911379bc100SJani Nikula if (adjusted_mode->crtc_hdisplay < 256)
912b5280cd0SWambui Karuga drm_err(&dev_priv->drm, "hactive is less then 256 pixels\n");
913379bc100SJani Nikula
914379bc100SJani Nikula /* if RGB666 format, then hactive must be multiple of 4 pixels */
915379bc100SJani Nikula if (intel_dsi->pixel_format == MIPI_DSI_FMT_RGB666 && hactive % 4 != 0)
916b5280cd0SWambui Karuga drm_err(&dev_priv->drm,
917b5280cd0SWambui Karuga "hactive pixels are not multiple of 4\n");
918379bc100SJani Nikula
919379bc100SJani Nikula /* program TRANS_HTOTAL register */
920379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
921379bc100SJani Nikula dsi_trans = dsi_port_to_transcoder(port);
922e5799743SJani Nikula intel_de_write(dev_priv, TRANS_HTOTAL(dev_priv, dsi_trans),
923050db7d7SVille Syrjälä HACTIVE(hactive - 1) | HTOTAL(htotal - 1));
924379bc100SJani Nikula }
925379bc100SJani Nikula
926379bc100SJani Nikula /* TRANS_HSYNC register to be programmed only for video mode */
927b9277832SVandita Kulkarni if (is_vid_mode(intel_dsi)) {
9288f0991ccSJani Nikula if (intel_dsi->video_mode == NON_BURST_SYNC_PULSE) {
929379bc100SJani Nikula /* BSPEC: hsync size should be atleast 16 pixels */
930379bc100SJani Nikula if (hsync_size < 16)
931b5280cd0SWambui Karuga drm_err(&dev_priv->drm,
932b5280cd0SWambui Karuga "hsync size < 16 pixels\n");
933379bc100SJani Nikula }
934379bc100SJani Nikula
935379bc100SJani Nikula if (hback_porch < 16)
936b5280cd0SWambui Karuga drm_err(&dev_priv->drm, "hback porch < 16 pixels\n");
937379bc100SJani Nikula
938379bc100SJani Nikula if (intel_dsi->dual_link) {
939379bc100SJani Nikula hsync_start /= 2;
940379bc100SJani Nikula hsync_end /= 2;
941379bc100SJani Nikula }
942379bc100SJani Nikula
943379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
944379bc100SJani Nikula dsi_trans = dsi_port_to_transcoder(port);
9459b2db3bbSJani Nikula intel_de_write(dev_priv,
9469b2db3bbSJani Nikula TRANS_HSYNC(dev_priv, dsi_trans),
947050db7d7SVille Syrjälä HSYNC_START(hsync_start - 1) | HSYNC_END(hsync_end - 1));
948379bc100SJani Nikula }
949379bc100SJani Nikula }
950379bc100SJani Nikula
951379bc100SJani Nikula /* program TRANS_VTOTAL register */
952379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
953379bc100SJani Nikula dsi_trans = dsi_port_to_transcoder(port);
954379bc100SJani Nikula /*
955379bc100SJani Nikula * FIXME: Programing this by assuming progressive mode, since
956379bc100SJani Nikula * non-interlaced info from VBT is not saved inside
957379bc100SJani Nikula * struct drm_display_mode.
958379bc100SJani Nikula * For interlace mode: program required pixel minus 2
959379bc100SJani Nikula */
960b3e773f6SJani Nikula intel_de_write(dev_priv, TRANS_VTOTAL(dev_priv, dsi_trans),
961050db7d7SVille Syrjälä VACTIVE(vactive - 1) | VTOTAL(vtotal - 1));
962379bc100SJani Nikula }
963379bc100SJani Nikula
964379bc100SJani Nikula if (vsync_end < vsync_start || vsync_end > vtotal)
965b5280cd0SWambui Karuga drm_err(&dev_priv->drm, "Invalid vsync_end value\n");
966379bc100SJani Nikula
967379bc100SJani Nikula if (vsync_start < vactive)
968b5280cd0SWambui Karuga drm_err(&dev_priv->drm, "vsync_start less than vactive\n");
969379bc100SJani Nikula
970b9277832SVandita Kulkarni /* program TRANS_VSYNC register for video mode only */
971b9277832SVandita Kulkarni if (is_vid_mode(intel_dsi)) {
972379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
973379bc100SJani Nikula dsi_trans = dsi_port_to_transcoder(port);
9749cacbd23SJani Nikula intel_de_write(dev_priv,
9759cacbd23SJani Nikula TRANS_VSYNC(dev_priv, dsi_trans),
976050db7d7SVille Syrjälä VSYNC_START(vsync_start - 1) | VSYNC_END(vsync_end - 1));
977379bc100SJani Nikula }
978b9277832SVandita Kulkarni }
979379bc100SJani Nikula
980379bc100SJani Nikula /*
981b9277832SVandita Kulkarni * FIXME: It has to be programmed only for video modes and interlaced
982379bc100SJani Nikula * modes. Put the check condition here once interlaced
983379bc100SJani Nikula * info available as described above.
984379bc100SJani Nikula * program TRANS_VSYNCSHIFT register
985379bc100SJani Nikula */
986b9277832SVandita Kulkarni if (is_vid_mode(intel_dsi)) {
987379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
988379bc100SJani Nikula dsi_trans = dsi_port_to_transcoder(port);
9898925350cSJani Nikula intel_de_write(dev_priv,
9908925350cSJani Nikula TRANS_VSYNCSHIFT(dev_priv, dsi_trans),
991b9277832SVandita Kulkarni vsync_shift);
992b9277832SVandita Kulkarni }
993379bc100SJani Nikula }
9943522a33aSVandita Kulkarni
9951552dd6eSVille Syrjälä /*
9961552dd6eSVille Syrjälä * program TRANS_VBLANK register, should be same as vtotal programmed
9971552dd6eSVille Syrjälä *
9981552dd6eSVille Syrjälä * FIXME get rid of these local hacks and do it right,
9991552dd6eSVille Syrjälä * this will not handle eg. delayed vblank correctly.
10001552dd6eSVille Syrjälä */
1001005e9537SMatt Roper if (DISPLAY_VER(dev_priv) >= 12) {
10023522a33aSVandita Kulkarni for_each_dsi_port(port, intel_dsi->ports) {
10033522a33aSVandita Kulkarni dsi_trans = dsi_port_to_transcoder(port);
100445f10393SJani Nikula intel_de_write(dev_priv,
100545f10393SJani Nikula TRANS_VBLANK(dev_priv, dsi_trans),
1006050db7d7SVille Syrjälä VBLANK_START(vactive - 1) | VBLANK_END(vtotal - 1));
10073522a33aSVandita Kulkarni }
10083522a33aSVandita Kulkarni }
1009379bc100SJani Nikula }
1010379bc100SJani Nikula
gen11_dsi_enable_transcoder(struct intel_encoder * encoder)1011379bc100SJani Nikula static void gen11_dsi_enable_transcoder(struct intel_encoder *encoder)
1012379bc100SJani Nikula {
1013379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
1014b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
1015379bc100SJani Nikula enum port port;
1016379bc100SJani Nikula enum transcoder dsi_trans;
1017379bc100SJani Nikula
1018379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
1019379bc100SJani Nikula dsi_trans = dsi_port_to_transcoder(port);
1020984b61c3SJani Nikula intel_de_rmw(dev_priv, TRANSCONF(dev_priv, dsi_trans), 0,
1021984b61c3SJani Nikula TRANSCONF_ENABLE);
1022379bc100SJani Nikula
1023379bc100SJani Nikula /* wait for transcoder to be enabled */
1024984b61c3SJani Nikula if (intel_de_wait_for_set(dev_priv, TRANSCONF(dev_priv, dsi_trans),
10253eb08ea5SVille Syrjälä TRANSCONF_STATE_ENABLE, 10))
1026b5280cd0SWambui Karuga drm_err(&dev_priv->drm,
1027b5280cd0SWambui Karuga "DSI transcoder not enabled\n");
1028379bc100SJani Nikula }
1029379bc100SJani Nikula }
1030379bc100SJani Nikula
gen11_dsi_setup_timeouts(struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state)103104865139SJani Nikula static void gen11_dsi_setup_timeouts(struct intel_encoder *encoder,
103204865139SJani Nikula const struct intel_crtc_state *crtc_state)
1033379bc100SJani Nikula {
1034379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
1035b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
1036379bc100SJani Nikula enum port port;
1037379bc100SJani Nikula enum transcoder dsi_trans;
10381a45d681SAndrzej Hajda u32 hs_tx_timeout, lp_rx_timeout, ta_timeout, divisor, mul;
1039379bc100SJani Nikula
1040379bc100SJani Nikula /*
1041379bc100SJani Nikula * escape clock count calculation:
1042379bc100SJani Nikula * BYTE_CLK_COUNT = TIME_NS/(8 * UI)
1043379bc100SJani Nikula * UI (nsec) = (10^6)/Bitrate
1044379bc100SJani Nikula * TIME_NS = (BYTE_CLK_COUNT * 8 * 10^6)/ Bitrate
1045379bc100SJani Nikula * ESCAPE_CLK_COUNT = TIME_NS/ESC_CLK_NS
1046379bc100SJani Nikula */
104704865139SJani Nikula divisor = intel_dsi_tlpx_ns(intel_dsi) * afe_clk(encoder, crtc_state) * 1000;
1048379bc100SJani Nikula mul = 8 * 1000000;
1049379bc100SJani Nikula hs_tx_timeout = DIV_ROUND_UP(intel_dsi->hs_tx_timeout * mul,
1050379bc100SJani Nikula divisor);
1051379bc100SJani Nikula lp_rx_timeout = DIV_ROUND_UP(intel_dsi->lp_rx_timeout * mul, divisor);
1052379bc100SJani Nikula ta_timeout = DIV_ROUND_UP(intel_dsi->turn_arnd_val * mul, divisor);
1053379bc100SJani Nikula
1054379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
1055379bc100SJani Nikula dsi_trans = dsi_port_to_transcoder(port);
1056379bc100SJani Nikula
1057379bc100SJani Nikula /* program hst_tx_timeout */
10581a45d681SAndrzej Hajda intel_de_rmw(dev_priv, DSI_HSTX_TO(dsi_trans),
10591a45d681SAndrzej Hajda HSTX_TIMEOUT_VALUE_MASK,
10601a45d681SAndrzej Hajda HSTX_TIMEOUT_VALUE(hs_tx_timeout));
1061379bc100SJani Nikula
1062379bc100SJani Nikula /* FIXME: DSI_CALIB_TO */
1063379bc100SJani Nikula
1064379bc100SJani Nikula /* program lp_rx_host timeout */
10651a45d681SAndrzej Hajda intel_de_rmw(dev_priv, DSI_LPRX_HOST_TO(dsi_trans),
10661a45d681SAndrzej Hajda LPRX_TIMEOUT_VALUE_MASK,
10671a45d681SAndrzej Hajda LPRX_TIMEOUT_VALUE(lp_rx_timeout));
1068379bc100SJani Nikula
1069379bc100SJani Nikula /* FIXME: DSI_PWAIT_TO */
1070379bc100SJani Nikula
1071379bc100SJani Nikula /* program turn around timeout */
10721a45d681SAndrzej Hajda intel_de_rmw(dev_priv, DSI_TA_TO(dsi_trans),
10731a45d681SAndrzej Hajda TA_TIMEOUT_VALUE_MASK,
10741a45d681SAndrzej Hajda TA_TIMEOUT_VALUE(ta_timeout));
1075379bc100SJani Nikula }
1076379bc100SJani Nikula }
1077379bc100SJani Nikula
gen11_dsi_config_util_pin(struct intel_encoder * encoder,bool enable)1078b4b95b05SVandita Kulkarni static void gen11_dsi_config_util_pin(struct intel_encoder *encoder,
1079b4b95b05SVandita Kulkarni bool enable)
1080b4b95b05SVandita Kulkarni {
1081b4b95b05SVandita Kulkarni struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
1082b4b95b05SVandita Kulkarni struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
1083b4b95b05SVandita Kulkarni u32 tmp;
1084b4b95b05SVandita Kulkarni
1085b4b95b05SVandita Kulkarni /*
1086b4b95b05SVandita Kulkarni * used as TE i/p for DSI0,
1087b4b95b05SVandita Kulkarni * for dual link/DSI1 TE is from slave DSI1
1088b4b95b05SVandita Kulkarni * through GPIO.
1089b4b95b05SVandita Kulkarni */
1090b4b95b05SVandita Kulkarni if (is_vid_mode(intel_dsi) || (intel_dsi->ports & BIT(PORT_B)))
1091b4b95b05SVandita Kulkarni return;
1092b4b95b05SVandita Kulkarni
1093b4b95b05SVandita Kulkarni tmp = intel_de_read(dev_priv, UTIL_PIN_CTL);
1094b4b95b05SVandita Kulkarni
1095b4b95b05SVandita Kulkarni if (enable) {
1096b4b95b05SVandita Kulkarni tmp |= UTIL_PIN_DIRECTION_INPUT;
1097b4b95b05SVandita Kulkarni tmp |= UTIL_PIN_ENABLE;
1098b4b95b05SVandita Kulkarni } else {
1099b4b95b05SVandita Kulkarni tmp &= ~UTIL_PIN_ENABLE;
1100b4b95b05SVandita Kulkarni }
1101b4b95b05SVandita Kulkarni intel_de_write(dev_priv, UTIL_PIN_CTL, tmp);
1102b4b95b05SVandita Kulkarni }
1103b4b95b05SVandita Kulkarni
1104379bc100SJani Nikula static void
gen11_dsi_enable_port_and_phy(struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state)1105379bc100SJani Nikula gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder,
110604865139SJani Nikula const struct intel_crtc_state *crtc_state)
1107379bc100SJani Nikula {
1108379bc100SJani Nikula /* step 4a: power up all lanes of the DDI used by DSI */
1109379bc100SJani Nikula gen11_dsi_power_up_lanes(encoder);
1110379bc100SJani Nikula
1111379bc100SJani Nikula /* step 4b: configure lane sequencing of the Combo-PHY transmitters */
1112379bc100SJani Nikula gen11_dsi_config_phy_lanes_sequence(encoder);
1113379bc100SJani Nikula
1114379bc100SJani Nikula /* step 4c: configure voltage swing and skew */
1115379bc100SJani Nikula gen11_dsi_voltage_swing_program_seq(encoder);
1116379bc100SJani Nikula
1117d4121327SVille Syrjälä /* setup D-PHY timings */
1118d4121327SVille Syrjälä gen11_dsi_setup_dphy_timings(encoder, crtc_state);
1119d4121327SVille Syrjälä
1120379bc100SJani Nikula /* enable DDI buffer */
1121379bc100SJani Nikula gen11_dsi_enable_ddi_buffer(encoder);
1122379bc100SJani Nikula
1123a43d9281SVille Syrjälä gen11_dsi_gate_clocks(encoder);
1124a43d9281SVille Syrjälä
1125d4121327SVille Syrjälä gen11_dsi_setup_timings(encoder, crtc_state);
1126379bc100SJani Nikula
1127b4b95b05SVandita Kulkarni /* Since transcoder is configured to take events from GPIO */
1128b4b95b05SVandita Kulkarni gen11_dsi_config_util_pin(encoder, true);
1129b4b95b05SVandita Kulkarni
1130379bc100SJani Nikula /* step 4h: setup DSI protocol timeouts */
113104865139SJani Nikula gen11_dsi_setup_timeouts(encoder, crtc_state);
1132379bc100SJani Nikula
1133379bc100SJani Nikula /* Step (4h, 4i, 4j, 4k): Configure transcoder */
113404865139SJani Nikula gen11_dsi_configure_transcoder(encoder, crtc_state);
1135379bc100SJani Nikula }
1136379bc100SJani Nikula
gen11_dsi_powerup_panel(struct intel_encoder * encoder)1137379bc100SJani Nikula static void gen11_dsi_powerup_panel(struct intel_encoder *encoder)
1138379bc100SJani Nikula {
1139379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
1140b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
1141379bc100SJani Nikula struct mipi_dsi_device *dsi;
1142379bc100SJani Nikula enum port port;
1143379bc100SJani Nikula enum transcoder dsi_trans;
1144379bc100SJani Nikula u32 tmp;
1145379bc100SJani Nikula int ret;
1146379bc100SJani Nikula
1147379bc100SJani Nikula /* set maximum return packet size */
1148379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
1149379bc100SJani Nikula dsi_trans = dsi_port_to_transcoder(port);
1150379bc100SJani Nikula
1151379bc100SJani Nikula /*
1152379bc100SJani Nikula * FIXME: This uses the number of DW's currently in the payload
1153379bc100SJani Nikula * receive queue. This is probably not what we want here.
1154379bc100SJani Nikula */
11551c63f6dfSJani Nikula tmp = intel_de_read(dev_priv, DSI_CMD_RXCTL(dsi_trans));
1156379bc100SJani Nikula tmp &= NUMBER_RX_PLOAD_DW_MASK;
1157379bc100SJani Nikula /* multiply "Number Rx Payload DW" by 4 to get max value */
1158379bc100SJani Nikula tmp = tmp * 4;
1159379bc100SJani Nikula dsi = intel_dsi->dsi_hosts[port]->device;
1160379bc100SJani Nikula ret = mipi_dsi_set_maximum_return_packet_size(dsi, tmp);
1161379bc100SJani Nikula if (ret < 0)
1162b5280cd0SWambui Karuga drm_err(&dev_priv->drm,
1163b5280cd0SWambui Karuga "error setting max return pkt size%d\n", tmp);
1164379bc100SJani Nikula }
1165379bc100SJani Nikula
1166379bc100SJani Nikula intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP);
1167379bc100SJani Nikula
1168379bc100SJani Nikula /* ensure all panel commands dispatched before enabling transcoder */
1169379bc100SJani Nikula wait_for_cmds_dispatched_to_panel(encoder);
1170379bc100SJani Nikula }
1171379bc100SJani Nikula
gen11_dsi_pre_pll_enable(struct intel_atomic_state * state,struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state)1172ede9771dSVille Syrjälä static void gen11_dsi_pre_pll_enable(struct intel_atomic_state *state,
1173ede9771dSVille Syrjälä struct intel_encoder *encoder,
117404865139SJani Nikula const struct intel_crtc_state *crtc_state,
1175379bc100SJani Nikula const struct drm_connector_state *conn_state)
1176379bc100SJani Nikula {
117786ecd3b3SVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
117886ecd3b3SVille Syrjälä
1179201963a8SVille Syrjälä intel_dsi_wait_panel_power_cycle(intel_dsi);
1180201963a8SVille Syrjälä
118186ecd3b3SVille Syrjälä intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_ON);
118286ecd3b3SVille Syrjälä msleep(intel_dsi->panel_on_delay);
118386ecd3b3SVille Syrjälä intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET);
118486ecd3b3SVille Syrjälä
1185379bc100SJani Nikula /* step2: enable IO power */
1186379bc100SJani Nikula gen11_dsi_enable_io_power(encoder);
1187379bc100SJani Nikula
1188379bc100SJani Nikula /* step3: enable DSI PLL */
118904865139SJani Nikula gen11_dsi_program_esc_clk_div(encoder, crtc_state);
1190379bc100SJani Nikula }
1191379bc100SJani Nikula
gen11_dsi_pre_enable(struct intel_atomic_state * state,struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)1192ede9771dSVille Syrjälä static void gen11_dsi_pre_enable(struct intel_atomic_state *state,
1193ede9771dSVille Syrjälä struct intel_encoder *encoder,
1194379bc100SJani Nikula const struct intel_crtc_state *pipe_config,
1195379bc100SJani Nikula const struct drm_connector_state *conn_state)
1196379bc100SJani Nikula {
1197379bc100SJani Nikula /* step3b */
1198379bc100SJani Nikula gen11_dsi_map_pll(encoder, pipe_config);
1199379bc100SJani Nikula
1200379bc100SJani Nikula /* step4: enable DSI port and DPHY */
1201379bc100SJani Nikula gen11_dsi_enable_port_and_phy(encoder, pipe_config);
1202379bc100SJani Nikula
1203379bc100SJani Nikula /* step5: program and powerup panel */
1204379bc100SJani Nikula gen11_dsi_powerup_panel(encoder);
1205379bc100SJani Nikula
12063126977dSVille Syrjälä intel_dsc_dsi_pps_write(encoder, pipe_config);
12073126977dSVille Syrjälä
1208379bc100SJani Nikula /* step6c: configure transcoder timings */
1209379bc100SJani Nikula gen11_dsi_set_transcoder_timings(encoder, pipe_config);
1210379bc100SJani Nikula }
1211379bc100SJani Nikula
1212544021e3STejas Upadhyay /*
1213544021e3STejas Upadhyay * Wa_1409054076:icl,jsl,ehl
1214544021e3STejas Upadhyay * When pipe A is disabled and MIPI DSI is enabled on pipe B,
1215544021e3STejas Upadhyay * the AMT KVMR feature will incorrectly see pipe A as enabled.
1216544021e3STejas Upadhyay * Set 0x42080 bit 23=1 before enabling DSI on pipe B and leave
1217544021e3STejas Upadhyay * it set while DSI is enabled on pipe B
1218544021e3STejas Upadhyay */
icl_apply_kvmr_pipe_a_wa(struct intel_encoder * encoder,enum pipe pipe,bool enable)1219544021e3STejas Upadhyay static void icl_apply_kvmr_pipe_a_wa(struct intel_encoder *encoder,
1220544021e3STejas Upadhyay enum pipe pipe, bool enable)
1221544021e3STejas Upadhyay {
1222544021e3STejas Upadhyay struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
1223544021e3STejas Upadhyay
1224544021e3STejas Upadhyay if (DISPLAY_VER(dev_priv) == 11 && pipe == PIPE_B)
1225544021e3STejas Upadhyay intel_de_rmw(dev_priv, CHICKEN_PAR1_1,
1226544021e3STejas Upadhyay IGNORE_KVMR_PIPE_A,
1227544021e3STejas Upadhyay enable ? IGNORE_KVMR_PIPE_A : 0);
1228544021e3STejas Upadhyay }
1229f87c46c4SVandita Kulkarni
1230f87c46c4SVandita Kulkarni /*
1231f87c46c4SVandita Kulkarni * Wa_16012360555:adl-p
1232f87c46c4SVandita Kulkarni * SW will have to program the "LP to HS Wakeup Guardband"
1233f87c46c4SVandita Kulkarni * to account for the repeaters on the HS Request/Ready
1234f87c46c4SVandita Kulkarni * PPI signaling between the Display engine and the DPHY.
1235f87c46c4SVandita Kulkarni */
adlp_set_lp_hs_wakeup_gb(struct intel_encoder * encoder)1236f87c46c4SVandita Kulkarni static void adlp_set_lp_hs_wakeup_gb(struct intel_encoder *encoder)
1237f87c46c4SVandita Kulkarni {
1238f87c46c4SVandita Kulkarni struct drm_i915_private *i915 = to_i915(encoder->base.dev);
1239f87c46c4SVandita Kulkarni struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
1240f87c46c4SVandita Kulkarni enum port port;
1241f87c46c4SVandita Kulkarni
1242f87c46c4SVandita Kulkarni if (DISPLAY_VER(i915) == 13) {
1243f87c46c4SVandita Kulkarni for_each_dsi_port(port, intel_dsi->ports)
1244f87c46c4SVandita Kulkarni intel_de_rmw(i915, TGL_DSI_CHKN_REG(port),
12456f07707fSVandita Kulkarni TGL_DSI_CHKN_LSHS_GB_MASK,
12466f07707fSVandita Kulkarni TGL_DSI_CHKN_LSHS_GB(4));
1247f87c46c4SVandita Kulkarni }
1248f87c46c4SVandita Kulkarni }
1249f87c46c4SVandita Kulkarni
gen11_dsi_enable(struct intel_atomic_state * state,struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state)1250ede9771dSVille Syrjälä static void gen11_dsi_enable(struct intel_atomic_state *state,
1251ede9771dSVille Syrjälä struct intel_encoder *encoder,
125221fd23acSJani Nikula const struct intel_crtc_state *crtc_state,
125321fd23acSJani Nikula const struct drm_connector_state *conn_state)
125421fd23acSJani Nikula {
125587e9bb49SVandita Kulkarni struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
12563d41ec41SVille Syrjälä struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
125787e9bb49SVandita Kulkarni
1258544021e3STejas Upadhyay /* Wa_1409054076:icl,jsl,ehl */
1259544021e3STejas Upadhyay icl_apply_kvmr_pipe_a_wa(encoder, crtc->pipe, true);
1260544021e3STejas Upadhyay
1261f87c46c4SVandita Kulkarni /* Wa_16012360555:adl-p */
1262f87c46c4SVandita Kulkarni adlp_set_lp_hs_wakeup_gb(encoder);
1263f87c46c4SVandita Kulkarni
126487e9bb49SVandita Kulkarni /* step6d: enable dsi transcoder */
126587e9bb49SVandita Kulkarni gen11_dsi_enable_transcoder(encoder);
126687e9bb49SVandita Kulkarni
126794ae4612SVille Syrjälä intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON);
126894ae4612SVille Syrjälä
126987e9bb49SVandita Kulkarni /* step7: enable backlight */
1270c0a52f8bSJani Nikula intel_backlight_enable(crtc_state, conn_state);
127187e9bb49SVandita Kulkarni intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON);
127287e9bb49SVandita Kulkarni
127321fd23acSJani Nikula intel_crtc_vblank_on(crtc_state);
127421fd23acSJani Nikula }
127521fd23acSJani Nikula
gen11_dsi_disable_transcoder(struct intel_encoder * encoder)1276379bc100SJani Nikula static void gen11_dsi_disable_transcoder(struct intel_encoder *encoder)
1277379bc100SJani Nikula {
1278379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
1279b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
1280379bc100SJani Nikula enum port port;
1281379bc100SJani Nikula enum transcoder dsi_trans;
1282379bc100SJani Nikula
1283379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
1284379bc100SJani Nikula dsi_trans = dsi_port_to_transcoder(port);
1285379bc100SJani Nikula
1286379bc100SJani Nikula /* disable transcoder */
1287984b61c3SJani Nikula intel_de_rmw(dev_priv, TRANSCONF(dev_priv, dsi_trans),
1288984b61c3SJani Nikula TRANSCONF_ENABLE, 0);
1289379bc100SJani Nikula
1290379bc100SJani Nikula /* wait for transcoder to be disabled */
1291984b61c3SJani Nikula if (intel_de_wait_for_clear(dev_priv, TRANSCONF(dev_priv, dsi_trans),
12923eb08ea5SVille Syrjälä TRANSCONF_STATE_ENABLE, 50))
1293b5280cd0SWambui Karuga drm_err(&dev_priv->drm,
1294b5280cd0SWambui Karuga "DSI trancoder not disabled\n");
1295379bc100SJani Nikula }
1296379bc100SJani Nikula }
1297379bc100SJani Nikula
gen11_dsi_powerdown_panel(struct intel_encoder * encoder)1298379bc100SJani Nikula static void gen11_dsi_powerdown_panel(struct intel_encoder *encoder)
1299379bc100SJani Nikula {
1300b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
1301379bc100SJani Nikula
1302379bc100SJani Nikula intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_OFF);
1303201963a8SVille Syrjälä
1304379bc100SJani Nikula /* ensure cmds dispatched to panel */
1305379bc100SJani Nikula wait_for_cmds_dispatched_to_panel(encoder);
1306379bc100SJani Nikula }
1307379bc100SJani Nikula
gen11_dsi_deconfigure_trancoder(struct intel_encoder * encoder)1308379bc100SJani Nikula static void gen11_dsi_deconfigure_trancoder(struct intel_encoder *encoder)
1309379bc100SJani Nikula {
1310379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
1311b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
1312379bc100SJani Nikula enum port port;
1313379bc100SJani Nikula enum transcoder dsi_trans;
1314379bc100SJani Nikula u32 tmp;
1315379bc100SJani Nikula
1316b4b95b05SVandita Kulkarni /* disable periodic update mode */
1317b4b95b05SVandita Kulkarni if (is_cmd_mode(intel_dsi)) {
13181a45d681SAndrzej Hajda for_each_dsi_port(port, intel_dsi->ports)
13191a45d681SAndrzej Hajda intel_de_rmw(dev_priv, DSI_CMD_FRMCTL(port),
13201a45d681SAndrzej Hajda DSI_PERIODIC_FRAME_UPDATE_ENABLE, 0);
1321b4b95b05SVandita Kulkarni }
1322b4b95b05SVandita Kulkarni
1323379bc100SJani Nikula /* put dsi link in ULPS */
1324379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
1325379bc100SJani Nikula dsi_trans = dsi_port_to_transcoder(port);
13261c63f6dfSJani Nikula tmp = intel_de_read(dev_priv, DSI_LP_MSG(dsi_trans));
1327379bc100SJani Nikula tmp |= LINK_ENTER_ULPS;
1328379bc100SJani Nikula tmp &= ~LINK_ULPS_TYPE_LP11;
13291c63f6dfSJani Nikula intel_de_write(dev_priv, DSI_LP_MSG(dsi_trans), tmp);
1330379bc100SJani Nikula
13311c63f6dfSJani Nikula if (wait_for_us((intel_de_read(dev_priv, DSI_LP_MSG(dsi_trans)) &
1332379bc100SJani Nikula LINK_IN_ULPS),
1333379bc100SJani Nikula 10))
1334b5280cd0SWambui Karuga drm_err(&dev_priv->drm, "DSI link not in ULPS\n");
1335379bc100SJani Nikula }
1336379bc100SJani Nikula
1337379bc100SJani Nikula /* disable ddi function */
1338379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
1339379bc100SJani Nikula dsi_trans = dsi_port_to_transcoder(port);
1340b092d6adSJani Nikula intel_de_rmw(dev_priv,
1341b092d6adSJani Nikula TRANS_DDI_FUNC_CTL(dev_priv, dsi_trans),
13421a45d681SAndrzej Hajda TRANS_DDI_FUNC_ENABLE, 0);
1343379bc100SJani Nikula }
1344379bc100SJani Nikula
1345379bc100SJani Nikula /* disable port sync mode if dual link */
1346379bc100SJani Nikula if (intel_dsi->dual_link) {
1347379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
1348379bc100SJani Nikula dsi_trans = dsi_port_to_transcoder(port);
134976f1b2b1SJani Nikula intel_de_rmw(dev_priv,
135076f1b2b1SJani Nikula TRANS_DDI_FUNC_CTL2(dev_priv, dsi_trans),
13511a45d681SAndrzej Hajda PORT_SYNC_MODE_ENABLE, 0);
1352379bc100SJani Nikula }
1353379bc100SJani Nikula }
1354379bc100SJani Nikula }
1355379bc100SJani Nikula
gen11_dsi_disable_port(struct intel_encoder * encoder)1356379bc100SJani Nikula static void gen11_dsi_disable_port(struct intel_encoder *encoder)
1357379bc100SJani Nikula {
1358379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
1359b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
1360379bc100SJani Nikula enum port port;
1361379bc100SJani Nikula
1362379bc100SJani Nikula gen11_dsi_ungate_clocks(encoder);
1363379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
13641a45d681SAndrzej Hajda intel_de_rmw(dev_priv, DDI_BUF_CTL(port), DDI_BUF_CTL_ENABLE, 0);
1365379bc100SJani Nikula
13661c63f6dfSJani Nikula if (wait_for_us((intel_de_read(dev_priv, DDI_BUF_CTL(port)) &
1367379bc100SJani Nikula DDI_BUF_IS_IDLE),
1368379bc100SJani Nikula 8))
1369b5280cd0SWambui Karuga drm_err(&dev_priv->drm,
1370b5280cd0SWambui Karuga "DDI port:%c buffer not idle\n",
1371379bc100SJani Nikula port_name(port));
1372379bc100SJani Nikula }
1373379bc100SJani Nikula gen11_dsi_gate_clocks(encoder);
1374379bc100SJani Nikula }
1375379bc100SJani Nikula
gen11_dsi_disable_io_power(struct intel_encoder * encoder)1376379bc100SJani Nikula static void gen11_dsi_disable_io_power(struct intel_encoder *encoder)
1377379bc100SJani Nikula {
1378379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
1379b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
1380379bc100SJani Nikula enum port port;
1381379bc100SJani Nikula
1382379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
1383379bc100SJani Nikula intel_wakeref_t wakeref;
1384379bc100SJani Nikula
1385379bc100SJani Nikula wakeref = fetch_and_zero(&intel_dsi->io_wakeref[port]);
1386379bc100SJani Nikula intel_display_power_put(dev_priv,
1387379bc100SJani Nikula port == PORT_A ?
13880ba2661dSImre Deak POWER_DOMAIN_PORT_DDI_IO_A :
13890ba2661dSImre Deak POWER_DOMAIN_PORT_DDI_IO_B,
1390379bc100SJani Nikula wakeref);
1391379bc100SJani Nikula }
1392379bc100SJani Nikula
1393379bc100SJani Nikula /* set mode to DDI */
13941a45d681SAndrzej Hajda for_each_dsi_port(port, intel_dsi->ports)
13951a45d681SAndrzej Hajda intel_de_rmw(dev_priv, ICL_DSI_IO_MODECTL(port),
13961a45d681SAndrzej Hajda COMBO_PHY_MODE_DSI, 0);
1397379bc100SJani Nikula }
1398379bc100SJani Nikula
gen11_dsi_disable(struct intel_atomic_state * state,struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)1399ede9771dSVille Syrjälä static void gen11_dsi_disable(struct intel_atomic_state *state,
1400ede9771dSVille Syrjälä struct intel_encoder *encoder,
1401379bc100SJani Nikula const struct intel_crtc_state *old_crtc_state,
1402379bc100SJani Nikula const struct drm_connector_state *old_conn_state)
1403379bc100SJani Nikula {
1404b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
1405379bc100SJani Nikula
1406379bc100SJani Nikula /* step1: turn off backlight */
1407379bc100SJani Nikula intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_OFF);
1408c0a52f8bSJani Nikula intel_backlight_disable(old_conn_state);
1409a57aa1e3SVille Syrjälä }
1410a57aa1e3SVille Syrjälä
gen11_dsi_post_disable(struct intel_atomic_state * state,struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)1411a57aa1e3SVille Syrjälä static void gen11_dsi_post_disable(struct intel_atomic_state *state,
1412a57aa1e3SVille Syrjälä struct intel_encoder *encoder,
1413a57aa1e3SVille Syrjälä const struct intel_crtc_state *old_crtc_state,
1414a57aa1e3SVille Syrjälä const struct drm_connector_state *old_conn_state)
1415a57aa1e3SVille Syrjälä {
14165263a63cSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
14173d41ec41SVille Syrjälä struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
1418a57aa1e3SVille Syrjälä
1419a57aa1e3SVille Syrjälä intel_crtc_vblank_off(old_crtc_state);
1420379bc100SJani Nikula
1421379bc100SJani Nikula /* step2d,e: disable transcoder and wait */
1422379bc100SJani Nikula gen11_dsi_disable_transcoder(encoder);
1423379bc100SJani Nikula
1424544021e3STejas Upadhyay /* Wa_1409054076:icl,jsl,ehl */
1425544021e3STejas Upadhyay icl_apply_kvmr_pipe_a_wa(encoder, crtc->pipe, false);
1426544021e3STejas Upadhyay
1427379bc100SJani Nikula /* step2f,g: powerdown panel */
1428379bc100SJani Nikula gen11_dsi_powerdown_panel(encoder);
1429379bc100SJani Nikula
1430379bc100SJani Nikula /* step2h,i,j: deconfig trancoder */
1431379bc100SJani Nikula gen11_dsi_deconfigure_trancoder(encoder);
1432379bc100SJani Nikula
143329428c85SVille Syrjälä intel_dsc_disable(old_crtc_state);
143429428c85SVille Syrjälä skl_scaler_disable(old_crtc_state);
143529428c85SVille Syrjälä
1436379bc100SJani Nikula /* step3: disable port */
1437379bc100SJani Nikula gen11_dsi_disable_port(encoder);
1438379bc100SJani Nikula
1439b4b95b05SVandita Kulkarni gen11_dsi_config_util_pin(encoder, false);
1440b4b95b05SVandita Kulkarni
1441379bc100SJani Nikula /* step4: disable IO power */
1442379bc100SJani Nikula gen11_dsi_disable_io_power(encoder);
14435263a63cSVille Syrjälä
14445263a63cSVille Syrjälä intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_ASSERT_RESET);
14455263a63cSVille Syrjälä
14465263a63cSVille Syrjälä msleep(intel_dsi->panel_off_delay);
14475263a63cSVille Syrjälä intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_OFF);
14485263a63cSVille Syrjälä
14495263a63cSVille Syrjälä intel_dsi->panel_power_off_time = ktime_get_boottime();
1450773b4b54SVille Syrjälä }
1451773b4b54SVille Syrjälä
gen11_dsi_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)14522b68392eSJani Nikula static enum drm_mode_status gen11_dsi_mode_valid(struct drm_connector *connector,
14532b68392eSJani Nikula struct drm_display_mode *mode)
14542b68392eSJani Nikula {
1455e0ef2daaSVille Syrjälä struct drm_i915_private *i915 = to_i915(connector->dev);
1456e0ef2daaSVille Syrjälä enum drm_mode_status status;
1457e0ef2daaSVille Syrjälä
1458e0ef2daaSVille Syrjälä status = intel_cpu_transcoder_mode_valid(i915, mode);
1459e0ef2daaSVille Syrjälä if (status != MODE_OK)
1460e0ef2daaSVille Syrjälä return status;
1461e0ef2daaSVille Syrjälä
14622b68392eSJani Nikula /* FIXME: DSC? */
14632b68392eSJani Nikula return intel_dsi_mode_valid(connector, mode);
14642b68392eSJani Nikula }
14652b68392eSJani Nikula
gen11_dsi_get_timings(struct intel_encoder * encoder,struct intel_crtc_state * pipe_config)1466379bc100SJani Nikula static void gen11_dsi_get_timings(struct intel_encoder *encoder,
1467379bc100SJani Nikula struct intel_crtc_state *pipe_config)
1468379bc100SJani Nikula {
1469b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
1470379bc100SJani Nikula struct drm_display_mode *adjusted_mode =
14711326a92cSMaarten Lankhorst &pipe_config->hw.adjusted_mode;
1472379bc100SJani Nikula
147359a266f0SAnkit Nautiyal if (pipe_config->dsc.compressed_bpp_x16) {
14748466a141SImre Deak int div = fxp_q4_to_int(pipe_config->dsc.compressed_bpp_x16);
1475c2bb35e9SVandita Kulkarni int mul = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
1476c2bb35e9SVandita Kulkarni
1477c2bb35e9SVandita Kulkarni adjusted_mode->crtc_htotal =
1478c2bb35e9SVandita Kulkarni DIV_ROUND_UP(adjusted_mode->crtc_htotal * mul, div);
1479c2bb35e9SVandita Kulkarni adjusted_mode->crtc_hsync_start =
1480c2bb35e9SVandita Kulkarni DIV_ROUND_UP(adjusted_mode->crtc_hsync_start * mul, div);
1481c2bb35e9SVandita Kulkarni adjusted_mode->crtc_hsync_end =
1482c2bb35e9SVandita Kulkarni DIV_ROUND_UP(adjusted_mode->crtc_hsync_end * mul, div);
1483c2bb35e9SVandita Kulkarni }
1484c2bb35e9SVandita Kulkarni
1485379bc100SJani Nikula if (intel_dsi->dual_link) {
1486379bc100SJani Nikula adjusted_mode->crtc_hdisplay *= 2;
1487379bc100SJani Nikula if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
1488379bc100SJani Nikula adjusted_mode->crtc_hdisplay -=
1489379bc100SJani Nikula intel_dsi->pixel_overlap;
1490379bc100SJani Nikula adjusted_mode->crtc_htotal *= 2;
1491379bc100SJani Nikula }
1492379bc100SJani Nikula adjusted_mode->crtc_hblank_start = adjusted_mode->crtc_hdisplay;
1493379bc100SJani Nikula adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_htotal;
1494379bc100SJani Nikula
1495379bc100SJani Nikula if (intel_dsi->operation_mode == INTEL_DSI_VIDEO_MODE) {
1496379bc100SJani Nikula if (intel_dsi->dual_link) {
1497379bc100SJani Nikula adjusted_mode->crtc_hsync_start *= 2;
1498379bc100SJani Nikula adjusted_mode->crtc_hsync_end *= 2;
1499379bc100SJani Nikula }
1500379bc100SJani Nikula }
1501379bc100SJani Nikula adjusted_mode->crtc_vblank_start = adjusted_mode->crtc_vdisplay;
1502379bc100SJani Nikula adjusted_mode->crtc_vblank_end = adjusted_mode->crtc_vtotal;
1503379bc100SJani Nikula }
1504379bc100SJani Nikula
gen11_dsi_is_periodic_cmd_mode(struct intel_dsi * intel_dsi)1505cebb28acSVandita Kulkarni static bool gen11_dsi_is_periodic_cmd_mode(struct intel_dsi *intel_dsi)
1506cebb28acSVandita Kulkarni {
1507cebb28acSVandita Kulkarni struct drm_device *dev = intel_dsi->base.base.dev;
1508cebb28acSVandita Kulkarni struct drm_i915_private *dev_priv = to_i915(dev);
1509cebb28acSVandita Kulkarni enum transcoder dsi_trans;
1510cebb28acSVandita Kulkarni u32 val;
1511cebb28acSVandita Kulkarni
1512cebb28acSVandita Kulkarni if (intel_dsi->ports == BIT(PORT_B))
1513cebb28acSVandita Kulkarni dsi_trans = TRANSCODER_DSI_1;
1514cebb28acSVandita Kulkarni else
1515cebb28acSVandita Kulkarni dsi_trans = TRANSCODER_DSI_0;
1516cebb28acSVandita Kulkarni
1517cebb28acSVandita Kulkarni val = intel_de_read(dev_priv, DSI_TRANS_FUNC_CONF(dsi_trans));
1518cebb28acSVandita Kulkarni return (val & DSI_PERIODIC_FRAME_UPDATE_ENABLE);
1519cebb28acSVandita Kulkarni }
1520cebb28acSVandita Kulkarni
gen11_dsi_get_cmd_mode_config(struct intel_dsi * intel_dsi,struct intel_crtc_state * pipe_config)15215682a41fSVandita Kulkarni static void gen11_dsi_get_cmd_mode_config(struct intel_dsi *intel_dsi,
15225682a41fSVandita Kulkarni struct intel_crtc_state *pipe_config)
15235682a41fSVandita Kulkarni {
15245682a41fSVandita Kulkarni if (intel_dsi->ports == (BIT(PORT_B) | BIT(PORT_A)))
15255682a41fSVandita Kulkarni pipe_config->mode_flags |= I915_MODE_FLAG_DSI_USE_TE1 |
15265682a41fSVandita Kulkarni I915_MODE_FLAG_DSI_USE_TE0;
15275682a41fSVandita Kulkarni else if (intel_dsi->ports == BIT(PORT_B))
15285682a41fSVandita Kulkarni pipe_config->mode_flags |= I915_MODE_FLAG_DSI_USE_TE1;
15295682a41fSVandita Kulkarni else
15305682a41fSVandita Kulkarni pipe_config->mode_flags |= I915_MODE_FLAG_DSI_USE_TE0;
15315682a41fSVandita Kulkarni }
15325682a41fSVandita Kulkarni
gen11_dsi_get_config(struct intel_encoder * encoder,struct intel_crtc_state * pipe_config)1533379bc100SJani Nikula static void gen11_dsi_get_config(struct intel_encoder *encoder,
1534379bc100SJani Nikula struct intel_crtc_state *pipe_config)
1535379bc100SJani Nikula {
15362225f3c6SMaarten Lankhorst struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
1537b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
1538379bc100SJani Nikula
1539351221ffSVille Syrjälä intel_ddi_get_clock(encoder, pipe_config, icl_ddi_combo_get_pll(encoder));
1540379bc100SJani Nikula
15411326a92cSMaarten Lankhorst pipe_config->hw.adjusted_mode.crtc_clock = intel_dsi->pclk;
1542379bc100SJani Nikula if (intel_dsi->dual_link)
15431326a92cSMaarten Lankhorst pipe_config->hw.adjusted_mode.crtc_clock *= 2;
1544379bc100SJani Nikula
1545379bc100SJani Nikula gen11_dsi_get_timings(encoder, pipe_config);
1546379bc100SJani Nikula pipe_config->output_types |= BIT(INTEL_OUTPUT_DSI);
1547c640f6c5SVille Syrjälä pipe_config->pipe_bpp = bdw_get_pipe_misc_bpp(crtc);
1548cebb28acSVandita Kulkarni
15495682a41fSVandita Kulkarni /* Get the details on which TE should be enabled */
15505682a41fSVandita Kulkarni if (is_cmd_mode(intel_dsi))
15515682a41fSVandita Kulkarni gen11_dsi_get_cmd_mode_config(intel_dsi, pipe_config);
15525682a41fSVandita Kulkarni
1553cebb28acSVandita Kulkarni if (gen11_dsi_is_periodic_cmd_mode(intel_dsi))
1554af157b76SVille Syrjälä pipe_config->mode_flags |= I915_MODE_FLAG_DSI_PERIODIC_CMD_MODE;
1555379bc100SJani Nikula }
1556379bc100SJani Nikula
gen11_dsi_sync_state(struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state)1557544021e3STejas Upadhyay static void gen11_dsi_sync_state(struct intel_encoder *encoder,
1558544021e3STejas Upadhyay const struct intel_crtc_state *crtc_state)
1559544021e3STejas Upadhyay {
1560544021e3STejas Upadhyay struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
15617194dc99SImre Deak struct intel_crtc *intel_crtc;
15627194dc99SImre Deak enum pipe pipe;
15637194dc99SImre Deak
15647194dc99SImre Deak if (!crtc_state)
15657194dc99SImre Deak return;
15667194dc99SImre Deak
15677194dc99SImre Deak intel_crtc = to_intel_crtc(crtc_state->uapi.crtc);
15687194dc99SImre Deak pipe = intel_crtc->pipe;
1569544021e3STejas Upadhyay
1570544021e3STejas Upadhyay /* wa verify 1409054076:icl,jsl,ehl */
1571544021e3STejas Upadhyay if (DISPLAY_VER(dev_priv) == 11 && pipe == PIPE_B &&
1572544021e3STejas Upadhyay !(intel_de_read(dev_priv, CHICKEN_PAR1_1) & IGNORE_KVMR_PIPE_A))
1573544021e3STejas Upadhyay drm_dbg_kms(&dev_priv->drm,
1574544021e3STejas Upadhyay "[ENCODER:%d:%s] BIOS left IGNORE_KVMR_PIPE_A cleared with pipe B enabled\n",
1575544021e3STejas Upadhyay encoder->base.base.id,
1576544021e3STejas Upadhyay encoder->base.name);
1577544021e3STejas Upadhyay }
1578544021e3STejas Upadhyay
gen11_dsi_dsc_compute_config(struct intel_encoder * encoder,struct intel_crtc_state * crtc_state)15792b68392eSJani Nikula static int gen11_dsi_dsc_compute_config(struct intel_encoder *encoder,
15802b68392eSJani Nikula struct intel_crtc_state *crtc_state)
15812b68392eSJani Nikula {
15822b68392eSJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
15832b68392eSJani Nikula struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config;
1584005e9537SMatt Roper int dsc_max_bpc = DISPLAY_VER(dev_priv) >= 12 ? 12 : 10;
15852b68392eSJani Nikula bool use_dsc;
15862b68392eSJani Nikula int ret;
15872b68392eSJani Nikula
15882b68392eSJani Nikula use_dsc = intel_bios_get_dsc_params(encoder, crtc_state, dsc_max_bpc);
15892b68392eSJani Nikula if (!use_dsc)
15902b68392eSJani Nikula return 0;
15912b68392eSJani Nikula
15922b68392eSJani Nikula if (crtc_state->pipe_bpp < 8 * 3)
15932b68392eSJani Nikula return -EINVAL;
15942b68392eSJani Nikula
15952b68392eSJani Nikula /* FIXME: split only when necessary */
15962b68392eSJani Nikula if (crtc_state->dsc.slice_count > 1)
15972b68392eSJani Nikula crtc_state->dsc.dsc_split = true;
15982b68392eSJani Nikula
1599420798a0SJani Nikula /* FIXME: initialize from VBT */
1600420798a0SJani Nikula vdsc_cfg->rc_model_size = DSC_RC_MODEL_SIZE_CONST;
1601420798a0SJani Nikula
1602e72df53dSAnkit Nautiyal vdsc_cfg->pic_height = crtc_state->hw.adjusted_mode.crtc_vdisplay;
1603e72df53dSAnkit Nautiyal
16043126977dSVille Syrjälä ret = intel_dsc_compute_params(crtc_state);
16052b68392eSJani Nikula if (ret)
16062b68392eSJani Nikula return ret;
16072b68392eSJani Nikula
16082b68392eSJani Nikula /* DSI specific sanity checks on the common code */
16093dbe5e11SPankaj Bharadiya drm_WARN_ON(&dev_priv->drm, vdsc_cfg->vbr_enable);
16103dbe5e11SPankaj Bharadiya drm_WARN_ON(&dev_priv->drm, vdsc_cfg->simple_422);
16113dbe5e11SPankaj Bharadiya drm_WARN_ON(&dev_priv->drm,
16123dbe5e11SPankaj Bharadiya vdsc_cfg->pic_width % vdsc_cfg->slice_width);
16133dbe5e11SPankaj Bharadiya drm_WARN_ON(&dev_priv->drm, vdsc_cfg->slice_height < 8);
16143dbe5e11SPankaj Bharadiya drm_WARN_ON(&dev_priv->drm,
16153dbe5e11SPankaj Bharadiya vdsc_cfg->pic_height % vdsc_cfg->slice_height);
16162b68392eSJani Nikula
16172b68392eSJani Nikula ret = drm_dsc_compute_rc_parameters(vdsc_cfg);
16182b68392eSJani Nikula if (ret)
16192b68392eSJani Nikula return ret;
16202b68392eSJani Nikula
16212b68392eSJani Nikula crtc_state->dsc.compression_enable = true;
16222b68392eSJani Nikula
16232b68392eSJani Nikula return 0;
16242b68392eSJani Nikula }
16252b68392eSJani Nikula
gen11_dsi_compute_config(struct intel_encoder * encoder,struct intel_crtc_state * pipe_config,struct drm_connector_state * conn_state)1626379bc100SJani Nikula static int gen11_dsi_compute_config(struct intel_encoder *encoder,
1627379bc100SJani Nikula struct intel_crtc_state *pipe_config,
1628379bc100SJani Nikula struct drm_connector_state *conn_state)
1629379bc100SJani Nikula {
1630dd10a80fSJani Nikula struct drm_i915_private *i915 = to_i915(encoder->base.dev);
16319eae5bacSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
1632379bc100SJani Nikula struct intel_connector *intel_connector = intel_dsi->attached_connector;
1633379bc100SJani Nikula struct drm_display_mode *adjusted_mode =
16341326a92cSMaarten Lankhorst &pipe_config->hw.adjusted_mode;
1635d7ff281cSVille Syrjälä int ret;
1636379bc100SJani Nikula
1637a04d27cdSAnkit Nautiyal pipe_config->sink_format = INTEL_OUTPUT_FORMAT_RGB;
1638379bc100SJani Nikula pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
1639cff4c2c6SVille Syrjälä
1640cff4c2c6SVille Syrjälä ret = intel_panel_compute_config(intel_connector, adjusted_mode);
1641cff4c2c6SVille Syrjälä if (ret)
1642cff4c2c6SVille Syrjälä return ret;
1643d7ff281cSVille Syrjälä
16444b93f49dSJani Nikula ret = intel_panel_fitting(pipe_config, conn_state);
1645d7ff281cSVille Syrjälä if (ret)
1646d7ff281cSVille Syrjälä return ret;
1647379bc100SJani Nikula
1648379bc100SJani Nikula adjusted_mode->flags = 0;
1649379bc100SJani Nikula
1650379bc100SJani Nikula /* Dual link goes to trancoder DSI'0' */
1651379bc100SJani Nikula if (intel_dsi->ports == BIT(PORT_B))
1652379bc100SJani Nikula pipe_config->cpu_transcoder = TRANSCODER_DSI_1;
1653379bc100SJani Nikula else
1654379bc100SJani Nikula pipe_config->cpu_transcoder = TRANSCODER_DSI_0;
1655379bc100SJani Nikula
165650003bf5SJani Nikula if (intel_dsi->pixel_format == MIPI_DSI_FMT_RGB888)
165750003bf5SJani Nikula pipe_config->pipe_bpp = 24;
165850003bf5SJani Nikula else
165950003bf5SJani Nikula pipe_config->pipe_bpp = 18;
166050003bf5SJani Nikula
1661379bc100SJani Nikula pipe_config->clock_set = true;
16622b68392eSJani Nikula
16632b68392eSJani Nikula if (gen11_dsi_dsc_compute_config(encoder, pipe_config))
1664dd10a80fSJani Nikula drm_dbg_kms(&i915->drm, "Attempting to use DSC failed\n");
16652b68392eSJani Nikula
166604865139SJani Nikula pipe_config->port_clock = afe_clk(encoder, pipe_config) / 5;
1667379bc100SJani Nikula
1668f78a862dSVandita Kulkarni /*
1669f78a862dSVandita Kulkarni * In case of TE GATE cmd mode, we
1670f78a862dSVandita Kulkarni * receive TE from the slave if
1671f78a862dSVandita Kulkarni * dual link is enabled
1672f78a862dSVandita Kulkarni */
16735682a41fSVandita Kulkarni if (is_cmd_mode(intel_dsi))
16745682a41fSVandita Kulkarni gen11_dsi_get_cmd_mode_config(intel_dsi, pipe_config);
1675f78a862dSVandita Kulkarni
1676379bc100SJani Nikula return 0;
1677379bc100SJani Nikula }
1678379bc100SJani Nikula
gen11_dsi_get_power_domains(struct intel_encoder * encoder,struct intel_crtc_state * crtc_state)1679379bc100SJani Nikula static void gen11_dsi_get_power_domains(struct intel_encoder *encoder,
1680379bc100SJani Nikula struct intel_crtc_state *crtc_state)
1681379bc100SJani Nikula {
16822b68392eSJani Nikula struct drm_i915_private *i915 = to_i915(encoder->base.dev);
16832b68392eSJani Nikula
1684b7d02c3aSVille Syrjälä get_dsi_io_power_domains(i915,
1685b7d02c3aSVille Syrjälä enc_to_intel_dsi(encoder));
1686379bc100SJani Nikula }
1687379bc100SJani Nikula
gen11_dsi_get_hw_state(struct intel_encoder * encoder,enum pipe * pipe)1688379bc100SJani Nikula static bool gen11_dsi_get_hw_state(struct intel_encoder *encoder,
1689379bc100SJani Nikula enum pipe *pipe)
1690379bc100SJani Nikula {
1691379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
1692b7d02c3aSVille Syrjälä struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
1693379bc100SJani Nikula enum transcoder dsi_trans;
1694379bc100SJani Nikula intel_wakeref_t wakeref;
1695379bc100SJani Nikula enum port port;
1696379bc100SJani Nikula bool ret = false;
1697379bc100SJani Nikula u32 tmp;
1698379bc100SJani Nikula
1699379bc100SJani Nikula wakeref = intel_display_power_get_if_enabled(dev_priv,
1700379bc100SJani Nikula encoder->power_domain);
1701379bc100SJani Nikula if (!wakeref)
1702379bc100SJani Nikula return false;
1703379bc100SJani Nikula
1704379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
1705379bc100SJani Nikula dsi_trans = dsi_port_to_transcoder(port);
1706b092d6adSJani Nikula tmp = intel_de_read(dev_priv,
1707b092d6adSJani Nikula TRANS_DDI_FUNC_CTL(dev_priv, dsi_trans));
1708379bc100SJani Nikula switch (tmp & TRANS_DDI_EDP_INPUT_MASK) {
1709379bc100SJani Nikula case TRANS_DDI_EDP_INPUT_A_ON:
1710379bc100SJani Nikula *pipe = PIPE_A;
1711379bc100SJani Nikula break;
1712379bc100SJani Nikula case TRANS_DDI_EDP_INPUT_B_ONOFF:
1713379bc100SJani Nikula *pipe = PIPE_B;
1714379bc100SJani Nikula break;
1715379bc100SJani Nikula case TRANS_DDI_EDP_INPUT_C_ONOFF:
1716379bc100SJani Nikula *pipe = PIPE_C;
1717379bc100SJani Nikula break;
17184d89adc7SJosé Roberto de Souza case TRANS_DDI_EDP_INPUT_D_ONOFF:
17194d89adc7SJosé Roberto de Souza *pipe = PIPE_D;
17204d89adc7SJosé Roberto de Souza break;
1721379bc100SJani Nikula default:
1722b5280cd0SWambui Karuga drm_err(&dev_priv->drm, "Invalid PIPE input\n");
1723379bc100SJani Nikula goto out;
1724379bc100SJani Nikula }
1725379bc100SJani Nikula
1726984b61c3SJani Nikula tmp = intel_de_read(dev_priv, TRANSCONF(dev_priv, dsi_trans));
17273eb08ea5SVille Syrjälä ret = tmp & TRANSCONF_ENABLE;
1728379bc100SJani Nikula }
1729379bc100SJani Nikula out:
1730379bc100SJani Nikula intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
1731379bc100SJani Nikula return ret;
1732379bc100SJani Nikula }
1733379bc100SJani Nikula
gen11_dsi_initial_fastset_check(struct intel_encoder * encoder,struct intel_crtc_state * crtc_state)1734b671d6efSImre Deak static bool gen11_dsi_initial_fastset_check(struct intel_encoder *encoder,
1735b671d6efSImre Deak struct intel_crtc_state *crtc_state)
1736b671d6efSImre Deak {
1737b671d6efSImre Deak if (crtc_state->dsc.compression_enable) {
1738b671d6efSImre Deak drm_dbg_kms(encoder->base.dev, "Forcing full modeset due to DSC being enabled\n");
1739b671d6efSImre Deak crtc_state->uapi.mode_changed = true;
1740b671d6efSImre Deak
1741b671d6efSImre Deak return false;
1742b671d6efSImre Deak }
1743b671d6efSImre Deak
1744b671d6efSImre Deak return true;
1745b671d6efSImre Deak }
1746b671d6efSImre Deak
gen11_dsi_encoder_destroy(struct drm_encoder * encoder)1747379bc100SJani Nikula static void gen11_dsi_encoder_destroy(struct drm_encoder *encoder)
1748379bc100SJani Nikula {
1749379bc100SJani Nikula intel_encoder_destroy(encoder);
1750379bc100SJani Nikula }
1751379bc100SJani Nikula
1752379bc100SJani Nikula static const struct drm_encoder_funcs gen11_dsi_encoder_funcs = {
1753379bc100SJani Nikula .destroy = gen11_dsi_encoder_destroy,
1754379bc100SJani Nikula };
1755379bc100SJani Nikula
1756379bc100SJani Nikula static const struct drm_connector_funcs gen11_dsi_connector_funcs = {
1757b81dddb9SVille Syrjälä .detect = intel_panel_detect,
1758379bc100SJani Nikula .late_register = intel_connector_register,
1759379bc100SJani Nikula .early_unregister = intel_connector_unregister,
1760379bc100SJani Nikula .destroy = intel_connector_destroy,
1761379bc100SJani Nikula .fill_modes = drm_helper_probe_single_connector_modes,
1762379bc100SJani Nikula .atomic_get_property = intel_digital_connector_atomic_get_property,
1763379bc100SJani Nikula .atomic_set_property = intel_digital_connector_atomic_set_property,
1764379bc100SJani Nikula .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
1765379bc100SJani Nikula .atomic_duplicate_state = intel_digital_connector_duplicate_state,
1766379bc100SJani Nikula };
1767379bc100SJani Nikula
1768379bc100SJani Nikula static const struct drm_connector_helper_funcs gen11_dsi_connector_helper_funcs = {
1769379bc100SJani Nikula .get_modes = intel_dsi_get_modes,
17702b68392eSJani Nikula .mode_valid = gen11_dsi_mode_valid,
1771379bc100SJani Nikula .atomic_check = intel_digital_connector_atomic_check,
1772379bc100SJani Nikula };
1773379bc100SJani Nikula
gen11_dsi_host_attach(struct mipi_dsi_host * host,struct mipi_dsi_device * dsi)1774379bc100SJani Nikula static int gen11_dsi_host_attach(struct mipi_dsi_host *host,
1775379bc100SJani Nikula struct mipi_dsi_device *dsi)
1776379bc100SJani Nikula {
1777379bc100SJani Nikula return 0;
1778379bc100SJani Nikula }
1779379bc100SJani Nikula
gen11_dsi_host_detach(struct mipi_dsi_host * host,struct mipi_dsi_device * dsi)1780379bc100SJani Nikula static int gen11_dsi_host_detach(struct mipi_dsi_host *host,
1781379bc100SJani Nikula struct mipi_dsi_device *dsi)
1782379bc100SJani Nikula {
1783379bc100SJani Nikula return 0;
1784379bc100SJani Nikula }
1785379bc100SJani Nikula
gen11_dsi_host_transfer(struct mipi_dsi_host * host,const struct mipi_dsi_msg * msg)1786379bc100SJani Nikula static ssize_t gen11_dsi_host_transfer(struct mipi_dsi_host *host,
1787379bc100SJani Nikula const struct mipi_dsi_msg *msg)
1788379bc100SJani Nikula {
1789379bc100SJani Nikula struct intel_dsi_host *intel_dsi_host = to_intel_dsi_host(host);
1790379bc100SJani Nikula struct mipi_dsi_packet dsi_pkt;
1791379bc100SJani Nikula ssize_t ret;
1792379bc100SJani Nikula bool enable_lpdt = false;
1793379bc100SJani Nikula
1794379bc100SJani Nikula ret = mipi_dsi_create_packet(&dsi_pkt, msg);
1795379bc100SJani Nikula if (ret < 0)
1796379bc100SJani Nikula return ret;
1797379bc100SJani Nikula
1798379bc100SJani Nikula if (msg->flags & MIPI_DSI_MSG_USE_LPM)
1799379bc100SJani Nikula enable_lpdt = true;
1800379bc100SJani Nikula
1801379bc100SJani Nikula /* only long packet contains payload */
1802379bc100SJani Nikula if (mipi_dsi_packet_format_is_long(msg->type)) {
18033e2947cdSJani Nikula ret = dsi_send_pkt_payld(intel_dsi_host, &dsi_pkt);
1804379bc100SJani Nikula if (ret < 0)
1805379bc100SJani Nikula return ret;
1806379bc100SJani Nikula }
1807379bc100SJani Nikula
18085ebd50d3SLee Shawn C /* send packet header */
18093e2947cdSJani Nikula ret = dsi_send_pkt_hdr(intel_dsi_host, &dsi_pkt, enable_lpdt);
18105ebd50d3SLee Shawn C if (ret < 0)
18115ebd50d3SLee Shawn C return ret;
18125ebd50d3SLee Shawn C
1813379bc100SJani Nikula //TODO: add payload receive code if needed
1814379bc100SJani Nikula
1815379bc100SJani Nikula ret = sizeof(dsi_pkt.header) + dsi_pkt.payload_length;
1816379bc100SJani Nikula
1817379bc100SJani Nikula return ret;
1818379bc100SJani Nikula }
1819379bc100SJani Nikula
1820379bc100SJani Nikula static const struct mipi_dsi_host_ops gen11_dsi_host_ops = {
1821379bc100SJani Nikula .attach = gen11_dsi_host_attach,
1822379bc100SJani Nikula .detach = gen11_dsi_host_detach,
1823379bc100SJani Nikula .transfer = gen11_dsi_host_transfer,
1824379bc100SJani Nikula };
1825379bc100SJani Nikula
1826379bc100SJani Nikula #define ICL_PREPARE_CNT_MAX 0x7
1827379bc100SJani Nikula #define ICL_CLK_ZERO_CNT_MAX 0xf
1828379bc100SJani Nikula #define ICL_TRAIL_CNT_MAX 0x7
1829379bc100SJani Nikula #define ICL_TCLK_PRE_CNT_MAX 0x3
1830379bc100SJani Nikula #define ICL_TCLK_POST_CNT_MAX 0x7
1831379bc100SJani Nikula #define ICL_HS_ZERO_CNT_MAX 0xf
1832379bc100SJani Nikula #define ICL_EXIT_ZERO_CNT_MAX 0x7
1833379bc100SJani Nikula
icl_dphy_param_init(struct intel_dsi * intel_dsi)1834379bc100SJani Nikula static void icl_dphy_param_init(struct intel_dsi *intel_dsi)
1835379bc100SJani Nikula {
1836379bc100SJani Nikula struct drm_device *dev = intel_dsi->base.base.dev;
1837379bc100SJani Nikula struct drm_i915_private *dev_priv = to_i915(dev);
18383cf05076SVille Syrjälä struct intel_connector *connector = intel_dsi->attached_connector;
18393cf05076SVille Syrjälä struct mipi_config *mipi_config = connector->panel.vbt.dsi.config;
1840379bc100SJani Nikula u32 tlpx_ns;
1841379bc100SJani Nikula u32 prepare_cnt, exit_zero_cnt, clk_zero_cnt, trail_cnt;
1842379bc100SJani Nikula u32 ths_prepare_ns, tclk_trail_ns;
1843379bc100SJani Nikula u32 hs_zero_cnt;
1844fc3bbd57SWilliam Tseng u32 tclk_pre_cnt;
1845379bc100SJani Nikula
1846379bc100SJani Nikula tlpx_ns = intel_dsi_tlpx_ns(intel_dsi);
1847379bc100SJani Nikula
1848379bc100SJani Nikula tclk_trail_ns = max(mipi_config->tclk_trail, mipi_config->ths_trail);
1849379bc100SJani Nikula ths_prepare_ns = max(mipi_config->ths_prepare,
1850379bc100SJani Nikula mipi_config->tclk_prepare);
1851379bc100SJani Nikula
1852379bc100SJani Nikula /*
1853379bc100SJani Nikula * prepare cnt in escape clocks
1854379bc100SJani Nikula * this field represents a hexadecimal value with a precision
1855379bc100SJani Nikula * of 1.2 – i.e. the most significant bit is the integer
1856379bc100SJani Nikula * and the least significant 2 bits are fraction bits.
1857379bc100SJani Nikula * so, the field can represent a range of 0.25 to 1.75
1858379bc100SJani Nikula */
1859379bc100SJani Nikula prepare_cnt = DIV_ROUND_UP(ths_prepare_ns * 4, tlpx_ns);
1860379bc100SJani Nikula if (prepare_cnt > ICL_PREPARE_CNT_MAX) {
1861b5280cd0SWambui Karuga drm_dbg_kms(&dev_priv->drm, "prepare_cnt out of range (%d)\n",
1862b5280cd0SWambui Karuga prepare_cnt);
1863379bc100SJani Nikula prepare_cnt = ICL_PREPARE_CNT_MAX;
1864379bc100SJani Nikula }
1865379bc100SJani Nikula
1866379bc100SJani Nikula /* clk zero count in escape clocks */
1867379bc100SJani Nikula clk_zero_cnt = DIV_ROUND_UP(mipi_config->tclk_prepare_clkzero -
1868379bc100SJani Nikula ths_prepare_ns, tlpx_ns);
1869379bc100SJani Nikula if (clk_zero_cnt > ICL_CLK_ZERO_CNT_MAX) {
1870b5280cd0SWambui Karuga drm_dbg_kms(&dev_priv->drm,
1871b5280cd0SWambui Karuga "clk_zero_cnt out of range (%d)\n", clk_zero_cnt);
1872379bc100SJani Nikula clk_zero_cnt = ICL_CLK_ZERO_CNT_MAX;
1873379bc100SJani Nikula }
1874379bc100SJani Nikula
1875379bc100SJani Nikula /* trail cnt in escape clocks*/
1876379bc100SJani Nikula trail_cnt = DIV_ROUND_UP(tclk_trail_ns, tlpx_ns);
1877379bc100SJani Nikula if (trail_cnt > ICL_TRAIL_CNT_MAX) {
1878b5280cd0SWambui Karuga drm_dbg_kms(&dev_priv->drm, "trail_cnt out of range (%d)\n",
1879b5280cd0SWambui Karuga trail_cnt);
1880379bc100SJani Nikula trail_cnt = ICL_TRAIL_CNT_MAX;
1881379bc100SJani Nikula }
1882379bc100SJani Nikula
1883379bc100SJani Nikula /* tclk pre count in escape clocks */
1884379bc100SJani Nikula tclk_pre_cnt = DIV_ROUND_UP(mipi_config->tclk_pre, tlpx_ns);
1885379bc100SJani Nikula if (tclk_pre_cnt > ICL_TCLK_PRE_CNT_MAX) {
1886b5280cd0SWambui Karuga drm_dbg_kms(&dev_priv->drm,
1887b5280cd0SWambui Karuga "tclk_pre_cnt out of range (%d)\n", tclk_pre_cnt);
1888379bc100SJani Nikula tclk_pre_cnt = ICL_TCLK_PRE_CNT_MAX;
1889379bc100SJani Nikula }
1890379bc100SJani Nikula
1891379bc100SJani Nikula /* hs zero cnt in escape clocks */
1892379bc100SJani Nikula hs_zero_cnt = DIV_ROUND_UP(mipi_config->ths_prepare_hszero -
1893379bc100SJani Nikula ths_prepare_ns, tlpx_ns);
1894379bc100SJani Nikula if (hs_zero_cnt > ICL_HS_ZERO_CNT_MAX) {
1895b5280cd0SWambui Karuga drm_dbg_kms(&dev_priv->drm, "hs_zero_cnt out of range (%d)\n",
1896b5280cd0SWambui Karuga hs_zero_cnt);
1897379bc100SJani Nikula hs_zero_cnt = ICL_HS_ZERO_CNT_MAX;
1898379bc100SJani Nikula }
1899379bc100SJani Nikula
1900379bc100SJani Nikula /* hs exit zero cnt in escape clocks */
1901379bc100SJani Nikula exit_zero_cnt = DIV_ROUND_UP(mipi_config->ths_exit, tlpx_ns);
1902379bc100SJani Nikula if (exit_zero_cnt > ICL_EXIT_ZERO_CNT_MAX) {
1903b5280cd0SWambui Karuga drm_dbg_kms(&dev_priv->drm,
1904b5280cd0SWambui Karuga "exit_zero_cnt out of range (%d)\n",
1905b5280cd0SWambui Karuga exit_zero_cnt);
1906379bc100SJani Nikula exit_zero_cnt = ICL_EXIT_ZERO_CNT_MAX;
1907379bc100SJani Nikula }
1908379bc100SJani Nikula
1909379bc100SJani Nikula /* clock lane dphy timings */
1910379bc100SJani Nikula intel_dsi->dphy_reg = (CLK_PREPARE_OVERRIDE |
1911379bc100SJani Nikula CLK_PREPARE(prepare_cnt) |
1912379bc100SJani Nikula CLK_ZERO_OVERRIDE |
1913379bc100SJani Nikula CLK_ZERO(clk_zero_cnt) |
1914379bc100SJani Nikula CLK_PRE_OVERRIDE |
1915379bc100SJani Nikula CLK_PRE(tclk_pre_cnt) |
1916379bc100SJani Nikula CLK_TRAIL_OVERRIDE |
1917379bc100SJani Nikula CLK_TRAIL(trail_cnt));
1918379bc100SJani Nikula
1919379bc100SJani Nikula /* data lanes dphy timings */
1920379bc100SJani Nikula intel_dsi->dphy_data_lane_reg = (HS_PREPARE_OVERRIDE |
1921379bc100SJani Nikula HS_PREPARE(prepare_cnt) |
1922379bc100SJani Nikula HS_ZERO_OVERRIDE |
1923379bc100SJani Nikula HS_ZERO(hs_zero_cnt) |
1924379bc100SJani Nikula HS_TRAIL_OVERRIDE |
1925379bc100SJani Nikula HS_TRAIL(trail_cnt) |
1926379bc100SJani Nikula HS_EXIT_OVERRIDE |
1927379bc100SJani Nikula HS_EXIT(exit_zero_cnt));
1928379bc100SJani Nikula
1929379bc100SJani Nikula intel_dsi_log_params(intel_dsi);
1930379bc100SJani Nikula }
1931379bc100SJani Nikula
icl_dsi_add_properties(struct intel_connector * connector)1932f6d39f56SVille Syrjälä static void icl_dsi_add_properties(struct intel_connector *connector)
1933f384e48dSVandita Kulkarni {
1934f6d39f56SVille Syrjälä const struct drm_display_mode *fixed_mode =
1935f6d39f56SVille Syrjälä intel_panel_preferred_fixed_mode(connector);
1936f384e48dSVandita Kulkarni
19376ac2f04bSVille Syrjälä intel_attach_scaling_mode_property(&connector->base);
1938f384e48dSVandita Kulkarni
193969654c63SDerek Basehore drm_connector_set_panel_orientation_with_quirk(&connector->base,
194069654c63SDerek Basehore intel_dsi_get_panel_orientation(connector),
1941dee54887SVille Syrjälä fixed_mode->hdisplay,
1942dee54887SVille Syrjälä fixed_mode->vdisplay);
1943f384e48dSVandita Kulkarni }
1944f384e48dSVandita Kulkarni
icl_dsi_init(struct drm_i915_private * dev_priv,const struct intel_bios_encoder_data * devdata)1945021a62a5SVille Syrjälä void icl_dsi_init(struct drm_i915_private *dev_priv,
1946021a62a5SVille Syrjälä const struct intel_bios_encoder_data *devdata)
1947379bc100SJani Nikula {
1948*9aec6f76SJani Nikula struct intel_display *display = &dev_priv->display;
1949379bc100SJani Nikula struct intel_dsi *intel_dsi;
1950379bc100SJani Nikula struct intel_encoder *encoder;
1951379bc100SJani Nikula struct intel_connector *intel_connector;
1952379bc100SJani Nikula struct drm_connector *connector;
1953379bc100SJani Nikula enum port port;
1954379bc100SJani Nikula
1955021a62a5SVille Syrjälä port = intel_bios_encoder_port(devdata);
1956021a62a5SVille Syrjälä if (port == PORT_NONE)
1957379bc100SJani Nikula return;
1958379bc100SJani Nikula
1959379bc100SJani Nikula intel_dsi = kzalloc(sizeof(*intel_dsi), GFP_KERNEL);
1960379bc100SJani Nikula if (!intel_dsi)
1961379bc100SJani Nikula return;
1962379bc100SJani Nikula
1963379bc100SJani Nikula intel_connector = intel_connector_alloc();
1964379bc100SJani Nikula if (!intel_connector) {
1965379bc100SJani Nikula kfree(intel_dsi);
1966379bc100SJani Nikula return;
1967379bc100SJani Nikula }
1968379bc100SJani Nikula
1969379bc100SJani Nikula encoder = &intel_dsi->base;
1970379bc100SJani Nikula intel_dsi->attached_connector = intel_connector;
1971379bc100SJani Nikula connector = &intel_connector->base;
1972379bc100SJani Nikula
1973021a62a5SVille Syrjälä encoder->devdata = devdata;
1974021a62a5SVille Syrjälä
1975379bc100SJani Nikula /* register DSI encoder with DRM subsystem */
19763703060dSAndrzej Hajda drm_encoder_init(&dev_priv->drm, &encoder->base, &gen11_dsi_encoder_funcs,
1977379bc100SJani Nikula DRM_MODE_ENCODER_DSI, "DSI %c", port_name(port));
1978379bc100SJani Nikula
1979379bc100SJani Nikula encoder->pre_pll_enable = gen11_dsi_pre_pll_enable;
1980379bc100SJani Nikula encoder->pre_enable = gen11_dsi_pre_enable;
198121fd23acSJani Nikula encoder->enable = gen11_dsi_enable;
1982379bc100SJani Nikula encoder->disable = gen11_dsi_disable;
1983773b4b54SVille Syrjälä encoder->post_disable = gen11_dsi_post_disable;
1984379bc100SJani Nikula encoder->port = port;
1985379bc100SJani Nikula encoder->get_config = gen11_dsi_get_config;
1986544021e3STejas Upadhyay encoder->sync_state = gen11_dsi_sync_state;
1987c0a52f8bSJani Nikula encoder->update_pipe = intel_backlight_update;
1988379bc100SJani Nikula encoder->compute_config = gen11_dsi_compute_config;
1989379bc100SJani Nikula encoder->get_hw_state = gen11_dsi_get_hw_state;
1990b671d6efSImre Deak encoder->initial_fastset_check = gen11_dsi_initial_fastset_check;
1991379bc100SJani Nikula encoder->type = INTEL_OUTPUT_DSI;
1992379bc100SJani Nikula encoder->cloneable = 0;
199334053ee1SVille Syrjälä encoder->pipe_mask = ~0;
1994379bc100SJani Nikula encoder->power_domain = POWER_DOMAIN_PORT_DSI;
1995379bc100SJani Nikula encoder->get_power_domains = gen11_dsi_get_power_domains;
199687bd8498SVille Syrjälä encoder->disable_clock = gen11_dsi_gate_clocks;
19970fbd8694SVille Syrjälä encoder->is_clock_enabled = gen11_dsi_is_clock_enabled;
1998e3972476SVille Syrjälä encoder->shutdown = intel_dsi_shutdown;
1999379bc100SJani Nikula
2000379bc100SJani Nikula /* register DSI connector with DRM subsystem */
20013703060dSAndrzej Hajda drm_connector_init(&dev_priv->drm, connector, &gen11_dsi_connector_funcs,
2002379bc100SJani Nikula DRM_MODE_CONNECTOR_DSI);
2003379bc100SJani Nikula drm_connector_helper_add(connector, &gen11_dsi_connector_helper_funcs);
2004379bc100SJani Nikula connector->display_info.subpixel_order = SubPixelHorizontalRGB;
2005379bc100SJani Nikula intel_connector->get_hw_state = intel_connector_get_hw_state;
2006379bc100SJani Nikula
2007379bc100SJani Nikula /* attach connector to encoder */
2008379bc100SJani Nikula intel_connector_attach_encoder(intel_connector, encoder);
2009379bc100SJani Nikula
2010201963a8SVille Syrjälä intel_dsi->panel_power_off_time = ktime_get_boottime();
2011201963a8SVille Syrjälä
2012*9aec6f76SJani Nikula intel_bios_init_panel_late(display, &intel_connector->panel, encoder->devdata, NULL);
20133cf05076SVille Syrjälä
20143703060dSAndrzej Hajda mutex_lock(&dev_priv->drm.mode_config.mutex);
2015db10c14aSVille Syrjälä intel_panel_add_vbt_lfp_fixed_mode(intel_connector);
20163703060dSAndrzej Hajda mutex_unlock(&dev_priv->drm.mode_config.mutex);
2017379bc100SJani Nikula
2018db10c14aSVille Syrjälä if (!intel_panel_preferred_fixed_mode(intel_connector)) {
2019b5280cd0SWambui Karuga drm_err(&dev_priv->drm, "DSI fixed mode info missing\n");
2020379bc100SJani Nikula goto err;
2021379bc100SJani Nikula }
2022379bc100SJani Nikula
202315d045fdSJani Nikula intel_panel_init(intel_connector, NULL);
2024db10c14aSVille Syrjälä
2025c0a52f8bSJani Nikula intel_backlight_setup(intel_connector, INVALID_PIPE);
2026379bc100SJani Nikula
20273cf05076SVille Syrjälä if (intel_connector->panel.vbt.dsi.config->dual_link)
2028379bc100SJani Nikula intel_dsi->ports = BIT(PORT_A) | BIT(PORT_B);
2029379bc100SJani Nikula else
2030379bc100SJani Nikula intel_dsi->ports = BIT(port);
2031379bc100SJani Nikula
2032f4a6c7a4SJani Nikula if (drm_WARN_ON(&dev_priv->drm, intel_connector->panel.vbt.dsi.bl_ports & ~intel_dsi->ports))
2033f4a6c7a4SJani Nikula intel_connector->panel.vbt.dsi.bl_ports &= intel_dsi->ports;
2034f4a6c7a4SJani Nikula
2035f4a6c7a4SJani Nikula if (drm_WARN_ON(&dev_priv->drm, intel_connector->panel.vbt.dsi.cabc_ports & ~intel_dsi->ports))
2036f4a6c7a4SJani Nikula intel_connector->panel.vbt.dsi.cabc_ports &= intel_dsi->ports;
2037f4a6c7a4SJani Nikula
2038379bc100SJani Nikula for_each_dsi_port(port, intel_dsi->ports) {
2039379bc100SJani Nikula struct intel_dsi_host *host;
2040379bc100SJani Nikula
2041379bc100SJani Nikula host = intel_dsi_host_init(intel_dsi, &gen11_dsi_host_ops, port);
2042379bc100SJani Nikula if (!host)
2043379bc100SJani Nikula goto err;
2044379bc100SJani Nikula
2045379bc100SJani Nikula intel_dsi->dsi_hosts[port] = host;
2046379bc100SJani Nikula }
2047379bc100SJani Nikula
2048379bc100SJani Nikula if (!intel_dsi_vbt_init(intel_dsi, MIPI_DSI_GENERIC_PANEL_ID)) {
2049b5280cd0SWambui Karuga drm_dbg_kms(&dev_priv->drm, "no device found\n");
2050379bc100SJani Nikula goto err;
2051379bc100SJani Nikula }
2052379bc100SJani Nikula
2053379bc100SJani Nikula icl_dphy_param_init(intel_dsi);
2054f384e48dSVandita Kulkarni
2055f6d39f56SVille Syrjälä icl_dsi_add_properties(intel_connector);
2056379bc100SJani Nikula return;
2057379bc100SJani Nikula
2058379bc100SJani Nikula err:
2059d1613061SVivek Kasireddy drm_connector_cleanup(connector);
2060379bc100SJani Nikula drm_encoder_cleanup(&encoder->base);
2061379bc100SJani Nikula kfree(intel_dsi);
2062379bc100SJani Nikula kfree(intel_connector);
2063379bc100SJani Nikula }
2064