2019-06-05 07:06:52

by Andrey Smirnov

[permalink] [raw]
Subject: [PATCH v3 00/15] tc358767 driver improvements

Everyone:

This series contains various improvements (at least in my mind) and
fixes that I made to tc358767 while working with the code of the
driver. Hopefuly each patch is self explanatory.

Feedback is welcome!

Thanks,
Andrey Smirnov

Changes since [v2]:

- Patchset rebased on top of v4 of Tomi's series that recently
went in (https://patchwork.freedesktop.org/series/58176/#rev5)

- AUX transfer code converted to user regmap_bulk_read(),
regmap_bulk_write()

Changes since [v1]:

- Patchset rebased on top of
https://patchwork.freedesktop.org/series/58176/

- Patches to remove both tc_write() and tc_read() helpers added

- Patches to rework AUX transfer code added

- Both "drm/bridge: tc358767: Simplify polling in
tc_main_link_setup()" and "drm/bridge: tc358767: Simplify
polling in tc_link_training()" changed to use tc_poll_timeout()
instead of regmap_read_poll_timeout()

[v2] lkml.kernel.org/r/[email protected]
[v1] lkml.kernel.org/r/[email protected]


Andrey Smirnov (15):
drm/bridge: tc358767: Simplify tc_poll_timeout()
drm/bridge: tc358767: Simplify polling in tc_main_link_setup()
drm/bridge: tc358767: Simplify polling in tc_link_training()
drm/bridge: tc358767: Simplify tc_set_video_mode()
drm/bridge: tc358767: Drop custom tc_write()/tc_read() accessors
drm/bridge: tc358767: Simplify AUX data read
drm/bridge: tc358767: Simplify AUX data write
drm/bridge: tc358767: Increase AUX transfer length limit
drm/bridge: tc358767: Use reported AUX transfer size
drm/bridge: tc358767: Add support for address-only I2C transfers
drm/bridge: tc358767: Introduce tc_set_syspllparam()
drm/bridge: tc358767: Introduce tc_pllupdate_pllen()
drm/bridge: tc358767: Simplify tc_aux_wait_busy()
drm/bridge: tc358767: Drop unnecessary 8 byte buffer
drm/bridge: tc358767: Replace magic number in tc_main_link_enable()

drivers/gpu/drm/bridge/tc358767.c | 668 ++++++++++++++++++------------
1 file changed, 392 insertions(+), 276 deletions(-)

--
2.21.0


2019-06-05 07:06:52

by Andrey Smirnov

[permalink] [raw]
Subject: [PATCH v3 01/15] drm/bridge: tc358767: Simplify tc_poll_timeout()

Implementation of tc_poll_timeout() is almost a 100% copy-and-paste of
the code for regmap_read_poll_timeout(). Replace copied code with a
call to the original. While at it change tc_poll_timeout to accept
"struct tc_data *" instead of "struct regmap *" for brevity. No
functional change intended.

Signed-off-by: Andrey Smirnov <[email protected]>
Reviewed-by: Andrzej Hajda <[email protected]>
Reviewed-by: Laurent Pinchart <[email protected]>
Cc: Archit Taneja <[email protected]>
Cc: Andrzej Hajda <[email protected]>
Cc: Laurent Pinchart <[email protected]>
Cc: Tomi Valkeinen <[email protected]>
Cc: Andrey Gusakov <[email protected]>
Cc: Philipp Zabel <[email protected]>
Cc: Cory Tusar <[email protected]>
Cc: Chris Healy <[email protected]>
Cc: Lucas Stach <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
drivers/gpu/drm/bridge/tc358767.c | 26 ++++++--------------------
1 file changed, 6 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index 58e3ca0e25af..fb8a1942ec54 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -264,34 +264,21 @@ static inline struct tc_data *connector_to_tc(struct drm_connector *c)
goto err; \
} while (0)

-static inline int tc_poll_timeout(struct regmap *map, unsigned int addr,
+static inline int tc_poll_timeout(struct tc_data *tc, unsigned int addr,
unsigned int cond_mask,
unsigned int cond_value,
unsigned long sleep_us, u64 timeout_us)
{
- ktime_t timeout = ktime_add_us(ktime_get(), timeout_us);
unsigned int val;
- int ret;

- for (;;) {
- ret = regmap_read(map, addr, &val);
- if (ret)
- break;
- if ((val & cond_mask) == cond_value)
- break;
- if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) {
- ret = regmap_read(map, addr, &val);
- break;
- }
- if (sleep_us)
- usleep_range((sleep_us >> 2) + 1, sleep_us);
- }
- return ret ?: (((val & cond_mask) == cond_value) ? 0 : -ETIMEDOUT);
+ return regmap_read_poll_timeout(tc->regmap, addr, val,
+ (val & cond_mask) == cond_value,
+ sleep_us, timeout_us);
}

static int tc_aux_wait_busy(struct tc_data *tc, unsigned int timeout_ms)
{
- return tc_poll_timeout(tc->regmap, DP0_AUXSTATUS, AUX_BUSY, 0,
+ return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0,
1000, 1000 * timeout_ms);
}

@@ -598,8 +585,7 @@ static int tc_aux_link_setup(struct tc_data *tc)
tc_write(DP1_PLLCTRL, PLLUPDATE | PLLEN);
tc_wait_pll_lock(tc);

