On Thu, Dec 3, 2009 at 8:08 PM, Dave Airlie <[email protected]> wrote:
> From: Dave Airlie <[email protected]>
>
> Both radeon and nouveau can re-use this code so move it up a level
> so they can. However the hw interfaces for aux ch are different
> enough that the code to translate from mode, address, bytes
> to actual hw interfaces isn't generic, so move that code into the
> Intel driver.
>

I think this is a good first step, but I think eventually we should
split the generic code into two files:
drm_dp_aux_algo.c/h - aux channel i2c algo
drm_dp_helper.c/h - DP register defs, helper functions for selecting
lanes/bw, etc.

Thoughts?

Alex

> Signed-off-by: Dave Airlie <[email protected]>
> ---
>  drivers/gpu/drm/Makefile             |    2 +-
>  drivers/gpu/drm/drm_dp_i2c_helper.c  |  209 ++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/Makefile        |    1 -
>  drivers/gpu/drm/i915/intel_display.c |    2 +-
>  drivers/gpu/drm/i915/intel_dp.c      |   72 ++++++++-
>  drivers/gpu/drm/i915/intel_dp.h      |  144 ------------------
>  drivers/gpu/drm/i915/intel_dp_i2c.c  |  273 
> ----------------------------------
>  include/drm/drm_dp_helper.h          |  149 ++++++++++++++++++
>  8 files changed, 426 insertions(+), 426 deletions(-)
>  create mode 100644 drivers/gpu/drm/drm_dp_i2c_helper.c
>  delete mode 100644 drivers/gpu/drm/i915/intel_dp.h
>  delete mode 100644 drivers/gpu/drm/i915/intel_dp_i2c.c
>  create mode 100644 include/drm/drm_dp_helper.h
>
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 3c8827a..91567ac 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -15,7 +15,7 @@ drm-y       :=        drm_auth.o drm_bufs.o drm_cache.o \
>
>  drm-$(CONFIG_COMPAT) += drm_ioc32.o
>
> -drm_kms_helper-y := drm_fb_helper.o drm_crtc_helper.o
> +drm_kms_helper-y := drm_fb_helper.o drm_crtc_helper.o drm_dp_i2c_helper.o
>
>  obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
>
> diff --git a/drivers/gpu/drm/drm_dp_i2c_helper.c 
> b/drivers/gpu/drm/drm_dp_i2c_helper.c
> new file mode 100644
> index 0000000..f1c7c85
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_dp_i2c_helper.c
> @@ -0,0 +1,209 @@
> +/*
> + * 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 <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/slab.h>
> +#include <linux/init.h>
> +#include <linux/errno.h>
> +#include <linux/sched.h>
> +#include <linux/i2c.h>
> +#include "drm_dp_helper.h"
> +#include "drmP.h"
> +
> +/* Run a single AUX_CH I2C transaction, writing/reading data as necessary */
> +static int
> +i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode,
> +                           uint8_t write_byte, uint8_t *read_byte)
> +{
> +       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
> +       int ret;
> +
> +       ret = (*algo_data->aux_ch)(adapter, mode,
> +                                  write_byte, read_byte);
> +       return ret;
> +}
> +
> +/*
> + * I2C over AUX CH
> + */
> +
> +/*
> + * Send the address. If the I2C link is running, this 'restarts'
> + * the connection with the new address, this is used for doing
> + * a write followed by a read (as needed for DDC)
> + */
> +static int
> +i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool 
> reading)
> +{
> +       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
> +       int mode = MODE_I2C_START;
> +       int ret;
> +
> +       if (reading)
> +               mode |= MODE_I2C_READ;
> +       else
> +               mode |= MODE_I2C_WRITE;
> +       algo_data->address = address;
> +       algo_data->running = true;
> +       ret = i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL);
> +       return ret;
> +}
> +
> +/*
> + * Stop the I2C transaction. This closes out the link, sending
> + * a bare address packet with the MOT bit turned off
> + */
> +static void
> +i2c_algo_dp_aux_stop(struct i2c_adapter *adapter, bool reading)
> +{
> +       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
> +       int mode = MODE_I2C_STOP;
> +
> +       if (reading)
> +               mode |= MODE_I2C_READ;
> +       else
> +               mode |= MODE_I2C_WRITE;
> +       if (algo_data->running) {
> +               (void) i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL);
> +               algo_data->running = false;
> +       }
> +}
> +
> +/*
> + * Write a single byte to the current I2C address, the
> + * the I2C link must be running or this returns -EIO
> + */
> +static int
> +i2c_algo_dp_aux_put_byte(struct i2c_adapter *adapter, u8 byte)
> +{
> +       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
> +       int ret;
> +
> +       if (!algo_data->running)
> +               return -EIO;
> +
> +       ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_WRITE, byte, 
> NULL);
> +       return ret;
> +}
> +
> +/*
> + * Read a single byte from the current I2C address, the
> + * I2C link must be running or this returns -EIO
> + */
> +static int
> +i2c_algo_dp_aux_get_byte(struct i2c_adapter *adapter, u8 *byte_ret)
> +{
> +       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
> +       int ret;
> +
> +       if (!algo_data->running)
> +               return -EIO;
> +
> +       ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_READ, 0, 
> byte_ret);
> +       return ret;
> +}
> +
> +static int
> +i2c_algo_dp_aux_xfer(struct i2c_adapter *adapter,
> +                    struct i2c_msg *msgs,
> +                    int num)
> +{
> +       int ret = 0;
> +       bool reading = false;
> +       int m;
> +       int b;
> +
> +       for (m = 0; m < num; m++) {
> +               u16 len = msgs[m].len;
> +               u8 *buf = msgs[m].buf;
> +               reading = (msgs[m].flags & I2C_M_RD) != 0;
> +               ret = i2c_algo_dp_aux_address(adapter, msgs[m].addr, reading);
> +               if (ret < 0)
> +                       break;
> +               if (reading) {
> +                       for (b = 0; b < len; b++) {
> +                               ret = i2c_algo_dp_aux_get_byte(adapter, 
> &buf[b]);
> +                               if (ret < 0)
> +                                       break;
> +                       }
> +               } else {
> +                       for (b = 0; b < len; b++) {
> +                               ret = i2c_algo_dp_aux_put_byte(adapter, 
> buf[b]);
> +                               if (ret < 0)
> +                                       break;
> +                       }
> +               }
> +               if (ret < 0)
> +                       break;
> +       }
> +       if (ret >= 0)
> +               ret = num;
> +       i2c_algo_dp_aux_stop(adapter, reading);
> +       DRM_DEBUG("dp_aux_xfer return %d\n", ret);
> +       return ret;
> +}
> +
> +static u32
> +i2c_algo_dp_aux_functionality(struct i2c_adapter *adapter)
> +{
> +       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
> +              I2C_FUNC_SMBUS_READ_BLOCK_DATA |
> +              I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
> +              I2C_FUNC_10BIT_ADDR;
> +}
> +
> +static const struct i2c_algorithm i2c_dp_aux_algo = {
> +       .master_xfer    = i2c_algo_dp_aux_xfer,
> +       .functionality  = i2c_algo_dp_aux_functionality,
> +};
> +
> +static void
> +i2c_dp_aux_reset_bus(struct i2c_adapter *adapter)
> +{
> +       (void) i2c_algo_dp_aux_address(adapter, 0, false);
> +       (void) i2c_algo_dp_aux_stop(adapter, false);
> +
> +}
> +
> +static int
> +i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter)
> +{
> +       adapter->algo = &i2c_dp_aux_algo;
> +       adapter->retries = 3;
> +       i2c_dp_aux_reset_bus(adapter);
> +       return 0;
> +}
> +
> +int
> +i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
> +{
> +       int error;
> +
> +       error = i2c_dp_aux_prepare_bus(adapter);
> +       if (error)
> +               return error;
> +       error = i2c_add_adapter(adapter);
> +       return error;
> +}
> +EXPORT_SYMBOL(i2c_dp_aux_add_bus);
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index fa7b9be..e3d0492 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -15,7 +15,6 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
>          intel_lvds.o \
>          intel_bios.o \
>          intel_dp.o \
> -         intel_dp_i2c.o \
>          intel_hdmi.o \
>          intel_sdvo.o \
>          intel_modes.o \
> diff --git a/drivers/gpu/drm/i915/intel_display.c 
> b/drivers/gpu/drm/i915/intel_display.c
> index 3ba6546..ccd180d 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -32,7 +32,7 @@
>  #include "intel_drv.h"
>  #include "i915_drm.h"
>  #include "i915_drv.h"
> -#include "intel_dp.h"
> +#include "drm_dp_helper.h"
>
>  #include "drm_crtc_helper.h"
>
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index d834475..63424d5 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -33,7 +33,7 @@
>  #include "intel_drv.h"
>  #include "i915_drm.h"
>  #include "i915_drv.h"
> -#include "intel_dp.h"
> +#include "drm_dp_helper.h"
>
>  #define DP_LINK_STATUS_SIZE    6
>  #define DP_LINK_CHECK_TIMEOUT  (10 * 1000)
> @@ -382,17 +382,77 @@ intel_dp_aux_native_read(struct intel_output 
> *intel_output,
>  }
>
>  static int
> -intel_dp_i2c_aux_ch(struct i2c_adapter *adapter,
> -                   uint8_t *send, int send_bytes,
> -                   uint8_t *recv, int recv_bytes)
> +intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
> +                   uint8_t write_byte, uint8_t *read_byte)
>  {
> +       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
>        struct intel_dp_priv *dp_priv = container_of(adapter,
>                                                     struct intel_dp_priv,
>                                                     adapter);
>        struct intel_output *intel_output = dp_priv->intel_output;
> +       uint16_t address = algo_data->address;
> +       uint8_t msg[5];
> +       uint8_t reply[2];
> +       int msg_bytes;
> +       int reply_bytes;
> +       int ret;
> +
> +       /* Set up the command byte */
> +       if (mode & MODE_I2C_READ)
> +               msg[0] = AUX_I2C_READ << 4;
> +       else
> +               msg[0] = AUX_I2C_WRITE << 4;
> +
> +       if (!(mode & MODE_I2C_STOP))
> +               msg[0] |= AUX_I2C_MOT << 4;
> +
> +       msg[1] = address >> 8;
> +       msg[2] = address;
> +
> +       switch (mode) {
> +       case MODE_I2C_WRITE:
> +               msg[3] = 0;
> +               msg[4] = write_byte;
> +               msg_bytes = 5;
> +               reply_bytes = 1;
> +               break;
> +       case MODE_I2C_READ:
> +               msg[3] = 0;
> +               msg_bytes = 4;
> +               reply_bytes = 2;
> +               break;
> +       default:
> +               msg_bytes = 3;
> +               reply_bytes = 1;
> +               break;
> +       }
>
> -       return intel_dp_aux_ch(intel_output,
> -                              send, send_bytes, recv, recv_bytes);
> +       for (;;) {
> +         ret = intel_dp_aux_ch(intel_output,
> +                               msg, msg_bytes,
> +                               reply, reply_bytes);
> +               if (ret < 0) {
> +                       DRM_DEBUG("aux_ch failed %d\n", ret);
> +                       return ret;
> +               }
> +               switch (reply[0] & AUX_I2C_REPLY_MASK) {
> +               case AUX_I2C_REPLY_ACK:
> +                       if (mode == MODE_I2C_READ) {
> +                               *read_byte = reply[1];
> +                       }
> +                       return reply_bytes - 1;
> +               case AUX_I2C_REPLY_NACK:
> +                       DRM_DEBUG("aux_ch nack\n");
> +                       return -EREMOTEIO;
> +               case AUX_I2C_REPLY_DEFER:
> +                       DRM_DEBUG("aux_ch defer\n");
> +                       udelay(100);
> +                       break;
> +               default:
> +                       DRM_ERROR("aux_ch invalid reply 0x%02x\n", reply[0]);
> +                       return -EREMOTEIO;
> +               }
> +       }
>  }
>
>  static int
> diff --git a/drivers/gpu/drm/i915/intel_dp.h b/drivers/gpu/drm/i915/intel_dp.h
> deleted file mode 100644
> index 2b38054..0000000
> --- a/drivers/gpu/drm/i915/intel_dp.h
> +++ /dev/null
> @@ -1,144 +0,0 @@
> -/*
> - * Copyright © 2008 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.
> - */
> -
> -#ifndef _INTEL_DP_H_
> -#define _INTEL_DP_H_
> -
> -/* From the VESA DisplayPort spec */
> -
> -#define AUX_NATIVE_WRITE       0x8
> -#define AUX_NATIVE_READ                0x9
> -#define AUX_I2C_WRITE          0x0
> -#define AUX_I2C_READ           0x1
> -#define AUX_I2C_STATUS         0x2
> -#define AUX_I2C_MOT            0x4
> -
> -#define AUX_NATIVE_REPLY_ACK   (0x0 << 4)
> -#define AUX_NATIVE_REPLY_NACK  (0x1 << 4)
> -#define AUX_NATIVE_REPLY_DEFER (0x2 << 4)
> -#define AUX_NATIVE_REPLY_MASK  (0x3 << 4)
> -
> -#define AUX_I2C_REPLY_ACK      (0x0 << 6)
> -#define AUX_I2C_REPLY_NACK     (0x1 << 6)
> -#define AUX_I2C_REPLY_DEFER    (0x2 << 6)
> -#define AUX_I2C_REPLY_MASK     (0x3 << 6)
> -
> -/* AUX CH addresses */
> -#define        DP_LINK_BW_SET          0x100
> -# define DP_LINK_BW_1_62                   0x06
> -# define DP_LINK_BW_2_7                            0x0a
> -
> -#define DP_LANE_COUNT_SET      0x101
> -# define DP_LANE_COUNT_MASK                0x0f
> -# define DP_LANE_COUNT_ENHANCED_FRAME_EN    (1 << 7)
> -
> -#define DP_TRAINING_PATTERN_SET        0x102
> -
> -# define DP_TRAINING_PATTERN_DISABLE       0
> -# define DP_TRAINING_PATTERN_1             1
> -# define DP_TRAINING_PATTERN_2             2
> -# define DP_TRAINING_PATTERN_MASK          0x3
> -
> -# define DP_LINK_QUAL_PATTERN_DISABLE      (0 << 2)
> -# define DP_LINK_QUAL_PATTERN_D10_2        (1 << 2)
> -# define DP_LINK_QUAL_PATTERN_ERROR_RATE    (2 << 2)
> -# define DP_LINK_QUAL_PATTERN_PRBS7        (3 << 2)
> -# define DP_LINK_QUAL_PATTERN_MASK         (3 << 2)
> -
> -# define DP_RECOVERED_CLOCK_OUT_EN         (1 << 4)
> -# define DP_LINK_SCRAMBLING_DISABLE        (1 << 5)
> -
> -# define DP_SYMBOL_ERROR_COUNT_BOTH        (0 << 6)
> -# define DP_SYMBOL_ERROR_COUNT_DISPARITY    (1 << 6)
> -# define DP_SYMBOL_ERROR_COUNT_SYMBOL      (2 << 6)
> -# define DP_SYMBOL_ERROR_COUNT_MASK        (3 << 6)
> -
> -#define DP_TRAINING_LANE0_SET              0x103
> -#define DP_TRAINING_LANE1_SET              0x104
> -#define DP_TRAINING_LANE2_SET              0x105
> -#define DP_TRAINING_LANE3_SET              0x106
> -
> -# define DP_TRAIN_VOLTAGE_SWING_MASK       0x3
> -# define DP_TRAIN_VOLTAGE_SWING_SHIFT      0
> -# define DP_TRAIN_MAX_SWING_REACHED        (1 << 2)
> -# define DP_TRAIN_VOLTAGE_SWING_400        (0 << 0)
> -# define DP_TRAIN_VOLTAGE_SWING_600        (1 << 0)
> -# define DP_TRAIN_VOLTAGE_SWING_800        (2 << 0)
> -# define DP_TRAIN_VOLTAGE_SWING_1200       (3 << 0)
> -
> -# define DP_TRAIN_PRE_EMPHASIS_MASK        (3 << 3)
> -# define DP_TRAIN_PRE_EMPHASIS_0           (0 << 3)
> -# define DP_TRAIN_PRE_EMPHASIS_3_5         (1 << 3)
> -# define DP_TRAIN_PRE_EMPHASIS_6           (2 << 3)
> -# define DP_TRAIN_PRE_EMPHASIS_9_5         (3 << 3)
> -
> -# define DP_TRAIN_PRE_EMPHASIS_SHIFT       3
> -# define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED  (1 << 5)
> -
> -#define DP_DOWNSPREAD_CTRL                 0x107
> -# define DP_SPREAD_AMP_0_5                 (1 << 4)
> -
> -#define DP_MAIN_LINK_CHANNEL_CODING_SET            0x108
> -# define DP_SET_ANSI_8B10B                 (1 << 0)
> -
> -#define DP_LANE0_1_STATUS                  0x202
> -#define DP_LANE2_3_STATUS                  0x203
> -
> -# define DP_LANE_CR_DONE                   (1 << 0)
> -# define DP_LANE_CHANNEL_EQ_DONE           (1 << 1)
> -# define DP_LANE_SYMBOL_LOCKED             (1 << 2)
> -
> -#define DP_LANE_ALIGN_STATUS_UPDATED       0x204
> -
> -#define DP_INTERLANE_ALIGN_DONE                    (1 << 0)
> -#define DP_DOWNSTREAM_PORT_STATUS_CHANGED   (1 << 6)
> -#define DP_LINK_STATUS_UPDATED             (1 << 7)
> -
> -#define DP_SINK_STATUS                     0x205
> -
> -#define DP_RECEIVE_PORT_0_STATUS           (1 << 0)
> -#define DP_RECEIVE_PORT_1_STATUS           (1 << 1)
> -
> -#define DP_ADJUST_REQUEST_LANE0_1          0x206
> -#define DP_ADJUST_REQUEST_LANE2_3          0x207
> -
> -#define DP_ADJUST_VOLTAGE_SWING_LANE0_MASK  0x03
> -#define DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT 0
> -#define DP_ADJUST_PRE_EMPHASIS_LANE0_MASK   0x0c
> -#define DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT  2
> -#define DP_ADJUST_VOLTAGE_SWING_LANE1_MASK  0x30
> -#define DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT 4
> -#define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK   0xc0
> -#define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT  6
> -
> -struct i2c_algo_dp_aux_data {
> -       bool running;
> -       u16 address;
> -       int (*aux_ch) (struct i2c_adapter *adapter,
> -                      uint8_t *send, int send_bytes,
> -                      uint8_t *recv, int recv_bytes);
> -};
> -
> -int
> -i2c_dp_aux_add_bus(struct i2c_adapter *adapter);
> -
> -#endif /* _INTEL_DP_H_ */
> diff --git a/drivers/gpu/drm/i915/intel_dp_i2c.c 
> b/drivers/gpu/drm/i915/intel_dp_i2c.c
> deleted file mode 100644
> index a63b6f5..0000000
> --- a/drivers/gpu/drm/i915/intel_dp_i2c.c
> +++ /dev/null
> @@ -1,273 +0,0 @@
> -/*
> - * 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 <linux/kernel.h>
> -#include <linux/module.h>
> -#include <linux/delay.h>
> -#include <linux/slab.h>
> -#include <linux/init.h>
> -#include <linux/errno.h>
> -#include <linux/sched.h>
> -#include <linux/i2c.h>
> -#include "intel_dp.h"
> -#include "drmP.h"
> -
> -/* Run a single AUX_CH I2C transaction, writing/reading data as necessary */
> -
> -#define MODE_I2C_START 1
> -#define MODE_I2C_WRITE 2
> -#define MODE_I2C_READ  4
> -#define MODE_I2C_STOP  8
> -
> -static int
> -i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode,
> -                           uint8_t write_byte, uint8_t *read_byte)
> -{
> -       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
> -       uint16_t address = algo_data->address;
> -       uint8_t msg[5];
> -       uint8_t reply[2];
> -       int msg_bytes;
> -       int reply_bytes;
> -       int ret;
> -
> -       /* Set up the command byte */
> -       if (mode & MODE_I2C_READ)
> -               msg[0] = AUX_I2C_READ << 4;
> -       else
> -               msg[0] = AUX_I2C_WRITE << 4;
> -
> -       if (!(mode & MODE_I2C_STOP))
> -               msg[0] |= AUX_I2C_MOT << 4;
> -
> -       msg[1] = address >> 8;
> -       msg[2] = address;
> -
> -       switch (mode) {
> -       case MODE_I2C_WRITE:
> -               msg[3] = 0;
> -               msg[4] = write_byte;
> -               msg_bytes = 5;
> -               reply_bytes = 1;
> -               break;
> -       case MODE_I2C_READ:
> -               msg[3] = 0;
> -               msg_bytes = 4;
> -               reply_bytes = 2;
> -               break;
> -       default:
> -               msg_bytes = 3;
> -               reply_bytes = 1;
> -               break;
> -       }
> -
> -       for (;;) {
> -               ret = (*algo_data->aux_ch)(adapter,
> -                                          msg, msg_bytes,
> -                                          reply, reply_bytes);
> -               if (ret < 0) {
> -                       DRM_DEBUG("aux_ch failed %d\n", ret);
> -                       return ret;
> -               }
> -               switch (reply[0] & AUX_I2C_REPLY_MASK) {
> -               case AUX_I2C_REPLY_ACK:
> -                       if (mode == MODE_I2C_READ) {
> -                               *read_byte = reply[1];
> -                       }
> -                       return reply_bytes - 1;
> -               case AUX_I2C_REPLY_NACK:
> -                       DRM_DEBUG("aux_ch nack\n");
> -                       return -EREMOTEIO;
> -               case AUX_I2C_REPLY_DEFER:
> -                       DRM_DEBUG("aux_ch defer\n");
> -                       udelay(100);
> -                       break;
> -               default:
> -                       DRM_ERROR("aux_ch invalid reply 0x%02x\n", reply[0]);
> -                       return -EREMOTEIO;
> -               }
> -       }
> -}
> -
> -/*
> - * I2C over AUX CH
> - */
> -
> -/*
> - * Send the address. If the I2C link is running, this 'restarts'
> - * the connection with the new address, this is used for doing
> - * a write followed by a read (as needed for DDC)
> - */
> -static int
> -i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool 
> reading)
> -{
> -       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
> -       int mode = MODE_I2C_START;
> -       int ret;
> -
> -       if (reading)
> -               mode |= MODE_I2C_READ;
> -       else
> -               mode |= MODE_I2C_WRITE;
> -       algo_data->address = address;
> -       algo_data->running = true;
> -       ret = i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL);
> -       return ret;
> -}
> -
> -/*
> - * Stop the I2C transaction. This closes out the link, sending
> - * a bare address packet with the MOT bit turned off
> - */
> -static void
> -i2c_algo_dp_aux_stop(struct i2c_adapter *adapter, bool reading)
> -{
> -       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
> -       int mode = MODE_I2C_STOP;
> -
> -       if (reading)
> -               mode |= MODE_I2C_READ;
> -       else
> -               mode |= MODE_I2C_WRITE;
> -       if (algo_data->running) {
> -               (void) i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL);
> -               algo_data->running = false;
> -       }
> -}
> -
> -/*
> - * Write a single byte to the current I2C address, the
> - * the I2C link must be running or this returns -EIO
> - */
> -static int
> -i2c_algo_dp_aux_put_byte(struct i2c_adapter *adapter, u8 byte)
> -{
> -       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
> -       int ret;
> -
> -       if (!algo_data->running)
> -               return -EIO;
> -
> -       ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_WRITE, byte, 
> NULL);
> -       return ret;
> -}
> -
> -/*
> - * Read a single byte from the current I2C address, the
> - * I2C link must be running or this returns -EIO
> - */
> -static int
> -i2c_algo_dp_aux_get_byte(struct i2c_adapter *adapter, u8 *byte_ret)
> -{
> -       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
> -       int ret;
> -
> -       if (!algo_data->running)
> -               return -EIO;
> -
> -       ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_READ, 0, 
> byte_ret);
> -       return ret;
> -}
> -
> -static int
> -i2c_algo_dp_aux_xfer(struct i2c_adapter *adapter,
> -                    struct i2c_msg *msgs,
> -                    int num)
> -{
> -       int ret = 0;
> -       bool reading = false;
> -       int m;
> -       int b;
> -
> -       for (m = 0; m < num; m++) {
> -               u16 len = msgs[m].len;
> -               u8 *buf = msgs[m].buf;
> -               reading = (msgs[m].flags & I2C_M_RD) != 0;
> -               ret = i2c_algo_dp_aux_address(adapter, msgs[m].addr, reading);
> -               if (ret < 0)
> -                       break;
> -               if (reading) {
> -                       for (b = 0; b < len; b++) {
> -                               ret = i2c_algo_dp_aux_get_byte(adapter, 
> &buf[b]);
> -                               if (ret < 0)
> -                                       break;
> -                       }
> -               } else {
> -                       for (b = 0; b < len; b++) {
> -                               ret = i2c_algo_dp_aux_put_byte(adapter, 
> buf[b]);
> -                               if (ret < 0)
> -                                       break;
> -                       }
> -               }
> -               if (ret < 0)
> -                       break;
> -       }
> -       if (ret >= 0)
> -               ret = num;
> -       i2c_algo_dp_aux_stop(adapter, reading);
> -       DRM_DEBUG("dp_aux_xfer return %d\n", ret);
> -       return ret;
> -}
> -
> -static u32
> -i2c_algo_dp_aux_functionality(struct i2c_adapter *adapter)
> -{
> -       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
> -              I2C_FUNC_SMBUS_READ_BLOCK_DATA |
> -              I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
> -              I2C_FUNC_10BIT_ADDR;
> -}
> -
> -static const struct i2c_algorithm i2c_dp_aux_algo = {
> -       .master_xfer    = i2c_algo_dp_aux_xfer,
> -       .functionality  = i2c_algo_dp_aux_functionality,
> -};
> -
> -static void
> -i2c_dp_aux_reset_bus(struct i2c_adapter *adapter)
> -{
> -       (void) i2c_algo_dp_aux_address(adapter, 0, false);
> -       (void) i2c_algo_dp_aux_stop(adapter, false);
> -
> -}
> -
> -static int
> -i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter)
> -{
> -       adapter->algo = &i2c_dp_aux_algo;
> -       adapter->retries = 3;
> -       i2c_dp_aux_reset_bus(adapter);
> -       return 0;
> -}
> -
> -int
> -i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
> -{
> -       int error;
> -
> -       error = i2c_dp_aux_prepare_bus(adapter);
> -       if (error)
> -               return error;
> -       error = i2c_add_adapter(adapter);
> -       return error;
> -}
> -EXPORT_SYMBOL(i2c_dp_aux_add_bus);
> diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
> new file mode 100644
> index 0000000..e49879c
> --- /dev/null
> +++ b/include/drm/drm_dp_helper.h
> @@ -0,0 +1,149 @@
> +/*
> + * Copyright © 2008 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.
> + */
> +
> +#ifndef _DRM_DP_HELPER_H_
> +#define _DRM_DP_HELPER_H_
> +
> +/* From the VESA DisplayPort spec */
> +
> +#define AUX_NATIVE_WRITE       0x8
> +#define AUX_NATIVE_READ                0x9
> +#define AUX_I2C_WRITE          0x0
> +#define AUX_I2C_READ           0x1
> +#define AUX_I2C_STATUS         0x2
> +#define AUX_I2C_MOT            0x4
> +
> +#define AUX_NATIVE_REPLY_ACK   (0x0 << 4)
> +#define AUX_NATIVE_REPLY_NACK  (0x1 << 4)
> +#define AUX_NATIVE_REPLY_DEFER (0x2 << 4)
> +#define AUX_NATIVE_REPLY_MASK  (0x3 << 4)
> +
> +#define AUX_I2C_REPLY_ACK      (0x0 << 6)
> +#define AUX_I2C_REPLY_NACK     (0x1 << 6)
> +#define AUX_I2C_REPLY_DEFER    (0x2 << 6)
> +#define AUX_I2C_REPLY_MASK     (0x3 << 6)
> +
> +/* AUX CH addresses */
> +#define        DP_LINK_BW_SET          0x100
> +# define DP_LINK_BW_1_62                   0x06
> +# define DP_LINK_BW_2_7                            0x0a
> +
> +#define DP_LANE_COUNT_SET      0x101
> +# define DP_LANE_COUNT_MASK                0x0f
> +# define DP_LANE_COUNT_ENHANCED_FRAME_EN    (1 << 7)
> +
> +#define DP_TRAINING_PATTERN_SET        0x102
> +
> +# define DP_TRAINING_PATTERN_DISABLE       0
> +# define DP_TRAINING_PATTERN_1             1
> +# define DP_TRAINING_PATTERN_2             2
> +# define DP_TRAINING_PATTERN_MASK          0x3
> +
> +# define DP_LINK_QUAL_PATTERN_DISABLE      (0 << 2)
> +# define DP_LINK_QUAL_PATTERN_D10_2        (1 << 2)
> +# define DP_LINK_QUAL_PATTERN_ERROR_RATE    (2 << 2)
> +# define DP_LINK_QUAL_PATTERN_PRBS7        (3 << 2)
> +# define DP_LINK_QUAL_PATTERN_MASK         (3 << 2)
> +
> +# define DP_RECOVERED_CLOCK_OUT_EN         (1 << 4)
> +# define DP_LINK_SCRAMBLING_DISABLE        (1 << 5)
> +
> +# define DP_SYMBOL_ERROR_COUNT_BOTH        (0 << 6)
> +# define DP_SYMBOL_ERROR_COUNT_DISPARITY    (1 << 6)
> +# define DP_SYMBOL_ERROR_COUNT_SYMBOL      (2 << 6)
> +# define DP_SYMBOL_ERROR_COUNT_MASK        (3 << 6)
> +
> +#define DP_TRAINING_LANE0_SET              0x103
> +#define DP_TRAINING_LANE1_SET              0x104
> +#define DP_TRAINING_LANE2_SET              0x105
> +#define DP_TRAINING_LANE3_SET              0x106
> +
> +# define DP_TRAIN_VOLTAGE_SWING_MASK       0x3
> +# define DP_TRAIN_VOLTAGE_SWING_SHIFT      0
> +# define DP_TRAIN_MAX_SWING_REACHED        (1 << 2)
> +# define DP_TRAIN_VOLTAGE_SWING_400        (0 << 0)
> +# define DP_TRAIN_VOLTAGE_SWING_600        (1 << 0)
> +# define DP_TRAIN_VOLTAGE_SWING_800        (2 << 0)
> +# define DP_TRAIN_VOLTAGE_SWING_1200       (3 << 0)
> +
> +# define DP_TRAIN_PRE_EMPHASIS_MASK        (3 << 3)
> +# define DP_TRAIN_PRE_EMPHASIS_0           (0 << 3)
> +# define DP_TRAIN_PRE_EMPHASIS_3_5         (1 << 3)
> +# define DP_TRAIN_PRE_EMPHASIS_6           (2 << 3)
> +# define DP_TRAIN_PRE_EMPHASIS_9_5         (3 << 3)
> +
> +# define DP_TRAIN_PRE_EMPHASIS_SHIFT       3
> +# define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED  (1 << 5)
> +
> +#define DP_DOWNSPREAD_CTRL                 0x107
> +# define DP_SPREAD_AMP_0_5                 (1 << 4)
> +
> +#define DP_MAIN_LINK_CHANNEL_CODING_SET            0x108
> +# define DP_SET_ANSI_8B10B                 (1 << 0)
> +
> +#define DP_LANE0_1_STATUS                  0x202
> +#define DP_LANE2_3_STATUS                  0x203
> +
> +# define DP_LANE_CR_DONE                   (1 << 0)
> +# define DP_LANE_CHANNEL_EQ_DONE           (1 << 1)
> +# define DP_LANE_SYMBOL_LOCKED             (1 << 2)
> +
> +#define DP_LANE_ALIGN_STATUS_UPDATED       0x204
> +
> +#define DP_INTERLANE_ALIGN_DONE                    (1 << 0)
> +#define DP_DOWNSTREAM_PORT_STATUS_CHANGED   (1 << 6)
> +#define DP_LINK_STATUS_UPDATED             (1 << 7)
> +
> +#define DP_SINK_STATUS                     0x205
> +
> +#define DP_RECEIVE_PORT_0_STATUS           (1 << 0)
> +#define DP_RECEIVE_PORT_1_STATUS           (1 << 1)
> +
> +#define DP_ADJUST_REQUEST_LANE0_1          0x206
> +#define DP_ADJUST_REQUEST_LANE2_3          0x207
> +
> +#define DP_ADJUST_VOLTAGE_SWING_LANE0_MASK  0x03
> +#define DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT 0
> +#define DP_ADJUST_PRE_EMPHASIS_LANE0_MASK   0x0c
> +#define DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT  2
> +#define DP_ADJUST_VOLTAGE_SWING_LANE1_MASK  0x30
> +#define DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT 4
> +#define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK   0xc0
> +#define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT  6
> +
> +#define MODE_I2C_START 1
> +#define MODE_I2C_WRITE 2
> +#define MODE_I2C_READ  4
> +#define MODE_I2C_STOP  8
> +
> +struct i2c_algo_dp_aux_data {
> +       bool running;
> +       u16 address;
> +       int (*aux_ch) (struct i2c_adapter *adapter,
> +                      int mode, uint8_t write_byte,
> +                      uint8_t *read_byte);
> +};
> +
> +int
> +i2c_dp_aux_add_bus(struct i2c_adapter *adapter);
> +
> +#endif /* _DRM_DP_HELPER_H_ */
> --
> 1.6.5.2
>
>
>
> ------------------------------------------------------------------------------
> Join us December 9, 2009 for the Red Hat Virtual Experience,
> a free event focused on virtualization and cloud computing.
> Attend in-depth sessions from your desk. Your couch. Anywhere.
> http://p.sf.net/sfu/redhat-sfdev2dev
> --
> _______________________________________________
> Dri-devel mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/dri-devel
>
>

------------------------------------------------------------------------------
Join us December 9, 2009 for the Red Hat Virtual Experience,
a free event focused on virtualization and cloud computing. 
Attend in-depth sessions from your desk. Your couch. Anywhere.
http://p.sf.net/sfu/redhat-sfdev2dev
--
_______________________________________________
Dri-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to