From: "Ville Syrjälä" <ville.syrjala@linux.intel.com>
To: Jani Nikula <jani.nikula@intel.com>
Cc: intel-gfx@lists.freedesktop.org, yogesh.mohan.marimuthu@intel.com
Subject: Re: [PATCH v2 08/15] drm/i915: add basic MIPI DSI output support
Date: Tue, 20 Aug 2013 17:23:13 +0300 [thread overview]
Message-ID: <20130820142313.GW7159@intel.com> (raw)
In-Reply-To: <7a5baa3c1d7a8fe77ec4581a5ad8f39738dd49e3.1376655793.git.jani.nikula@intel.com>
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 <jani.nikula@intel.com>
> Signed-off-by: Shobhit Kumar <shobhit.kumar@intel.com>
> ---
> 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 := 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/intel_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_object *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/intel_dsi.c
> new file mode 100644
> index 0000000..d7eddbd
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/intel_dsi.c
> @@ -0,0 +1,534 @@
> +/*
> + * Copyright © 2013 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * 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, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> + * DEALINGS IN THE SOFTWARE.
> + *
> + * Author: Jani Nikula <jani.nikula@intel.com>
> + */
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_edid.h>
> +#include <drm/i915_drm.h>
> +#include <linux/slab.h>
> +#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[] = {
> +};
> +
> +static struct intel_dsi *intel_attached_dsi(struct drm_connector *connector)
> +{
> + 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 == INTEL_DSI_VIDEO_MODE;
> +}
> +
> +static inline bool is_cmd_mode(struct intel_dsi *intel_dsi)
> +{
> + return intel_dsi->dev.type == 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 = container_of(encoder, struct intel_dsi,
> + base);
> + struct intel_connector *intel_connector = intel_dsi->attached_connector;
> + struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
> + struct drm_display_mode *adjusted_mode = &config->adjusted_mode;
> + struct drm_display_mode *mode = &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 = encoder->base.dev->dev_private;
> + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
> + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
> + int pipe = intel_crtc->pipe;
> + u32 temp;
> +
> + DRM_DEBUG_KMS("\n");
> +
> + temp = I915_READ(MIPI_DEVICE_READY(pipe));
> + temp &= ~ULPS_STATE_MASK;
> + temp &= ~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 = 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 = encoder->base.dev->dev_private;
> + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
> + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
> + int pipe = 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 = 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 = I915_READ(MIPI_DEVICE_READY(pipe));
> + temp &= ~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 &= ~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 = encoder->base.dev->dev_private;
> + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
> +
> + DRM_DEBUG_KMS("\n");
> +
> + /* XXX: this is wrong */
> + if (intel_crtc) {
> + u32 val;
> +
> + *pipe = intel_crtc->pipe;
> +
> + /* XXX: only works for video mode */
> + val = 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 = to_intel_connector(connector);
> + struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
> + struct intel_dsi *intel_dsi = 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 = encoder->dev;
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
> + struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
> + int pipe = intel_crtc->pipe;
> + unsigned int bpp = intel_crtc->config.pipe_bpp;
> + unsigned int lane_count = intel_dsi->lane_count;
> +
> + u16 hactive, hfp, hsync, hbp, vfp, vsync, vbp;
> +
> + hactive = mode->hdisplay;
> + hfp = mode->hsync_start - mode->hdisplay;
> + hsync = mode->hsync_end - mode->hsync_start;
> + hbp = mode->htotal - mode->hsync_end;
> +
> + vfp = mode->vsync_start - mode->vdisplay;
> + vsync = mode->vsync_end - mode->vsync_start;
> + vbp = mode->vtotal - mode->vsync_end;
> +
> + /* horizontal values are in terms of high speed byte clock */
> + hactive = txbyteclkhs(hactive, bpp, lane_count);
> + hfp = txbyteclkhs(hfp, bpp, lane_count);
> + hsync = txbyteclkhs(hsync, bpp, lane_count);
> + hbp = 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 = &intel_encoder->base;
> + struct drm_device *dev = encoder->dev;
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
> + struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
> + struct drm_display_mode *adjusted_mode =
> + &intel_crtc->config.adjusted_mode;
> + int pipe = intel_crtc->pipe;
> + unsigned int bpp = 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 = I915_READ(MIPI_CTRL(0));
> + tmp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
> + I915_WRITE(MIPI_CTRL(0), tmp | ESCAPE_CLOCK_DIVIDER_1);
> +
> + /* read request priority is per pipe */
> + tmp = I915_READ(MIPI_CTRL(pipe));
> + tmp &= ~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 = intel_dsi->lane_count << DATA_LANES_PRG_REG_SHIFT;
> + if (is_cmd_mode(intel_dsi)) {
> + val |= intel_dsi->channel << CMD_MODE_CHANNEL_NUMBER_SHIFT;
> + val |= CMD_MODE_DATA_WIDTH_8_BIT; /* XXX */
> + } else {
> + val |= intel_dsi->channel << VID_MODE_CHANNEL_NUMBER_SHIFT;
> +
> + /* XXX: cross-check bpp vs. pixel format? */
> + val |= 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 == 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 = 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 = to_intel_connector(connector);
> + 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 = 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 = to_intel_connector(connector);
> +
> + 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 = {
> + .destroy = intel_encoder_destroy,
> +};
> +
> +static const struct drm_connector_helper_funcs intel_dsi_connector_helper_funcs = {
> + .get_modes = intel_dsi_get_modes,
> + .mode_valid = intel_dsi_mode_valid,
> + .best_encoder = intel_best_encoder,
> +};
> +
> +static const struct drm_connector_funcs intel_dsi_connector_funcs = {
> + .dpms = intel_connector_dpms,
> + .detect = intel_dsi_detect,
> + .destroy = intel_dsi_destroy,
> + .fill_modes = 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 = NULL;
> + const struct intel_dsi_device *dsi;
> + unsigned int i;
> +
> + DRM_DEBUG_KMS("\n");
> +
> + intel_dsi = kzalloc(sizeof(*intel_dsi), GFP_KERNEL);
> + if (!intel_dsi)
> + return false;
> +
> + intel_connector = kzalloc(sizeof(*intel_connector), GFP_KERNEL);
> + if (!intel_connector) {
> + kfree(intel_dsi);
> + return false;
> + }
> +
> + intel_encoder = &intel_dsi->base;
> + encoder = &intel_encoder->base;
> + intel_dsi->attached_connector = intel_connector;
> +
> + connector = &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 = intel_dsi_hot_plug;
> + intel_encoder->compute_config = intel_dsi_compute_config;
> + intel_encoder->pre_pll_enable = intel_dsi_pre_pll_enable;
> + intel_encoder->pre_enable = intel_dsi_pre_enable;
> + intel_encoder->enable = intel_dsi_enable;
> + intel_encoder->mode_set = intel_dsi_mode_set;
> + intel_encoder->disable = intel_dsi_disable;
> + intel_encoder->post_disable = intel_dsi_post_disable;
> + intel_encoder->get_hw_state = intel_dsi_get_hw_state;
> + intel_encoder->get_config = intel_dsi_get_config;
> +
> + intel_connector->get_hw_state = intel_connector_get_hw_state;
> +
> + for (i = 0; i < ARRAY_SIZE(intel_dsi_devices); i++) {
> + dsi = &intel_dsi_devices[i];
> + intel_dsi->dev = *dsi;
> +
> + if (dsi->dev_ops->init(&intel_dsi->dev))
> + break;
> + }
> +
> + if (i == ARRAY_SIZE(intel_dsi_devices)) {
> + DRM_DEBUG_KMS("no device found\n");
> + goto err;
> + }
> +
> + intel_encoder->type = INTEL_OUTPUT_DSI;
> + intel_encoder->crtc_mask = (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 = 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 = SubPixelHorizontalRGB; /*XXX*/
> + connector->interlace_allowed = false;
> + connector->doublescan_allowed = false;
> +
> + intel_connector_attach_encoder(intel_connector, intel_encoder);
> +
> + drm_sysfs_connector_add(connector);
> +
> + fixed_mode = dsi->dev_ops->get_modes(&intel_dsi->dev);
> + if (!fixed_mode) {
> + DRM_DEBUG_KMS("no fixed mode\n");
> + goto err;
> + }
> +
> + fixed_mode->type |= 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älä
Intel OTC
next prev parent reply other threads:[~2013-08-20 14:23 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-08-16 12:35 [PATCH v2 00/15] drm/i915: Baytrail MIPI DSI support Jani Nikula
2013-08-16 12:35 ` [PATCH v2 01/15] drm: add MIPI DSI encoder and connector types Jani Nikula
2013-08-20 12:05 ` [PATCH] " Jani Nikula
2013-08-16 12:35 ` [PATCH v2 02/15] drm/i915: add more VLV IOSF sideband ports accessors Jani Nikula
2013-08-16 12:35 ` [PATCH v2 03/15] drm/i915: add VLV pipeconf bit definition for DSI PLL lock Jani Nikula
2013-08-20 14:12 ` Ville Syrjälä
2013-08-16 12:35 ` [PATCH v2 04/15] drm/i915: add MIPI DSI register definitions Jani Nikula
2013-08-16 12:35 ` [PATCH v2 05/15] drm/i915: add MIPI DSI output type and subtypes Jani Nikula
2013-08-16 12:35 ` [PATCH v2 06/15] drm/i915: add structs for MIPI DSI output Jani Nikula
2013-08-16 12:35 ` [PATCH v2 07/15] drm/i915: add MIPI DSI command sending routines Jani Nikula
2013-08-20 14:13 ` Ville Syrjälä
2013-08-16 12:35 ` [PATCH v2 08/15] drm/i915: add basic MIPI DSI output support Jani Nikula
2013-08-20 14:23 ` Ville Syrjälä [this message]
2013-08-16 12:35 ` [PATCH v2 09/15] drm/i915: add VLV DSI PLL Calculations Jani Nikula
2013-08-20 18:35 ` Ville Syrjälä
2013-08-16 12:35 ` [PATCH v2 10/15] drm/i915: fix PLL assertions for DSI PLL Jani Nikula
2013-08-16 12:35 ` [PATCH v2 11/15] drm/i915: don't enable DPLL for DSI Jani Nikula
2013-08-16 12:36 ` [PATCH v2 12/15] drm/i915: Band Gap WA Jani Nikula
2013-08-23 16:21 ` Ville Syrjälä
2013-08-16 12:36 ` [PATCH v2 13/15] drm/i915: Parse the MIPI related VBT Block and store relevant info Jani Nikula
2013-08-16 12:36 ` [PATCH v2 14/15] drm/i915: initialize DSI output on VLV Jani Nikula
2013-08-16 12:36 ` [PATCH v2 15/15] drm/i915: add AUO MIPI DSI display sub-encoder Jani Nikula
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20130820142313.GW7159@intel.com \
--to=ville.syrjala@linux.intel.com \
--cc=intel-gfx@lists.freedesktop.org \
--cc=jani.nikula@intel.com \
--cc=yogesh.mohan.marimuthu@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.