- ret = tc_poll_timeout(tc->regmap, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1,
- 1000);
+ ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
if (ret == -ETIMEDOUT) {
dev_err(tc->dev, "Timeout waiting for PHY to become ready");
return ret;
--
2.21.0

2019-06-05 07:07:01

by Andrey Smirnov

[permalink] [raw]
Subject: [PATCH v3 03/15] drm/bridge: tc358767: Simplify polling in tc_link_training()

Replace explicit polling in tc_link_training() with equivalent call to
tc_poll_timeout() for simplicity. No functional change intended (not
including slightly altered debug output).

Signed-off-by: Andrey Smirnov <[email protected]>
Cc: Archit Taneja <[email protected]>
Cc: Andrzej Hajda <[email protected]>
Cc: Laurent Pinchart <[email protected]>
Cc: Tomi Valkeinen <[email protected]>
Cc: Andrey Gusakov <[email protected]>
Cc: Philipp Zabel <[email protected]>
Cc: Cory Tusar <[email protected]>
Cc: Chris Healy <[email protected]>
Cc: Lucas Stach <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
drivers/gpu/drm/bridge/tc358767.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index 5e1e73a91696..115cffc55a96 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -748,22 +748,19 @@ static int tc_set_video_mode(struct tc_data *tc,

static int tc_wait_link_training(struct tc_data *tc)
{
- u32 timeout = 1000;
u32 value;
int ret;

- do {
- udelay(1);
- tc_read(DP0_LTSTAT, &value);
- } while ((!(value & LT_LOOPDONE)) && (--timeout));
-
- if (timeout == 0) {
+ ret = tc_poll_timeout(tc, DP0_LTSTAT, LT_LOOPDONE,
+ LT_LOOPDONE, 1, 1000);
+ if (ret) {
dev_err(tc->dev, "Link training timeout waiting for LT_LOOPDONE!\n");
- return -ETIMEDOUT;
+ return ret;
}

- return (value >> 8) & 0x7;
+ tc_read(DP0_LTSTAT, &value);

+ return (value >> 8) & 0x7;
err:
return ret;
}
--
2.21.0

2019-06-05 07:07:02

by Andrey Smirnov

[permalink] [raw]
Subject: [PATCH v3 02/15] drm/bridge: tc358767: Simplify polling in tc_main_link_setup()

Replace explicit polling loop with equivalent call to
tc_poll_timeout() for brevity. No functional change intended.

Signed-off-by: Andrey Smirnov <[email protected]>
Cc: Archit Taneja <[email protected]>
Cc: Andrzej Hajda <[email protected]>
Cc: Laurent Pinchart <[email protected]>
Cc: Tomi Valkeinen <[email protected]>
Cc: Andrey Gusakov <[email protected]>
Cc: Philipp Zabel <[email protected]>
Cc: Cory Tusar <[email protected]>
Cc: Chris Healy <[email protected]>
Cc: Lucas Stach <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
drivers/gpu/drm/bridge/tc358767.c | 15 +++++----------
1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index fb8a1942ec54..5e1e73a91696 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -774,7 +774,6 @@ static int tc_main_link_enable(struct tc_data *tc)
struct device *dev = tc->dev;
unsigned int rate;
u32 dp_phy_ctrl;
- int timeout;
u32 value;
int ret;
u8 tmp[8];
@@ -831,15 +830,11 @@ static int tc_main_link_enable(struct tc_data *tc)
dp_phy_ctrl &= ~(DP_PHY_RST | PHY_M1_RST | PHY_M0_RST);
tc_write(DP_PHY_CTRL, dp_phy_ctrl);

- timeout = 1000;
- do {
- tc_read(DP_PHY_CTRL, &value);
- udelay(1);
- } while ((!(value & PHY_RDY)) && (--timeout));
-
- if (timeout == 0) {
- dev_err(dev, "timeout waiting for phy become ready");
- return -ETIMEDOUT;
+ ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
+ if (ret) {
+ if (ret == -ETIMEDOUT)
+ dev_err(dev, "timeout waiting for phy become ready");
+ return ret;
}

/* Set misc: 8 bits per color */
--
2.21.0

2019-06-05 07:07:11

by Andrey Smirnov

[permalink] [raw]
Subject: [PATCH v3 05/15] drm/bridge: tc358767: Drop custom tc_write()/tc_read() accessors

A very unfortunate aspect of tc_write()/tc_read() macro helpers is
that they capture quite a bit of context around them and thus require
the caller to have magic variables 'ret' and 'tc' as well as label
'err'. That makes a number of code paths rather counterintuitive and
somewhat clunky, for example tc_stream_clock_calc() ends up being like
this:

int ret;

tc_write(DP0_VIDMNGEN1, 32768);

return 0;
err:
return ret;

which is rather surprising when you read the code for the first
time. Since those helpers arguably aren't really saving that much code
and there's no way of fixing them without making them too verbose to
be worth it change the driver code to not use them at all.

Signed-off-by: Andrey Smirnov <[email protected]>
Cc: Archit Taneja <[email protected]>
Cc: Andrzej Hajda <[email protected]>
Cc: Laurent Pinchart <[email protected]>
Cc: Tomi Valkeinen <[email protected]>
Cc: Andrey Gusakov <[email protected]>
Cc: Philipp Zabel <[email protected]>
Cc: Cory Tusar <[email protected]>
Cc: Chris Healy <[email protected]>
Cc: Lucas Stach <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
drivers/gpu/drm/bridge/tc358767.c | 381 ++++++++++++++++++------------
1 file changed, 229 insertions(+), 152 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index c0fc686ce5ec..e197ce0fb166 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -280,20 +280,6 @@ static inline struct tc_data *connector_to_tc(struct drm_connector *c)
return container_of(c, struct tc_data, connector);
}

-/* Simple macros to avoid repeated error checks */
-#define tc_write(reg, var) \
- do { \
- ret = regmap_write(tc->regmap, reg, var); \
- if (ret) \
- goto err; \
- } while (0)
-#define tc_read(reg, var) \
- do { \
- ret = regmap_read(tc->regmap, reg, var); \
- if (ret) \
- goto err; \
- } while (0)
-
static inline int tc_poll_timeout(struct tc_data *tc, unsigned int addr,
unsigned int cond_mask,
unsigned int cond_value,
@@ -351,7 +337,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,

ret = tc_aux_wait_busy(tc, 100);
if (ret)
- goto err;
+ return ret;

if (request == DP_AUX_I2C_WRITE || request == DP_AUX_NATIVE_WRITE) {
/* Store data */
@@ -362,7 +348,11 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
tmp = (tmp << 8) | buf[i];
i++;
if (((i % 4) == 0) || (i == size)) {
- tc_write(DP0_AUXWDATA((i - 1) >> 2), tmp);
+ ret = regmap_write(tc->regmap,
+ DP0_AUXWDATA((i - 1) >> 2),
+ tmp);
+ if (ret)
+ return ret;
tmp = 0;
}
}
@@ -372,23 +362,32 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
}

/* Store address */
- tc_write(DP0_AUXADDR, msg->address);
+ ret = regmap_write(tc->regmap, DP0_AUXADDR, msg->address);
+ if (ret)
+ return ret;
/* Start transfer */
- tc_write(DP0_AUXCFG0, ((size - 1) << 8) | request);
+ ret = regmap_write(tc->regmap, DP0_AUXCFG0,
+ ((size - 1) << 8) | request);
+ if (ret)
+ return ret;

ret = tc_aux_wait_busy(tc, 100);
if (ret)
- goto err;
+ return ret;

ret = tc_aux_get_status(tc, &msg->reply);
if (ret)
- goto err;
+ return ret;

if (request == DP_AUX_I2C_READ || request == DP_AUX_NATIVE_READ) {
/* Read data */
while (i < size) {
- if ((i % 4) == 0)
- tc_read(DP0_AUXRDATA(i >> 2), &tmp);
+ if ((i % 4) == 0) {
+ ret = regmap_read(tc->regmap,
+ DP0_AUXRDATA(i >> 2), &tmp);
+ if (ret)
+ return ret;
+ }
buf[i] = tmp & 0xff;
tmp = tmp >> 8;
i++;
@@ -396,8 +395,6 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
}

return size;
-err:
- return ret;
}

static const char * const training_pattern1_errors[] = {
@@ -454,6 +451,7 @@ static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, u32 pixelclock)
int ext_div[] = {1, 2, 3, 5, 7};
int best_pixelclock = 0;
int vco_hi = 0;
+ u32 pxl_pllparam;

dev_dbg(tc->dev, "PLL: requested %d pixelclock, ref %d\n", pixelclock,
refclk);
@@ -523,24 +521,29 @@ static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, u32 pixelclock)
best_mul = 0;

/* Power up PLL and switch to bypass */
- tc_write(PXL_PLLCTRL, PLLBYP | PLLEN);
+ ret = regmap_write(tc->regmap, PXL_PLLCTRL, PLLBYP | PLLEN);
+ if (ret)
+ return ret;
+
+ pxl_pllparam = vco_hi << 24; /* For PLL VCO >= 300 MHz = 1 */
+ pxl_pllparam |= ext_div[best_pre] << 20; /* External Pre-divider */
+ pxl_pllparam |= ext_div[best_post] << 16; /* External Post-divider */
+ pxl_pllparam |= IN_SEL_REFCLK; /* Use RefClk as PLL input */
+ pxl_pllparam |= best_div << 8; /* Divider for PLL RefClk */
+ pxl_pllparam |= best_mul; /* Multiplier for PLL */

- tc_write(PXL_PLLPARAM,
- (vco_hi << 24) | /* For PLL VCO >= 300 MHz = 1 */
- (ext_div[best_pre] << 20) | /* External Pre-divider */
- (ext_div[best_post] << 16) | /* External Post-divider */
- IN_SEL_REFCLK | /* Use RefClk as PLL input */
- (best_div << 8) | /* Divider for PLL RefClk */
- (best_mul << 0)); /* Multiplier for PLL */
+ ret = regmap_write(tc->regmap, PXL_PLLPARAM, pxl_pllparam);
+ if (ret)
+ return ret;

/* Force PLL parameter update and disable bypass */
- tc_write(PXL_PLLCTRL, PLLUPDATE | PLLEN);
+ ret = regmap_write(tc->regmap, PXL_PLLCTRL, PLLUPDATE | PLLEN);
+ if (ret)
+ return ret;

tc_wait_pll_lock(tc);

return 0;
-err:
- return ret;
}

static int tc_pxl_pll_dis(struct tc_data *tc)
@@ -551,7 +554,6 @@ static int tc_pxl_pll_dis(struct tc_data *tc)

static int tc_stream_clock_calc(struct tc_data *tc)
{
- int ret;
/*
* If the Stream clock and Link Symbol clock are
* asynchronous with each other, the value of M changes over
@@ -567,16 +569,13 @@ static int tc_stream_clock_calc(struct tc_data *tc)
* M/N = f_STRMCLK / f_LSCLK
*
*/
- tc_write(DP0_VIDMNGEN1, 32768);
-
- return 0;
-err:
- return ret;
+ return regmap_write(tc->regmap, DP0_VIDMNGEN1, 32768);
}

static int tc_aux_link_setup(struct tc_data *tc)
{
unsigned long rate;
+ u32 dp0_auxcfg1;
u32 value;
int ret;

@@ -601,18 +600,25 @@ static int tc_aux_link_setup(struct tc_data *tc)

/* Setup DP-PHY / PLL */
value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
- tc_write(SYS_PLLPARAM, value);
-
- tc_write(DP_PHY_CTRL, BGREN | PWR_SW_EN | PHY_A0_EN);
+ ret = regmap_write(tc->regmap, SYS_PLLPARAM, value);
+ if (ret)
+ goto err;

+ ret = regmap_write(tc->regmap, DP_PHY_CTRL, BGREN | PWR_SW_EN | PHY_A0_EN);
+ if (ret)
+ goto err;
/*
* Initially PLLs are in bypass. Force PLL parameter update,
* disable PLL bypass, enable PLL
*/
- tc_write(DP0_PLLCTRL, PLLUPDATE | PLLEN);
+ ret = regmap_write(tc->regmap, DP0_PLLCTRL, PLLUPDATE | PLLEN);
+ if (ret)
+ goto err;
tc_wait_pll_lock(tc);

- tc_write(DP1_PLLCTRL, PLLUPDATE | PLLEN);
+ ret = regmap_write(tc->regmap, DP1_PLLCTRL, PLLUPDATE | PLLEN);
+ if (ret)
+ goto err;
tc_wait_pll_lock(tc);

ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
@@ -624,9 +630,13 @@ static int tc_aux_link_setup(struct tc_data *tc)
}

/* Setup AUX link */
- tc_write(DP0_AUXCFG1, AUX_RX_FILTER_EN |
- (0x06 << 8) | /* Aux Bit Period Calculator Threshold */
- (0x3f << 0)); /* Aux Response Timeout Timer */
+ dp0_auxcfg1 = AUX_RX_FILTER_EN;
+ dp0_auxcfg1 |= 0x06 << 8; /* Aux Bit Period Calculator Threshold */
+ dp0_auxcfg1 |= 0x3f << 0; /* Aux Response Timeout Timer */
+
+ ret = regmap_write(tc->regmap, DP0_AUXCFG1, dp0_auxcfg1);
+ if (ret)
+ goto err;

return 0;
err:
@@ -727,48 +737,73 @@ static int tc_set_video_mode(struct tc_data *tc,
* assume we do not need any delay when DPI is a source of
* sync signals
*/
- tc_write(VPCTRL0,
- FIELD_PREP(VSDELAY, 0) |
- OPXLFMT_RGB888 | FRMSYNC_DISABLED | MSF_DISABLED);
- tc_write(HTIM01,
- FIELD_PREP(HBPR, ALIGN(left_margin, 2)) |
- FIELD_PREP(HPW, ALIGN(hsync_len, 2)));
- tc_write(HTIM02,
- FIELD_PREP(HDISPR, ALIGN(mode->hdisplay, 2)) |
- FIELD_PREP(HFPR, ALIGN(right_margin, 2)));
- tc_write(VTIM01,
- FIELD_PREP(VBPR, upper_margin) |
- FIELD_PREP(VSPR, vsync_len));
- tc_write(VTIM02,
- FIELD_PREP(VFPR, lower_margin) |
- FIELD_PREP(VDISPR, mode->vdisplay));
- tc_write(VFUEN0, VFUEN); /* update settings */
+ ret = regmap_write(tc->regmap, VPCTRL0,
+ FIELD_PREP(VSDELAY, 0) |
+ OPXLFMT_RGB888 | FRMSYNC_DISABLED | MSF_DISABLED);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(tc->regmap, HTIM01,
+ FIELD_PREP(HBPR, ALIGN(left_margin, 2)) |
+ FIELD_PREP(HPW, ALIGN(hsync_len, 2)));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(tc->regmap, HTIM02,
+ FIELD_PREP(HDISPR, ALIGN(mode->hdisplay, 2)) |
+ FIELD_PREP(HFPR, ALIGN(right_margin, 2)));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(tc->regmap, VTIM01,
+ FIELD_PREP(VBPR, upper_margin) |
+ FIELD_PREP(VSPR, vsync_len));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(tc->regmap, VTIM02,
+ FIELD_PREP(VFPR, lower_margin) |
+ FIELD_PREP(VDISPR, mode->vdisplay));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(tc->regmap, VFUEN0, VFUEN); /* update settings */
+ if (ret)
+ return ret;

/* Test pattern settings */
- tc_write(TSTCTL,
- FIELD_PREP(COLOR_R, 120) |
- FIELD_PREP(COLOR_G, 20) |
- FIELD_PREP(COLOR_B, 99) |
- ENI2CFILTER |
- FIELD_PREP(COLOR_BAR_MODE, COLOR_BAR_MODE_BARS));
+ ret = regmap_write(tc->regmap, TSTCTL,
+ FIELD_PREP(COLOR_R, 120) |
+ FIELD_PREP(COLOR_G, 20) |
+ FIELD_PREP(COLOR_B, 99) |
+ ENI2CFILTER |
+ FIELD_PREP(COLOR_BAR_MODE, COLOR_BAR_MODE_BARS));
+ if (ret)
+ return ret;

/* DP Main Stream Attributes */
vid_sync_dly = hsync_len + left_margin + mode->hdisplay;
- tc_write(DP0_VIDSYNCDELAY,
+ ret = regmap_write(tc->regmap, DP0_VIDSYNCDELAY,
FIELD_PREP(THRESH_DLY, max_tu_symbol) |
FIELD_PREP(VID_SYNC_DLY, vid_sync_dly));

- tc_write(DP0_TOTALVAL,
- FIELD_PREP(H_TOTAL, mode->htotal) |
- FIELD_PREP(V_TOTAL, mode->vtotal));
+ ret = regmap_write(tc->regmap, DP0_TOTALVAL,
+ FIELD_PREP(H_TOTAL, mode->htotal) |
+ FIELD_PREP(V_TOTAL, mode->vtotal));
+ if (ret)
+ return ret;

- tc_write(DP0_STARTVAL,
- FIELD_PREP(H_START, left_margin + hsync_len) |
- FIELD_PREP(V_START, upper_margin + vsync_len));
+ ret = regmap_write(tc->regmap, DP0_STARTVAL,
+ FIELD_PREP(H_START, left_margin + hsync_len) |
+ FIELD_PREP(V_START, upper_margin + vsync_len));
+ if (ret)
+ return ret;

- tc_write(DP0_ACTIVEVAL,
- FIELD_PREP(V_ACT, mode->vdisplay) |
- FIELD_PREP(H_ACT, mode->hdisplay));
+ ret = regmap_write(tc->regmap, DP0_ACTIVEVAL,
+ FIELD_PREP(V_ACT, mode->vdisplay) |
+ FIELD_PREP(H_ACT, mode->hdisplay));
+ if (ret)
+ return ret;

dp0_syncval = FIELD_PREP(VS_WIDTH, vsync_len) |
FIELD_PREP(HS_WIDTH, hsync_len);
@@ -779,21 +814,25 @@ static int tc_set_video_mode(struct tc_data *tc,
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
dp0_syncval |= SYNCVAL_HS_POL_ACTIVE_LOW;

- tc_write(DP0_SYNCVAL, dp0_syncval);
+ ret = regmap_write(tc->regmap, DP0_SYNCVAL, dp0_syncval);
+ if (ret)
+ return ret;

- tc_write(DPIPXLFMT,
- VS_POL_ACTIVE_LOW | HS_POL_ACTIVE_LOW |
- DE_POL_ACTIVE_HIGH | SUB_CFG_TYPE_CONFIG1 |
- DPI_BPP_RGB888);
+ ret = regmap_write(tc->regmap, DPIPXLFMT,
+ VS_POL_ACTIVE_LOW | HS_POL_ACTIVE_LOW |
+ DE_POL_ACTIVE_HIGH | SUB_CFG_TYPE_CONFIG1 |
+ DPI_BPP_RGB888);
+ if (ret)
+ return ret;

- tc_write(DP0_MISC,
- FIELD_PREP(MAX_TU_SYMBOL, max_tu_symbol) |
- FIELD_PREP(TU_SIZE, TU_SIZE_RECOMMENDED) |
- BPC_8);
+ ret = regmap_write(tc->regmap, DP0_MISC,
+ FIELD_PREP(MAX_TU_SYMBOL, max_tu_symbol) |
+ FIELD_PREP(TU_SIZE, TU_SIZE_RECOMMENDED) |
+ BPC_8);
+ if (ret)
+ return ret;

return 0;
-err:
- return ret;
}

static int tc_wait_link_training(struct tc_data *tc)
@@ -808,11 +847,11 @@ static int tc_wait_link_training(struct tc_data *tc)
return ret;
}

- tc_read(DP0_LTSTAT, &value);
+ ret = regmap_read(tc->regmap, DP0_LTSTAT, &value);
+ if (ret)
+ return ret;

return (value >> 8) & 0x7;
-err:
- return ret;
}

static int tc_main_link_enable(struct tc_data *tc)
@@ -827,15 +866,25 @@ static int tc_main_link_enable(struct tc_data *tc)

dev_dbg(tc->dev, "link enable\n");

- tc_read(DP0CTL, &value);
- if (WARN_ON(value & DP_EN))
- tc_write(DP0CTL, 0);
+ ret = regmap_read(tc->regmap, DP0CTL, &value);
+ if (ret)
+ return ret;
+
+ if (WARN_ON(value & DP_EN)) {
+ ret = regmap_write(tc->regmap, DP0CTL, 0);
+ if (ret)
+ return ret;
+ }

- tc_write(DP0_SRCCTRL, tc_srcctrl(tc));
+ ret = regmap_write(tc->regmap, DP0_SRCCTRL, tc_srcctrl(tc));
+ if (ret)
+ return ret;
/* SSCG and BW27 on DP1 must be set to the same as on DP0 */
- tc_write(DP1_SRCCTRL,
+ ret = regmap_write(tc->regmap, DP1_SRCCTRL,
(tc->link.spread ? DP0_SRCCTRL_SSCG : 0) |
((tc->link.base.rate != 162000) ? DP0_SRCCTRL_BW27 : 0));
+ if (ret)
+ return ret;

rate = clk_get_rate(tc->refclk);
switch (rate) {
@@ -855,27 +904,36 @@ static int tc_main_link_enable(struct tc_data *tc)
return -EINVAL;
}
value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
- tc_write(SYS_PLLPARAM, value);
+ ret = regmap_write(tc->regmap, SYS_PLLPARAM, value);
+ if (ret)
+ return ret;

/* Setup Main Link */
dp_phy_ctrl = BGREN | PWR_SW_EN | PHY_A0_EN | PHY_M0_EN;
if (tc->link.base.num_lanes == 2)
dp_phy_ctrl |= PHY_2LANE;
- tc_write(DP_PHY_CTRL, dp_phy_ctrl);
+
+ ret = regmap_write(tc->regmap, DP_PHY_CTRL, dp_phy_ctrl);
+ if (ret)
+ return ret;

/* PLL setup */
- tc_write(DP0_PLLCTRL, PLLUPDATE | PLLEN);
+ ret = regmap_write(tc->regmap, DP0_PLLCTRL, PLLUPDATE | PLLEN);
+ if (ret)
+ return ret;
tc_wait_pll_lock(tc);

- tc_write(DP1_PLLCTRL, PLLUPDATE | PLLEN);
+ ret = regmap_write(tc->regmap, DP1_PLLCTRL, PLLUPDATE | PLLEN);
+ if (ret)
+ return ret;
tc_wait_pll_lock(tc);

/* Reset/Enable Main Links */
dp_phy_ctrl |= DP_PHY_RST | PHY_M1_RST | PHY_M0_RST;
- tc_write(DP_PHY_CTRL, dp_phy_ctrl);
+ ret = regmap_write(tc->regmap, DP_PHY_CTRL, dp_phy_ctrl);
usleep_range(100, 200);
dp_phy_ctrl &= ~(DP_PHY_RST | PHY_M1_RST | PHY_M0_RST);
- tc_write(DP_PHY_CTRL, dp_phy_ctrl);
+ ret = regmap_write(tc->regmap, DP_PHY_CTRL, dp_phy_ctrl);

ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
if (ret) {
@@ -887,7 +945,7 @@ static int tc_main_link_enable(struct tc_data *tc)
/* Set misc: 8 bits per color */
ret = regmap_update_bits(tc->regmap, DP0_MISC, BPC_8, BPC_8);
if (ret)
- goto err;
+ return ret;

/*
* ASSR mode
@@ -940,53 +998,71 @@ static int tc_main_link_enable(struct tc_data *tc)
/* Clock-Recovery */

/* Set DPCD 0x102 for Training Pattern 1 */
- tc_write(DP0_SNKLTCTRL, DP_LINK_SCRAMBLING_DISABLE |
- DP_TRAINING_PATTERN_1);
+ ret = regmap_write(tc->regmap, DP0_SNKLTCTRL,
+ DP_LINK_SCRAMBLING_DISABLE |
+ DP_TRAINING_PATTERN_1);
+ if (ret)
+ return ret;

- tc_write(DP0_LTLOOPCTRL,
- (15 << 28) | /* Defer Iteration Count */
- (15 << 24) | /* Loop Iteration Count */
- (0xd << 0)); /* Loop Timer Delay */
+ ret = regmap_write(tc->regmap, DP0_LTLOOPCTRL,
+ (15 << 28) | /* Defer Iteration Count */
+ (15 << 24) | /* Loop Iteration Count */
+ (0xd << 0)); /* Loop Timer Delay */
+ if (ret)
+ return ret;

- tc_write(DP0_SRCCTRL, tc_srcctrl(tc) | DP0_SRCCTRL_SCRMBLDIS |
- DP0_SRCCTRL_AUTOCORRECT | DP0_SRCCTRL_TP1);
+ ret = regmap_write(tc->regmap, DP0_SRCCTRL,
+ tc_srcctrl(tc) | DP0_SRCCTRL_SCRMBLDIS |
+ DP0_SRCCTRL_AUTOCORRECT |
+ DP0_SRCCTRL_TP1);
+ if (ret)
+ return ret;

/* Enable DP0 to start Link Training */
- tc_write(DP0CTL,
- ((tc->link.base.capabilities & DP_LINK_CAP_ENHANCED_FRAMING) ? EF_EN : 0) |
- DP_EN);
+ ret = regmap_write(tc->regmap, DP0CTL,
+ ((tc->link.base.capabilities &
+ DP_LINK_CAP_ENHANCED_FRAMING) ? EF_EN : 0) |
+ DP_EN);
+ if (ret)
+ return ret;

/* wait */
+
ret = tc_wait_link_training(tc);
if (ret < 0)
- goto err;
+ return ret;

if (ret) {
dev_err(tc->dev, "Link training phase 1 failed: %s\n",
training_pattern1_errors[ret]);
- ret = -ENODEV;
- goto err;
+ return -ENODEV;
}

/* Channel Equalization */

/* Set DPCD 0x102 for Training Pattern 2 */
- tc_write(DP0_SNKLTCTRL, DP_LINK_SCRAMBLING_DISABLE |
- DP_TRAINING_PATTERN_2);
+ ret = regmap_write(tc->regmap, DP0_SNKLTCTRL,
+ DP_LINK_SCRAMBLING_DISABLE |
+ DP_TRAINING_PATTERN_2);
+ if (ret)
+ return ret;

- tc_write(DP0_SRCCTRL, tc_srcctrl(tc) | DP0_SRCCTRL_SCRMBLDIS |
- DP0_SRCCTRL_AUTOCORRECT | DP0_SRCCTRL_TP2);
+ ret = regmap_write(tc->regmap, DP0_SRCCTRL,
+ tc_srcctrl(tc) | DP0_SRCCTRL_SCRMBLDIS |
+ DP0_SRCCTRL_AUTOCORRECT |
+ DP0_SRCCTRL_TP2);
+ if (ret)
+ return ret;

/* wait */
ret = tc_wait_link_training(tc);
if (ret < 0)
- goto err;
+ return ret;

if (ret) {
dev_err(tc->dev, "Link training phase 2 failed: %s\n",
training_pattern2_errors[ret]);
- ret = -ENODEV;
- goto err;
+ return -ENODEV;
}

/*
@@ -999,7 +1075,10 @@ static int tc_main_link_enable(struct tc_data *tc)
*/

/* Clear Training Pattern, set AutoCorrect Mode = 1 */
- tc_write(DP0_SRCCTRL, tc_srcctrl(tc) | DP0_SRCCTRL_AUTOCORRECT);
+ ret = regmap_write(tc->regmap, DP0_SRCCTRL, tc_srcctrl(tc) |
+ DP0_SRCCTRL_AUTOCORRECT);
+ if (ret)
+ return ret;

/* Clear DPCD 0x102 */
/* Note: Can Not use DP0_SNKLTCTRL (0x06E4) short cut */
@@ -1043,7 +1122,7 @@ static int tc_main_link_enable(struct tc_data *tc)
dev_err(dev, "0x0205 SINK_STATUS: 0x%02x\n", tmp[3]);
dev_err(dev, "0x0206 ADJUST_REQUEST_LANE0_1: 0x%02x\n", tmp[4]);
dev_err(dev, "0x0207 ADJUST_REQUEST_LANE2_3: 0x%02x\n", tmp[5]);
- goto err;
+ return ret;
}

return 0;
@@ -1052,7 +1131,6 @@ static int tc_main_link_enable(struct tc_data *tc)
return ret;
err_dpcd_write:
dev_err(tc->dev, "Failed to write DPCD: %d\n", ret);
-err:
return ret;
}

@@ -1062,12 +1140,11 @@ static int tc_main_link_disable(struct tc_data *tc)

dev_dbg(tc->dev, "link disable\n");

- tc_write(DP0_SRCCTRL, 0);
- tc_write(DP0CTL, 0);
+ ret = regmap_write(tc->regmap, DP0_SRCCTRL, 0);
+ if (ret)
+ return ret;

- return 0;
-err:
- return ret;
+ return regmap_write(tc->regmap, DP0CTL, 0);
}

static int tc_stream_enable(struct tc_data *tc)
@@ -1082,7 +1159,7 @@ static int tc_stream_enable(struct tc_data *tc)
ret = tc_pxl_pll_en(tc, clk_get_rate(tc->refclk),
1000 * tc->mode.clock);
if (ret)
- goto err;
+ return ret;
}

