From mboxrd@z Thu Jan 1 00:00:00 1970 From: Ville =?iso-8859-1?Q?Syrj=E4l=E4?= Subject: Re: [PATCH v2 08/15] drm/i915: add basic MIPI DSI output support Date: Tue, 20 Aug 2013 17:23:13 +0300 Message-ID: <20130820142313.GW7159@intel.com> References: <7a5baa3c1d7a8fe77ec4581a5ad8f39738dd49e3.1376655793.git.jani.nikula@intel.com> Mime-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Return-path: Received: from mga03.intel.com (mga03.intel.com [143.182.124.21]) by gabe.freedesktop.org (Postfix) with ESMTP id 2E2D4E70CB for ; Tue, 20 Aug 2013 07:23:18 -0700 (PDT) Content-Disposition: inline In-Reply-To: <7a5baa3c1d7a8fe77ec4581a5ad8f39738dd49e3.1376655793.git.jani.nikula@intel.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: intel-gfx-bounces+gcfxdi-intel-gfx=m.gmane.org@lists.freedesktop.org Errors-To: intel-gfx-bounces+gcfxdi-intel-gfx=m.gmane.org@lists.freedesktop.org To: Jani Nikula Cc: intel-gfx@lists.freedesktop.org, yogesh.mohan.marimuthu@intel.com List-Id: intel-gfx@lists.freedesktop.org On Fri, Aug 16, 2013 at 03:35:56PM +0300, Jani Nikula wrote: > This does not include any panel specific sub-encoders yet. > = > v2: Fix fixed mode handling (Daniel) > = > Signed-off-by: Jani Nikula > Signed-off-by: Shobhit Kumar > --- > drivers/gpu/drm/i915/Makefile | 1 + > drivers/gpu/drm/i915/intel_drv.h | 1 + > drivers/gpu/drm/i915/intel_dsi.c | 534 ++++++++++++++++++++++++++++++++= ++++++ > 3 files changed, 536 insertions(+) > create mode 100644 drivers/gpu/drm/i915/intel_dsi.c > = > diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile > index 8bffd29..5864c5b 100644 > --- a/drivers/gpu/drm/i915/Makefile > +++ b/drivers/gpu/drm/i915/Makefile > @@ -21,6 +21,7 @@ i915-y :=3D i915_drv.o i915_dma.o i915_irq.o \ > intel_display.o \ > intel_crt.o \ > intel_lvds.o \ > + intel_dsi.o \ > intel_dsi_cmd.o \ > intel_bios.o \ > intel_ddi.o \ > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/inte= l_drv.h > index a31abc6..cbe3df1 100644 > --- a/drivers/gpu/drm/i915/intel_drv.h > +++ b/drivers/gpu/drm/i915/intel_drv.h > @@ -525,6 +525,7 @@ extern void intel_mark_fb_busy(struct drm_i915_gem_ob= ject *obj, > struct intel_ring_buffer *ring); > extern void intel_mark_idle(struct drm_device *dev); > extern void intel_lvds_init(struct drm_device *dev); > +extern bool intel_dsi_init(struct drm_device *dev); > extern bool intel_is_dual_link_lvds(struct drm_device *dev); > extern void intel_dp_init(struct drm_device *dev, int output_reg, > enum port port); > diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/inte= l_dsi.c > new file mode 100644 > index 0000000..d7eddbd > --- /dev/null > +++ b/drivers/gpu/drm/i915/intel_dsi.c > @@ -0,0 +1,534 @@ > +/* > + * Copyright =A9 2013 Intel Corporation > + * > + * Permission is hereby granted, free of charge, to any person obtaining= a > + * copy of this software and associated documentation files (the "Softwa= re"), > + * to deal in the Software without restriction, including without limita= tion > + * the rights to use, copy, modify, merge, publish, distribute, sublicen= se, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice (including the = next > + * paragraph) shall be included in all copies or substantial portions of= the > + * Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRE= SS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILI= TY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SH= ALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR = OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISI= NG > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER > + * DEALINGS IN THE SOFTWARE. > + * > + * Author: Jani Nikula > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include "i915_drv.h" > +#include "intel_drv.h" > +#include "intel_dsi.h" > +#include "intel_dsi_cmd.h" > + > +/* the sub-encoders aka panel drivers */ > +static const struct intel_dsi_device intel_dsi_devices[] =3D { > +}; > + > +static struct intel_dsi *intel_attached_dsi(struct drm_connector *connec= tor) > +{ > + return container_of(intel_attached_encoder(connector), > + struct intel_dsi, base); > +} > + > +static inline bool is_vid_mode(struct intel_dsi *intel_dsi) > +{ > + return intel_dsi->dev.type =3D=3D INTEL_DSI_VIDEO_MODE; > +} > + > +static inline bool is_cmd_mode(struct intel_dsi *intel_dsi) > +{ > + return intel_dsi->dev.type =3D=3D INTEL_DSI_COMMAND_MODE; > +} > + > +static void intel_dsi_hot_plug(struct intel_encoder *encoder) > +{ > + DRM_DEBUG_KMS("\n"); > +} > + > +static bool intel_dsi_compute_config(struct intel_encoder *encoder, > + struct intel_crtc_config *config) > +{ > + struct intel_dsi *intel_dsi =3D container_of(encoder, struct intel_dsi, > + base); > + struct intel_connector *intel_connector =3D intel_dsi->attached_connect= or; > + struct drm_display_mode *fixed_mode =3D intel_connector->panel.fixed_mo= de; > + struct drm_display_mode *adjusted_mode =3D &config->adjusted_mode; > + struct drm_display_mode *mode =3D &config->requested_mode; > + > + DRM_DEBUG_KMS("\n"); > + > + if (fixed_mode) > + intel_fixed_panel_mode(fixed_mode, adjusted_mode); > + > + if (intel_dsi->dev.dev_ops->mode_fixup) > + return intel_dsi->dev.dev_ops->mode_fixup(&intel_dsi->dev, > + mode, adjusted_mode); > + > + return true; > +} > + > +static void intel_dsi_pre_pll_enable(struct intel_encoder *encoder) > +{ > + DRM_DEBUG_KMS("\n"); > +} > + > +static void intel_dsi_pre_enable(struct intel_encoder *encoder) > +{ > + DRM_DEBUG_KMS("\n"); > +} > + > +static void intel_dsi_enable(struct intel_encoder *encoder) > +{ > + struct drm_i915_private *dev_priv =3D encoder->base.dev->dev_private; > + struct intel_crtc *intel_crtc =3D to_intel_crtc(encoder->base.crtc); > + struct intel_dsi *intel_dsi =3D enc_to_intel_dsi(&encoder->base); > + int pipe =3D intel_crtc->pipe; > + u32 temp; > + > + DRM_DEBUG_KMS("\n"); > + > + temp =3D I915_READ(MIPI_DEVICE_READY(pipe)); > + temp &=3D ~ULPS_STATE_MASK; > + temp &=3D ~DEVICE_READY; /* XXX: assuming it's already !ready */ The spec seems to be telling me that we shouldn't frob w/ DEVICE_READY when in ULPS. So maybe we should not clear DEVICE_READY? Although it should not be set when we get here, so I guess I'm worrying about nothing. > + I915_WRITE(MIPI_DEVICE_READY(pipe), temp | ULPS_STATE_EXIT); > + msleep(20); /* XXX */ > + I915_WRITE(MIPI_DEVICE_READY(pipe), temp); > + msleep(20); /* XXX */ > + I915_WRITE(MIPI_DEVICE_READY(pipe), temp | DEVICE_READY); > + > + if (is_cmd_mode(intel_dsi)) > + I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(pipe), 8 * 4); > + > + /* Do this here, or let the slave encoder do it in ->dpms? */ > + if (is_vid_mode(intel_dsi)) { > + dpi_send_cmd(intel_dsi, TURN_ON); > + msleep(100); > + } > + > + /* assert ip_tg_enable signal */ > + temp =3D I915_READ(MIPI_PORT_CTRL(pipe)); > + I915_WRITE(MIPI_PORT_CTRL(pipe), temp | DPI_ENABLE); > + POSTING_READ(MIPI_PORT_CTRL(pipe)); Should be wrapped in is_vid_mode() check, no? > + > + intel_dsi->dev.dev_ops->enable(&intel_dsi->dev); > +} > + > +static void intel_dsi_disable(struct intel_encoder *encoder) > +{ > + struct drm_i915_private *dev_priv =3D encoder->base.dev->dev_private; > + struct intel_crtc *intel_crtc =3D to_intel_crtc(encoder->base.crtc); > + struct intel_dsi *intel_dsi =3D enc_to_intel_dsi(&encoder->base); > + int pipe =3D intel_crtc->pipe; > + u32 temp; > + > + DRM_DEBUG_KMS("\n"); > + > + intel_dsi->dev.dev_ops->disable(&intel_dsi->dev); > + > + if (is_vid_mode(intel_dsi)) > + dpi_send_cmd(intel_dsi, SHUTDOWN); > + > + if (is_vid_mode(intel_dsi)) { > + /* de-assert ip_tg_enable signal */ > + temp =3D I915_READ(MIPI_PORT_CTRL(pipe)); > + I915_WRITE(MIPI_PORT_CTRL(pipe), temp & ~DPI_ENABLE); > + POSTING_READ(MIPI_PORT_CTRL(pipe)); > + } > + > + /* XXX: wait for fifos before ulps entry */ > + > + temp =3D I915_READ(MIPI_DEVICE_READY(pipe)); > + temp &=3D ~ULPS_STATE_MASK; Here too I suppose we might do this ULPS state clearing after we've cleared DEVICE_READY. But again the device should not be in ULPS here, so it may be a bit pointless. > + temp &=3D ~DEVICE_READY; > + I915_WRITE(MIPI_DEVICE_READY(pipe), temp); > + msleep(5); > + I915_WRITE(MIPI_DEVICE_READY(pipe), temp | ULPS_STATE_ENTER); > +} > + > +static void intel_dsi_post_disable(struct intel_encoder *encoder) > +{ > + DRM_DEBUG_KMS("\n"); > +} > + > +static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, > + enum pipe *pipe) > +{ > + struct drm_i915_private *dev_priv =3D encoder->base.dev->dev_private; > + struct intel_crtc *intel_crtc =3D to_intel_crtc(encoder->base.crtc); > + > + DRM_DEBUG_KMS("\n"); > + > + /* XXX: this is wrong */ > + if (intel_crtc) { > + u32 val; > + > + *pipe =3D intel_crtc->pipe; > + > + /* XXX: only works for video mode */ > + val =3D I915_READ(MIPI_PORT_CTRL(*pipe)); > + return val & DPI_ENABLE; > + } > + > + /* XXX: do we also need to call > + * intel_dsi->dev.dev_ops->get_hw_state(&intel_dsi->dev); > + */ > + > + return false; > +} > + > +static void intel_dsi_get_config(struct intel_encoder *encoder, > + struct intel_crtc_config *pipe_config) > +{ > + DRM_DEBUG_KMS("\n"); > + > + /* XXX: read flags, set to adjusted_mode */ > +} > + > +static int intel_dsi_mode_valid(struct drm_connector *connector, > + struct drm_display_mode *mode) > +{ > + struct intel_connector *intel_connector =3D to_intel_connector(connecto= r); > + struct drm_display_mode *fixed_mode =3D intel_connector->panel.fixed_mo= de; > + struct intel_dsi *intel_dsi =3D intel_attached_dsi(connector); > + > + DRM_DEBUG_KMS("\n"); > + > + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) { > + DRM_DEBUG_KMS("MODE_NO_DBLESCAN\n"); > + return MODE_NO_DBLESCAN; > + } > + > + if (fixed_mode) { > + if (mode->hdisplay > fixed_mode->hdisplay) > + return MODE_PANEL; > + if (mode->vdisplay > fixed_mode->vdisplay) > + return MODE_PANEL; > + } > + > + return intel_dsi->dev.dev_ops->mode_valid(&intel_dsi->dev, mode); > +} > + > +/* return pixels in terms of txbyteclkhs */ > +static u16 txbyteclkhs(u16 pixels, int bpp, int lane_count) > +{ > + return DIV_ROUND_UP(DIV_ROUND_UP(pixels * bpp, 8), lane_count); > +} > + > +static void set_dsi_timings(struct drm_encoder *encoder, > + const struct drm_display_mode *mode) > +{ > + struct drm_device *dev =3D encoder->dev; > + struct drm_i915_private *dev_priv =3D dev->dev_private; > + struct intel_crtc *intel_crtc =3D to_intel_crtc(encoder->crtc); > + struct intel_dsi *intel_dsi =3D enc_to_intel_dsi(encoder); > + int pipe =3D intel_crtc->pipe; > + unsigned int bpp =3D intel_crtc->config.pipe_bpp; > + unsigned int lane_count =3D intel_dsi->lane_count; > + > + u16 hactive, hfp, hsync, hbp, vfp, vsync, vbp; > + > + hactive =3D mode->hdisplay; > + hfp =3D mode->hsync_start - mode->hdisplay; > + hsync =3D mode->hsync_end - mode->hsync_start; > + hbp =3D mode->htotal - mode->hsync_end; > + > + vfp =3D mode->vsync_start - mode->vdisplay; > + vsync =3D mode->vsync_end - mode->vsync_start; > + vbp =3D mode->vtotal - mode->vsync_end; > + > + /* horizontal values are in terms of high speed byte clock */ > + hactive =3D txbyteclkhs(hactive, bpp, lane_count); > + hfp =3D txbyteclkhs(hfp, bpp, lane_count); > + hsync =3D txbyteclkhs(hsync, bpp, lane_count); > + hbp =3D txbyteclkhs(hbp, bpp, lane_count); > + > + I915_WRITE(MIPI_HACTIVE_AREA_COUNT(pipe), hactive); > + I915_WRITE(MIPI_HFP_COUNT(pipe), hfp); > + > + /* meaningful for video mode non-burst sync pulse mode only, can be zero > + * for non-burst sync events and burst modes */ > + I915_WRITE(MIPI_HSYNC_PADDING_COUNT(pipe), hsync); > + I915_WRITE(MIPI_HBP_COUNT(pipe), hbp); > + > + /* vertical values are in terms of lines */ > + I915_WRITE(MIPI_VFP_COUNT(pipe), vfp); > + I915_WRITE(MIPI_VSYNC_PADDING_COUNT(pipe), vsync); > + I915_WRITE(MIPI_VBP_COUNT(pipe), vbp); > +} > + > +static void intel_dsi_mode_set(struct intel_encoder *intel_encoder) > +{ > + struct drm_encoder *encoder =3D &intel_encoder->base; > + struct drm_device *dev =3D encoder->dev; > + struct drm_i915_private *dev_priv =3D dev->dev_private; > + struct intel_crtc *intel_crtc =3D to_intel_crtc(encoder->crtc); > + struct intel_dsi *intel_dsi =3D enc_to_intel_dsi(encoder); > + struct drm_display_mode *adjusted_mode =3D > + &intel_crtc->config.adjusted_mode; > + int pipe =3D intel_crtc->pipe; > + unsigned int bpp =3D intel_crtc->config.pipe_bpp; > + u32 val, tmp; > + > + DRM_DEBUG_KMS("pipe %d\n", pipe); > + > + /* escape clock divider, 20MHz, shared for A and C. device ready must be > + * off when doing this! txclkesc? */ > + tmp =3D I915_READ(MIPI_CTRL(0)); > + tmp &=3D ~ESCAPE_CLOCK_DIVIDER_MASK; > + I915_WRITE(MIPI_CTRL(0), tmp | ESCAPE_CLOCK_DIVIDER_1); > + > + /* read request priority is per pipe */ > + tmp =3D I915_READ(MIPI_CTRL(pipe)); > + tmp &=3D ~READ_REQUEST_PRIORITY_MASK; > + I915_WRITE(MIPI_CTRL(pipe), tmp | READ_REQUEST_PRIORITY_HIGH); > + > + /* XXX: why here, why like this? handling in irq handler?! */ > + I915_WRITE(MIPI_INTR_STAT(pipe), 0xffffffff); > + I915_WRITE(MIPI_INTR_EN(pipe), 0xffffffff); > + > + I915_WRITE(MIPI_DPHY_PARAM(pipe), > + 0x3c << EXIT_ZERO_COUNT_SHIFT | > + 0x1f << TRAIL_COUNT_SHIFT | > + 0xc5 << CLK_ZERO_COUNT_SHIFT | > + 0x1f << PREPARE_COUNT_SHIFT); > + > + I915_WRITE(MIPI_DPI_RESOLUTION(pipe), > + adjusted_mode->vdisplay << VERTICAL_ADDRESS_SHIFT | > + adjusted_mode->hdisplay << HORIZONTAL_ADDRESS_SHIFT); > + > + set_dsi_timings(encoder, adjusted_mode); > + > + val =3D intel_dsi->lane_count << DATA_LANES_PRG_REG_SHIFT; > + if (is_cmd_mode(intel_dsi)) { > + val |=3D intel_dsi->channel << CMD_MODE_CHANNEL_NUMBER_SHIFT; > + val |=3D CMD_MODE_DATA_WIDTH_8_BIT; /* XXX */ > + } else { > + val |=3D intel_dsi->channel << VID_MODE_CHANNEL_NUMBER_SHIFT; > + > + /* XXX: cross-check bpp vs. pixel format? */ > + val |=3D intel_dsi->pixel_format; > + } > + I915_WRITE(MIPI_DSI_FUNC_PRG(pipe), val); > + > + /* timeouts for recovery. one frame IIUC. if counter expires, EOT and > + * stop state. */ > + > + if (is_vid_mode(intel_dsi) && > + intel_dsi->video_mode_format =3D=3D VIDEO_MODE_BURST) { > + I915_WRITE(MIPI_HS_TX_TIMEOUT(pipe), > + txbyteclkhs(adjusted_mode->htotal + 1, bpp, > + intel_dsi->lane_count)); Should the +1 maybe be outside the txbyteclkhs()? > + } else { > + I915_WRITE(MIPI_HS_TX_TIMEOUT(pipe), > + txbyteclkhs(adjusted_mode->vtotal * > + adjusted_mode->htotal, > + bpp, intel_dsi->lane_count)); +1 needed here too isn't it? > + } > + I915_WRITE(MIPI_LP_RX_TIMEOUT(pipe), 0xffff); Hmm. Spec says this should be somewhere between 21 and 117+max_payload_bytes*16. If we take max_payload_bytes to be 512 based on the generic data FIFO size, then we'd get 8309 as the absolute max we will ever need. > + I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(pipe), 0x14); > + > + I915_WRITE(MIPI_DEVICE_RESET_TIMER(pipe), 0xffff); These two are the max according to the spec. Seems OK. > + > + /* dphy stuff */ > + > + /* in terms of low power clock */ > + I915_WRITE(MIPI_INIT_COUNT(pipe), 0x7d0); Maybe add a note that the actual initialization period is 100 usec, so people don't have to reverse compute it. Or maybe even add some txclkesc variable/define and explicitly calculate this. Maybe it would be clearer to write these timeout values in decimal, though the spec seems to prefer hex in some cases. > + > + /* recovery disables */ > + I915_WRITE(MIPI_EOT_DISABLE(pipe), intel_dsi->eot_disable); > + > + /* in terms of txbyteclkhs. actual high to low switch + > + * MIPI_STOP_STATE_STALL * MIPI_LP_BYTECLK. > + * > + * XXX: write MIPI_STOP_STATE_STALL? > + */ > + I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(pipe), 0x46); > + > + /* XXX: low power clock equivalence in terms of byte clock. the number > + * of byte clocks occupied in one low power clock. based on txbyteclkhs > + * and txclkesc. txclkesc time / txbyteclk time * (105 + > + * MIPI_STOP_STATE_STALL) / 105.??? > + */ > + I915_WRITE(MIPI_LP_BYTECLK(pipe), 4); > + > + /* the bw essential for transmitting 16 long packets containing 252 > + * bytes meant for dcs write memory command is programmed in this > + * register in terms of byte clocks. based on dsi transfer rate and the > + * number of lanes configured the time taken to transmit 16 long packets > + * in a dsi stream varies. */ > + I915_WRITE(MIPI_DBI_BW_CTRL(pipe), 0x820); > + > + I915_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT(pipe), > + 0xa << LP_HS_SSW_CNT_SHIFT | > + 0x14 << HS_LP_PWR_SW_CNT_SHIFT); Hmm. Actualky calculating all this stuff might be nice. But I guess we can leave that for later. > + > + if (is_vid_mode(intel_dsi)) > + I915_WRITE(MIPI_VIDEO_MODE_FORMAT(pipe), > + intel_dsi->video_mode_format); > +} > + > +static enum drm_connector_status > +intel_dsi_detect(struct drm_connector *connector, bool force) > +{ > + struct intel_dsi *intel_dsi =3D intel_attached_dsi(connector); > + DRM_DEBUG_KMS("\n"); > + return intel_dsi->dev.dev_ops->detect(&intel_dsi->dev); > +} > + > +static int intel_dsi_get_modes(struct drm_connector *connector) > +{ > + struct intel_connector *intel_connector =3D to_intel_connector(connecto= r); > + struct drm_display_mode *mode; > + > + DRM_DEBUG_KMS("\n"); > + > + if (!intel_connector->panel.fixed_mode) { > + DRM_DEBUG_KMS("no fixed mode\n"); > + return 0; > + } > + > + mode =3D drm_mode_duplicate(connector->dev, > + intel_connector->panel.fixed_mode); > + if (!mode) { > + DRM_DEBUG_KMS("drm_mode_duplicate failed\n"); > + return 0; > + } > + > + drm_mode_probed_add(connector, mode); > + return 1; > +} > + > +static void intel_dsi_destroy(struct drm_connector *connector) > +{ > + struct intel_connector *intel_connector =3D to_intel_connector(connecto= r); > + > + DRM_DEBUG_KMS("\n"); > + intel_panel_fini(&intel_connector->panel); > + drm_sysfs_connector_remove(connector); > + drm_connector_cleanup(connector); > + kfree(connector); > +} > + > +static const struct drm_encoder_funcs intel_dsi_funcs =3D { > + .destroy =3D intel_encoder_destroy, > +}; > + > +static const struct drm_connector_helper_funcs intel_dsi_connector_helpe= r_funcs =3D { > + .get_modes =3D intel_dsi_get_modes, > + .mode_valid =3D intel_dsi_mode_valid, > + .best_encoder =3D intel_best_encoder, > +}; > + > +static const struct drm_connector_funcs intel_dsi_connector_funcs =3D { > + .dpms =3D intel_connector_dpms, > + .detect =3D intel_dsi_detect, > + .destroy =3D intel_dsi_destroy, > + .fill_modes =3D drm_helper_probe_single_connector_modes, > +}; > + > +bool intel_dsi_init(struct drm_device *dev) > +{ > + struct intel_dsi *intel_dsi; > + struct intel_encoder *intel_encoder; > + struct drm_encoder *encoder; > + struct intel_connector *intel_connector; > + struct drm_connector *connector; > + struct drm_display_mode *fixed_mode =3D NULL; > + const struct intel_dsi_device *dsi; > + unsigned int i; > + > + DRM_DEBUG_KMS("\n"); > + > + intel_dsi =3D kzalloc(sizeof(*intel_dsi), GFP_KERNEL); > + if (!intel_dsi) > + return false; > + > + intel_connector =3D kzalloc(sizeof(*intel_connector), GFP_KERNEL); > + if (!intel_connector) { > + kfree(intel_dsi); > + return false; > + } > + > + intel_encoder =3D &intel_dsi->base; > + encoder =3D &intel_encoder->base; > + intel_dsi->attached_connector =3D intel_connector; > + > + connector =3D &intel_connector->base; > + > + drm_encoder_init(dev, encoder, &intel_dsi_funcs, DRM_MODE_ENCODER_DSI); > + > + /* XXX: very likely not all of these are needed */ > + intel_encoder->hot_plug =3D intel_dsi_hot_plug; > + intel_encoder->compute_config =3D intel_dsi_compute_config; > + intel_encoder->pre_pll_enable =3D intel_dsi_pre_pll_enable; > + intel_encoder->pre_enable =3D intel_dsi_pre_enable; > + intel_encoder->enable =3D intel_dsi_enable; > + intel_encoder->mode_set =3D intel_dsi_mode_set; > + intel_encoder->disable =3D intel_dsi_disable; > + intel_encoder->post_disable =3D intel_dsi_post_disable; > + intel_encoder->get_hw_state =3D intel_dsi_get_hw_state; > + intel_encoder->get_config =3D intel_dsi_get_config; > + > + intel_connector->get_hw_state =3D intel_connector_get_hw_state; > + > + for (i =3D 0; i < ARRAY_SIZE(intel_dsi_devices); i++) { > + dsi =3D &intel_dsi_devices[i]; > + intel_dsi->dev =3D *dsi; > + > + if (dsi->dev_ops->init(&intel_dsi->dev)) > + break; > + } > + > + if (i =3D=3D ARRAY_SIZE(intel_dsi_devices)) { > + DRM_DEBUG_KMS("no device found\n"); > + goto err; > + } > + > + intel_encoder->type =3D INTEL_OUTPUT_DSI; > + intel_encoder->crtc_mask =3D (1 << 0); /* XXX */ Maybe just pass in "pipe" since we have DSI for both A and B. Although I didn't look at the DSI PLL code yet, so I'm not sure we can actually use both DSI outputs at the same time currently. I suppose both need to be running at the same freq since we have only one PLL, and we have to take care of the PLL sharing somewhere. > + > + intel_encoder->cloneable =3D false; > + drm_connector_init(dev, connector, &intel_dsi_connector_funcs, > + DRM_MODE_CONNECTOR_DSI); > + > + drm_connector_helper_add(connector, &intel_dsi_connector_helper_funcs); > + > + connector->display_info.subpixel_order =3D SubPixelHorizontalRGB; /*XXX= */ > + connector->interlace_allowed =3D false; > + connector->doublescan_allowed =3D false; > + > + intel_connector_attach_encoder(intel_connector, intel_encoder); > + > + drm_sysfs_connector_add(connector); > + > + fixed_mode =3D dsi->dev_ops->get_modes(&intel_dsi->dev); > + if (!fixed_mode) { > + DRM_DEBUG_KMS("no fixed mode\n"); > + goto err; > + } > + > + fixed_mode->type |=3D DRM_MODE_TYPE_PREFERRED; > + intel_panel_init(&intel_connector->panel, fixed_mode); > + > + return true; > + > +err: > + drm_encoder_cleanup(&intel_encoder->base); > + kfree(intel_dsi); > + kfree(intel_connector); > + > + return false; > +} > -- = > 1.7.9.5 > = > _______________________________________________ > Intel-gfx mailing list > Intel-gfx@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/intel-gfx -- = Ville Syrj=E4l=E4 Intel OTC