Skip to content

Commit

Permalink
drm/bridge: extract some Analogix I2C DP common code
Browse files Browse the repository at this point in the history
Some code can be shared within different DP bridges by Analogix.
Extract them to analogix_dp.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
Signed-off-by: Torsten Duwe <duwe@suse.de>
Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Link: https://patchwork.freedesktop.org/patch/msgid/20191107135214.966BD68BFE@verein.lst.de
  • Loading branch information
Icenowy Zheng authored and Maxime Ripard committed Nov 8, 2019
1 parent ad9301a commit 0712eca
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 146 deletions.
2 changes: 1 addition & 1 deletion drivers/gpu/drm/bridge/analogix/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
analogix_dp-objs := analogix_dp_core.o analogix_dp_reg.o
analogix_dp-objs := analogix_dp_core.o analogix_dp_reg.o analogix-i2c-dptx.o
obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix_dp.o
146 changes: 1 addition & 145 deletions drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@
#define I2C_IDX_RX_P1 4

#define XTAL_CLK 270 /* 27M */
#define AUX_CH_BUFFER_SIZE 16
#define AUX_WAIT_TIMEOUT_MS 15

static const u8 anx7808_i2c_addresses[] = {
[I2C_IDX_TX_P0] = 0x78,
Expand Down Expand Up @@ -107,153 +105,11 @@ static int anx78xx_clear_bits(struct regmap *map, u8 reg, u8 mask)
return regmap_update_bits(map, reg, mask, 0);
}

static bool anx78xx_aux_op_finished(struct anx78xx *anx78xx)
{
unsigned int value;
int err;

err = regmap_read(anx78xx->map[I2C_IDX_TX_P0], SP_DP_AUX_CH_CTRL2_REG,
&value);
if (err < 0)
return false;

return (value & SP_AUX_EN) == 0;
}

static int anx78xx_aux_wait(struct anx78xx *anx78xx)
{
unsigned long timeout;
unsigned int status;
int err;

timeout = jiffies + msecs_to_jiffies(AUX_WAIT_TIMEOUT_MS) + 1;

while (!anx78xx_aux_op_finished(anx78xx)) {
if (time_after(jiffies, timeout)) {
if (!anx78xx_aux_op_finished(anx78xx)) {
DRM_ERROR("Timed out waiting AUX to finish\n");
return -ETIMEDOUT;
}

break;
}

usleep_range(1000, 2000);
}

/* Read the AUX channel access status */
err = regmap_read(anx78xx->map[I2C_IDX_TX_P0], SP_AUX_CH_STATUS_REG,
&status);
if (err < 0) {
DRM_ERROR("Failed to read from AUX channel: %d\n", err);
return err;
}

if (status & SP_AUX_STATUS) {
DRM_ERROR("Failed to wait for AUX channel (status: %02x)\n",
status);
return -ETIMEDOUT;
}

return 0;
}

static int anx78xx_aux_address(struct anx78xx *anx78xx, unsigned int addr)
{
int err;

err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], SP_AUX_ADDR_7_0_REG,
addr & 0xff);
if (err)
return err;

err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], SP_AUX_ADDR_15_8_REG,
(addr & 0xff00) >> 8);
if (err)
return err;

/*
* DP AUX CH Address Register #2, only update bits[3:0]
* [7:4] RESERVED
* [3:0] AUX_ADDR[19:16], Register control AUX CH address.
*/
err = regmap_update_bits(anx78xx->map[I2C_IDX_TX_P0],
SP_AUX_ADDR_19_16_REG,
SP_AUX_ADDR_19_16_MASK,
(addr & 0xf0000) >> 16);

if (err)
return err;

return 0;
}

static ssize_t anx78xx_aux_transfer(struct drm_dp_aux *aux,
struct drm_dp_aux_msg *msg)
{
struct anx78xx *anx78xx = container_of(aux, struct anx78xx, aux);
u8 ctrl1 = msg->request;
u8 ctrl2 = SP_AUX_EN;
u8 *buffer = msg->buffer;
int err;

/* The DP AUX transmit and receive buffer has 16 bytes. */
if (WARN_ON(msg->size > AUX_CH_BUFFER_SIZE))
return -E2BIG;

/* Zero-sized messages specify address-only transactions. */
if (msg->size < 1)
ctrl2 |= SP_ADDR_ONLY;
else /* For non-zero-sized set the length field. */
ctrl1 |= (msg->size - 1) << SP_AUX_LENGTH_SHIFT;

if ((msg->request & DP_AUX_I2C_READ) == 0) {
/* When WRITE | MOT write values to data buffer */
err = regmap_bulk_write(anx78xx->map[I2C_IDX_TX_P0],
SP_DP_BUF_DATA0_REG, buffer,
msg->size);
if (err)
return err;
}

/* Write address and request */
err = anx78xx_aux_address(anx78xx, msg->address);
if (err)
return err;

err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], SP_DP_AUX_CH_CTRL1_REG,
ctrl1);
if (err)
return err;

/* Start transaction */
err = regmap_update_bits(anx78xx->map[I2C_IDX_TX_P0],
SP_DP_AUX_CH_CTRL2_REG, SP_ADDR_ONLY |
SP_AUX_EN, ctrl2);
if (err)
return err;

err = anx78xx_aux_wait(anx78xx);
if (err)
return err;

msg->reply = DP_AUX_I2C_REPLY_ACK;

if ((msg->size > 0) && (msg->request & DP_AUX_I2C_READ)) {
/* Read values from data buffer */
err = regmap_bulk_read(anx78xx->map[I2C_IDX_TX_P0],
SP_DP_BUF_DATA0_REG, buffer,
msg->size);
if (err)
return err;
}