ret = tc_set_video_mode(tc, &tc->mode);
@@ -1097,7 +1174,9 @@ static int tc_stream_enable(struct tc_data *tc)
value = VID_MN_GEN | DP_EN;
if (tc->link.base.capabilities & DP_LINK_CAP_ENHANCED_FRAMING)
value |= EF_EN;
- tc_write(DP0CTL, value);
+ ret = regmap_write(tc->regmap, DP0CTL, value);
+ if (ret)
+ return ret;
/*
* VID_EN assertion should be delayed by at least N * LSCLK
* cycles from the time VID_MN_GEN is enabled in order to
@@ -1107,36 +1186,35 @@ static int tc_stream_enable(struct tc_data *tc)
*/
usleep_range(500, 1000);
value |= VID_EN;
- tc_write(DP0CTL, value);
+ ret = regmap_write(tc->regmap, DP0CTL, value);
+ if (ret)
+ return ret;
/* Set input interface */
value = DP0_AUDSRC_NO_INPUT;
if (tc_test_pattern)
value |= DP0_VIDSRC_COLOR_BAR;
else
value |= DP0_VIDSRC_DPI_RX;
- tc_write(SYSCTRL, value);
+ ret = regmap_write(tc->regmap, SYSCTRL, value);
+ if (ret)
+ return ret;

return 0;
-err:
- return ret;
}

static int tc_stream_disable(struct tc_data *tc)
{
int ret;
- u32 val;

dev_dbg(tc->dev, "disable video stream\n");

- tc_read(DP0CTL, &val);
- val &= ~VID_EN;
- tc_write(DP0CTL, val);
+ ret = regmap_update_bits(tc->regmap, DP0CTL, VID_EN, 0);
+ if (ret)
+ return ret;

tc_pxl_pll_dis(tc);

return 0;
-err:
- return ret;
}

static void tc_bridge_pre_enable(struct drm_bridge *bridge)
@@ -1328,7 +1406,9 @@ static enum drm_connector_status tc_connector_detect(struct drm_connector *conne
return connector_status_unknown;
}

- tc_read(GPIOI, &val);
+ ret = regmap_read(tc->regmap, GPIOI, &val);
+ if (ret)
+ return connector_status_unknown;

conn = val & BIT(tc->hpd_pin);

@@ -1336,9 +1416,6 @@ static enum drm_connector_status tc_connector_detect(struct drm_connector *conne
return connector_status_connected;
else
return connector_status_disconnected;
-
-err:
- return connector_status_unknown;
}

static const struct drm_connector_funcs tc_connector_funcs = {
--
2.21.0

2019-06-05 07:07:19

by Andrey Smirnov

[permalink] [raw]
Subject: [PATCH v3 07/15] drm/bridge: tc358767: Simplify AUX data write

Simplify AUX data write by dropping index arithmetic and shifting and
replacing it with a call to a helper function that does three things:

1. Copies user-provided data into a write buffer
2. Optionally fixes the endianness of the write buffer (not needed
on LE hosts)
3. Transfers contenst of the write buffer to up to 4 32-bit
registers on the chip

Note that separate data endianness fix:

tmp = (tmp << 8) | buf[i];

that was reserved for DP_AUX_I2C_WRITE looks really strange, since it
will place data differently depending on the passed user-data
size. E.g. for a write of 1 byte, data transferred to the chip would
look like:

[byte0] [dummy1] [dummy2] [dummy3]

whereas for a write of 4 bytes we'd get:

[byte3] [byte2] [byte1] [byte0]

Since there's no indication in the datasheet that I2C write buffer
should be treated differently than AUX write buffer and no comment in
the original code explaining why it was done this way, that special
I2C write buffer transformation was dropped in this patch.

Signed-off-by: Andrey Smirnov <[email protected]>
Cc: Archit Taneja <[email protected]>
Cc: Andrzej Hajda <[email protected]>
Cc: Laurent Pinchart <[email protected]>
Cc: Tomi Valkeinen <[email protected]>
Cc: Andrey Gusakov <[email protected]>
Cc: Philipp Zabel <[email protected]>
Cc: Cory Tusar <[email protected]>
Cc: Chris Healy <[email protected]>
Cc: Lucas Stach <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
drivers/gpu/drm/bridge/tc358767.c | 59 +++++++++++++++++++------------
1 file changed, 37 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index da47d81e7109..260fbcd0271e 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -321,6 +321,32 @@ static int tc_aux_get_status(struct tc_data *tc, u8 *reply)
return 0;
}

+static int tc_aux_write_data(struct tc_data *tc, const void *data,
+ size_t size)
+{
+ u32 auxwdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)] = { 0 };
+ int ret, i, count = DIV_ROUND_UP(size, sizeof(u32));
+
+ memcpy(auxwdata, data, size);
+
+ for (i = 0; i < count; i++) {
+ /*
+ * Our regmap is configured as LE
+ * for register data, so we need
+ * undo any byte swapping that will
+ * happened to preserve original
+ * byte order.
+ */
+ cpu_to_le32s(&auxwdata[i]);
+ }
+
+ ret = regmap_bulk_write(tc->regmap, DP0_AUXWDATA(0), auxwdata, count);
+ if (ret)
+ return ret;
+
+ return size;
+}
+
static int tc_aux_read_data(struct tc_data *tc, void *data, size_t size)
{
u32 auxrdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)];
@@ -350,9 +376,6 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
struct tc_data *tc = aux_to_tc(aux);
size_t size = min_t(size_t, 8, msg->size);
u8 request = msg->request & ~DP_AUX_I2C_MOT;
- u8 *buf = msg->buffer;
- u32 tmp = 0;
- int i = 0;
int ret;

if (size == 0)
@@ -362,25 +385,17 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;

- if (request == DP_AUX_I2C_WRITE || request == DP_AUX_NATIVE_WRITE) {
- /* Store data */
- while (i < size) {
- if (request == DP_AUX_NATIVE_WRITE)
- tmp = tmp | (buf[i] << (8 * (i & 0x3)));
- else
- tmp = (tmp << 8) | buf[i];
- i++;
- if (((i % 4) == 0) || (i == size)) {
- ret = regmap_write(tc->regmap,
- DP0_AUXWDATA((i - 1) >> 2),
- tmp);
- if (ret)
- return ret;
- tmp = 0;
- }
- }
- } else if (request != DP_AUX_I2C_READ &&
- request != DP_AUX_NATIVE_READ) {
+ switch (request) {
+ case DP_AUX_NATIVE_READ:
+ case DP_AUX_I2C_READ:
+ break;
+ case DP_AUX_NATIVE_WRITE:
+ case DP_AUX_I2C_WRITE:
+ ret = tc_aux_write_data(tc, msg->buffer, size);
+ if (ret < 0)
+ return ret;
+ break;
+ default:
return -EINVAL;
}

--
2.21.0

2019-06-05 07:07:25

by Andrey Smirnov

[permalink] [raw]
Subject: [PATCH v3 10/15] drm/bridge: tc358767: Add support for address-only I2C transfers

Transfer size of zero means a request to do an address-only
transfer. Since the HW support this, we probably shouldn't be just
ignoring such requests. While at it allow DP_AUX_I2C_MOT flag to pass
through, since it is supported by the HW as well.

Signed-off-by: Andrey Smirnov <[email protected]>
Cc: Archit Taneja <[email protected]>
Cc: Andrzej Hajda <[email protected]>
Cc: Laurent Pinchart <[email protected]>
Cc: Tomi Valkeinen <[email protected]>
Cc: Andrey Gusakov <[email protected]>
Cc: Philipp Zabel <[email protected]>
Cc: Cory Tusar <[email protected]>
Cc: Chris Healy <[email protected]>
Cc: Lucas Stach <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
drivers/gpu/drm/bridge/tc358767.c | 30 +++++++++++++++++++++++-------
1 file changed, 23 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index 90ec33caacbc..7b84fbb72973 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -145,6 +145,8 @@

/* AUX channel */
#define DP0_AUXCFG0 0x0660
+#define DP0_AUXCFG0_BSIZE GENMASK(11, 8)
+#define DP0_AUXCFG0_ADDR_ONLY BIT(4)
#define DP0_AUXCFG1 0x0664
#define AUX_RX_FILTER_EN BIT(16)

@@ -347,6 +349,18 @@ static int tc_aux_read_data(struct tc_data *tc, void *data, size_t size)
return size;
}

+static u32 tc_auxcfg0(struct drm_dp_aux_msg *msg, size_t size)
+{
+ u32 auxcfg0 = msg->request;
+
+ if (size)
+ auxcfg0 |= FIELD_PREP(DP0_AUXCFG0_BSIZE, size - 1);
+ else
+ auxcfg0 |= DP0_AUXCFG0_ADDR_ONLY;
+
+ return auxcfg0;
+}
+
static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
struct drm_dp_aux_msg *msg)
{
@@ -356,9 +370,6 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
u32 auxstatus;
int ret;

- if (size == 0)
- return 0;
-
ret = tc_aux_wait_busy(tc, 100);
if (ret)
return ret;
@@ -382,8 +393,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
/* Start transfer */
- ret = regmap_write(tc->regmap, DP0_AUXCFG0,
- ((size - 1) << 8) | request);
+ ret = regmap_write(tc->regmap, DP0_AUXCFG0, tc_auxcfg0(msg, size));
if (ret)
return ret;

@@ -397,8 +407,14 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,

if (auxstatus & AUX_TIMEOUT)
return -ETIMEDOUT;
-
- size = FIELD_GET(AUX_BYTES, auxstatus);
+ /*
+ * For some reason address-only DP_AUX_I2C_WRITE (MOT), still
+ * reports 1 byte transferred in its status. To deal we that
+ * we ignore aux_bytes field if we know that this was an
+ * address-only transfer
+ */
+ if (size)
+ size = FIELD_GET(AUX_BYTES, auxstatus);
msg->reply = FIELD_GET(AUX_STATUS, auxstatus);

switch (request) {
--
2.21.0

2019-06-05 07:07:28

by Andrey Smirnov

[permalink] [raw]
Subject: [PATCH v3 11/15] drm/bridge: tc358767: Introduce tc_set_syspllparam()

Move common code converting clock rate to an appropriate constant and
configuring SYS_PLLPARAM register into a separate routine and convert
the rest of the code to use it. No functional change intended.

Signed-off-by: Andrey Smirnov <[email protected]>
Reviewed-by: Laurent Pinchart <[email protected]>
Cc: Archit Taneja <[email protected]>
Cc: Andrzej Hajda <[email protected]>
Cc: Laurent Pinchart <[email protected]>
Cc: Tomi Valkeinen <[email protected]>
Cc: Andrey Gusakov <[email protected]>
Cc: Philipp Zabel <[email protected]>
Cc: Chris Healy <[email protected]>
Cc: Cory Tusar <[email protected]>
Cc: Lucas Stach <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
drivers/gpu/drm/bridge/tc358767.c | 46 +++++++++++--------------------
1 file changed, 16 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index 7b84fbb72973..c58714daa0a1 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -601,35 +601,40 @@ static int tc_stream_clock_calc(struct tc_data *tc)
return regmap_write(tc->regmap, DP0_VIDMNGEN1, 32768);
}

-static int tc_aux_link_setup(struct tc_data *tc)
+static int tc_set_syspllparam(struct tc_data *tc)
{
unsigned long rate;
- u32 dp0_auxcfg1;
- u32 value;
- int ret;
+ u32 pllparam = SYSCLK_SEL_LSCLK | LSCLK_DIV_2;

rate = clk_get_rate(tc->refclk);
switch (rate) {
case 38400000:
- value = REF_FREQ_38M4;
+ pllparam |= REF_FREQ_38M4;
break;
case 26000000:
- value = REF_FREQ_26M;
+ pllparam |= REF_FREQ_26M;
break;
case 19200000:
- value = REF_FREQ_19M2;
+ pllparam |= REF_FREQ_19M2;
break;
case 13000000:
- value = REF_FREQ_13M;
+ pllparam |= REF_FREQ_13M;
break;
default:
dev_err(tc->dev, "Invalid refclk rate: %lu Hz\n", rate);
return -EINVAL;
}

+ return regmap_write(tc->regmap, SYS_PLLPARAM, pllparam);
+}
+
+static int tc_aux_link_setup(struct tc_data *tc)
+{
+ int ret;
+ u32 dp0_auxcfg1;
+
/* Setup DP-PHY / PLL */
- value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
- ret = regmap_write(tc->regmap, SYS_PLLPARAM, value);
+ ret = tc_set_syspllparam(tc);
if (ret)
goto err;

@@ -887,7 +892,6 @@ static int tc_main_link_enable(struct tc_data *tc)
{
struct drm_dp_aux *aux = &tc->aux;
struct device *dev = tc->dev;
- unsigned int rate;
u32 dp_phy_ctrl;
u32 value;
int ret;
@@ -915,25 +919,7 @@ static int tc_main_link_enable(struct tc_data *tc)
if (ret)
return ret;

- rate = clk_get_rate(tc->refclk);
- switch (rate) {
- case 38400000:
- value = REF_FREQ_38M4;
- break;
- case 26000000:
- value = REF_FREQ_26M;
- break;
- case 19200000:
- value = REF_FREQ_19M2;
- break;
- case 13000000:
- value = REF_FREQ_13M;
- break;
- default:
- return -EINVAL;
- }
- value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
- ret = regmap_write(tc->regmap, SYS_PLLPARAM, value);
+ ret = tc_set_syspllparam(tc);
if (ret)
return ret;

--
2.21.0

2019-06-05 07:07:34

by Andrey Smirnov

[permalink] [raw]
Subject: [PATCH v3 12/15] drm/bridge: tc358767: Introduce tc_pllupdate_pllen()

tc_wait_pll_lock() is always called as a follow-up for updating
PLLUPDATE and PLLEN bit of a given PLL control register. To simplify
things, merge the two operation into a single helper function
tc_pllupdate_pllen() and convert the rest of the code to use it. No
functional change intended.

Signed-off-by: Andrey Smirnov <[email protected]>
Reviewed-by: Laurent Pinchart <[email protected]>
Cc: Archit Taneja <[email protected]>
Cc: Andrzej Hajda <[email protected]>
Cc: Laurent Pinchart <[email protected]>
Cc: Tomi Valkeinen <[email protected]>
Cc: Andrey Gusakov <[email protected]>
Cc: Philipp Zabel <[email protected]>
Cc: Cory Tusar <[email protected]>
Cc: Chris Healy <[email protected]>
Cc: Lucas Stach <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
drivers/gpu/drm/bridge/tc358767.c | 30 ++++++++++++++----------------
1 file changed, 14 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index c58714daa0a1..a04401cf2a92 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -463,10 +463,18 @@ static u32 tc_srcctrl(struct tc_data *tc)
return reg;
}

-static void tc_wait_pll_lock(struct tc_data *tc)
+static int tc_pllupdate_pllen(struct tc_data *tc, unsigned int pllctrl)
{
+ int ret;
+
+ ret = regmap_write(tc->regmap, pllctrl, PLLUPDATE | PLLEN);
+ if (ret)
+ return ret;
+
/* Wait for PLL to lock: up to 2.09 ms, depending on refclk */
usleep_range(3000, 6000);
+
+ return 0;
}

static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, u32 pixelclock)
@@ -566,13 +574,7 @@ static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, u32 pixelclock)
return ret;

/* Force PLL parameter update and disable bypass */
- ret = regmap_write(tc->regmap, PXL_PLLCTRL, PLLUPDATE | PLLEN);
- if (ret)
- return ret;
-
- tc_wait_pll_lock(tc);
-
- return 0;
+ return tc_pllupdate_pllen(tc, PXL_PLLCTRL);
}

static int tc_pxl_pll_dis(struct tc_data *tc)
@@ -645,15 +647,13 @@ static int tc_aux_link_setup(struct tc_data *tc)
* Initially PLLs are in bypass. Force PLL parameter update,
* disable PLL bypass, enable PLL
*/
- ret = regmap_write(tc->regmap, DP0_PLLCTRL, PLLUPDATE | PLLEN);
+ ret = tc_pllupdate_pllen(tc, DP0_PLLCTRL);
if (ret)
goto err;
- tc_wait_pll_lock(tc);

- ret = regmap_write(tc->regmap, DP1_PLLCTRL, PLLUPDATE | PLLEN);
+ ret = tc_pllupdate_pllen(tc, DP1_PLLCTRL);
if (ret)
goto err;
- tc_wait_pll_lock(tc);

ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
if (ret == -ETIMEDOUT) {
@@ -933,15 +933,13 @@ static int tc_main_link_enable(struct tc_data *tc)
return ret;

/* PLL setup */
- ret = regmap_write(tc->regmap, DP0_PLLCTRL, PLLUPDATE | PLLEN);
+ ret = tc_pllupdate_pllen(tc, DP0_PLLCTRL);
if (ret)
return ret;
- tc_wait_pll_lock(tc);

- ret = regmap_write(tc->regmap, DP1_PLLCTRL, PLLUPDATE | PLLEN);
+ ret = tc_pllupdate_pllen(tc, DP1_PLLCTRL);
if (ret)
return ret;
- tc_wait_pll_lock(tc);

/* Reset/Enable Main Links */
dp_phy_ctrl |= DP_PHY_RST | PHY_M1_RST | PHY_M0_RST;
--
2.21.0

2019-06-05 07:07:34

by Andrey Smirnov

[permalink] [raw]
Subject: [PATCH v3 13/15] drm/bridge: tc358767: Simplify tc_aux_wait_busy()

We never pass anything but 100 as timeout_ms to tc_aux_wait_busy(), so
we may as well hardcode that value and simplify function's signature.

Signed-off-by: Andrey Smirnov <[email protected]>
Cc: Archit Taneja <[email protected]>
Cc: Andrzej Hajda <[email protected]>
Cc: Laurent Pinchart <[email protected]>
Cc: Tomi Valkeinen <[email protected]>
Cc: Andrey Gusakov <[email protected]>
Cc: Philipp Zabel <[email protected]>
Cc: Cory Tusar <[email protected]>
Cc: Chris Healy <[email protected]>
Cc: Lucas Stach <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
drivers/gpu/drm/bridge/tc358767.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index a04401cf2a92..4fe7641f84ee 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -294,10 +294,9 @@ static inline int tc_poll_timeout(struct tc_data *tc, unsigned int addr,
sleep_us, timeout_us);
}

