diff mbox series

[2/4] drm/bridge: tc358767: Move hardware init to enable callback

Message ID 20211127032405.283435-2-marex@denx.de (mailing list archive)
State New, archived
Headers show
Series [1/4] dt-bindings: display: bridge: tc358867: Document DPI output support | expand

Commit Message

Marek Vasut Nov. 27, 2021, 3:24 a.m. UTC
The TC358767/TC358867/TC9595 are all capable of operating either from
attached Xtal or from DSI clock lane clock. In case the later is used,
all I2C accesses will fail until the DSI clock lane is running and
supplying clock to the chip.

Move all hardware initialization to enable callback to guarantee the
DSI clock lane is running before accessing the hardware. In case Xtal
is attached to the chip, this change has no effect.

Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Andrzej Hajda <a.hajda@samsung.com>
Cc: Jernej Skrabec <jernej.skrabec@siol.net>
Cc: Jonas Karlman <jonas@kwiboo.se>
Cc: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
Cc: Neil Armstrong <narmstrong@baylibre.com>
Cc: Sam Ravnborg <sam@ravnborg.org>
---
 drivers/gpu/drm/bridge/tc358767.c | 111 +++++++++++++++++-------------
 1 file changed, 63 insertions(+), 48 deletions(-)

Comments

Dave Stevenson Dec. 6, 2021, 6:01 p.m. UTC | #1
Hi Marek

On Sat, 27 Nov 2021 at 03:24, Marek Vasut <marex@denx.de> wrote:
>
> The TC358767/TC358867/TC9595 are all capable of operating either from
> attached Xtal or from DSI clock lane clock. In case the later is used,
> all I2C accesses will fail until the DSI clock lane is running and
> supplying clock to the chip.
>
> Move all hardware initialization to enable callback to guarantee the
> DSI clock lane is running before accessing the hardware. In case Xtal
> is attached to the chip, this change has no effect.

This puzzles me as there seem to be a couple of ambiguities over how
it would be used.

Firstly the DT binding lists the clock as a required property, but
there isn't one present if deriving the clock from the DSI clock lane.

Secondly the datasheet states that the DSI Reference Clock Source
Division Selection is done by the MODE1 pin, and switches between
HSCKBY2 divided by 7 and HSCKBY2 divided by 9. There is a stated
assumption that HSCK is either 364MHz or 468MHz, thereby ending up
with 26MHz. To do this we have to be running DSI in burst mode, but
the support for that in DRM is near zero.

Can I ask how the chip has actually been configured and run in this mode?

Thanks
  Dave