err = anx78xx_clear_bits(anx78xx->map[I2C_IDX_TX_P0],
SP_DP_AUX_CH_CTRL2_REG, SP_ADDR_ONLY);
if (err)
return err;

return msg->size;
return anx_dp_aux_transfer(anx78xx->map[I2C_IDX_TX_P0], msg);
}

static int anx78xx_set_hpd(struct anx78xx *anx78xx)
Expand Down
165 changes: 165 additions & 0 deletions drivers/gpu/drm/bridge/analogix/analogix-i2c-dptx.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright(c) 2016, Analogix Semiconductor.
*
* Based on anx7808 driver obtained from chromeos with copyright:
* Copyright(c) 2013, Google Inc.
*/
#include <linux/regmap.h>

#include <drm/drm.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_print.h>

#include "analogix-i2c-dptx.h"

#define AUX_WAIT_TIMEOUT_MS 15
#define AUX_CH_BUFFER_SIZE 16

static int anx_i2c_dp_clear_bits(struct regmap *map, u8 reg, u8 mask)
{
return regmap_update_bits(map, reg, mask, 0);
}

static bool anx_dp_aux_op_finished(struct regmap *map_dptx)
{
unsigned int value;
int err;

err = regmap_read(map_dptx, SP_DP_AUX_CH_CTRL2_REG, &value);
if (err < 0)
return false;

return (value & SP_AUX_EN) == 0;
}

static int anx_dp_aux_wait(struct regmap *map_dptx)
{
unsigned long timeout;
unsigned int status;
int err;

timeout = jiffies + msecs_to_jiffies(AUX_WAIT_TIMEOUT_MS) + 1;

while (!anx_dp_aux_op_finished(map_dptx)) {
if (time_after(jiffies, timeout)) {
if (!anx_dp_aux_op_finished(map_dptx)) {
DRM_ERROR("Timed out waiting AUX to finish\n");
return -ETIMEDOUT;
}

break;
}

usleep_range(1000, 2000);
}

/* Read the AUX channel access status */
err = regmap_read(map_dptx, SP_AUX_CH_STATUS_REG, &status);
if (err < 0) {
DRM_ERROR("Failed to read from AUX channel: %d\n", err);
return err;
}

if (status & SP_AUX_STATUS) {
DRM_ERROR("Failed to wait for AUX channel (status: %02x)\n",
status);
return -ETIMEDOUT;
}

return 0;
}

static int anx_dp_aux_address(struct regmap *map_dptx, unsigned int addr)
{
int err;

err = regmap_write(map_dptx, SP_AUX_ADDR_7_0_REG, addr & 0xff);
if (err)
return err;

err = regmap_write(map_dptx, SP_AUX_ADDR_15_8_REG,
(addr & 0xff00) >> 8);
if (err)
return err;

/*
* DP AUX CH Address Register #2, only update bits[3:0]
* [7:4] RESERVED
* [3:0] AUX_ADDR[19:16], Register control AUX CH address.
*/
err = regmap_update_bits(map_dptx, SP_AUX_ADDR_19_16_REG,
SP_AUX_ADDR_19_16_MASK,
(addr & 0xf0000) >> 16);

if (err)
return err;

return 0;
}

ssize_t anx_dp_aux_transfer(struct regmap *map_dptx,
struct drm_dp_aux_msg *msg)
{
u8 ctrl1 = msg->request;
u8 ctrl2 = SP_AUX_EN;
u8 *buffer = msg->buffer;
int err;

/* The DP AUX transmit and receive buffer has 16 bytes. */
if (WARN_ON(msg->size > AUX_CH_BUFFER_SIZE))
return -E2BIG;

/* Zero-sized messages specify address-only transactions. */
if (msg->size < 1)
ctrl2 |= SP_ADDR_ONLY;
else /* For non-zero-sized set the length field. */
ctrl1 |= (msg->size - 1) << SP_AUX_LENGTH_SHIFT;

if ((msg->request & DP_AUX_I2C_READ) == 0) {
/* When WRITE | MOT write values to data buffer */
err = regmap_bulk_write(map_dptx,
SP_DP_BUF_DATA0_REG, buffer,
msg->size);
if (err)
return err;
}

/* Write address and request */
err = anx_dp_aux_address(map_dptx, msg->address);
if (err)
return err;

err = regmap_write(map_dptx, SP_DP_AUX_CH_CTRL1_REG, ctrl1);
if (err)
return err;

/* Start transaction */
err = regmap_update_bits(map_dptx, SP_DP_AUX_CH_CTRL2_REG,
SP_ADDR_ONLY | SP_AUX_EN, ctrl2);
if (err)
return err;

err = anx_dp_aux_wait(map_dptx);
if (err)
return err;

msg->reply = DP_AUX_I2C_REPLY_ACK;

if ((msg->size > 0) && (msg->request & DP_AUX_I2C_READ)) {
/* Read values from data buffer */
err = regmap_bulk_read(map_dptx,
SP_DP_BUF_DATA0_REG, buffer,
msg->size);
if (err)
return err;
}

err = anx_i2c_dp_clear_bits(map_dptx, SP_DP_AUX_CH_CTRL2_REG,
SP_ADDR_ONLY);
if (err)
return err;

return msg->size;
}
EXPORT_SYMBOL_GPL(anx_dp_aux_transfer);
3 changes: 3 additions & 0 deletions drivers/gpu/drm/bridge/analogix/analogix-i2c-dptx.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,4 +242,7 @@
/* DP AUX Buffer Data Registers */
#define SP_DP_BUF_DATA0_REG 0xf0

ssize_t anx_dp_aux_transfer(struct regmap *map_dptx,
struct drm_dp_aux_msg *msg);

#endif

0 comments on commit 0712eca

Please sign in to comment.