-static int tc_aux_wait_busy(struct tc_data *tc, unsigned int timeout_ms)
+static int tc_aux_wait_busy(struct tc_data *tc)
{
- return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0,
- 1000, 1000 * timeout_ms);
+ return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0, 1000, 100000);
}

static int tc_aux_write_data(struct tc_data *tc, const void *data,
@@ -370,7 +369,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
u32 auxstatus;
int ret;

- ret = tc_aux_wait_busy(tc, 100);
+ ret = tc_aux_wait_busy(tc);
if (ret)
return ret;

@@ -397,7 +396,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;

- ret = tc_aux_wait_busy(tc, 100);
+ ret = tc_aux_wait_busy(tc);
if (ret)
return ret;

--
2.21.0

2019-06-05 07:07:46

by Andrey Smirnov

[permalink] [raw]
Subject: [PATCH v3 14/15] drm/bridge: tc358767: Drop unnecessary 8 byte buffer

tc_get_display_props() never reads more than a byte via AUX, so
there's no need to reserve 8 for that purpose. No function change
intended.

Signed-off-by: Andrey Smirnov <[email protected]>
Cc: Archit Taneja <[email protected]>
Cc: Andrzej Hajda <[email protected]>
Cc: Laurent Pinchart <[email protected]>
Cc: Tomi Valkeinen <[email protected]>
Cc: Andrey Gusakov <[email protected]>
Cc: Philipp Zabel <[email protected]>
Cc: Cory Tusar <[email protected]>
Cc: Chris Healy <[email protected]>
Cc: Lucas Stach <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
drivers/gpu/drm/bridge/tc358767.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index 4fe7641f84ee..41a976dff13b 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -680,8 +680,7 @@ static int tc_aux_link_setup(struct tc_data *tc)
static int tc_get_display_props(struct tc_data *tc)
{
int ret;
- /* temp buffer */
- u8 tmp[8];
+ u8 reg;

/* Read DP Rx Link Capability */
ret = drm_dp_link_probe(&tc->aux, &tc->link.base);
@@ -697,21 +696,21 @@ static int tc_get_display_props(struct tc_data *tc)
tc->link.base.num_lanes = 2;
}

- ret = drm_dp_dpcd_readb(&tc->aux, DP_MAX_DOWNSPREAD, tmp);
+ ret = drm_dp_dpcd_readb(&tc->aux, DP_MAX_DOWNSPREAD, &reg);
if (ret < 0)
goto err_dpcd_read;
- tc->link.spread = tmp[0] & DP_MAX_DOWNSPREAD_0_5;
+ tc->link.spread = reg & DP_MAX_DOWNSPREAD_0_5;

- ret = drm_dp_dpcd_readb(&tc->aux, DP_MAIN_LINK_CHANNEL_CODING, tmp);
+ ret = drm_dp_dpcd_readb(&tc->aux, DP_MAIN_LINK_CHANNEL_CODING, &reg);
if (ret < 0)
goto err_dpcd_read;

tc->link.scrambler_dis = false;
/* read assr */
- ret = drm_dp_dpcd_readb(&tc->aux, DP_EDP_CONFIGURATION_SET, tmp);
+ ret = drm_dp_dpcd_readb(&tc->aux, DP_EDP_CONFIGURATION_SET, &reg);
if (ret < 0)
goto err_dpcd_read;
- tc->link.assr = tmp[0] & DP_ALTERNATE_SCRAMBLER_RESET_ENABLE;
+ tc->link.assr = reg & DP_ALTERNATE_SCRAMBLER_RESET_ENABLE;

dev_dbg(tc->dev, "DPCD rev: %d.%d, rate: %s, lanes: %d, framing: %s\n",
tc->link.base.revision >> 4, tc->link.base.revision & 0x0f,
--
2.21.0

2019-06-05 07:08:07

by Andrey Smirnov

[permalink] [raw]
Subject: [PATCH v3 09/15] drm/bridge: tc358767: Use reported AUX transfer size

Don't assume that requested data transfer size is the same as amount
of data that was transferred. Change the code to get that information
from DP0_AUXSTATUS instead.

Since the check for AUX_BUSY in tc_aux_get_status() is pointless (it
will always called after tc_aux_wait_busy()) and there's only one user
of it, inline its code into tc_aux_transfer() instead of trying to
accommodate the change above.

Signed-off-by: Andrey Smirnov <[email protected]>
Cc: Archit Taneja <[email protected]>
Cc: Andrzej Hajda <[email protected]>
Cc: Laurent Pinchart <[email protected]>
Cc: Tomi Valkeinen <[email protected]>
Cc: Andrey Gusakov <[email protected]>
Cc: Philipp Zabel <[email protected]>
Cc: Cory Tusar <[email protected]>
Cc: Chris Healy <[email protected]>
Cc: Lucas Stach <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
drivers/gpu/drm/bridge/tc358767.c | 40 ++++++++++---------------------
1 file changed, 12 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index 0125e2f7e076..90ec33caacbc 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -152,10 +152,10 @@
#define DP0_AUXWDATA(i) (0x066c + (i) * 4)
#define DP0_AUXRDATA(i) (0x067c + (i) * 4)
#define DP0_AUXSTATUS 0x068c
-#define AUX_STATUS_MASK 0xf0
-#define AUX_STATUS_SHIFT 4
-#define AUX_TIMEOUT BIT(1)
-#define AUX_BUSY BIT(0)
+#define AUX_BYTES GENMASK(15, 8)
+#define AUX_STATUS GENMASK(7, 4)
+#define AUX_TIMEOUT BIT(1)
+#define AUX_BUSY BIT(0)
#define DP0_AUXI2CADR 0x0698

/* Link Training */
@@ -298,29 +298,6 @@ static int tc_aux_wait_busy(struct tc_data *tc, unsigned int timeout_ms)
1000, 1000 * timeout_ms);
}

-static int tc_aux_get_status(struct tc_data *tc, u8 *reply)
-{
- int ret;
- u32 value;
-
- ret = regmap_read(tc->regmap, DP0_AUXSTATUS, &value);
- if (ret < 0)
- return ret;
-
- if (value & AUX_BUSY) {
- dev_err(tc->dev, "aux busy!\n");
- return -EBUSY;
- }
-
- if (value & AUX_TIMEOUT) {
- dev_err(tc->dev, "aux access timeout!\n");
- return -ETIMEDOUT;
- }
-
- *reply = (value & AUX_STATUS_MASK) >> AUX_STATUS_SHIFT;
- return 0;
-}
-
static int tc_aux_write_data(struct tc_data *tc, const void *data,
size_t size)
{
@@ -376,6 +353,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
struct tc_data *tc = aux_to_tc(aux);
size_t size = min_t(size_t, DP_AUX_MAX_PAYLOAD_BYTES - 1, msg->size);
u8 request = msg->request & ~DP_AUX_I2C_MOT;
+ u32 auxstatus;
int ret;

if (size == 0)
@@ -413,10 +391,16 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;

- ret = tc_aux_get_status(tc, &msg->reply);
+ ret = regmap_read(tc->regmap, DP0_AUXSTATUS, &auxstatus);
if (ret)
return ret;

+ if (auxstatus & AUX_TIMEOUT)
+ return -ETIMEDOUT;
+
+ size = FIELD_GET(AUX_BYTES, auxstatus);
+ msg->reply = FIELD_GET(AUX_STATUS, auxstatus);
+
switch (request) {
case DP_AUX_NATIVE_READ:
case DP_AUX_I2C_READ:
--
2.21.0

2019-06-05 07:08:13

by Andrey Smirnov

[permalink] [raw]
Subject: [PATCH v3 08/15] drm/bridge: tc358767: Increase AUX transfer length limit

According to the datasheet tc358767 can transfer up to 16 bytes via
its AUX channel, so the artificial limit of 8 apperas to be too
low. However only up to 15-bytes seem to be actually supported and
trying to use 16-byte transfers results in transfers failing
sporadically (with bogus status in case of I2C transfers), so limit it
to 15.

Signed-off-by: Andrey Smirnov <[email protected]>
Cc: Archit Taneja <[email protected]>
Cc: Andrzej Hajda <[email protected]>
Cc: Laurent Pinchart <[email protected]>
Cc: Tomi Valkeinen <[email protected]>
Cc: Andrey Gusakov <[email protected]>
Cc: Philipp Zabel <[email protected]>
Cc: Cory Tusar <[email protected]>
Cc: Chris Healy <[email protected]>
Cc: Lucas Stach <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
drivers/gpu/drm/bridge/tc358767.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index 260fbcd0271e..0125e2f7e076 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -374,7 +374,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
struct drm_dp_aux_msg *msg)
{
struct tc_data *tc = aux_to_tc(aux);
- size_t size = min_t(size_t, 8, msg->size);
+ size_t size = min_t(size_t, DP_AUX_MAX_PAYLOAD_BYTES - 1, msg->size);
u8 request = msg->request & ~DP_AUX_I2C_MOT;
int ret;

--
2.21.0

2019-06-05 07:08:24

by Andrey Smirnov

[permalink] [raw]
Subject: [PATCH v3 04/15] drm/bridge: tc358767: Simplify tc_set_video_mode()

Simplify tc_set_video_mode() by replacing explicit shifting using
macros from <linux/bitfield.h>. No functional change intended.

Signed-off-by: Andrey Smirnov <[email protected]>
Cc: Archit Taneja <[email protected]>
Cc: Andrzej Hajda <[email protected]>
Cc: Laurent Pinchart <[email protected]>
Cc: Tomi Valkeinen <[email protected]>
Cc: Andrey Gusakov <[email protected]>
Cc: Philipp Zabel <[email protected]>
Cc: Cory Tusar <[email protected]>
Cc: Chris Healy <[email protected]>
Cc: Lucas Stach <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
drivers/gpu/drm/bridge/tc358767.c | 106 ++++++++++++++++++++++--------
1 file changed, 78 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index 115cffc55a96..c0fc686ce5ec 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -24,6 +24,7 @@
* GNU General Public License for more details.
*/

+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
@@ -56,6 +57,7 @@

/* Video Path */
#define VPCTRL0 0x0450
+#define VSDELAY GENMASK(31, 20)
#define OPXLFMT_RGB666 (0 << 8)
#define OPXLFMT_RGB888 (1 << 8)
#define FRMSYNC_DISABLED (0 << 4) /* Video Timing Gen Disabled */
@@ -63,9 +65,17 @@
#define MSF_DISABLED (0 << 0) /* Magic Square FRC disabled */
#define MSF_ENABLED (1 << 0) /* Magic Square FRC enabled */
#define HTIM01 0x0454
+#define HPW GENMASK(8, 0)
+#define HBPR GENMASK(24, 16)
#define HTIM02 0x0458
+#define HDISPR GENMASK(10, 0)
+#define HFPR GENMASK(24, 16)
#define VTIM01 0x045c
+#define VSPR GENMASK(7, 0)
+#define VBPR GENMASK(23, 16)
#define VTIM02 0x0460
+#define VFPR GENMASK(23, 16)
+#define VDISPR GENMASK(10, 0)
#define VFUEN0 0x0464
#define VFUEN BIT(0) /* Video Frame Timing Upload */

@@ -108,14 +118,28 @@
/* Main Channel */
#define DP0_SECSAMPLE 0x0640
#define DP0_VIDSYNCDELAY 0x0644
+#define VID_SYNC_DLY GENMASK(15, 0)
+#define THRESH_DLY GENMASK(31, 16)
+
#define DP0_TOTALVAL 0x0648
+#define H_TOTAL GENMASK(15, 0)
+#define V_TOTAL GENMASK(31, 16)
#define DP0_STARTVAL 0x064c
+#define H_START GENMASK(15, 0)
+#define V_START GENMASK(31, 16)
#define DP0_ACTIVEVAL 0x0650
+#define H_ACT GENMASK(15, 0)
+#define V_ACT GENMASK(31, 16)
+
#define DP0_SYNCVAL 0x0654
+#define VS_WIDTH GENMASK(30, 16)
+#define HS_WIDTH GENMASK(14, 0)
#define SYNCVAL_HS_POL_ACTIVE_LOW (1 << 15)
#define SYNCVAL_VS_POL_ACTIVE_LOW (1 << 31)
#define DP0_MISC 0x0658
#define TU_SIZE_RECOMMENDED (63) /* LSCLK cycles per TU */
+#define MAX_TU_SYMBOL GENMASK(28, 23)
+#define TU_SIZE GENMASK(21, 16)
#define BPC_6 (0 << 5)
#define BPC_8 (1 << 5)

@@ -192,6 +216,12 @@

/* Test & Debug */
#define TSTCTL 0x0a00
+#define COLOR_R GENMASK(31, 24)
+#define COLOR_G GENMASK(23, 16)
+#define COLOR_B GENMASK(15, 8)
+#define ENI2CFILTER BIT(4)
+#define COLOR_BAR_MODE GENMASK(1, 0)
+#define COLOR_BAR_MODE_BARS 2
#define PLL_DBG 0x0a04

static bool tc_test_pattern;
@@ -672,6 +702,7 @@ static int tc_set_video_mode(struct tc_data *tc,
int upper_margin = mode->vtotal - mode->vsync_end;
int lower_margin = mode->vsync_start - mode->vdisplay;
int vsync_len = mode->vsync_end - mode->vsync_start;
+ u32 dp0_syncval;

/*
* Recommended maximum number of symbols transferred in a transfer unit:
@@ -696,50 +727,69 @@ static int tc_set_video_mode(struct tc_data *tc,
* assume we do not need any delay when DPI is a source of
* sync signals
*/
- tc_write(VPCTRL0, (0 << 20) /* VSDELAY */ |
+ tc_write(VPCTRL0,
+ FIELD_PREP(VSDELAY, 0) |
OPXLFMT_RGB888 | FRMSYNC_DISABLED | MSF_DISABLED);
- tc_write(HTIM01, (ALIGN(left_margin, 2) << 16) | /* H back porch */
- (ALIGN(hsync_len, 2) << 0)); /* Hsync */
- tc_write(HTIM02, (ALIGN(right_margin, 2) << 16) | /* H front porch */
- (ALIGN(mode->hdisplay, 2) << 0)); /* width */
- tc_write(VTIM01, (upper_margin << 16) | /* V back porch */
- (vsync_len << 0)); /* Vsync */
- tc_write(VTIM02, (lower_margin << 16) | /* V front porch */
- (mode->vdisplay << 0)); /* height */
+ tc_write(HTIM01,
+ FIELD_PREP(HBPR, ALIGN(left_margin, 2)) |
+ FIELD_PREP(HPW, ALIGN(hsync_len, 2)));
+ tc_write(HTIM02,
+ FIELD_PREP(HDISPR, ALIGN(mode->hdisplay, 2)) |
+ FIELD_PREP(HFPR, ALIGN(right_margin, 2)));
+ tc_write(VTIM01,
+ FIELD_PREP(VBPR, upper_margin) |
+ FIELD_PREP(VSPR, vsync_len));
+ tc_write(VTIM02,
+ FIELD_PREP(VFPR, lower_margin) |
+ FIELD_PREP(VDISPR, mode->vdisplay));
tc_write(VFUEN0, VFUEN); /* update settings */

/* Test pattern settings */
tc_write(TSTCTL,
- (120 << 24) | /* Red Color component value */
- (20 << 16) | /* Green Color component value */
- (99 << 8) | /* Blue Color component value */
- (1 << 4) | /* Enable I2C Filter */
- (2 << 0) | /* Color bar Mode */
- 0);
+ FIELD_PREP(COLOR_R, 120) |
+ FIELD_PREP(COLOR_G, 20) |
+ FIELD_PREP(COLOR_B, 99) |
+ ENI2CFILTER |
+ FIELD_PREP(COLOR_BAR_MODE, COLOR_BAR_MODE_BARS));

/* DP Main Stream Attributes */
vid_sync_dly = hsync_len + left_margin + mode->hdisplay;
tc_write(DP0_VIDSYNCDELAY,
- (max_tu_symbol << 16) | /* thresh_dly */
- (vid_sync_dly << 0));
+ FIELD_PREP(THRESH_DLY, max_tu_symbol) |
+ FIELD_PREP(VID_SYNC_DLY, vid_sync_dly));

- tc_write(DP0_TOTALVAL, (mode->vtotal << 16) | (mode->htotal));
+ tc_write(DP0_TOTALVAL,
+ FIELD_PREP(H_TOTAL, mode->htotal) |
+ FIELD_PREP(V_TOTAL, mode->vtotal));

tc_write(DP0_STARTVAL,
- ((upper_margin + vsync_len) << 16) |
- ((left_margin + hsync_len) << 0));
+ FIELD_PREP(H_START, left_margin + hsync_len) |
+ FIELD_PREP(V_START, upper_margin + vsync_len));
+
+ tc_write(DP0_ACTIVEVAL,
+ FIELD_PREP(V_ACT, mode->vdisplay) |
+ FIELD_PREP(H_ACT, mode->hdisplay));
+
+ dp0_syncval = FIELD_PREP(VS_WIDTH, vsync_len) |
+ FIELD_PREP(HS_WIDTH, hsync_len);
+
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ dp0_syncval |= SYNCVAL_VS_POL_ACTIVE_LOW;

- tc_write(DP0_ACTIVEVAL, (mode->vdisplay << 16) | (mode->hdisplay));
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ dp0_syncval |= SYNCVAL_HS_POL_ACTIVE_LOW;

- tc_write(DP0_SYNCVAL, (vsync_len << 16) | (hsync_len << 0) |
- ((mode->flags & DRM_MODE_FLAG_NHSYNC) ? SYNCVAL_HS_POL_ACTIVE_LOW : 0) |
- ((mode->flags & DRM_MODE_FLAG_NVSYNC) ? SYNCVAL_VS_POL_ACTIVE_LOW : 0));
+ tc_write(DP0_SYNCVAL, dp0_syncval);

- tc_write(DPIPXLFMT, VS_POL_ACTIVE_LOW | HS_POL_ACTIVE_LOW |
- DE_POL_ACTIVE_HIGH | SUB_CFG_TYPE_CONFIG1 | DPI_BPP_RGB888);
+ tc_write(DPIPXLFMT,
+ VS_POL_ACTIVE_LOW | HS_POL_ACTIVE_LOW |
+ DE_POL_ACTIVE_HIGH | SUB_CFG_TYPE_CONFIG1 |
+ DPI_BPP_RGB888);

- tc_write(DP0_MISC, (max_tu_symbol << 23) | (TU_SIZE_RECOMMENDED << 16) |
- BPC_8);
+ tc_write(DP0_MISC,
+ FIELD_PREP(MAX_TU_SYMBOL, max_tu_symbol) |
+ FIELD_PREP(TU_SIZE, TU_SIZE_RECOMMENDED) |
+ BPC_8);

return 0;
err:
--
2.21.0

2019-06-05 07:08:58

by Andrey Smirnov

[permalink] [raw]
Subject: [PATCH v3 15/15] drm/bridge: tc358767: Replace magic number in tc_main_link_enable()

We don't need 8 byte array, DP_LINK_STATUS_SIZE (6) should be
enough. This also gets rid of a magic number as a bonus.

Signed-off-by: Andrey Smirnov <[email protected]>
Cc: Archit Taneja <[email protected]>
Cc: Andrzej Hajda <[email protected]>
Cc: Laurent Pinchart <[email protected]>
Cc: Tomi Valkeinen <[email protected]>
Cc: Andrey Gusakov <[email protected]>
Cc: Philipp Zabel <[email protected]>
Cc: Cory Tusar <[email protected]>
Cc: Chris Healy <[email protected]>
Cc: Lucas Stach <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
drivers/gpu/drm/bridge/tc358767.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index 41a976dff13b..cf38f943e656 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -893,7 +893,7 @@ static int tc_main_link_enable(struct tc_data *tc)
u32 dp_phy_ctrl;
u32 value;
int ret;
- u8 tmp[8];
+ u8 tmp[DP_LINK_STATUS_SIZE];

dev_dbg(tc->dev, "link enable\n");

--
2.21.0

2019-06-05 07:09:34

by Andrey Smirnov

[permalink] [raw]
Subject: [PATCH v3 06/15] drm/bridge: tc358767: Simplify AUX data read

Simplify AUX data read by removing index arithmetic and shifting with
a helper functions that does three things:

1. Fetch data from up to 4 32-bit registers from the chip
2. Optionally fix data endianness (not needed on LE hosts)
3. Copy read data into user provided array.

Signed-off-by: Andrey Smirnov <[email protected]>
Cc: Archit Taneja <[email protected]>
Cc: Andrzej Hajda <[email protected]>
Cc: Laurent Pinchart <[email protected]>
Cc: Tomi Valkeinen <[email protected]>
Cc: Andrey Gusakov <[email protected]>
Cc: Philipp Zabel <[email protected]>
Cc: Cory Tusar <[email protected]>
Cc: Chris Healy <[email protected]>
Cc: Lucas Stach <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
drivers/gpu/drm/bridge/tc358767.c | 40 +++++++++++++++++++++----------
1 file changed, 27 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index e197ce0fb166..da47d81e7109 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -321,6 +321,29 @@ static int tc_aux_get_status(struct tc_data *tc, u8 *reply)
return 0;
}

+static int tc_aux_read_data(struct tc_data *tc, void *data, size_t size)
+{
+ u32 auxrdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)];
+ int ret, i, count = DIV_ROUND_UP(size, sizeof(u32));
+
+ ret = regmap_bulk_read(tc->regmap, DP0_AUXRDATA(0), auxrdata, count);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < count; i++) {
+ /*
+ * Our regmap is configured as LE for register data,
+ * so we need undo any byte swapping that might have
+ * happened to preserve original byte order.
+ */
+ le32_to_cpus(&auxrdata[i]);
+ }
+
+ memcpy(data, auxrdata, size);
+
+ return size;
+}
+
static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
struct drm_dp_aux_msg *msg)
{
@@ -379,19 +402,10 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;

- if (request == DP_AUX_I2C_READ || request == DP_AUX_NATIVE_READ) {
- /* Read data */
- while (i < size) {
- if ((i % 4) == 0) {
- ret = regmap_read(tc->regmap,
- DP0_AUXRDATA(i >> 2), &tmp);
- if (ret)
- return ret;
- }
- buf[i] = tmp & 0xff;
- tmp = tmp >> 8;
- i++;
- }
+ switch (request) {
+ case DP_AUX_NATIVE_READ:
+ case DP_AUX_I2C_READ:
+ return tc_aux_read_data(tc, msg->buffer, size);
}

return size;
--
2.21.0

2019-06-06 08:03:42

by Andrzej Hajda

[permalink] [raw]
Subject: Re: [PATCH v3 02/15] drm/bridge: tc358767: Simplify polling in tc_main_link_setup()

On 05.06.2019 09:04, Andrey Smirnov wrote:
> Replace explicit polling loop with equivalent call to
> tc_poll_timeout() for brevity. No functional change intended.
>
> Signed-off-by: Andrey Smirnov <[email protected]>
> Cc: Archit Taneja <[email protected]>
> Cc: Andrzej Hajda <[email protected]>
> Cc: Laurent Pinchart <[email protected]>
> Cc: Tomi Valkeinen <[email protected]>
> Cc: Andrey Gusakov <[email protected]>
> Cc: Philipp Zabel <[email protected]>
> Cc: Cory Tusar <[email protected]>
> Cc: Chris Healy <[email protected]>
> Cc: Lucas Stach <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> ---
> drivers/gpu/drm/bridge/tc358767.c | 15 +++++----------
> 1 file changed, 5 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
> index fb8a1942ec54..5e1e73a91696 100644
> --- a/drivers/gpu/drm/bridge/tc358767.c
> +++ b/drivers/gpu/drm/bridge/tc358767.c
> @@ -774,7 +774,6 @@ static int tc_main_link_enable(struct tc_data *tc)
> struct device *dev = tc->dev;
> unsigned int rate;
> u32 dp_phy_ctrl;
> - int timeout;
> u32 value;
> int ret;
> u8 tmp[8];
> @@ -831,15 +830,11 @@ static int tc_main_link_enable(struct tc_data *tc)
> dp_phy_ctrl &= ~(DP_PHY_RST | PHY_M1_RST | PHY_M0_RST);
> tc_write(DP_PHY_CTRL, dp_phy_ctrl);
>
> - timeout = 1000;
> - do {
> - tc_read(DP_PHY_CTRL, &value);
> - udelay(1);
> - } while ((!(value & PHY_RDY)) && (--timeout));
> -
> - if (timeout == 0) {
> - dev_err(dev, "timeout waiting for phy become ready");
> - return -ETIMEDOUT;
> + ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
> + if (ret) {
> + if (ret == -ETIMEDOUT)
> + dev_err(dev, "timeout waiting for phy become ready");
> + return ret;


Reviewed-by: Andrzej Hajda <[email protected]>

 --
Regards
Andrzej


> }
>
> /* Set misc: 8 bits per color */


2019-06-06 08:19:22

by Andrzej Hajda

[permalink] [raw]
Subject: Re: [PATCH v3 04/15] drm/bridge: tc358767: Simplify tc_set_video_mode()

On 05.06.2019 09:04, Andrey Smirnov wrote:
> Simplify tc_set_video_mode() by replacing explicit shifting using
> macros from <linux/bitfield.h>. No functional change intended.
>
> Signed-off-by: Andrey Smirnov <[email protected]>
> Cc: Archit Taneja <[email protected]>
> Cc: Andrzej Hajda <[email protected]>
> Cc: Laurent Pinchart <[email protected]>
> Cc: Tomi Valkeinen <[email protected]>
> Cc: Andrey Gusakov <[email protected]>
> Cc: Philipp Zabel <[email protected]>
> Cc: Cory Tusar <[email protected]>
> Cc: Chris Healy <[email protected]>
> Cc: Lucas Stach <[email protected]>
> Cc: [email protected]
> Cc: [email protected]


Reviewed-by: Andrzej Hajda <[email protected]>

 --
Regards
Andrzej


> ---
> drivers/gpu/drm/bridge/tc358767.c | 106 ++++++++++++++++++++++--------
> 1 file changed, 78 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
> index 115cffc55a96..c0fc686ce5ec 100644
> --- a/drivers/gpu/drm/bridge/tc358767.c
> +++ b/drivers/gpu/drm/bridge/tc358767.c
> @@ -24,6 +24,7 @@
> * GNU General Public License for more details.
> */
>
> +#include <linux/bitfield.h>
> #include <linux/clk.h>
> #include <linux/device.h>
> #include <linux/gpio/consumer.h>
> @@ -56,6 +57,7 @@
>
> /* Video Path */
> #define VPCTRL0 0x0450
> +#define VSDELAY GENMASK(31, 20)
> #define OPXLFMT_RGB666 (0 << 8)
> #define OPXLFMT_RGB888 (1 << 8)
> #define FRMSYNC_DISABLED (0 << 4) /* Video Timing Gen Disabled */
> @@ -63,9 +65,17 @@
> #define MSF_DISABLED (0 << 0) /* Magic Square FRC disabled */
> #define MSF_ENABLED (1 << 0) /* Magic Square FRC enabled */
> #define HTIM01 0x0454
> +#define HPW GENMASK(8, 0)
> +#define HBPR GENMASK(24, 16)
> #define HTIM02 0x0458
> +#define HDISPR GENMASK(10, 0)
> +#define HFPR GENMASK(24, 16)
> #define VTIM01 0x045c
> +#define VSPR GENMASK(7, 0)
> +#define VBPR GENMASK(23, 16)
> #define VTIM02 0x0460
> +#define VFPR GENMASK(23, 16)
> +#define VDISPR GENMASK(10, 0)
> #define VFUEN0 0x0464
> #define VFUEN BIT(0) /* Video Frame Timing Upload */
>
> @@ -108,14 +118,28 @@
> /* Main Channel */
> #define DP0_SECSAMPLE 0x0640
> #define DP0_VIDSYNCDELAY 0x0644
> +#define VID_SYNC_DLY GENMASK(15, 0)
> +#define THRESH_DLY GENMASK(31, 16)
> +
> #define DP0_TOTALVAL 0x0648
> +#define H_TOTAL GENMASK(15, 0)
> +#define V_TOTAL GENMASK(31, 16)
> #define DP0_STARTVAL 0x064c
> +#define H_START GENMASK(15, 0)
> +#define V_START GENMASK(31, 16)
> #define DP0_ACTIVEVAL 0x0650
> +#define H_ACT GENMASK(15, 0)
> +#define V_ACT GENMASK(31, 16)
> +
> #define DP0_SYNCVAL 0x0654
> +#define VS_WIDTH GENMASK(30, 16)
> +#define HS_WIDTH GENMASK(14, 0)
> #define SYNCVAL_HS_POL_ACTIVE_LOW (1 << 15)
> #define SYNCVAL_VS_POL_ACTIVE_LOW (1 << 31)
> #define DP0_MISC 0x0658
> #define TU_SIZE_RECOMMENDED (63) /* LSCLK cycles per TU */
> +#define MAX_TU_SYMBOL GENMASK(28, 23)
> +#define TU_SIZE GENMASK(21, 16)
> #define BPC_6 (0 << 5)
> #define BPC_8 (1 << 5)
>
> @@ -192,6 +216,12 @@
>
> /* Test & Debug */
> #define TSTCTL 0x0a00
> +#define COLOR_R GENMASK(31, 24)
> +#define COLOR_G GENMASK(23, 16)
> +#define COLOR_B GENMASK(15, 8)
> +#define ENI2CFILTER BIT(4)
> +#define COLOR_BAR_MODE GENMASK(1, 0)
> +#define COLOR_BAR_MODE_BARS 2
> #define PLL_DBG 0x0a04
>
> static bool tc_test_pattern;
> @@ -672,6 +702,7 @@ static int tc_set_video_mode(struct tc_data *tc,
> int upper_margin = mode->vtotal - mode->vsync_end;
> int lower_margin = mode->vsync_start - mode->vdisplay;
> int vsync_len = mode->vsync_end - mode->vsync_start;
> + u32 dp0_syncval;
>
> /*
> * Recommended maximum number of symbols transferred in a transfer unit:
> @@ -696,50 +727,69 @@ static int tc_set_video_mode(struct tc_data *tc,
> * assume we do not need any delay when DPI is a source of
> * sync signals
> */
> - tc_write(VPCTRL0, (0 << 20) /* VSDELAY */ |
> + tc_write(VPCTRL0,
> + FIELD_PREP(VSDELAY, 0) |
> OPXLFMT_RGB888 | FRMSYNC_DISABLED | MSF_DISABLED);
> - tc_write(HTIM01, (ALIGN(left_margin, 2) << 16) | /* H back porch */
> - (ALIGN(hsync_len, 2) << 0)); /* Hsync */
> - tc_write(HTIM02, (ALIGN(right_margin, 2) << 16) | /* H front porch */
> - (ALIGN(mode->hdisplay, 2) << 0)); /* width */
> - tc_write(VTIM01, (upper_margin << 16) | /* V back porch */
> - (vsync_len << 0)); /* Vsync */
> - tc_write(VTIM02, (lower_margin << 16) | /* V front porch */
> - (mode->vdisplay << 0)); /* height */
> + tc_write(HTIM01,
> + FIELD_PREP(HBPR, ALIGN(left_margin, 2)) |
> + FIELD_PREP(HPW, ALIGN(hsync_len, 2)));
> + tc_write(HTIM02,
> + FIELD_PREP(HDISPR, ALIGN(mode->hdisplay, 2)) |
> + FIELD_PREP(HFPR, ALIGN(right_margin, 2)));
> + tc_write(VTIM01,
> + FIELD_PREP(VBPR, upper_margin) |
> + FIELD_PREP(VSPR, vsync_len));
> + tc_write(VTIM02,
> + FIELD_PREP(VFPR, lower_margin) |
> + FIELD_PREP(VDISPR, mode->vdisplay));
> tc_write(VFUEN0, VFUEN); /* update settings */
>
> /* Test pattern settings */
> tc_write(TSTCTL,
> - (120 << 24) | /* Red Color component value */
> - (20 << 16) | /* Green Color component value */
> - (99 << 8) | /* Blue Color component value */
> - (1 << 4) | /* Enable I2C Filter */
> - (2 << 0) | /* Color bar Mode */
> - 0);
> + FIELD_PREP(COLOR_R, 120) |
> + FIELD_PREP(COLOR_G, 20) |
> + FIELD_PREP(COLOR_B, 99) |
> + ENI2CFILTER |
> + FIELD_PREP(COLOR_BAR_MODE, COLOR_BAR_MODE_BARS));
>
> /* DP Main Stream Attributes */
> vid_sync_dly = hsync_len + left_margin + mode->hdisplay;
> tc_write(DP0_VIDSYNCDELAY,
> - (max_tu_symbol << 16) | /* thresh_dly */
> - (vid_sync_dly << 0));
> + FIELD_PREP(THRESH_DLY, max_tu_symbol) |
> + FIELD_PREP(VID_SYNC_DLY, vid_sync_dly));
>
> - tc_write(DP0_TOTALVAL, (mode->vtotal << 16) | (mode->htotal));
> + tc_write(DP0_TOTALVAL,
> + FIELD_PREP(H_TOTAL, mode->htotal) |
> + FIELD_PREP(V_TOTAL, mode->vtotal));
>
> tc_write(DP0_STARTVAL,
> - ((upper_margin + vsync_len) << 16) |
> - ((left_margin + hsync_len) << 0));
> + FIELD_PREP(H_START, left_margin + hsync_len) |
> + FIELD_PREP(V_START, upper_margin + vsync_len));
> +
> + tc_write(DP0_ACTIVEVAL,
> + FIELD_PREP(V_ACT, mode->vdisplay) |
> + FIELD_PREP(H_ACT, mode->hdisplay));
> +
> + dp0_syncval = FIELD_PREP(VS_WIDTH, vsync_len) |
> + FIELD_PREP(HS_WIDTH, hsync_len);
> +
> + if (mode->flags & DRM_MODE_FLAG_NVSYNC)
> + dp0_syncval |= SYNCVAL_VS_POL_ACTIVE_LOW;
>
> - tc_write(DP0_ACTIVEVAL, (mode->vdisplay << 16) | (mode->hdisplay));
> + if (mode->flags & DRM_MODE_FLAG_NHSYNC)
> + dp0_syncval |= SYNCVAL_HS_POL_ACTIVE_LOW;
>
> - tc_write(DP0_SYNCVAL, (vsync_len << 16) | (hsync_len << 0) |
> - ((mode->flags & DRM_MODE_FLAG_NHSYNC) ? SYNCVAL_HS_POL_ACTIVE_LOW : 0) |
> - ((mode->flags & DRM_MODE_FLAG_NVSYNC) ? SYNCVAL_VS_POL_ACTIVE_LOW : 0));
> + tc_write(DP0_SYNCVAL, dp0_syncval);
>
> - tc_write(DPIPXLFMT, VS_POL_ACTIVE_LOW | HS_POL_ACTIVE_LOW |
> - DE_POL_ACTIVE_HIGH | SUB_CFG_TYPE_CONFIG1 | DPI_BPP_RGB888);
> + tc_write(DPIPXLFMT,
> + VS_POL_ACTIVE_LOW | HS_POL_ACTIVE_LOW |
> + DE_POL_ACTIVE_HIGH | SUB_CFG_TYPE_CONFIG1 |
> + DPI_BPP_RGB888);
>
> - tc_write(DP0_MISC, (max_tu_symbol << 23) | (TU_SIZE_RECOMMENDED << 16) |
> - BPC_8);
> + tc_write(DP0_MISC,
> + FIELD_PREP(MAX_TU_SYMBOL, max_tu_symbol) |
> + FIELD_PREP(TU_SIZE, TU_SIZE_RECOMMENDED) |
> + BPC_8);
>
> return 0;
> err:


2019-06-06 10:36:21

by Andrzej Hajda

[permalink] [raw]
Subject: Re: [PATCH v3 05/15] drm/bridge: tc358767: Drop custom tc_write()/tc_read() accessors

On 05.06.2019 09:04, Andrey Smirnov wrote:
> A very unfortunate aspect of tc_write()/tc_read() macro helpers is
> that they capture quite a bit of context around them and thus require
> the caller to have magic variables 'ret' and 'tc' as well as label
> 'err'. That makes a number of code paths rather counterintuitive and
> somewhat clunky, for example tc_stream_clock_calc() ends up being like
> this:
>
> int ret;
>
> tc_write(DP0_VIDMNGEN1, 32768);
>
> return 0;
> err:
> return ret;
>
> which is rather surprising when you read the code for the first
> time. Since those helpers arguably aren't really saving that much code
> and there's no way of fixing them without making them too verbose to
> be worth it change the driver code to not use them at all.


On the other side, error checking after every registry access is very
annoying and significantly augments the code, makes it redundant and
less readable. To avoid it one can cache error state, and do not perform
real work until the error is clear. For example with following accessor:

void tc_write(struct tc_data *tc, u32 reg, u32 val){

    int ret;

    if (tc->error) //This check is IMPORTANT

        return;

    ret =regmap_write(...);

    if (ret >= 0)

        return;

    tc->error = ret;

    dev_err(tc->dev, "Error writing register %#x\n", reg);

}

You can safely write code like:

    tc_write(tc, DP_PHY_CTRL, BGREN | PWR_SW_EN | PHY_A0_EN);

    tc_write(tc, DP0_PLLCTRL, PLLUPDATE | PLLEN);

    tc_write(tc, DP1_PLLCTRL, PLLUPDATE | PLLEN);

    if (tc->error) {

        tc->error = 0;

        goto err;

    }

This is of course loose suggestion.

Anyway:

Reviewed-by: Andrzej Hajda <[email protected]>

 --
Regards
Andrzej



>
> Signed-off-by: Andrey Smirnov <[email protected]>
> Cc: Archit Taneja <[email protected]>
> Cc: Andrzej Hajda <[email protected]>
> Cc: Laurent Pinchart <[email protected]>
> Cc: Tomi Valkeinen <[email protected]>
> Cc: Andrey Gusakov <[email protected]>
> Cc: Philipp Zabel <[email protected]>
> Cc: Cory Tusar <[email protected]>
> Cc: Chris Healy <[email protected]>
> Cc: Lucas Stach <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> ---
> drivers/gpu/drm/bridge/tc358767.c | 381 ++++++++++++++++++------------
> 1 file changed, 229 insertions(+), 152 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
> index c0fc686ce5ec..e197ce0fb166 100644
> --- a/drivers/gpu/drm/bridge/tc358767.c
> +++ b/drivers/gpu/drm/bridge/tc358767.c
> @@ -280,20 +280,6 @@ static inline struct tc_data *connector_to_tc(struct drm_connector *c)
> return container_of(c, struct tc_data, connector);
> }
>
> -/* Simple macros to avoid repeated error checks */
> -#define tc_write(reg, var) \
> - do { \
> - ret = regmap_write(tc->regmap, reg, var); \
> - if (ret) \
> - goto err; \
> - } while (0)
> -#define tc_read(reg, var) \
> - do { \
> - ret = regmap_read(tc->regmap, reg, var); \
> - if (ret) \
> - goto err; \
> - } while (0)
> -
> static inline int tc_poll_timeout(struct tc_data *tc, unsigned int addr,
> unsigned int cond_mask,
> unsigned int cond_value,
> @@ -351,7 +337,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
>
> ret = tc_aux_wait_busy(tc, 100);
> if (ret)
> - goto err;
> + return ret;
>
> if (request == DP_AUX_I2C_WRITE || request == DP_AUX_NATIVE_WRITE) {
> /* Store data */
> @@ -362,7 +348,11 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
> tmp = (tmp << 8) | buf[i];
> i++;
> if (((i % 4) == 0) || (i == size)) {
> - tc_write(DP0_AUXWDATA((i - 1) >> 2), tmp);
> + ret = regmap_write(tc->regmap,
> + DP0_AUXWDATA((i - 1) >> 2),
> + tmp);
> + if (ret)
> + return ret;
> tmp = 0;
> }
> }
> @@ -372,23 +362,32 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
> }
>
> /* Store address */
> - tc_write(DP0_AUXADDR, msg->address);
> + ret = regmap_write(tc->regmap, DP0_AUXADDR, msg->address);
> + if (ret)
> + return ret;
> /* Start transfer */
> - tc_write(DP0_AUXCFG0, ((size - 1) << 8) | request);
> + ret = regmap_write(tc->regmap, DP0_AUXCFG0,
> + ((size - 1) << 8) | request);
> + if (ret)
> + return ret;
>
> ret = tc_aux_wait_busy(tc, 100);
> if (ret)
> - goto err;
> + return ret;
>
> ret = tc_aux_get_status(tc, &msg->reply);
> if (ret)
> - goto err;
> + return ret;
>
> if (request == DP_AUX_I2C_READ || request == DP_AUX_NATIVE_READ) {
> /* Read data */
> while (i < size) {
> - if ((i % 4) == 0)
> - tc_read(DP0_AUXRDATA(i >> 2), &tmp);
> + if ((i % 4) == 0) {
> + ret = regmap_read(tc->regmap,
> + DP0_AUXRDATA(i >> 2), &tmp);
> + if (ret)
> + return ret;
> + }
> buf[i] = tmp & 0xff;
> tmp = tmp >> 8;
> i++;
> @@ -396,8 +395,6 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
> }
>
> return size;
> -err:
> - return ret;
> }
>
> static const char * const training_pattern1_errors[] = {
> @@ -454,6 +451,7 @@ static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, u32 pixelclock)
> int ext_div[] = {1, 2, 3, 5, 7};
> int best_pixelclock = 0;
> int vco_hi = 0;
> + u32 pxl_pllparam;
>
> dev_dbg(tc->dev, "PLL: requested %d pixelclock, ref %d\n", pixelclock,
> refclk);
> @@ -523,24 +521,29 @@ static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, u32 pixelclock)
> best_mul = 0;
>
> /* Power up PLL and switch to bypass */
> - tc_write(PXL_PLLCTRL, PLLBYP | PLLEN);
> + ret = regmap_write(tc->regmap, PXL_PLLCTRL, PLLBYP | PLLEN);
> + if (ret)
> + return ret;
> +
> + pxl_pllparam = vco_hi << 24; /* For PLL VCO >= 300 MHz = 1 */
> + pxl_pllparam |= ext_div[best_pre] << 20; /* External Pre-divider */
> + pxl_pllparam |= ext_div[best_post] << 16; /* External Post-divider */
> + pxl_pllparam |= IN_SEL_REFCLK; /* Use RefClk as PLL input */
> + pxl_pllparam |= best_div << 8; /* Divider for PLL RefClk */
> + pxl_pllparam |= best_mul; /* Multiplier for PLL */
>
> - tc_write(PXL_PLLPARAM,
> - (vco_hi << 24) | /* For PLL VCO >= 300 MHz = 1 */
> - (ext_div[best_pre] << 20) | /* External Pre-divider */
> - (ext_div[best_post] << 16) | /* External Post-divider */
> - IN_SEL_REFCLK | /* Use RefClk as PLL input */
> - (best_div << 8) | /* Divider for PLL RefClk */
> - (best_mul << 0)); /* Multiplier for PLL */
> + ret = regmap_write(tc->regmap, PXL_PLLPARAM, pxl_pllparam);
> + if (ret)
> + return ret;
>
> /* Force PLL parameter update and disable bypass */
> - tc_write(PXL_PLLCTRL, PLLUPDATE | PLLEN);
> + ret = regmap_write(tc->regmap, PXL_PLLCTRL, PLLUPDATE | PLLEN);
> + if (ret)
> + return ret;
>
> tc_wait_pll_lock(tc);
>
> return 0;
> -err:
> - return ret;
> }
>
> static int tc_pxl_pll_dis(struct tc_data *tc)
> @@ -551,7 +554,6 @@ static int tc_pxl_pll_dis(struct tc_data *tc)
>
> static int tc_stream_clock_calc(struct tc_data *tc)
> {
> - int ret;
> /*
> * If the Stream clock and Link Symbol clock are
> * asynchronous with each other, the value of M changes over
> @@ -567,16 +569,13 @@ static int tc_stream_clock_calc(struct tc_data *tc)
> * M/N = f_STRMCLK / f_LSCLK
> *
> */
> - tc_write(DP0_VIDMNGEN1, 32768);
> -
> - return 0;
> -err:
> - return ret;
> + return regmap_write(tc->regmap, DP0_VIDMNGEN1, 32768);
> }
>
> static int tc_aux_link_setup(struct tc_data *tc)
> {
> unsigned long rate;
> + u32 dp0_auxcfg1;
> u32 value;
> int ret;
>
> @@ -601,18 +600,25 @@ static int tc_aux_link_setup(struct tc_data *tc)
>
> /* Setup DP-PHY / PLL */
> value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
> - tc_write(SYS_PLLPARAM, value);
> -
> - tc_write(DP_PHY_CTRL, BGREN | PWR_SW_EN | PHY_A0_EN);
> + ret = regmap_write(tc->regmap, SYS_PLLPARAM, value);
> + if (ret)
> + goto err;
>
> + ret = regmap_write(tc->regmap, DP_PHY_CTRL, BGREN | PWR_SW_EN | PHY_A0_EN);
> + if (ret)
> + goto err;
> /*
> * Initially PLLs are in bypass. Force PLL parameter update,
> * disable PLL bypass, enable PLL
> */
> - tc_write(DP0_PLLCTRL, PLLUPDATE | PLLEN);
> + ret = regmap_write(tc->regmap, DP0_PLLCTRL, PLLUPDATE | PLLEN);
> + if (ret)
> + goto err;
> tc_wait_pll_lock(tc);
>
> - tc_write(DP1_PLLCTRL, PLLUPDATE | PLLEN);
> + ret = regmap_write(tc->regmap, DP1_PLLCTRL, PLLUPDATE | PLLEN);
> + if (ret)
> + goto err;
> tc_wait_pll_lock(tc);
>
> ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
> @@ -624,9 +630,13 @@ static int tc_aux_link_setup(struct tc_data *tc)
> }
>
> /* Setup AUX link */
> - tc_write(DP0_AUXCFG1, AUX_RX_FILTER_EN |
> - (0x06 << 8) | /* Aux Bit Period Calculator Threshold */
> - (0x3f << 0)); /* Aux Response Timeout Timer */
> + dp0_auxcfg1 = AUX_RX_FILTER_EN;
> + dp0_auxcfg1 |= 0x06 << 8; /* Aux Bit Period Calculator Threshold */
> + dp0_auxcfg1 |= 0x3f << 0; /* Aux Response Timeout Timer */
> +
> + ret = regmap_write(tc->regmap, DP0_AUXCFG1, dp0_auxcfg1);
> + if (ret)
> + goto err;
>
> return 0;
> err:
> @@ -727,48 +737,73 @@ static int tc_set_video_mode(struct tc_data *tc,
> * assume we do not need any delay when DPI is a source of
> * sync signals
> */
> - tc_write(VPCTRL0,
> - FIELD_PREP(VSDELAY, 0) |
> - OPXLFMT_RGB888 | FRMSYNC_DISABLED | MSF_DISABLED);
> - tc_write(HTIM01,
> - FIELD_PREP(HBPR, ALIGN(left_margin, 2)) |
> - FIELD_PREP(HPW, ALIGN(hsync_len, 2)));
> - tc_write(HTIM02,
> - FIELD_PREP(HDISPR, ALIGN(mode->hdisplay, 2)) |
> - FIELD_PREP(HFPR, ALIGN(right_margin, 2)));
> - tc_write(VTIM01,
> - FIELD_PREP(VBPR, upper_margin) |
> - FIELD_PREP(VSPR, vsync_len));
> - tc_write(VTIM02,
> - FIELD_PREP(VFPR, lower_margin) |
> - FIELD_PREP(VDISPR, mode->vdisplay));
> - tc_write(VFUEN0, VFUEN); /* update settings */
> + ret = regmap_write(tc->regmap, VPCTRL0,
> + FIELD_PREP(VSDELAY, 0) |
> + OPXLFMT_RGB888 | FRMSYNC_DISABLED | MSF_DISABLED);
> + if (ret)
> + return ret;
> +
> + ret = regmap_write(tc->regmap, HTIM01,
> + FIELD_PREP(HBPR, ALIGN(left_margin, 2)) |
> + FIELD_PREP(HPW, ALIGN(hsync_len, 2)));
> + if (ret)
> + return ret;
> +
> + ret = regmap_write(tc->regmap, HTIM02,
> + FIELD_PREP(HDISPR, ALIGN(mode->hdisplay, 2)) |
> + FIELD_PREP(HFPR, ALIGN(right_margin, 2)));
> + if (ret)
> + return ret;
> +
> + ret = regmap_write(tc->regmap, VTIM01,
> + FIELD_PREP(VBPR, upper_margin) |
> + FIELD_PREP(VSPR, vsync_len));
> + if (ret)
> + return ret;
> +
> + ret = regmap_write(tc->regmap, VTIM02,
> + FIELD_PREP(VFPR, lower_margin) |
> + FIELD_PREP(VDISPR, mode->vdisplay));
> + if (ret)
> + return ret;
> +
> + ret = regmap_write(tc->regmap, VFUEN0, VFUEN); /* update settings */
> + if (ret)
> + return ret;
>
> /* Test pattern settings */
> - tc_write(TSTCTL,
> - FIELD_PREP(COLOR_R, 120) |
> - FIELD_PREP(COLOR_G, 20) |
> - FIELD_PREP(COLOR_B, 99) |
> - ENI2CFILTER |
> - FIELD_PREP(COLOR_BAR_MODE, COLOR_BAR_MODE_BARS));
> + ret = regmap_write(tc->regmap, TSTCTL,
> + FIELD_PREP(COLOR_R, 120) |
> + FIELD_PREP(COLOR_G, 20) |
> + FIELD_PREP(COLOR_B, 99) |
> + ENI2CFILTER |
> + FIELD_PREP(COLOR_BAR_MODE, COLOR_BAR_MODE_BARS));
> + if (ret)
> + return ret;
>
> /* DP Main Stream Attributes */
> vid_sync_dly = hsync_len + left_margin + mode->hdisplay;
> - tc_write(DP0_VIDSYNCDELAY,
> + ret = regmap_write(tc->regmap, DP0_VIDSYNCDELAY,
> FIELD_PREP(THRESH_DLY, max_tu_symbol) |
> FIELD_PREP(VID_SYNC_DLY, vid_sync_dly));
>
> - tc_write(DP0_TOTALVAL,
> - FIELD_PREP(H_TOTAL, mode->htotal) |
> - FIELD_PREP(V_TOTAL, mode->vtotal));
> + ret = regmap_write(tc->regmap, DP0_TOTALVAL,
> + FIELD_PREP(H_TOTAL, mode->htotal) |
> + FIELD_PREP(V_TOTAL, mode->vtotal));
> + if (ret)
> + return ret;
>
> - tc_write(DP0_STARTVAL,
> - FIELD_PREP(H_START, left_margin + hsync_len) |
> - FIELD_PREP(V_START, upper_margin + vsync_len));
> + ret = regmap_write(tc->regmap, DP0_STARTVAL,
> + FIELD_PREP(H_START, left_margin + hsync_len) |
> + FIELD_PREP(V_START, upper_margin + vsync_len));
> + if (ret)
> + return ret;
>
> - tc_write(DP0_ACTIVEVAL,
> - FIELD_PREP(V_ACT, mode->vdisplay) |
> - FIELD_PREP(H_ACT, mode->hdisplay));
> + ret = regmap_write(tc->regmap, DP0_ACTIVEVAL,
> + FIELD_PREP(V_ACT, mode->vdisplay) |
> + FIELD_PREP(H_ACT, mode->hdisplay));
> + if (ret)
> + return ret;
>
> dp0_syncval = FIELD_PREP(VS_WIDTH, vsync_len) |
> FIELD_PREP(HS_WIDTH, hsync_len);
> @@ -779,21 +814,25 @@ static int tc_set_video_mode(struct tc_data *tc,
> if (mode->flags & DRM_MODE_FLAG_NHSYNC)
> dp0_syncval |= SYNCVAL_HS_POL_ACTIVE_LOW;
>
> - tc_write(DP0_SYNCVAL, dp0_syncval);
> + ret = regmap_write(tc->regmap, DP0_SYNCVAL, dp0_syncval);
> + if (ret)
> + return ret;
>
> - tc_write(DPIPXLFMT,
> - VS_POL_ACTIVE_LOW | HS_POL_ACTIVE_LOW |
> - DE_POL_ACTIVE_HIGH | SUB_CFG_TYPE_CONFIG1 |
> - DPI_BPP_RGB888);
> + ret = regmap_write(tc->regmap, DPIPXLFMT,
> + VS_POL_ACTIVE_LOW | HS_POL_ACTIVE_LOW |
> + DE_POL_ACTIVE_HIGH | SUB_CFG_TYPE_CONFIG1 |
> + DPI_BPP_RGB888);
> + if (ret)
> + return ret;
>
> - tc_write(DP0_MISC,
> - FIELD_PREP(MAX_TU_SYMBOL, max_tu_symbol) |
> - FIELD_PREP(TU_SIZE, TU_SIZE_RECOMMENDED) |
> - BPC_8);
> + ret = regmap_write(tc->regmap, DP0_MISC,
> + FIELD_PREP(MAX_TU_SYMBOL, max_tu_symbol) |
> + FIELD_PREP(TU_SIZE, TU_SIZE_RECOMMENDED) |
> + BPC_8);
> + if (ret)
> + return ret;
>
> return 0;
> -err:
> - return ret;
> }
>
> static int tc_wait_link_training(struct tc_data *tc)
> @@ -808,11 +847,11 @@ static int tc_wait_link_training(struct tc_data *tc)
> return ret;
> }
>
> - tc_read(DP0_LTSTAT, &value);
> + ret = regmap_read(tc->regmap, DP0_LTSTAT, &value);
> + if (ret)
> + return ret;
>
> return (value >> 8) & 0x7;
> -err:
> - return ret;
> }
>
> static int tc_main_link_enable(struct tc_data *tc)
> @@ -827,15 +866,25 @@ static int tc_main_link_enable(struct tc_data *tc)
>
> dev_dbg(tc->dev, "link enable\n");
>
> - tc_read(DP0CTL, &value);
> - if (WARN_ON(value & DP_EN))
> - tc_write(DP0CTL, 0);
> + ret = regmap_read(tc->regmap, DP0CTL, &value);
> + if (ret)
> + return ret;
> +
> + if (WARN_ON(value & DP_EN)) {
> + ret = regmap_write(tc->regmap, DP0CTL, 0);
> + if (ret)
> + return ret;
> + }
>
> - tc_write(DP0_SRCCTRL, tc_srcctrl(tc));
> + ret = regmap_write(tc->regmap, DP0_SRCCTRL, tc_srcctrl(tc));
> + if (ret)
> + return ret;
> /* SSCG and BW27 on DP1 must be set to the same as on DP0 */
> - tc_write(DP1_SRCCTRL,
> + ret = regmap_write(tc->regmap, DP1_SRCCTRL,
> (tc->link.spread ? DP0_SRCCTRL_SSCG : 0) |
> ((tc->link.base.rate != 162000) ? DP0_SRCCTRL_BW27 : 0));
> + if (ret)
> + return ret;
>
> rate = clk_get_rate(tc->refclk);
> switch (rate) {
> @@ -855,27 +904,36 @@ static int tc_main_link_enable(struct tc_data *tc)
> return -EINVAL;
> }
> value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
> - tc_write(SYS_PLLPARAM, value);
> + ret = regmap_write(tc->regmap, SYS_PLLPARAM, value);
> + if (ret)
> + return ret;
>
> /* Setup Main Link */
> dp_phy_ctrl = BGREN | PWR_SW_EN | PHY_A0_EN | PHY_M0_EN;
> if (tc->link.base.num_lanes == 2)
> dp_phy_ctrl |= PHY_2LANE;
> - tc_write(DP_PHY_CTRL, dp_phy_ctrl);
> +
> + ret = regmap_write(tc->regmap, DP_PHY_CTRL, dp_phy_ctrl);
> + if (ret)
> + return ret;
>
> /* PLL setup */
> - tc_write(DP0_PLLCTRL, PLLUPDATE | PLLEN);
> + ret = regmap_write(tc->regmap, DP0_PLLCTRL, PLLUPDATE | PLLEN);
> + if (ret)
> + return ret;
> tc_wait_pll_lock(tc);
>
> - tc_write(DP1_PLLCTRL, PLLUPDATE | PLLEN);
> + ret = regmap_write(tc->regmap, DP1_PLLCTRL, PLLUPDATE | PLLEN);
> + if (ret)
> + return ret;
> tc_wait_pll_lock(tc);
>
> /* Reset/Enable Main Links */
> dp_phy_ctrl |= DP_PHY_RST | PHY_M1_RST | PHY_M0_RST;
> - tc_write(DP_PHY_CTRL, dp_phy_ctrl);
> + ret = regmap_write(tc->regmap, DP_PHY_CTRL, dp_phy_ctrl);
> usleep_range(100, 200);
> dp_phy_ctrl &= ~(DP_PHY_RST | PHY_M1_RST | PHY_M0_RST);
> - tc_write(DP_PHY_CTRL, dp_phy_ctrl);
> + ret = regmap_write(tc->regmap, DP_PHY_CTRL, dp_phy_ctrl);
>
> ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
> if (ret) {
> @@ -887,7 +945,7 @@ static int tc_main_link_enable(struct tc_data *tc)
> /* Set misc: 8 bits per color */
> ret = regmap_update_bits(tc->regmap, DP0_MISC, BPC_8, BPC_8);
> if (ret)
> - goto err;
> + return ret;
>
> /*
> * ASSR mode
> @@ -940,53 +998,71 @@ static int tc_main_link_enable(struct tc_data *tc)
> /* Clock-Recovery */
>
> /* Set DPCD 0x102 for Training Pattern 1 */
> - tc_write(DP0_SNKLTCTRL, DP_LINK_SCRAMBLING_DISABLE |
> - DP_TRAINING_PATTERN_1);
> + ret = regmap_write(tc->regmap, DP0_SNKLTCTRL,
> + DP_LINK_SCRAMBLING_DISABLE |
> + DP_TRAINING_PATTERN_1);
> + if (ret)
> + return ret;
>
> - tc_write(DP0_LTLOOPCTRL,
> - (15 << 28) | /* Defer Iteration Count */
> - (15 << 24) | /* Loop Iteration Count */
> - (0xd << 0)); /* Loop Timer Delay */
> + ret = regmap_write(tc->regmap, DP0_LTLOOPCTRL,
> + (15 << 28) | /* Defer Iteration Count */
> + (15 << 24) | /* Loop Iteration Count */
> + (0xd << 0)); /* Loop Timer Delay */
> + if (ret)
> + return ret;
>
> - tc_write(DP0_SRCCTRL, tc_srcctrl(tc) | DP0_SRCCTRL_SCRMBLDIS |
> - DP0_SRCCTRL_AUTOCORRECT | DP0_SRCCTRL_TP1);
> + ret = regmap_write(tc->regmap, DP0_SRCCTRL,
> + tc_srcctrl(tc) | DP0_SRCCTRL_SCRMBLDIS |
> + DP0_SRCCTRL_AUTOCORRECT |
> + DP0_SRCCTRL_TP1);
> + if (ret)
> + return ret;
>
> /* Enable DP0 to start Link Training */
> - tc_write(DP0CTL,
> - ((tc->link.base.capabilities & DP_LINK_CAP_ENHANCED_FRAMING) ? EF_EN : 0) |
> - DP_EN);
> + ret = regmap_write(tc->regmap, DP0CTL,
> + ((tc->link.base.capabilities &
> + DP_LINK_CAP_ENHANCED_FRAMING) ? EF_EN : 0) |
> + DP_EN);
> + if (ret)
> + return ret;
>
> /* wait */
> +
> ret = tc_wait_link_training(tc);
> if (ret < 0)
> - goto err;
> + return ret;
>
> if (ret) {
> dev_err(tc->dev, "Link training phase 1 failed: %s\n",
> training_pattern1_errors[ret]);
> - ret = -ENODEV;
> - goto err;
> + return -ENODEV;
> }
>
> /* Channel Equalization */
>
> /* Set DPCD 0x102 for Training Pattern 2 */
> - tc_write(DP0_SNKLTCTRL, DP_LINK_SCRAMBLING_DISABLE |
> - DP_TRAINING_PATTERN_2);
> + ret = regmap_write(tc->regmap, DP0_SNKLTCTRL,
> + DP_LINK_SCRAMBLING_DISABLE |
> + DP_TRAINING_PATTERN_2);
> + if (ret)
> + return ret;
>
> - tc_write(DP0_SRCCTRL, tc_srcctrl(tc) | DP0_SRCCTRL_SCRMBLDIS |
> - DP0_SRCCTRL_AUTOCORRECT | DP0_SRCCTRL_TP2);
> + ret = regmap_write(tc->regmap, DP0_SRCCTRL,
> + tc_srcctrl(tc) | DP0_SRCCTRL_SCRMBLDIS |
> + DP0_SRCCTRL_AUTOCORRECT |
> + DP0_SRCCTRL_TP2);
> + if (ret)
> + return ret;
>
> /* wait */
> ret = tc_wait_link_training(tc);
> if (ret < 0)
> - goto err;
> + return ret;
>
> if (ret) {
> dev_err(tc->dev, "Link training phase 2 failed: %s\n",
> training_pattern2_errors[ret]);
> - ret = -ENODEV;
> - goto err;
> + return -ENODEV;
> }
>
> /*
> @@ -999,7 +1075,10 @@ static int tc_main_link_enable(struct tc_data *tc)
> */
>
> /* Clear Training Pattern, set AutoCorrect Mode = 1 */
> - tc_write(DP0_SRCCTRL, tc_srcctrl(tc) | DP0_SRCCTRL_AUTOCORRECT);
> + ret = regmap_write(tc->regmap, DP0_SRCCTRL, tc_srcctrl(tc) |
> + DP0_SRCCTRL_AUTOCORRECT);
> + if (ret)
> + return ret;
>
> /* Clear DPCD 0x102 */
> /* Note: Can Not use DP0_SNKLTCTRL (0x06E4) short cut */
> @@ -1043,7 +1122,7 @@ static int tc_main_link_enable(struct tc_data *tc)
> dev_err(dev, "0x0205 SINK_STATUS: 0x%02x\n", tmp[3]);
> dev_err(dev, "0x0206 ADJUST_REQUEST_LANE0_1: 0x%02x\n", tmp[4]);
> dev_err(dev, "0x0207 ADJUST_REQUEST_LANE2_3: 0x%02x\n", tmp[5]);
> - goto err;
> + return ret;
> }
>
> return 0;
> @@ -1052,7 +1131,6 @@ static int tc_main_link_enable(struct tc_data *tc)
> return ret;
> err_dpcd_write:
> dev_err(tc->dev, "Failed to write DPCD: %d\n", ret);
> -err:
> return ret;
> }
>
> @@ -1062,12 +1140,11 @@ static int tc_main_link_disable(struct tc_data *tc)
>
> dev_dbg(tc->dev, "link disable\n");
>
> - tc_write(DP0_SRCCTRL, 0);
> - tc_write(DP0CTL, 0);
> + ret = regmap_write(tc->regmap, DP0_SRCCTRL, 0);
> + if (ret)
> + return ret;
>
> - return 0;
> -err:
> - return ret;
> + return regmap_write(tc->regmap, DP0CTL, 0);
> }
>
> static int tc_stream_enable(struct tc_data *tc)
> @@ -1082,7 +1159,7 @@ static int tc_stream_enable(struct tc_data *tc)
> ret = tc_pxl_pll_en(tc, clk_get_rate(tc->refclk),
> 1000 * tc->mode.clock);
> if (ret)
> - goto err;
> + return ret;
> }
>
> ret = tc_set_video_mode(tc, &tc->mode);
> @@ -1097,7 +1174,9 @@ static int tc_stream_enable(struct tc_data *tc)
> value = VID_MN_GEN | DP_EN;
> if (tc->link.base.capabilities & DP_LINK_CAP_ENHANCED_FRAMING)
> value |= EF_EN;
> - tc_write(DP0CTL, value);
> + ret = regmap_write(tc->regmap, DP0CTL, value);
> + if (ret)
> + return ret;
> /*
> * VID_EN assertion should be delayed by at least N * LSCLK
> * cycles from the time VID_MN_GEN is enabled in order to
> @@ -1107,36 +1186,35 @@ static int tc_stream_enable(struct tc_data *tc)
> */
> usleep_range(500, 1000);
> value |= VID_EN;
> - tc_write(DP0CTL, value);
> + ret = regmap_write(tc->regmap, DP0CTL, value);
> + if (ret)
> + return ret;
> /* Set input interface */
> value = DP0_AUDSRC_NO_INPUT;
> if (tc_test_pattern)
> value |= DP0_VIDSRC_COLOR_BAR;
> else
> value |= DP0_VIDSRC_DPI_RX;
> - tc_write(SYSCTRL, value);
> + ret = regmap_write(tc->regmap, SYSCTRL, value);
> + if (ret)
> + return ret;
>
> return 0;
> -err:
> - return ret;
> }
>
> static int tc_stream_disable(struct tc_data *tc)
> {
> int ret;
> - u32 val;
>
> dev_dbg(tc->dev, "disable video stream\n");
>
> - tc_read(DP0CTL, &val);
> - val &= ~VID_EN;
> - tc_write(DP0CTL, val);
> + ret = regmap_update_bits(tc->regmap, DP0CTL, VID_EN, 0);
> + if (ret)
> + return ret;
>
> tc_pxl_pll_dis(tc);
>
> return 0;
> -err:
> - return ret;
> }
>
> static void tc_bridge_pre_enable(struct drm_bridge *bridge)
> @@ -1328,7 +1406,9 @@ static enum drm_connector_status tc_connector_detect(struct drm_connector *conne
> return connector_status_unknown;
> }
>
> - tc_read(GPIOI, &val);
> + ret = regmap_read(tc->regmap, GPIOI, &val);
> + if (ret)
> + return connector_status_unknown;
>
> conn = val & BIT(tc->hpd_pin);
>
> @@ -1336,9 +1416,6 @@ static enum drm_connector_status tc_connector_detect(struct drm_connector *conne
> return connector_status_connected;
> else
> return connector_status_disconnected;
> -
> -err:
> - return connector_status_unknown;
> }
>
> static const struct drm_connector_funcs tc_connector_funcs = {


2019-06-06 11:01:34

by Andrzej Hajda

[permalink] [raw]
Subject: Re: [PATCH v3 06/15] drm/bridge: tc358767: Simplify AUX data read

On 05.06.2019 09:04, Andrey Smirnov wrote:
> Simplify AUX data read by removing index arithmetic and shifting with
> a helper functions that does three things:
>
> 1. Fetch data from up to 4 32-bit registers from the chip
> 2. Optionally fix data endianness (not needed on LE hosts)
> 3. Copy read data into user provided array.
>
> Signed-off-by: Andrey Smirnov <[email protected]>
> Cc: Archit Taneja <[email protected]>
> Cc: Andrzej Hajda <[email protected]>
> Cc: Laurent Pinchart <[email protected]>
> Cc: Tomi Valkeinen <[email protected]>
> Cc: Andrey Gusakov <[email protected]>
> Cc: Philipp Zabel <[email protected]>
> Cc: Cory Tusar <[email protected]>
> Cc: Chris Healy <[email protected]>
> Cc: Lucas Stach <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> ---
> drivers/gpu/drm/bridge/tc358767.c | 40 +++++++++++++++++++++----------
> 1 file changed, 27 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
> index e197ce0fb166..da47d81e7109 100644
> --- a/drivers/gpu/drm/bridge/tc358767.c
> +++ b/drivers/gpu/drm/bridge/tc358767.c
> @@ -321,6 +321,29 @@ static int tc_aux_get_status(struct tc_data *tc, u8 *reply)
> return 0;
> }
>
> +static int tc_aux_read_data(struct tc_data *tc, void *data, size_t size)
> +{
> + u32 auxrdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)];
> + int ret, i, count = DIV_ROUND_UP(size, sizeof(u32));
> +
> + ret = regmap_bulk_read(tc->regmap, DP0_AUXRDATA(0), auxrdata, count);
> + if (ret)
> + return ret;
> +
> + for (i = 0; i < count; i++) {
> + /*
> + * Our regmap is configured as LE for register data,
> + * so we need undo any byte swapping that might have
> + * happened to preserve original byte order.
> + */
> + le32_to_cpus(&auxrdata[i]);
> + }
> +
> + memcpy(data, auxrdata, size);
> +
> + return size;
> +}
> +


Hmm, cannot we just use regmap_raw_read?

Beside this:

Reviewed-by: Andrzej Hajda <[email protected]>

 --
Regards
Andrzej



> static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
> struct drm_dp_aux_msg *msg)
> {
> @@ -379,19 +402,10 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
> if (ret)
> return ret;
>
> - if (request == DP_AUX_I2C_READ || request == DP_AUX_NATIVE_READ) {
> - /* Read data */
> - while (i < size) {
> - if ((i % 4) == 0) {
> - ret = regmap_read(tc->regmap,
> - DP0_AUXRDATA(i >> 2), &tmp);
> - if (ret)
> - return ret;
> - }
> - buf[i] = tmp & 0xff;
> - tmp = tmp >> 8;
> - i++;
> - }
> + switch (request) {
> + case DP_AUX_NATIVE_READ:
> + case DP_AUX_I2C_READ:
> + return tc_aux_read_data(tc, msg->buffer, size);
> }
>
> return size;


2019-06-06 11:22:06

by Andrzej Hajda

[permalink] [raw]
Subject: Re: [PATCH v3 03/15] drm/bridge: tc358767: Simplify polling in tc_link_training()

On 05.06.2019 09:04, Andrey Smirnov wrote:
> Replace explicit polling in tc_link_training() with equivalent call to
> tc_poll_timeout() for simplicity. No functional change intended (not
> including slightly altered debug output).
>
> Signed-off-by: Andrey Smirnov <[email protected]>
> Cc: Archit Taneja <[email protected]>
> Cc: Andrzej Hajda <[email protected]>
> Cc: Laurent Pinchart <[email protected]>
> Cc: Tomi Valkeinen <[email protected]>
> Cc: Andrey Gusakov <[email protected]>
> Cc: Philipp Zabel <[email protected]>
> Cc: Cory Tusar <[email protected]>
> Cc: Chris Healy <[email protected]>
> Cc: Lucas Stach <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> ---
> drivers/gpu/drm/bridge/tc358767.c | 15 ++++++---------
> 1 file changed, 6 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
> index 5e1e73a91696..115cffc55a96 100644
> --- a/drivers/gpu/drm/bridge/tc358767.c
> +++ b/drivers/gpu/drm/bridge/tc358767.c
> @@ -748,22 +748,19 @@ static int tc_set_video_mode(struct tc_data *tc,
>
> static int tc_wait_link_training(struct tc_data *tc)
> {
> - u32 timeout = 1000;
> u32 value;
> int ret;
>
> - do {
> - udelay(1);
> - tc_read(DP0_LTSTAT, &value);
> - } while ((!(value & LT_LOOPDONE)) && (--timeout));
> -
> - if (timeout == 0) {
> + ret = tc_poll_timeout(tc, DP0_LTSTAT, LT_LOOPDONE,
> + LT_LOOPDONE, 1, 1000);
> + if (ret) {
> dev_err(tc->dev, "Link training timeout waiting for LT_LOOPDONE!\n");
> - return -ETIMEDOUT;
> + return ret;
> }


Inconsistent coding, in previous patch you check (ret == -ETIMEDOUT) but
not here. To simplify the code you can assume that tc_poll_timeout < 0,
means timeout, in such case please adjust previous patch.


Beside this:

Reviewed-by: Andrzej Hajda <[email protected]>

 --
Regards
Andrzej


>
> - return (value >> 8) & 0x7;
> + tc_read(DP0_LTSTAT, &value);
>
> + return (value >> 8) & 0x7;
> err:
> return ret;
> }


2019-06-06 12:16:53

by Andrzej Hajda

[permalink] [raw]
Subject: Re: [PATCH v3 07/15] drm/bridge: tc358767: Simplify AUX data write

On 05.06.2019 09:04, Andrey Smirnov wrote:
> Simplify AUX data write by dropping index arithmetic and shifting and
> replacing it with a call to a helper function that does three things:
>
> 1. Copies user-provided data into a write buffer
> 2. Optionally fixes the endianness of the write buffer (not needed
> on LE hosts)
> 3. Transfers contenst of the write buffer to up to 4 32-bit
> registers on the chip
>
> Note that separate data endianness fix:
>
> tmp = (tmp << 8) | buf[i];
>
> that was reserved for DP_AUX_I2C_WRITE looks really strange, since it
> will place data differently depending on the passed user-data
> size. E.g. for a write of 1 byte, data transferred to the chip would
> look like:
>
> [byte0] [dummy1] [dummy2] [dummy3]
>
> whereas for a write of 4 bytes we'd get:
>
> [byte3] [byte2] [byte1] [byte0]
>
> Since there's no indication in the datasheet that I2C write buffer
> should be treated differently than AUX write buffer and no comment in
> the original code explaining why it was done this way, that special
> I2C write buffer transformation was dropped in this patch.
>
> Signed-off-by: Andrey Smirnov <[email protected]>
> Cc: Archit Taneja <[email protected]>
> Cc: Andrzej Hajda <[email protected]>
> Cc: Laurent Pinchart <[email protected]>
> Cc: Tomi Valkeinen <[email protected]>
> Cc: Andrey Gusakov <[email protected]>
> Cc: Philipp Zabel <[email protected]>
> Cc: Cory Tusar <[email protected]>
> Cc: Chris Healy <[email protected]>
> Cc: Lucas Stach <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> ---
> drivers/gpu/drm/bridge/tc358767.c | 59 +++++++++++++++++++------------
> 1 file changed, 37 insertions(+), 22 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
> index da47d81e7109..260fbcd0271e 100644
> --- a/drivers/gpu/drm/bridge/tc358767.c
> +++ b/drivers/gpu/drm/bridge/tc358767.c
> @@ -321,6 +321,32 @@ static int tc_aux_get_status(struct tc_data *tc, u8 *reply)
> return 0;
> }
>
> +static int tc_aux_write_data(struct tc_data *tc, const void *data,
> + size_t size)
> +{
> + u32 auxwdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)] = { 0 };
> + int ret, i, count = DIV_ROUND_UP(size, sizeof(u32));
> +
> + memcpy(auxwdata, data, size);
> +
> + for (i = 0; i < count; i++) {
> + /*
> + * Our regmap is configured as LE
> + * for register data, so we need
> + * undo any byte swapping that will
> + * happened to preserve original
> + * byte order.
> + */
> + cpu_to_le32s(&auxwdata[i]);
> + }
> +
> + ret = regmap_bulk_write(tc->regmap, DP0_AUXWDATA(0), auxwdata, count);
> + if (ret)
> + return ret;
> +
> + return size;
> +}


As prevoiusly maybe regmap_raw_write.

Beside this:

Reviewed-by: Andrzej Hajda <[email protected]>

 --
Regards
Andrzej


> +
> static int tc_aux_read_data(struct tc_data *tc, void *data, size_t size)
> {
> u32 auxrdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)];
> @@ -350,9 +376,6 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
> struct tc_data *tc = aux_to_tc(aux);
> size_t size = min_t(size_t, 8, msg->size);
> u8 request = msg->request & ~DP_AUX_I2C_MOT;
> - u8 *buf = msg->buffer;
> - u32 tmp = 0;
> - int i = 0;
> int ret;
>
> if (size == 0)
> @@ -362,25 +385,17 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
> if (ret)
> return ret;
>
> - if (request == DP_AUX_I2C_WRITE || request == DP_AUX_NATIVE_WRITE) {
> - /* Store data */
> - while (i < size) {
> - if (request == DP_AUX_NATIVE_WRITE)
> - tmp = tmp | (buf[i] << (8 * (i & 0x3)));
> - else
> - tmp = (tmp << 8) | buf[i];
> - i++;
> - if (((i % 4) == 0) || (i == size)) {
> - ret = regmap_write(tc->regmap,
> - DP0_AUXWDATA((i - 1) >> 2),
> - tmp);
> - if (ret)
> - return ret;
> - tmp = 0;
> - }
> - }
> - } else if (request != DP_AUX_I2C_READ &&
> - request != DP_AUX_NATIVE_READ) {
> + switch (request) {
> + case DP_AUX_NATIVE_READ:
> + case DP_AUX_I2C_READ:
> + break;
> + case DP_AUX_NATIVE_WRITE:
> + case DP_AUX_I2C_WRITE:
> + ret = tc_aux_write_data(tc, msg->buffer, size);
> + if (ret < 0)
> + return ret;
> + break;
> + default:
> return -EINVAL;
> }
>


2019-06-06 16:32:32

by Andrzej Hajda

[permalink] [raw]
Subject: Re: [PATCH v3 08/15] drm/bridge: tc358767: Increase AUX transfer length limit

On 05.06.2019 09:05, Andrey Smirnov wrote:
> According to the datasheet tc358767 can transfer up to 16 bytes via
> its AUX channel, so the artificial limit of 8 apperas to be too
> low. However only up to 15-bytes seem to be actually supported and
> trying to use 16-byte transfers results in transfers failing
> sporadically (with bogus status in case of I2C transfers), so limit it
> to 15.
>
> Signed-off-by: Andrey Smirnov <[email protected]>
> Cc: Archit Taneja <[email protected]>


Please remove Archit's mail (from all patches), it is no longer valid.


Reviewed-by: Andrzej Hajda <[email protected]>

 --
Regards
Andrzej


> Cc: Andrzej Hajda <[email protected]>
> Cc: Laurent Pinchart <[email protected]>
> Cc: Tomi Valkeinen <[email protected]>
> Cc: Andrey Gusakov <[email protected]>
> Cc: Philipp Zabel <[email protected]>
> Cc: Cory Tusar <[email protected]>
> Cc: Chris Healy <[email protected]>
> Cc: Lucas Stach <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> ---
> drivers/gpu/drm/bridge/tc358767.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
> index 260fbcd0271e..0125e2f7e076 100644
> --- a/drivers/gpu/drm/bridge/tc358767.c
> +++ b/drivers/gpu/drm/bridge/tc358767.c
> @@ -374,7 +374,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
> struct drm_dp_aux_msg *msg)
> {
> struct tc_data *tc = aux_to_tc(aux);
> - size_t size = min_t(size_t, 8, msg->size);
> + size_t size = min_t(size_t, DP_AUX_MAX_PAYLOAD_BYTES - 1, msg->size);
> u8 request = msg->request & ~DP_AUX_I2C_MOT;
> int ret;
>


2019-06-06 20:18:32

by Andrey Smirnov

[permalink] [raw]
Subject: Re: [PATCH v3 03/15] drm/bridge: tc358767: Simplify polling in tc_link_training()

On Thu, Jun 6, 2019 at 1:08 AM Andrzej Hajda <[email protected]> wrote:
>
> On 05.06.2019 09:04, Andrey Smirnov wrote:
> > Replace explicit polling in tc_link_training() with equivalent call to
> > tc_poll_timeout() for simplicity. No functional change intended (not
> > including slightly altered debug output).
> >
> > Signed-off-by: Andrey Smirnov <[email protected]>
> > Cc: Archit Taneja <[email protected]>
> > Cc: Andrzej Hajda <[email protected]>
> > Cc: Laurent Pinchart <[email protected]>
> > Cc: Tomi Valkeinen <[email protected]>
> > Cc: Andrey Gusakov <[email protected]>
> > Cc: Philipp Zabel <[email protected]>
> > Cc: Cory Tusar <[email protected]>
> > Cc: Chris Healy <[email protected]>
> > Cc: Lucas Stach <[email protected]>
> > Cc: [email protected]
> > Cc: [email protected]
> > ---
> > drivers/gpu/drm/bridge/tc358767.c | 15 ++++++---------
> > 1 file changed, 6 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
> > index 5e1e73a91696..115cffc55a96 100644
> > --- a/drivers/gpu/drm/bridge/tc358767.c
> > +++ b/drivers/gpu/drm/bridge/tc358767.c
> > @@ -748,22 +748,19 @@ static int tc_set_video_mode(struct tc_data *tc,
> >
> > static int tc_wait_link_training(struct tc_data *tc)
> > {
> > - u32 timeout = 1000;
> > u32 value;
> > int ret;
> >
> > - do {
> > - udelay(1);
> > - tc_read(DP0_LTSTAT, &value);
> > - } while ((!(value & LT_LOOPDONE)) && (--timeout));
> > -
> > - if (timeout == 0) {
> > + ret = tc_poll_timeout(tc, DP0_LTSTAT, LT_LOOPDONE,
> > + LT_LOOPDONE, 1, 1000);
> > + if (ret) {
> > dev_err(tc->dev, "Link training timeout waiting for LT_LOOPDONE!\n");
> > - return -ETIMEDOUT;
> > + return ret;
> > }
>
>
> Inconsistent coding, in previous patch you check (ret == -ETIMEDOUT) but
> not here. To simplify the code you can assume that tc_poll_timeout < 0,
> means timeout, in such case please adjust previous patch.
>

Sure, will do.

Thanks,
Andrey Smirnov

2019-06-06 20:19:25

by Andrey Smirnov

[permalink] [raw]
Subject: Re: [PATCH v3 05/15] drm/bridge: tc358767: Drop custom tc_write()/tc_read() accessors

On Thu, Jun 6, 2019 at 3:34 AM Andrzej Hajda <[email protected]> wrote:
>
> On 05.06.2019 09:04, Andrey Smirnov wrote:
> > A very unfortunate aspect of tc_write()/tc_read() macro helpers is
> > that they capture quite a bit of context around them and thus require
> > the caller to have magic variables 'ret' and 'tc' as well as label
> > 'err'. That makes a number of code paths rather counterintuitive and
> > somewhat clunky, for example tc_stream_clock_calc() ends up being like
> > this:
> >
> > int ret;
> >
> > tc_write(DP0_VIDMNGEN1, 32768);
> >
> > return 0;
> > err:
> > return ret;
> >
> > which is rather surprising when you read the code for the first
> > time. Since those helpers arguably aren't really saving that much code
> > and there's no way of fixing them without making them too verbose to
> > be worth it change the driver code to not use them at all.
>
>
> On the other side, error checking after every registry access is very
> annoying and significantly augments the code, makes it redundant and
> less readable. To avoid it one can cache error state, and do not perform
> real work until the error is clear. For example with following accessor:
>
> void tc_write(struct tc_data *tc, u32 reg, u32 val){
>
> int ret;
>
> if (tc->error) //This check is IMPORTANT
>
> return;
>
> ret =regmap_write(...);
>
> if (ret >= 0)
>
> return;
>
> tc->error = ret;
>
> dev_err(tc->dev, "Error writing register %#x\n", reg);
>
> }
>
> You can safely write code like:
>
> tc_write(tc, DP_PHY_CTRL, BGREN | PWR_SW_EN | PHY_A0_EN);
>
> tc_write(tc, DP0_PLLCTRL, PLLUPDATE | PLLEN);
>
> tc_write(tc, DP1_PLLCTRL, PLLUPDATE | PLLEN);
>
> if (tc->error) {
>
> tc->error = 0;
>
> goto err;
>
> }
>
> This is of course loose suggestion.
>

I am going to have to disagree with you on this one, unfortunately.
Using regmap API explicitly definitely makes code more verbose, less
readable or more annoying though? Not really from my perspective. With
regmap code I know what the code is doing the moment I look at it,
with the example above, not so much. I also find it annoying that I
now have to remember the tricks that tc_write is pulling internally as
well as be mindful of a global-ish error state object. My problem with
original code was that a) it traded explicitness for conciseness in a
an unfavorable way, which I still think is true for code above b) it
didn't provide a comprehensive abstraction completely removing regmap
API and still relied on things like regmap_update_bits() explicitly,
making the code even more confusing (true for above example as well).
I think this driver isn't big enough to have a dedicated person always
working on it and it will mostly see occasional commits from somewhat
random folks who are coming to the codebase fresh, so creating as
little "institutional knowledge", so to speak, in a form of a custom
exception-like mechanism and opting for explicit but verbose code
seems like a preferable choice.

Anyway, I get it that's it is a loose suggestion :-), just wanted to
provide a detailed explanation why I'd rather not go that way.

Thanks,
Andrey Smirnov

2019-06-06 21:56:36

by Andrey Smirnov

[permalink] [raw]
Subject: Re: [PATCH v3 06/15] drm/bridge: tc358767: Simplify AUX data read

On Thu, Jun 6, 2019 at 3:59 AM Andrzej Hajda <[email protected]> wrote:
>
> On 05.06.2019 09:04, Andrey Smirnov wrote:
> > Simplify AUX data read by removing index arithmetic and shifting with
> > a helper functions that does three things:
> >
> > 1. Fetch data from up to 4 32-bit registers from the chip
> > 2. Optionally fix data endianness (not needed on LE hosts)
> > 3. Copy read data into user provided array.
> >
> > Signed-off-by: Andrey Smirnov <[email protected]>
> > Cc: Archit Taneja <[email protected]>
> > Cc: Andrzej Hajda <[email protected]>
> > Cc: Laurent Pinchart <[email protected]>
> > Cc: Tomi Valkeinen <[email protected]>
> > Cc: Andrey Gusakov <[email protected]>
> > Cc: Philipp Zabel <[email protected]>
> > Cc: Cory Tusar <[email protected]>
> > Cc: Chris Healy <[email protected]>
> > Cc: Lucas Stach <[email protected]>
> > Cc: [email protected]
> > Cc: [email protected]
> > ---
> > drivers/gpu/drm/bridge/tc358767.c | 40 +++++++++++++++++++++----------
> > 1 file changed, 27 insertions(+), 13 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
> > index e197ce0fb166..da47d81e7109 100644
> > --- a/drivers/gpu/drm/bridge/tc358767.c
> > +++ b/drivers/gpu/drm/bridge/tc358767.c
> > @@ -321,6 +321,29 @@ static int tc_aux_get_status(struct tc_data *tc, u8 *reply)
> > return 0;
> > }
> >
> > +static int tc_aux_read_data(struct tc_data *tc, void *data, size_t size)
> > +{
> > + u32 auxrdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)];
> > + int ret, i, count = DIV_ROUND_UP(size, sizeof(u32));
> > +
> > + ret = regmap_bulk_read(tc->regmap, DP0_AUXRDATA(0), auxrdata, count);
> > + if (ret)
> > + return ret;
> > +
> > + for (i = 0; i < count; i++) {
> > + /*
> > + * Our regmap is configured as LE for register data,
> > + * so we need undo any byte swapping that might have
> > + * happened to preserve original byte order.
> > + */
> > + le32_to_cpus(&auxrdata[i]);
> > + }
> > +
> > + memcpy(data, auxrdata, size);
> > +
> > + return size;
> > +}
> > +
>
>
> Hmm, cannot we just use regmap_raw_read?

I'll give it a try in v4.

Thanks,
Andrey Smirnov