> Signed-off-by: Marek Vasut <marex@denx.de>
> Cc: Andrzej Hajda <a.hajda@samsung.com>
> Cc: Jernej Skrabec <jernej.skrabec@siol.net>
> Cc: Jonas Karlman <jonas@kwiboo.se>
> Cc: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
> Cc: Neil Armstrong <narmstrong@baylibre.com>
> Cc: Sam Ravnborg <sam@ravnborg.org>
> ---
>  drivers/gpu/drm/bridge/tc358767.c | 111 +++++++++++++++++-------------
>  1 file changed, 63 insertions(+), 48 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
> index 23a6f90b694b..f7fbf6f673e9 100644
> --- a/drivers/gpu/drm/bridge/tc358767.c
> +++ b/drivers/gpu/drm/bridge/tc358767.c
> @@ -1234,11 +1234,74 @@ static int tc_stream_disable(struct tc_data *tc)
>         return 0;
>  }
>
> +static int tc_hardware_init(struct tc_data *tc)
> +{
> +       int ret;
> +
> +       ret = regmap_read(tc->regmap, TC_IDREG, &tc->rev);
> +       if (ret) {
> +               dev_err(tc->dev, "can not read device ID: %d\n", ret);
> +               return ret;
> +       }
> +
> +       if ((tc->rev != 0x6601) && (tc->rev != 0x6603)) {
> +               dev_err(tc->dev, "invalid device ID: 0x%08x\n", tc->rev);
> +               return -EINVAL;
> +       }
> +
> +       tc->assr = (tc->rev == 0x6601); /* Enable ASSR for eDP panels */
> +
> +       if (!tc->reset_gpio) {
> +               /*
> +                * If the reset pin isn't present, do a software reset. It isn't
> +                * as thorough as the hardware reset, as we can't reset the I2C
> +                * communication block for obvious reasons, but it's getting the
> +                * chip into a defined state.
> +                */
> +               regmap_update_bits(tc->regmap, SYSRSTENB,
> +                               ENBLCD0 | ENBBM | ENBDSIRX | ENBREG | ENBHDCP,
> +                               0);
> +               regmap_update_bits(tc->regmap, SYSRSTENB,
> +                               ENBLCD0 | ENBBM | ENBDSIRX | ENBREG | ENBHDCP,
> +                               ENBLCD0 | ENBBM | ENBDSIRX | ENBREG | ENBHDCP);
> +               usleep_range(5000, 10000);
> +       }
> +
> +       if (tc->hpd_pin >= 0) {
> +               u32 lcnt_reg = tc->hpd_pin == 0 ? INT_GP0_LCNT : INT_GP1_LCNT;
> +               u32 h_lc = INT_GPIO_H(tc->hpd_pin) | INT_GPIO_LC(tc->hpd_pin);
> +
> +               /* Set LCNT to 2ms */
> +               regmap_write(tc->regmap, lcnt_reg,
> +                            clk_get_rate(tc->refclk) * 2 / 1000);
> +               /* We need the "alternate" mode for HPD */
> +               regmap_write(tc->regmap, GPIOM, BIT(tc->hpd_pin));
> +
> +               if (tc->have_irq) {
> +                       /* enable H & LC */
> +                       regmap_update_bits(tc->regmap, INTCTL_G, h_lc, h_lc);
> +               }
> +       }
> +
> +       if (tc->have_irq) {
> +               /* enable SysErr */
> +               regmap_write(tc->regmap, INTCTL_G, INT_SYSERR);
> +       }
> +
> +       return 0;
> +}
> +
>  static void tc_bridge_enable(struct drm_bridge *bridge)
>  {
>         struct tc_data *tc = bridge_to_tc(bridge);
>         int ret;
>
> +       ret = tc_hardware_init(tc);
> +       if (ret < 0) {
> +               dev_err(tc->dev, "failed to initialize bridge: %d\n", ret);
> +               return;
> +       }
> +
>         ret = tc_get_display_props(tc);
>         if (ret < 0) {
>                 dev_err(tc->dev, "failed to read display props: %d\n", ret);
> @@ -1626,9 +1689,6 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
>         }
>
>         if (client->irq > 0) {
> -               /* enable SysErr */
> -               regmap_write(tc->regmap, INTCTL_G, INT_SYSERR);
> -
>                 ret = devm_request_threaded_irq(dev, client->irq,
>                                                 NULL, tc_irq_handler,
>                                                 IRQF_ONESHOT,
> @@ -1641,51 +1701,6 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
>                 tc->have_irq = true;
>         }
>
> -       ret = regmap_read(tc->regmap, TC_IDREG, &tc->rev);
> -       if (ret) {
> -               dev_err(tc->dev, "can not read device ID: %d\n", ret);
> -               return ret;
> -       }
> -
> -       if ((tc->rev != 0x6601) && (tc->rev != 0x6603)) {
> -               dev_err(tc->dev, "invalid device ID: 0x%08x\n", tc->rev);
> -               return -EINVAL;
> -       }
> -
> -       tc->assr = (tc->rev == 0x6601); /* Enable ASSR for eDP panels */
> -
> -       if (!tc->reset_gpio) {
> -               /*
> -                * If the reset pin isn't present, do a software reset. It isn't
> -                * as thorough as the hardware reset, as we can't reset the I2C
> -                * communication block for obvious reasons, but it's getting the
> -                * chip into a defined state.
> -                */
> -               regmap_update_bits(tc->regmap, SYSRSTENB,
> -                               ENBLCD0 | ENBBM | ENBDSIRX | ENBREG | ENBHDCP,
> -                               0);
> -               regmap_update_bits(tc->regmap, SYSRSTENB,
> -                               ENBLCD0 | ENBBM | ENBDSIRX | ENBREG | ENBHDCP,
> -                               ENBLCD0 | ENBBM | ENBDSIRX | ENBREG | ENBHDCP);
> -               usleep_range(5000, 10000);
> -       }
> -
> -       if (tc->hpd_pin >= 0) {
> -               u32 lcnt_reg = tc->hpd_pin == 0 ? INT_GP0_LCNT : INT_GP1_LCNT;
> -               u32 h_lc = INT_GPIO_H(tc->hpd_pin) | INT_GPIO_LC(tc->hpd_pin);
> -
> -               /* Set LCNT to 2ms */
> -               regmap_write(tc->regmap, lcnt_reg,
> -                            clk_get_rate(tc->refclk) * 2 / 1000);
> -               /* We need the "alternate" mode for HPD */
> -               regmap_write(tc->regmap, GPIOM, BIT(tc->hpd_pin));
> -
> -               if (tc->have_irq) {
> -                       /* enable H & LC */
> -                       regmap_update_bits(tc->regmap, INTCTL_G, h_lc, h_lc);
> -               }
> -       }
> -
>         ret = tc_aux_link_setup(tc);
>         if (ret)
>                 return ret;
> --
> 2.33.0
>
Marek Vasut Dec. 6, 2021, 8:24 p.m. UTC | #2
On 12/6/21 19:01, Dave Stevenson wrote:
> Hi Marek

Hi,

>> The TC358767/TC358867/TC9595 are all capable of operating either from
>> attached Xtal or from DSI clock lane clock. In case the later is used,
>> all I2C accesses will fail until the DSI clock lane is running and
>> supplying clock to the chip.
>>
>> Move all hardware initialization to enable callback to guarantee the
>> DSI clock lane is running before accessing the hardware. In case Xtal
>> is attached to the chip, this change has no effect.
> 
> This puzzles me as there seem to be a couple of ambiguities over how
> it would be used.
> 
> Firstly the DT binding lists the clock as a required property, but
> there isn't one present if deriving the clock from the DSI clock lane.

That's correct, the clock for the internal PLLs are derived from the DSI 
clock lane.

> Secondly the datasheet states that the DSI Reference Clock Source
> Division Selection is done by the MODE1 pin, and switches between
> HSCKBY2 divided by 7 and HSCKBY2 divided by 9. There is a stated
> assumption that HSCK is either 364MHz or 468MHz, thereby ending up
> with 26MHz. To do this we have to be running DSI in burst mode, but
> the support for that in DRM is near zero.

Yes, you have to run the DSI clock lane at either of the two clock 
frequencies, that is rather limiting. The DSI has to be running in 
continuous clock mode, this has nothing to do with burst mode, the burst 
mode is a DSI host setting which is supported by most DSI hosts.

> Can I ask how the chip has actually been configured and run in this mode?

REFCLK Xtal disconnected and HSCKBY2/7 MODE0=H MODE1=L , that should be 
all you need. Do you plan to develop a board with this bridge ?
Dave Stevenson Dec. 7, 2021, 1:34 p.m. UTC | #3
On Mon, 6 Dec 2021 at 20:24, Marek Vasut <marex@denx.de> wrote:
>
> On 12/6/21 19:01, Dave Stevenson wrote:
> > Hi Marek
>
> Hi,
>
> >> The TC358767/TC358867/TC9595 are all capable of operating either from
> >> attached Xtal or from DSI clock lane clock. In case the later is used,
> >> all I2C accesses will fail until the DSI clock lane is running and
> >> supplying clock to the chip.
> >>
> >> Move all hardware initialization to enable callback to guarantee the
> >> DSI clock lane is running before accessing the hardware. In case Xtal
> >> is attached to the chip, this change has no effect.
> >
> > This puzzles me as there seem to be a couple of ambiguities over how
> > it would be used.
> >
> > Firstly the DT binding lists the clock as a required property, but
> > there isn't one present if deriving the clock from the DSI clock lane.
>
> That's correct, the clock for the internal PLLs are derived from the DSI
> clock lane.

Does that mean you're creating a dummy clock device?
If it's a required property then presumably yes, but it seems a little
odd as that reflck does not exist.

> > Secondly the datasheet states that the DSI Reference Clock Source
> > Division Selection is done by the MODE1 pin, and switches between
> > HSCKBY2 divided by 7 and HSCKBY2 divided by 9. There is a stated
> > assumption that HSCK is either 364MHz or 468MHz, thereby ending up
> > with 26MHz. To do this we have to be running DSI in burst mode, but
> > the support for that in DRM is near zero.
>
> Yes, you have to run the DSI clock lane at either of the two clock
> frequencies, that is rather limiting. The DSI has to be running in
> continuous clock mode, this has nothing to do with burst mode, the burst
> mode is a DSI host setting which is supported by most DSI hosts.

OK burst mode is technically dropping the lane to LP mode, and you
don't need that state transition.

To quote the Toshiba datasheet:
"As the clock derived from the
DSICLK has to be fixed at 13, 26, 19.2 or 38.4 MHz, the DSI Host may
need to run DSI clock lane at
higher frequency than needed by frame rate and may have to send the
DSI video mode transmissions in
burst mode (explained in DSI section of this specification) "

So where are you configuring the DSI clock lane to be running at one
of those frequencies? Or are you requiring your panel to be running
with a matching pixel clock?

> > Can I ask how the chip has actually been configured and run in this mode?
>
> REFCLK Xtal disconnected and HSCKBY2/7 MODE0=H MODE1=L , that should be
> all you need. Do you plan to develop a board with this bridge ?

Yes, I have a board with this chip in DSI to DPI mode that I'm trying
to get to work. The intent was to configure it via DSI LP commands
rather than I2C, but currently it's refusing to do anything.

  Dave
Marek Vasut Dec. 7, 2021, 1:59 p.m. UTC | #4
On 12/7/21 14:34, Dave Stevenson wrote:

Hi,

>>>> The TC358767/TC358867/TC9595 are all capable of operating either from
>>>> attached Xtal or from DSI clock lane clock. In case the later is used,
>>>> all I2C accesses will fail until the DSI clock lane is running and
>>>> supplying clock to the chip.
>>>>
>>>> Move all hardware initialization to enable callback to guarantee the
>>>> DSI clock lane is running before accessing the hardware. In case Xtal
>>>> is attached to the chip, this change has no effect.
>>>
>>> This puzzles me as there seem to be a couple of ambiguities over how
>>> it would be used.
>>>
>>> Firstly the DT binding lists the clock as a required property, but
>>> there isn't one present if deriving the clock from the DSI clock lane.
>>
>> That's correct, the clock for the internal PLLs are derived from the DSI
>> clock lane.
> 
> Does that mean you're creating a dummy clock device?
> If it's a required property then presumably yes, but it seems a little
> odd as that reflck does not exist.

No. The refclk will become optional, but for that I need some more 
infrastructure work, i.e. some way to communicate the requirements of 
the DSI clock lane to the DSI host.

>>> Secondly the datasheet states that the DSI Reference Clock Source
>>> Division Selection is done by the MODE1 pin, and switches between
>>> HSCKBY2 divided by 7 and HSCKBY2 divided by 9. There is a stated
>>> assumption that HSCK is either 364MHz or 468MHz, thereby ending up
>>> with 26MHz. To do this we have to be running DSI in burst mode, but
>>> the support for that in DRM is near zero.
>>
>> Yes, you have to run the DSI clock lane at either of the two clock
>> frequencies, that is rather limiting. The DSI has to be running in
>> continuous clock mode, this has nothing to do with burst mode, the burst
>> mode is a DSI host setting which is supported by most DSI hosts.
> 
> OK burst mode is technically dropping the lane to LP mode, and you
> don't need that state transition.
> 
> To quote the Toshiba datasheet:
> "As the clock derived from the
> DSICLK has to be fixed at 13, 26, 19.2 or 38.4 MHz, the DSI Host may
> need to run DSI clock lane at
> higher frequency than needed by frame rate and may have to send the
> DSI video mode transmissions in
> burst mode (explained in DSI section of this specification) "
> 
> So where are you configuring the DSI clock lane to be running at one
> of those frequencies? Or are you requiring your panel to be running
> with a matching pixel clock?

This is a preparatory patch, so nowhere yet. I forced the clock lane to 
the required clock frequency on the DSI host side thus far. You can 
still configure the chip to derive clock from Xtal, even with DSI as 
data input.

>>> Can I ask how the chip has actually been configured and run in this mode?
>>
>> REFCLK Xtal disconnected and HSCKBY2/7 MODE0=H MODE1=L , that should be
>> all you need. Do you plan to develop a board with this bridge ?
> 
> Yes, I have a board with this chip in DSI to DPI mode that I'm trying
> to get to work. The intent was to configure it via DSI LP commands
> rather than I2C, but currently it's refusing to do anything.

I see.
Dave Stevenson Dec. 7, 2021, 4:28 p.m. UTC | #5
On Tue, 7 Dec 2021 at 13:59, Marek Vasut <marex@denx.de> wrote:
>
> On 12/7/21 14:34, Dave Stevenson wrote:
>
> Hi,
>
> >>>> The TC358767/TC358867/TC9595 are all capable of operating either from
> >>>> attached Xtal or from DSI clock lane clock. In case the later is used,
> >>>> all I2C accesses will fail until the DSI clock lane is running and
> >>>> supplying clock to the chip.
> >>>>
> >>>> Move all hardware initialization to enable callback to guarantee the
> >>>> DSI clock lane is running before accessing the hardware. In case Xtal
> >>>> is attached to the chip, this change has no effect.
> >>>
> >>> This puzzles me as there seem to be a couple of ambiguities over how
> >>> it would be used.
> >>>
> >>> Firstly the DT binding lists the clock as a required property, but
> >>> there isn't one present if deriving the clock from the DSI clock lane.
> >>
> >> That's correct, the clock for the internal PLLs are derived from the DSI
> >> clock lane.
> >
> > Does that mean you're creating a dummy clock device?
> > If it's a required property then presumably yes, but it seems a little
> > odd as that reflck does not exist.
>
> No. The refclk will become optional, but for that I need some more
> infrastructure work, i.e. some way to communicate the requirements of
> the DSI clock lane to the DSI host.
>
> >>> Secondly the datasheet states that the DSI Reference Clock Source
> >>> Division Selection is done by the MODE1 pin, and switches between
> >>> HSCKBY2 divided by 7 and HSCKBY2 divided by 9. There is a stated
> >>> assumption that HSCK is either 364MHz or 468MHz, thereby ending up
> >>> with 26MHz. To do this we have to be running DSI in burst mode, but
> >>> the support for that in DRM is near zero.
> >>
> >> Yes, you have to run the DSI clock lane at either of the two clock
> >> frequencies, that is rather limiting. The DSI has to be running in
> >> continuous clock mode, this has nothing to do with burst mode, the burst
> >> mode is a DSI host setting which is supported by most DSI hosts.
> >
> > OK burst mode is technically dropping the lane to LP mode, and you
> > don't need that state transition.
> >
> > To quote the Toshiba datasheet:
> > "As the clock derived from the
> > DSICLK has to be fixed at 13, 26, 19.2 or 38.4 MHz, the DSI Host may
> > need to run DSI clock lane at
> > higher frequency than needed by frame rate and may have to send the
> > DSI video mode transmissions in
> > burst mode (explained in DSI section of this specification) "
> >
> > So where are you configuring the DSI clock lane to be running at one
> > of those frequencies? Or are you requiring your panel to be running
> > with a matching pixel clock?
>
> This is a preparatory patch, so nowhere yet. I forced the clock lane to
> the required clock frequency on the DSI host side thus far. You can
> still configure the chip to derive clock from Xtal, even with DSI as
> data input.

Ah, I'd read too much into the commit text and read it as already
fully implemented with a DSI derived clock instead of refclk. Sorry.

Are you already working on the infrastructure changes, or are they
just vaguely planned?

> >>> Can I ask how the chip has actually been configured and run in this mode?
> >>
> >> REFCLK Xtal disconnected and HSCKBY2/7 MODE0=H MODE1=L , that should be
> >> all you need. Do you plan to develop a board with this bridge ?
> >
> > Yes, I have a board with this chip in DSI to DPI mode that I'm trying
> > to get to work. The intent was to configure it via DSI LP commands
> > rather than I2C, but currently it's refusing to do anything.
>
> I see.
Marek Vasut Dec. 7, 2021, 4:43 p.m. UTC | #6
On 12/7/21 17:28, Dave Stevenson wrote:

Hi,

[...]

>>>>> Secondly the datasheet states that the DSI Reference Clock Source
>>>>> Division Selection is done by the MODE1 pin, and switches between
>>>>> HSCKBY2 divided by 7 and HSCKBY2 divided by 9. There is a stated
>>>>> assumption that HSCK is either 364MHz or 468MHz, thereby ending up
>>>>> with 26MHz. To do this we have to be running DSI in burst mode, but
>>>>> the support for that in DRM is near zero.
>>>>
>>>> Yes, you have to run the DSI clock lane at either of the two clock
>>>> frequencies, that is rather limiting. The DSI has to be running in
>>>> continuous clock mode, this has nothing to do with burst mode, the burst
>>>> mode is a DSI host setting which is supported by most DSI hosts.
>>>
>>> OK burst mode is technically dropping the lane to LP mode, and you
>>> don't need that state transition.
>>>
>>> To quote the Toshiba datasheet:
>>> "As the clock derived from the
>>> DSICLK has to be fixed at 13, 26, 19.2 or 38.4 MHz, the DSI Host may
>>> need to run DSI clock lane at
>>> higher frequency than needed by frame rate and may have to send the
>>> DSI video mode transmissions in
>>> burst mode (explained in DSI section of this specification) "
>>>
>>> So where are you configuring the DSI clock lane to be running at one
>>> of those frequencies? Or are you requiring your panel to be running
>>> with a matching pixel clock?
>>
>> This is a preparatory patch, so nowhere yet. I forced the clock lane to
>> the required clock frequency on the DSI host side thus far. You can
>> still configure the chip to derive clock from Xtal, even with DSI as
>> data input.
> 
> Ah, I'd read too much into the commit text and read it as already
> fully implemented with a DSI derived clock instead of refclk. Sorry.
> 
> Are you already working on the infrastructure changes, or are they
> just vaguely planned?

I plan to implement those changes, when I have time to do that.
diff mbox series

Patch

diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index 23a6f90b694b..f7fbf6f673e9 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -1234,11 +1234,74 @@  static int tc_stream_disable(struct tc_data *tc)
 	return 0;
 }
 
+static int tc_hardware_init(struct tc_data *tc)
+{
+	int ret;
+
+	ret = regmap_read(tc->regmap, TC_IDREG, &tc->rev);
+	if (ret) {
+		dev_err(tc->dev, "can not read device ID: %d\n", ret);
+		return ret;
+	}
+
+	if ((tc->rev != 0x6601) && (tc->rev != 0x6603)) {
+		dev_err(tc->dev, "invalid device ID: 0x%08x\n", tc->rev);
+		return -EINVAL;
+	}
+
+	tc->assr = (tc->rev == 0x6601); /* Enable ASSR for eDP panels */
+
+	if (!tc->reset_gpio) {
+		/*
+		 * If the reset pin isn't present, do a software reset. It isn't
+		 * as thorough as the hardware reset, as we can't reset the I2C
+		 * communication block for obvious reasons, but it's getting the
+		 * chip into a defined state.
+		 */
+		regmap_update_bits(tc->regmap, SYSRSTENB,
+				ENBLCD0 | ENBBM | ENBDSIRX | ENBREG | ENBHDCP,
+				0);
+		regmap_update_bits(tc->regmap, SYSRSTENB,
+				ENBLCD0 | ENBBM | ENBDSIRX | ENBREG | ENBHDCP,
+				ENBLCD0 | ENBBM | ENBDSIRX | ENBREG | ENBHDCP);
+		usleep_range(5000, 10000);
+	}
+
+	if (tc->hpd_pin >= 0) {
+		u32 lcnt_reg = tc->hpd_pin == 0 ? INT_GP0_LCNT : INT_GP1_LCNT;
+		u32 h_lc = INT_GPIO_H(tc->hpd_pin) | INT_GPIO_LC(tc->hpd_pin);
+
+		/* Set LCNT to 2ms */
+		regmap_write(tc->regmap, lcnt_reg,
+			     clk_get_rate(tc->refclk) * 2 / 1000);
+		/* We need the "alternate" mode for HPD */
+		regmap_write(tc->regmap, GPIOM, BIT(tc->hpd_pin));
+
+		if (tc->have_irq) {
+			/* enable H & LC */
+			regmap_update_bits(tc->regmap, INTCTL_G, h_lc, h_lc);
+		}
+	}
+
+	if (tc->have_irq) {
+		/* enable SysErr */
+		regmap_write(tc->regmap, INTCTL_G, INT_SYSERR);
+	}
+
+	return 0;
+}
+
 static void tc_bridge_enable(struct drm_bridge *bridge)
 {
 	struct tc_data *tc = bridge_to_tc(bridge);
 	int ret;
 
+	ret = tc_hardware_init(tc);
+	if (ret < 0) {
+		dev_err(tc->dev, "failed to initialize bridge: %d\n", ret);
+		return;
+	}
+
 	ret = tc_get_display_props(tc);
 	if (ret < 0) {
 		dev_err(tc->dev, "failed to read display props: %d\n", ret);
@@ -1626,9 +1689,6 @@  static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	}
 
 	if (client->irq > 0) {
-		/* enable SysErr */
-		regmap_write(tc->regmap, INTCTL_G, INT_SYSERR);
-
 		ret = devm_request_threaded_irq(dev, client->irq,
 						NULL, tc_irq_handler,
 						IRQF_ONESHOT,
@@ -1641,51 +1701,6 @@  static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
 		tc->have_irq = true;
 	}
 
-	ret = regmap_read(tc->regmap, TC_IDREG, &tc->rev);
-	if (ret) {
-		dev_err(tc->dev, "can not read device ID: %d\n", ret);
-		return ret;
-	}
-
-	if ((tc->rev != 0x6601) && (tc->rev != 0x6603)) {
-		dev_err(tc->dev, "invalid device ID: 0x%08x\n", tc->rev);
-		return -EINVAL;
-	}
-
-	tc->assr = (tc->rev == 0x6601); /* Enable ASSR for eDP panels */
-
-	if (!tc->reset_gpio) {
-		/*
-		 * If the reset pin isn't present, do a software reset. It isn't
-		 * as thorough as the hardware reset, as we can't reset the I2C
-		 * communication block for obvious reasons, but it's getting the
-		 * chip into a defined state.
-		 */
-		regmap_update_bits(tc->regmap, SYSRSTENB,
-				ENBLCD0 | ENBBM | ENBDSIRX | ENBREG | ENBHDCP,
-				0);
-		regmap_update_bits(tc->regmap, SYSRSTENB,
-				ENBLCD0 | ENBBM | ENBDSIRX | ENBREG | ENBHDCP,
-				ENBLCD0 | ENBBM | ENBDSIRX | ENBREG | ENBHDCP);
-		usleep_range(5000, 10000);
-	}
-
-	if (tc->hpd_pin >= 0) {
-		u32 lcnt_reg = tc->hpd_pin == 0 ? INT_GP0_LCNT : INT_GP1_LCNT;
-		u32 h_lc = INT_GPIO_H(tc->hpd_pin) | INT_GPIO_LC(tc->hpd_pin);
-
-		/* Set LCNT to 2ms */
-		regmap_write(tc->regmap, lcnt_reg,
-			     clk_get_rate(tc->refclk) * 2 / 1000);
-		/* We need the "alternate" mode for HPD */
-		regmap_write(tc->regmap, GPIOM, BIT(tc->hpd_pin));
-
-		if (tc->have_irq) {
-			/* enable H & LC */
-			regmap_update_bits(tc->regmap, INTCTL_G, h_lc, h_lc);
-		}
-	}
-
 	ret = tc_aux_link_setup(tc);
 	if (ret)
 		return ret;