On Tue, Sep 08, 2015 at 03:28:00PM +0300, Ander Conselvan de Oliveira wrote: > This adds a test that compiles the link training code from i915 into a > separate executable and uses it to train a fake sink device. The test > also uses device information from i915 to exercise the different code > paths for different hardwdare generations. > > In order to get the code to compile a lot of stubbing was necessary. It > was also easier to copy a few functions from the drm_dp_helpers instead > of getting the whole thing to compile as part of the test. Hmm. So the only device spefic information you really need is: - supported link rates - max vswing/pre-emph settings - DDI vs. not Cooking up a few configurations with varying options would seem fairly easy without having to pull in the whole device info, and the hw specific max vswing/pre-emphasis stuff. > --- > link-training-test/Makefile | 40 +++ > link-training-test/drm_dp_helper.c | 115 +++++++++ > link-training-test/intel_drv.h | 148 ++++++++++++ > link-training-test/link_training_test.c | 414 ++++++++++++++++++++++++++++++++ > 4 files changed, 717 insertions(+) > create mode 100644 link-training-test/Makefile > create mode 100644 link-training-test/drm_dp_helper.c > create mode 100644 link-training-test/intel_drv.h > create mode 100644 link-training-test/link_training_test.c > > diff --git a/link-training-test/Makefile b/link-training-test/Makefile > new file mode 100644 > index 0000000..07a9914 > --- /dev/null > +++ b/link-training-test/Makefile > @@ -0,0 +1,40 @@ > +KERNEL_SRC_DIR=/home/aconselv/linux > + > +# Files copied from i915 source tree > +COPIED_SOURCES = \ > + intel_dp_link_training.c \ > + intel_dev_info.c \ > + intel_dev_info.h \ > + i915_reg.h > + > +INTEL_DP_LINK_TRAINING_C = $(KERNEL_SRC_DIR)/drivers/gpu/drm/i915/intel_dp_link_training.c > + > +INCLUDEDIR = \ > + -I$(KERNEL_SRC_DIR)/include/drm \ > + -I$(KERNEL_SRC_DIR)/ \ > + -I. > + > +DEFINES = \ > + -D__KERNEL__ > + > +HEADER_FILES = \ > + intel_drv.h > + > +SOURCE_FILES = \ > + intel_dp_link_training.c \ > + link_training_test.c \ > + drm_dp_helper.c > + > +all: link_training_test > + > +#intel_dp_link_training.c: $(INTEL_DP_LINK_TRAINING_C) > +# cp $(INTEL_DP_LINK_TRAINING_C) . > + > +$(COPIED_SOURCES): %: $(KERNEL_SRC_DIR)/drivers/gpu/drm/i915/% > + cp $< $@ > + > +link_training_test: $(COPIED_SOURCES) $(SOURCE_FILES) $(HEADER_FILES) > + gcc -g3 -O0 -std=gnu99 -o link_training_test $(SOURCE_FILES) $(INCLUDEDIR) $(DEFINES) > + > +clean: > + rm link_training_test $(COPIED_SOURCES) > diff --git a/link-training-test/drm_dp_helper.c b/link-training-test/drm_dp_helper.c > new file mode 100644 > index 0000000..a8db7f9 > --- /dev/null > +++ b/link-training-test/drm_dp_helper.c > @@ -0,0 +1,115 @@ > +/* > + * Copyright © 2009 Keith Packard > + * > + * Permission to use, copy, modify, distribute, and sell this software and its > + * documentation for any purpose is hereby granted without fee, provided that > + * the above copyright notice appear in all copies and that both that copyright > + * notice and this permission notice appear in supporting documentation, and > + * that the name of the copyright holders not be used in advertising or > + * publicity pertaining to distribution of the software without specific, > + * written prior permission. The copyright holders make no representations > + * about the suitability of this software for any purpose. It is provided "as > + * is" without express or implied warranty. > + * > + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, > + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO > + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR > + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, > + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER > + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE > + * OF THIS SOFTWARE. > + */ > + > +#include "intel_drv.h" > + > +/* TODO: Get rid of this copy of drm_dp_helper functions. */ > + > +static u8 dp_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r) > +{ > + return link_status[r - DP_LANE0_1_STATUS]; > +} > + > +static u8 dp_get_lane_status(const u8 link_status[DP_LINK_STATUS_SIZE], > + int lane) > +{ > + int i = DP_LANE0_1_STATUS + (lane >> 1); > + int s = (lane & 1) * 4; > + u8 l = dp_link_status(link_status, i); > + return (l >> s) & 0xf; > +} > + > +bool drm_dp_channel_eq_ok(const u8 link_status[DP_LINK_STATUS_SIZE], > + int lane_count) > +{ > + u8 lane_align; > + u8 lane_status; > + int lane; > + > + lane_align = dp_link_status(link_status, > + DP_LANE_ALIGN_STATUS_UPDATED); > + if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0) > + return false; > + for (lane = 0; lane < lane_count; lane++) { > + lane_status = dp_get_lane_status(link_status, lane); > + if ((lane_status & DP_CHANNEL_EQ_BITS) != DP_CHANNEL_EQ_BITS) > + return false; > + } > + return true; > +} > + > +bool drm_dp_clock_recovery_ok(const u8 link_status[DP_LINK_STATUS_SIZE], > + int lane_count) > +{ > + int lane; > + u8 lane_status; > + > + for (lane = 0; lane < lane_count; lane++) { > + lane_status = dp_get_lane_status(link_status, lane); > + if ((lane_status & DP_LANE_CR_DONE) == 0) > + return false; > + } > + return true; > +} > + > +u8 drm_dp_get_adjust_request_voltage(const u8 link_status[DP_LINK_STATUS_SIZE], > + int lane) > +{ > + int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); > + int s = ((lane & 1) ? > + DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT : > + DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT); > + u8 l = dp_link_status(link_status, i); > + > + return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT; > +} > + > +u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SIZE], > + int lane) > +{ > + int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); > + int s = ((lane & 1) ? > + DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT : > + DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT); > + u8 l = dp_link_status(link_status, i); > + > + return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT; > +} > + > +/* FIXME: */ > +static void udelay() {} > +static void mdelay() {} > + > +void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { > + if (dpcd[DP_TRAINING_AUX_RD_INTERVAL] == 0) > + udelay(100); > + else > + mdelay(dpcd[DP_TRAINING_AUX_RD_INTERVAL] * 4); > +} > + > +void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { > + if (dpcd[DP_TRAINING_AUX_RD_INTERVAL] == 0) > + udelay(400); > + else > + mdelay(dpcd[DP_TRAINING_AUX_RD_INTERVAL] * 4); > +} > + > diff --git a/link-training-test/intel_drv.h b/link-training-test/intel_drv.h > new file mode 100644 > index 0000000..f7a6a6c > --- /dev/null > +++ b/link-training-test/intel_drv.h > @@ -0,0 +1,148 @@ > +/* > + * Copyright (c) 2006 Dave Airlie <airlied@xxxxxxxx> > + * Copyright (c) 2007-2015 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. > + */ > + > +#ifndef FAKE_INTEL_DRV_H > +#define FAKE_INTEL_DRV_H > + > +#include <stdio.h> > +#include <stdint.h> > +#include <stdbool.h> > +#include <string.h> > +#include <tools/include/linux/compiler.h> > + > +typedef unsigned char u8; > +typedef unsigned short u16; > +typedef unsigned int u32; > +typedef unsigned long size_t; > +typedef long ssize_t; > + > +struct drm_device { > + void *dev_private; > +}; > + > +static inline struct drm_i915_private *to_i915(const struct drm_device *dev) > +{ > + return dev->dev_private; > +} > + > +#define BUILD_BUG() > + > +#include "intel_dev_info.h" > + > +struct drm_i915_private { > + struct intel_device_info info; > + bool edp_low_vswing; > + enum intel_pch pch_type; > +}; > + > + > +struct i2c_adapter { > +}; > + > +struct mutex { > +}; > + > +#include <drm_dp_helper.h> > + > +#define DRM_ERROR printf > +#define DRM_DEBUG_KMS printf > + > +enum port { > + PORT_A = 0, > + PORT_B, > + PORT_C, > + PORT_D, > + PORT_E, > + I915_MAX_PORTS > +}; > +#define port_name(p) ((p) + 'A') > + > +struct drm_encoder { > + void *dev; > +}; > + > +struct intel_encoder { > + struct drm_encoder base; > +}; > + > +struct intel_dp { > + int link_rate; > + int lane_count; > + uint8_t link_bw; > + uint8_t num_sink_rates; > + uint8_t train_set[4]; > + bool train_set_valid; > + struct drm_dp_aux aux; > + uint8_t dpcd[DP_RECEIVER_CAP_SIZE]; > + uint32_t DP; > + bool use_tps3; > + > + /* Hold test private data */ > + void *priv; > +}; > + > +struct intel_digital_port { > + struct intel_encoder base; > + struct intel_dp dp; > + enum port port; > +}; > + > +#define offsetof(type, member) __builtin_offsetof (type, member) > +#define container_of(ptr, type, member) ({ \ > + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ > + (type *)( (char *)__mptr - offsetof(type,member) );}) > + > +static inline struct intel_digital_port * > +dp_to_dig_port(struct intel_dp *intel_dp) > +{ > + return container_of(intel_dp, struct intel_digital_port, dp); > +} > + > +void > +intel_dp_program_link_training_pattern(struct intel_dp *intel_dp, > + uint8_t dp_train_pat); > +void > +intel_dp_update_signal_levels(struct intel_dp *intel_dp); > +void intel_dp_set_idle_link_train(struct intel_dp *intel_dp); > +void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock, > + uint8_t *link_bw, uint8_t *rate_select); > +bool > +intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE]); > +void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder); > +void > +intel_dp_start_link_train(struct intel_dp *intel_dp); > +void > +intel_dp_stop_link_train(struct intel_dp *intel_dp); > +bool intel_dp_source_supports_hbr2(struct drm_device *dev); > + > +static inline struct drm_device *intel_dp_to_dev(struct intel_dp *intel_dp) > +{ > + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); > + > + return intel_dig_port->base.base.dev; > +} > + > +#include "i915_reg.h" > + > +#endif /* FAKE_INTEL_DRV_H */ > diff --git a/link-training-test/link_training_test.c b/link-training-test/link_training_test.c > new file mode 100644 > index 0000000..aa73b9e > --- /dev/null > +++ b/link-training-test/link_training_test.c > @@ -0,0 +1,414 @@ > +/* > + * Copyright © 2015 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. > + * > + * Authors: > + * Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@xxxxxxxxx> > + * > + */ > + > +#include <stdlib.h> > +#include <assert.h> > + > +#include "intel_drv.h" > +#include "i915_reg.h" > + > +struct sink_device { > + ssize_t (*dpcd_write)(struct sink_device *sink, unsigned int offset, > + void *buffer, size_t size); > + bool (*get_link_status)(struct sink_device *sink, > + uint8_t link_status[DP_LINK_STATUS_SIZE]); > + > + struct { > + bool lane_count_and_bw_set; > + bool training_pattern_1_set; > + bool started_with_non_zero_levels; > + bool cr_done; > + bool channel_eq_done; > + > + uint8_t dpcd[0x3000]; > + } data; > +}; > + > +/* Fake sink device implementation */ > + > +static uint8_t > +sink_device_lane_count(struct sink_device *sink) > +{ > + return sink->data.dpcd[DP_LANE_COUNT_SET]; > +} > + > +static uint8_t > +sink_device_get_training_pattern(struct sink_device *sink) > +{ > + return sink->data.dpcd[DP_TRAINING_PATTERN_SET] & DP_TRAINING_PATTERN_MASK; > +} > + > +static uint8_t > +sink_device_get_voltage_swing(struct sink_device *sink, int lane) > +{ > + return sink->data.dpcd[DP_TRAINING_LANE0_SET + lane] & > + DP_TRAIN_VOLTAGE_SWING_MASK; > +} > + > +static uint8_t > +sink_device_get_pre_emphasis_level(struct sink_device *sink, int lane) > +{ > + return sink->data.dpcd[DP_TRAINING_LANE0_SET + lane] & > + DP_TRAIN_PRE_EMPHASIS_MASK; > +} > + > +static void > +sink_device_check_lane_count_and_bw(struct sink_device *sink) > +{ > + if (sink->data.lane_count_and_bw_set) > + return; > + > + assert(sink->data.dpcd[DP_TRAINING_PATTERN_SET] == 0); > + > + if (sink->data.dpcd[DP_LINK_BW_SET] != 0 && > + sink->data.dpcd[DP_LANE_COUNT_SET] != 0) > + sink->data.lane_count_and_bw_set = true; > +} > + > +static void > +sink_device_check_pattern_1_set(struct sink_device *sink) > +{ > + if (!sink->data.lane_count_and_bw_set || > + sink->data.training_pattern_1_set) > + return; > + > + assert(sink_device_get_training_pattern(sink) <= DP_TRAINING_PATTERN_1); > + > + if (sink_device_get_training_pattern(sink) != DP_TRAINING_PATTERN_1) > + return; > + > + assert(sink->data.dpcd[DP_LINK_BW_SET] == DP_LINK_BW_1_62 || > + sink->data.dpcd[DP_LINK_BW_SET] == DP_LINK_BW_2_7); > + > + assert(sink->data.dpcd[DP_LANE_COUNT_SET] == 1 || > + sink->data.dpcd[DP_LANE_COUNT_SET] == 2 || > + sink->data.dpcd[DP_LANE_COUNT_SET] == 4); > + > + for (int lane = 0; lane < sink_device_lane_count(sink); lane++) { > + if (sink_device_get_voltage_swing(sink, lane) != DP_TRAIN_VOLTAGE_SWING_LEVEL_0 || > + sink_device_get_pre_emphasis_level(sink, lane) != DP_TRAIN_PRE_EMPH_LEVEL_0) > + sink->data.started_with_non_zero_levels = true; > + } > + > + sink->data.training_pattern_1_set = true; > +} > + > +static void > +sink_device_check_pattern_2_set(struct sink_device *sink) > +{ > + if (!sink->data.cr_done) > + return; > + > + assert(sink_device_get_training_pattern(sink) == DP_TRAINING_PATTERN_2); > +} > + > +static void > +sink_device_check_pattern_disable(struct sink_device *sink) > +{ > + if (!sink->data.cr_done || ! sink->data.channel_eq_done) > + return; > + > + assert(sink_device_get_training_pattern(sink) == DP_TRAINING_PATTERN_DISABLE); > +} > + > +static ssize_t > +sink_device_dpcd_write(struct sink_device *sink, unsigned int offset, > + void *buffer, size_t size) > +{ > + memcpy(sink->data.dpcd + offset, buffer, size); > + > + sink_device_check_lane_count_and_bw(sink); > + > + if (!sink->data.cr_done) > + sink_device_check_pattern_1_set(sink); > + else if (!sink->data.channel_eq_done) > + sink_device_check_pattern_2_set(sink); > + else > + sink_device_check_pattern_disable(sink); > + > + return size; > +} > + > +static bool > +sink_device_max_voltage_reached(struct sink_device *sink, int lane) > +{ > + return (sink->data.dpcd[DP_TRAINING_LANE0_SET + lane] & DP_TRAIN_MAX_SWING_REACHED) == > + DP_TRAIN_MAX_SWING_REACHED; > +} > + > +static bool > +sink_device_max_pre_emphasis_reached(struct sink_device *sink, int lane) > +{ > + return (sink->data.dpcd[DP_TRAINING_LANE0_SET + lane] & DP_TRAIN_MAX_PRE_EMPHASIS_REACHED) == > + DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; > +} > + > +static bool > +sink_device_request_higher_voltage_swing(struct sink_device *sink) > +{ > + bool max_reached; > + > + for (int lane = 0; lane < sink_device_lane_count(sink); lane++) { > + if (sink_device_max_voltage_reached(sink, lane)) { > + max_reached = true; > + break; > + } > + } > + > + if (max_reached) > + return false; > + > + for (int lane = 0; lane < sink_device_lane_count(sink); lane++) { > + sink->data.dpcd[DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1)] |= > + (sink_device_get_voltage_swing(sink, lane) + 1) << > + (DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT * (lane & 1)); > + } > + > + return true; > +} > + > +static bool > +sink_device_request_higher_pre_emphasis(struct sink_device *sink) > +{ > + bool max_reached; > + > + for (int lane = 0; lane < sink_device_lane_count(sink); lane++) { > + if (sink_device_max_pre_emphasis_reached(sink, lane)) { > + max_reached = true; > + break; > + } > + } > + > + if (max_reached) > + return false; > + > + for (int lane = 0; lane < sink_device_lane_count(sink); lane++) { > + sink->data.dpcd[DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1)] |= > + (sink_device_get_pre_emphasis_level(sink, lane) + 1) << > + (DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT + > + (DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT * (lane & 1))); > + } > + > + return true; > +} > + > +static void > +sink_device_mark_cr_done(struct sink_device *sink) > +{ > + for (int lane = 0; lane < sink_device_lane_count(sink); lane++) > + sink->data.dpcd[DP_LANE0_1_STATUS + (lane >> 1)] |= > + DP_LANE_CR_DONE << (4 * (lane & 1)); > + > + sink->data.cr_done = true; > +} > + > +static void > +sink_device_mark_channel_eq_done(struct sink_device *sink) > +{ > + for (int lane = 0; lane < sink_device_lane_count(sink); lane++) { > + uint8_t mask = (DP_LANE_CHANNEL_EQ_DONE | DP_LANE_SYMBOL_LOCKED); > + sink->data.dpcd[DP_LANE0_1_STATUS + (lane >> 1)] |= > + mask << (4 * (lane & 1)); > + } > + > + sink->data.dpcd[DP_LANE_ALIGN_STATUS_UPDATED] |= DP_INTERLANE_ALIGN_DONE; > + > + sink->data.channel_eq_done = true; > +} > + > +static bool > +sink_device_get_link_status(struct sink_device *sink, > + uint8_t link_status[DP_LINK_STATUS_SIZE]) > +{ > + if (!sink->data.cr_done) { > + if (!sink_device_request_higher_voltage_swing(sink)) > + sink_device_mark_cr_done(sink); > + } else if (!sink->data.channel_eq_done) { > + if (!sink_device_request_higher_pre_emphasis(sink)) > + sink_device_mark_channel_eq_done(sink); > + } > + > + memcpy(link_status, sink->data.dpcd + DP_LANE0_1_STATUS, > + DP_LINK_STATUS_SIZE); > + > + return true; > +} > + > +static struct sink_device simple_sink = { > + .get_link_status = sink_device_get_link_status, > + .dpcd_write = sink_device_dpcd_write, > +}; > + > +/* Glue code */ > + > +void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder) > +{ > +} > + > +void intel_dp_set_idle_link_train(struct intel_dp *intel_dp) > +{ > +} > + > +bool intel_dp_source_supports_hbr2(struct drm_device *dev) > +{ > + return false; > +} > + > +bool > +intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE]) > +{ > + struct sink_device *sink = intel_dp->priv; > + return sink->get_link_status(sink, link_status); > +} > + > +void > +intel_dp_update_signal_levels(struct intel_dp *intel_dp) > +{ > +} > + > +void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock, > + uint8_t *link_bw, uint8_t *rate_select) > +{ > + *link_bw = intel_dp->link_bw; > + *rate_select = 0; > +} > + > +void > +intel_dp_program_link_training_pattern(struct intel_dp *intel_dp, > + uint8_t dp_train_pat) > +{ > +} > + > +ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset, > + void *buffer, size_t size) > +{ > + struct intel_dp *intel_dp = > + container_of(aux, struct intel_dp, aux); > + struct sink_device *sink = intel_dp->priv; > + > + return sink->dpcd_write(sink, offset, buffer, size); > +} > + > +/* --- */ > + > +static struct intel_dp * > +intel_dp_create(struct drm_device *dev, int lanes, uint8_t link_bw) > +{ > + struct intel_digital_port *dig_port; > + > + dig_port = calloc(1, sizeof *dig_port); > + dig_port->base.base.dev = dev; > + dig_port->dp.lane_count = lanes; > + dig_port->dp.link_bw = link_bw; > + > + return &dig_port->dp; > +} > + > +static void > +intel_dp_destroy(struct intel_dp *intel_dp) > +{ > + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); > + free(dig_port); > +} > + > +/* FIXME: Yikes! */ > +#define BITS_PER_LONG 64 > +#include <include/linux/mod_devicetable.h> > +#include <i915_pciids.h> > +#include "intel_dev_info.c" > + > +static const struct pci_device_id pciidlist[] = { > + INTEL_PCI_IDS, > + {0, 0, 0} > +}; > + > +struct drm_device * > +drm_device_for_pci_id(const struct pci_device_id *id) > +{ > + struct drm_device *dev; > + struct drm_i915_private *dev_priv; > + > + dev = calloc(1, sizeof *dev); > + dev_priv = calloc(1, sizeof *dev_priv); > + assert(dev && dev_priv); > + > + dev->dev_private = dev_priv; > + > + memcpy(&dev_priv->info, (void *) id->driver_data, sizeof dev_priv->info); > + dev_priv->info.device_id = id->device; > + > + /* TODO: set dev_priv->pch_type with an appropriate value */ > + dev_priv->pch_type = PCH_NONE; > + > + return dev; > +} > + > +void > +drm_device_destroy(struct drm_device *dev) > +{ > + free(dev->dev_private); > + free(dev); > +} > + > +int > +main(int argc, char *argv[]) > +{ > + const struct pci_device_id *id; > + > + for (id = &pciidlist[0]; > + id->vendor != 0 && id->device != 0; > + id++) { > + struct drm_device *dev = drm_device_for_pci_id(id); > + struct intel_dp *intel_dp = > + intel_dp_create(dev, 4, DP_LINK_BW_2_7); > + > + if (IS_GEN2(dev) || IS_PINEVIEW(dev)) > + continue; > + > + printf("Testing with device id %04x, gen %d\n", > + INTEL_DEVID(dev), INTEL_INFO(dev)->gen); > + > + intel_dp->priv = &simple_sink; > + memset(&simple_sink.data, 0, sizeof simple_sink.data); > + simple_sink.data.dpcd[DP_MAX_LINK_RATE] = 0x0A; > + simple_sink.data.dpcd[DP_MAX_LANE_COUNT] = 0x04; > + > + intel_dp_start_link_train(intel_dp); > + intel_dp_stop_link_train(intel_dp); > + > + for (int lane = 0; lane < intel_dp->lane_count; lane++) > + printf("lane %i: vswing: %d, pre-emph: %d\n", lane, > + sink_device_get_voltage_swing(&simple_sink, lane), > + sink_device_get_pre_emphasis_level(&simple_sink, lane)); > + printf("\n"); > + > + intel_dp_destroy(intel_dp); > + drm_device_destroy(dev); > + } > + > + return 0; > +} > -- > 2.4.3 -- Ville Syrjälä Intel OTC _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx