Re: [PATCH RFC v2 2/6] drm/i2c: tda998x: Move tda998x to a couple encoder/connector

2014-04-01 Thread Laurent Pinchart
Hi Jean-François,

Sorry for the late reply.

On Thursday 27 March 2014 12:34:49 Jean-Francois Moine wrote:
 On Wed, 26 Mar 2014 18:33:09 +0100 Laurent Pinchart wrote:
  That could work in your case, but I don't really like that.
  
  We need to describe the hardware topology, that might be the only point we
  all agree on. There are various hardware topologies we need to support
  with different levels of complexity, and several ways to describe them,
  also with a wide range of complexities and features.
  
  The more complex the hardware topology, the more complex its description
  needs to be, and the more complex the code that will parse the
  description and handle the hardware will be. I don't think there's any
  doubt here.

 But also, the simpler is the topology and the simpler should be its
 description.

I wouldn't put it so strongly. I believe we can slightly relax our 
requirements regarding DT bindings complexity as long as drivers remain 
simple. There's of course no reason to use more complex bindings just for the 
sake of it.

 In your approach, the connections between endpoints are described in the
 components themselves, which makes hard for the DT maintainers to have a
 global understanding of the video subsystem.
 
 Having the topology described in the master device is clearer, even if it is
 complex.

First of all, let's clarify what a master device is. In the simple-video-
card example you've proposed the master device is a logical device (with a DT 
node that has no corresponding hardware device). The second approach I can 
think of is to make the IP core that implements the CRTC (which I usually call 
display controller) be the master device. Let's note that the second case 
makes both the link and global description DT binding styles possible.

My concern with the global description bindings style is that the approach 
only applies to simple hardware and can't be generalized. Now, I'm not too 
concerned about using that approach for simple hardware and a link-based 
approach for more complex hardware. The slave components, however, need to 
use a single DT bindings style, regardless of the DT bindings used by the 
master device. That's why I believe we should try to standardize one DT 
bindings style for master devices, even if it results in a slightly more 
complex DT description than strictly needed in some cases.

  A given device can be integrated in a wide variety of hardware with
  different complexities. A driver can't thus always assume that the whole
  composite display device will match a given class of topologies. This is
  especially true for encoders and connectors, they can be hooked up
  directly at the output of a very simple display controller, or can be
  part of a very complex graph. Encoder and connector drivers can't assume
  much about how they will be integrated. I want to avoid a situation where
  using an HDMI encoder already supported in mainline with a different SoC
  will result in having to rewrite the HDMI encoder driver.
 
 The tda998x chips are simple enough for being used in many boards: one video
 input and one serial digital output. I don't see in which circumstance the
 driver should be rewritten.

It shouldn't, that's the whole point ;-) I wasn't talking about the tda998x 
only, but about encoder drivers in general. I have a display controller in a 
Renesas SoC that has two LVDS encoders that output LVDS signals out of the 
SoC. One LVDS port is connected to an LVDS panel (a connector from a DRM point 
of view), the second one to an LVDS receiver that outputs parallel RGB data to 
an HDMI encoder. The LVDS encoder can't thus assume any particular downstream 
topology and its driver thus can't create DRM encoder and connector instances. 
The same could be true for an HDMI encoder in theory, although an HDMI encoder 
connected on the same board directly to an HDMI decoder that outputs RGB data 
to a panel is probably a case that will be rarely seen in practice.

In the general case an encoder driver can't assume any specific upstream or 
downstream topology. As long as DRM can't expose the real hardware topology to 
userspace, someone needs to decide on how to map the hardware topology to the 
DRM topology exposed to userspace. Encoder drivers can't take that role and 
thus shouldn't create DRM encoder and connector instances themselves.

  The story is a bit different for display controllers. While the hardware
  topology outside (and sometimes inside as well) of the SoC can vary, a
  display controller often approximately implies a given level of
  complexity. A cheap SoC with a simple display controller will likely not
  be used to drive a 4k display requiring 4 encoders running in parallel
  for instance. While I also want to avoid having to make significant
  changes to a display controller driver when using the SoC on a different
  board, I believe the requirement can be slightly relaxed here, and the
  display controller driver(s) can 

Re: [PATCH RFC v2 2/6] drm/i2c: tda998x: Move tda998x to a couple encoder/connector

2014-03-27 Thread Jean-Francois Moine
Hi Laurent,

On Wed, 26 Mar 2014 18:33:09 +0100
Laurent Pinchart laurent.pinch...@ideasonboard.com wrote:

 That could work in your case, but I don't really like that.
 
 We need to describe the hardware topology, that might be the only point we 
 all 
 agree on. There are various hardware topologies we need to support with 
 different levels of complexity, and several ways to describe them, also with 
 a 
 wide range of complexities and features.
 
 The more complex the hardware topology, the more complex its description 
 needs 
 to be, and the more complex the code that will parse the description and 
 handle the hardware will be. I don't think there's any doubt here.

But also, the simpler is the topology and the simpler should be its
description.

In your approach, the connections between endpoints are described in
the components themselves, which makes hard for the DT maintainers to
have a global understanding of the video subsystem.

Having the topology described in the master device is clearer, even if
it is complex.

 A given device can be integrated in a wide variety of hardware with different 
 complexities. A driver can't thus always assume that the whole composite 
 display device will match a given class of topologies. This is especially 
 true 
 for encoders and connectors, they can be hooked up directly at the output of 
 a 
 very simple display controller, or can be part of a very complex graph. 
 Encoder and connector drivers can't assume much about how they will be 
 integrated. I want to avoid a situation where using an HDMI encoder already 
 supported in mainline with a different SoC will result in having to rewrite 
 the HDMI encoder driver.

The tda998x chips are simple enough for being used in many boards: one
video input and one serial digital output. I don't see in which
circumstance the driver should be rewritten.

 The story is a bit different for display controllers. While the hardware 
 topology outside (and sometimes inside as well) of the SoC can vary, a 
 display 
 controller often approximately implies a given level of complexity. A cheap 
 SoC with a simple display controller will likely not be used to drive a 4k 
 display requiring 4 encoders running in parallel for instance. While I also 
 want to avoid having to make significant changes to a display controller 
 driver when using the SoC on a different board, I believe the requirement can 
 be slightly relaxed here, and the display controller driver(s) can assume 
 more 
 about the hardware topology than the encoder drivers.

I don't think that the display controllers or the encoders have to know
about the topology. They have well-knwon specific functions and the way
they are interconnected should not impact these functions. If that
would be the case, they should offer a particular configuration
interface to the master driver.

 I've asked myself whether we needed a single, one-size-fits-them-all DT 
 representation of the hardware topology. The view of the world from an 
 external encoder point of view must not depend on the SoC it is hooked up to 
 (this would prevent using a single encoder driver with multiple SoCs), which 
 calls for at least some form of standardization. The topology representation 
 on the display controller side may vary from display controller to display 
 controller, but I believe this would just result in code duplication and 
 having to solve the same problem in multiple drivers. For those reasons I 
 believe that the OF graph proposal to represent the display hardware topology 
 would be a good choice. The bindings are flexible enough to represent both 
 simple and complex hardware.

Your OF graph proposal is rather complex, and it does not even indicate
which way the data flows.

 Now, I don't want to force all display device drivers to implement complex 
 code when they only need to support simple hardware and simple hardware 
 topologies. Not only would that be rightfully rejected, I would be among the 
 ones nack'ing that approach. My opinion is that this calls for the creation 
 of 
 helpers to handle common cases. Several (possibly many) display systems only 
 need (or want) to support linear pipelines at their output(s), made of a 
 single encoder and a single connector. There's no point in duplicating DT 
 parsing or encoder/connector instantiation code in several drivers in that 
 case where helpers could be reused. Several sets of helpers could support 
 different kinds of topologies, with the driver author selecting a set of 
 helpers depending on the expected hardware topology complexity.

I don't like this 'helper' notion. See below.

 We also need to decide on who (as in which driver) will be responsible for 
 binding all devices together. As DRM exposes a single device to userspace, 
 there needs to be a single driver that will perform front line handling of 
 the 
 userspace API and delegate calls to the other drivers involved. I believe it 
 would be logical for that 

Re: [PATCH RFC v2 2/6] drm/i2c: tda998x: Move tda998x to a couple encoder/connector

2014-03-26 Thread Laurent Pinchart
Hi Jean-François,

On Tuesday 25 March 2014 16:55:48 Jean-Francois Moine wrote:
 On Mon, 24 Mar 2014 23:39:01 +0100 Laurent Pinchart wrote:
  On Friday 21 March 2014 09:17:32 Jean-Francois Moine wrote:
   The 'slave encoder' structure of the tda998x driver asks for glue
   between the DRM driver and the encoder/connector structures.
   
   This patch changes the driver to a normal DRM encoder/connector
   thanks to the infrastructure for componentised subsystems.
  
  I like the idea, but I'm not really happy with the implementation. Let me
  try to explain why below.
  
   Signed-off-by: Jean-Francois Moine moin...@free.fr
   ---
   
drivers/gpu/drm/i2c/tda998x_drv.c | 323 ---
1 file changed, 188 insertions(+), 135 deletions(-)
   
   diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c
   b/drivers/gpu/drm/i2c/tda998x_drv.c index fd6751c..1c25e40 100644
   --- a/drivers/gpu/drm/i2c/tda998x_drv.c
   +++ b/drivers/gpu/drm/i2c/tda998x_drv.c
  
  [snip]
  
   @@ -44,10 +45,14 @@ struct tda998x_priv {
 wait_queue_head_t wq_edid;
 volatile int wq_edid_wait;
   
   - struct drm_encoder *encoder;
   + struct drm_encoder encoder;
   + struct drm_connector connector;
   
};
  
  [snip]
  
   -static int
   -tda998x_probe(struct i2c_client *client, const struct i2c_device_id
   *id)
   +static int tda_bind(struct device *dev, struct device *master, void
   *data)
{
   + struct drm_device *drm = data;
  
  This is the part that bothers me. You're making two assumptions here, that
  the DRM driver will pass a struct drm_device pointer to the bind
  operation, and that the I2C encoder driver can take control of DRM
  encoder and connector creation. Although it could become problematic
  later, the first assumption isn't too much of an issue for now. I'll thus
  focus on the second one.
  
  The component framework isolate the encoder and DRM master drivers as far
  as component creation and binding is concerned, but doesn't provide a way
  for the two drivers to communicate together (nor should it). You're
  solving this by passing a pointer to the DRM device to the encoder bind
  operation, making the encoder driver create a DRM encoder and connector,
  and relying on the DRM core to orchestrate CRTCs, encoders and
  connectors. You thus assume that the encoder hardware should be
  represented by a DRM encoder object, and that its output is connected to
  a connector that should be represented by a DRM connector object. While
  this can work in your use case, that won't always hold true. Hardware
  encoders can be chained together, while DRM encoders can't. The DRM core
  has recently received support for bridge objects to overcome that
  limitation. Depending on the hardware topology, a given hardware encoder
  should be modeled as a DRM encoder or as a DRM bridge. That decision
  shouldn't be taken by the encoder driver but by the DRM master driver.
  The I2C encoder driver thus shouldn't create the DRM encoder and DRM
  connector itself.
  
  I believe the encoder/master communication problem should be solved
  differently. Instead of passing a pointer to the DRM device to the encoder
  driver and making the encoder driver control DRM encoder and connector
  creation, the encoder driver should instead create an object not visible
  to userspace that can be retrieved by the DRM master driver (possibly
  through registration with the DRM core, or by going through drvdata in the
  encoder's struct device). The DRM master could use that object to
  communicate with the encoder, and would register the DRM encoder and DRM
  connector itself based on hardware topology.
  
   + struct i2c_client *i2c_client = to_i2c_client(dev);
   + struct tda998x_priv *priv = i2c_get_clientdata(i2c_client);
   + struct drm_connector *connector = priv-connector;
   + struct drm_encoder *encoder = priv-encoder;
   + int ret;
   +
   + if (!try_module_get(THIS_MODULE)) {
   + dev_err(dev, cannot get module %s\n, THIS_MODULE-name);
   + return -EINVAL;
   + }
   +
   + ret = drm_connector_init(drm, connector,
   + connector_funcs,
   + DRM_MODE_CONNECTOR_HDMIA);
  
  This is one example of the shortcomings I've explained above. An encoder
  driver can't always know what connector type it is connected to. If I'm
  not mistaken possible options here are DVII, DVID, HDMIA and HDMIB. It
  should be up to the master driver to select the connector type based on
  its overall view of the hardware, or even to a connector driver that would
  be bound to a connector DT node (as proposed in
  https://www.mail-archive.com/devicetree@vger.kernel.org/msg16585.html).
   [snip]
 
 The tda998x, as a HDMI transmitter, has to deal with both video and
 audio.
 
 Whereas the hardware connection schemes are the same in both worlds,
 the way they are translated to computer objects are very different:
 
 - video
   DRM card - CRTCs - encoders - 

Re: [PATCH RFC v2 2/6] drm/i2c: tda998x: Move tda998x to a couple encoder/connector

2014-03-25 Thread Jean-Francois Moine
On Mon, 24 Mar 2014 23:39:01 +0100
Laurent Pinchart laurent.pinch...@ideasonboard.com wrote:

 Hi Jean-François,

Hi Laurent,

 Thank you for the patch.
 
 On Friday 21 March 2014 09:17:32 Jean-Francois Moine wrote:
  The 'slave encoder' structure of the tda998x driver asks for glue
  between the DRM driver and the encoder/connector structures.
  
  This patch changes the driver to a normal DRM encoder/connector
  thanks to the infrastructure for componentised subsystems.
 
 I like the idea, but I'm not really happy with the implementation. Let me try 
 to explain why below.
 
  Signed-off-by: Jean-Francois Moine moin...@free.fr
  ---
   drivers/gpu/drm/i2c/tda998x_drv.c | 323 +++
   1 file changed, 188 insertions(+), 135 deletions(-)
  
  diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c
  b/drivers/gpu/drm/i2c/tda998x_drv.c index fd6751c..1c25e40 100644
  --- a/drivers/gpu/drm/i2c/tda998x_drv.c
  +++ b/drivers/gpu/drm/i2c/tda998x_drv.c
 
 [snip]
 
  @@ -44,10 +45,14 @@ struct tda998x_priv {
  
  wait_queue_head_t wq_edid;
  volatile int wq_edid_wait;
  -   struct drm_encoder *encoder;
  +   struct drm_encoder encoder;
  +   struct drm_connector connector;
   };
 
 [snip]
 
  -static int
  -tda998x_probe(struct i2c_client *client, const struct i2c_device_id *id)
  +static int tda_bind(struct device *dev, struct device *master, void *data)
   {
  +   struct drm_device *drm = data;
 
 This is the part that bothers me. You're making two assumptions here, that 
 the 
 DRM driver will pass a struct drm_device pointer to the bind operation, and 
 that the I2C encoder driver can take control of DRM encoder and connector 
 creation. Although it could become problematic later, the first assumption 
 isn't too much of an issue for now. I'll thus focus on the second one.
 
 The component framework isolate the encoder and DRM master drivers as far as 
 component creation and binding is concerned, but doesn't provide a way for 
 the 
 two drivers to communicate together (nor should it). You're solving this by 
 passing a pointer to the DRM device to the encoder bind operation, making the 
 encoder driver create a DRM encoder and connector, and relying on the DRM 
 core 
 to orchestrate CRTCs, encoders and connectors. You thus assume that the 
 encoder hardware should be represented by a DRM encoder object, and that its 
 output is connected to a connector that should be represented by a DRM 
 connector object. While this can work in your use case, that won't always 
 hold 
 true. Hardware encoders can be chained together, while DRM encoders can't. 
 The 
 DRM core has recently received support for bridge objects to overcome that 
 limitation. Depending on the hardware topology, a given hardware encoder 
 should be modeled as a DRM encoder or as a DRM bridge. That decision 
 shouldn't 
 be taken by the encoder driver but by the DRM master driver. The I2C encoder 
 driver thus shouldn't create the DRM encoder and DRM connector itself.
 
 I believe the encoder/master communication problem should be solved 
 differently. Instead of passing a pointer to the DRM device to the encoder 
 driver and making the encoder driver control DRM encoder and connector 
 creation, the encoder driver should instead create an object not visible to 
 userspace that can be retrieved by the DRM master driver (possibly through 
 registration with the DRM core, or by going through drvdata in the encoder's 
 struct device). The DRM master could use that object to communicate with the 
 encoder, and would register the DRM encoder and DRM connector itself based on 
 hardware topology.
 
  +   struct i2c_client *i2c_client = to_i2c_client(dev);
  +   struct tda998x_priv *priv = i2c_get_clientdata(i2c_client);
  +   struct drm_connector *connector = priv-connector;
  +   struct drm_encoder *encoder = priv-encoder;
  +   int ret;
  +
  +   if (!try_module_get(THIS_MODULE)) {
  +   dev_err(dev, cannot get module %s\n, THIS_MODULE-name);
  +   return -EINVAL;
  +   }
  +
  +   ret = drm_connector_init(drm, connector,
  +   connector_funcs,
  +   DRM_MODE_CONNECTOR_HDMIA);
 
 This is one example of the shortcomings I've explained above. An encoder 
 driver can't always know what connector type it is connected to. If I'm not 
 mistaken possible options here are DVII, DVID, HDMIA and HDMIB. It should be 
 up to the master driver to select the connector type based on its overall 
 view 
 of the hardware, or even to a connector driver that would be bound to a 
 connector DT node (as proposed in 
 https://www.mail-archive.com/devicetree@vger.kernel.org/msg16585.html).
[snip]

The tda998x, as a HDMI transmitter, has to deal with both video and
audio.

Whereas the hardware connection schemes are the same in both worlds,
the way they are translated to computer objects are very different:

- video
DRM card - CRTCs - encoders - (bridges) - 

Re: [PATCH RFC v2 2/6] drm/i2c: tda998x: Move tda998x to a couple encoder/connector

2014-03-24 Thread Laurent Pinchart
Hi Jean-François,

Thank you for the patch.

On Friday 21 March 2014 09:17:32 Jean-Francois Moine wrote:
 The 'slave encoder' structure of the tda998x driver asks for glue
 between the DRM driver and the encoder/connector structures.
 
 This patch changes the driver to a normal DRM encoder/connector
 thanks to the infrastructure for componentised subsystems.

I like the idea, but I'm not really happy with the implementation. Let me try 
to explain why below.

 Signed-off-by: Jean-Francois Moine moin...@free.fr
 ---
  drivers/gpu/drm/i2c/tda998x_drv.c | 323 +++
  1 file changed, 188 insertions(+), 135 deletions(-)
 
 diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c
 b/drivers/gpu/drm/i2c/tda998x_drv.c index fd6751c..1c25e40 100644
 --- a/drivers/gpu/drm/i2c/tda998x_drv.c
 +++ b/drivers/gpu/drm/i2c/tda998x_drv.c

[snip]

 @@ -44,10 +45,14 @@ struct tda998x_priv {
 
   wait_queue_head_t wq_edid;
   volatile int wq_edid_wait;
 - struct drm_encoder *encoder;
 + struct drm_encoder encoder;
 + struct drm_connector connector;
  };

[snip]

 -static int
 -tda998x_probe(struct i2c_client *client, const struct i2c_device_id *id)
 +static int tda_bind(struct device *dev, struct device *master, void *data)
  {
 + struct drm_device *drm = data;

This is the part that bothers me. You're making two assumptions here, that the 
DRM driver will pass a struct drm_device pointer to the bind operation, and 
that the I2C encoder driver can take control of DRM encoder and connector 
creation. Although it could become problematic later, the first assumption 
isn't too much of an issue for now. I'll thus focus on the second one.

The component framework isolate the encoder and DRM master drivers as far as 
component creation and binding is concerned, but doesn't provide a way for the 
two drivers to communicate together (nor should it). You're solving this by 
passing a pointer to the DRM device to the encoder bind operation, making the 
encoder driver create a DRM encoder and connector, and relying on the DRM core 
to orchestrate CRTCs, encoders and connectors. You thus assume that the 
encoder hardware should be represented by a DRM encoder object, and that its 
output is connected to a connector that should be represented by a DRM 
connector object. While this can work in your use case, that won't always hold 
true. Hardware encoders can be chained together, while DRM encoders can't. The 
DRM core has recently received support for bridge objects to overcome that 
limitation. Depending on the hardware topology, a given hardware encoder 
should be modeled as a DRM encoder or as a DRM bridge. That decision shouldn't 
be taken by the encoder driver but by the DRM master driver. The I2C encoder 
driver thus shouldn't create the DRM encoder and DRM connector itself.

I believe the encoder/master communication problem should be solved 
differently. Instead of passing a pointer to the DRM device to the encoder 
driver and making the encoder driver control DRM encoder and connector 
creation, the encoder driver should instead create an object not visible to 
userspace that can be retrieved by the DRM master driver (possibly through 
registration with the DRM core, or by going through drvdata in the encoder's 
struct device). The DRM master could use that object to communicate with the 
encoder, and would register the DRM encoder and DRM connector itself based on 
hardware topology.

 + struct i2c_client *i2c_client = to_i2c_client(dev);
 + struct tda998x_priv *priv = i2c_get_clientdata(i2c_client);
 + struct drm_connector *connector = priv-connector;
 + struct drm_encoder *encoder = priv-encoder;
 + int ret;
 +
 + if (!try_module_get(THIS_MODULE)) {
 + dev_err(dev, cannot get module %s\n, THIS_MODULE-name);
 + return -EINVAL;
 + }
 +
 + ret = drm_connector_init(drm, connector,
 + connector_funcs,
 + DRM_MODE_CONNECTOR_HDMIA);

This is one example of the shortcomings I've explained above. An encoder 
driver can't always know what connector type it is connected to. If I'm not 
mistaken possible options here are DVII, DVID, HDMIA and HDMIB. It should be 
up to the master driver to select the connector type based on its overall view 
of the hardware, or even to a connector driver that would be bound to a 
connector DT node (as proposed in 
https://www.mail-archive.com/devicetree@vger.kernel.org/msg16585.html).

 + if (ret  0)
 + return ret;
 + drm_connector_helper_add(connector, connector_helper_funcs);
 +
 + ret = drm_encoder_init(drm, encoder,
 + encoder_funcs,
 + DRM_MODE_ENCODER_TMDS);
 +
 + encoder-possible_crtcs = 1;// 1  lcd_num
 +
 + if (ret  0)
 + goto err;
 + drm_encoder_helper_add(encoder, encoder_helper_funcs);
 +
 + ret = 

[PATCH RFC v2 2/6] drm/i2c: tda998x: Move tda998x to a couple encoder/connector

2014-03-21 Thread Jean-Francois Moine
The 'slave encoder' structure of the tda998x driver asks for glue
between the DRM driver and the encoder/connector structures.

This patch changes the driver to a normal DRM encoder/connector
thanks to the infrastructure for componentised subsystems.

Signed-off-by: Jean-Francois Moine moin...@free.fr
---
 drivers/gpu/drm/i2c/tda998x_drv.c | 323 ++
 1 file changed, 188 insertions(+), 135 deletions(-)

diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c 
b/drivers/gpu/drm/i2c/tda998x_drv.c
index fd6751c..1c25e40 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -20,11 +20,12 @@
 #include linux/hdmi.h
 #include linux/module.h
 #include linux/irq.h
+#include linux/of_platform.h
+#include linux/component.h
 #include sound/asoundef.h
 
 #include drm/drmP.h
 #include drm/drm_crtc_helper.h
-#include drm/drm_encoder_slave.h
 #include drm/drm_edid.h
 #include drm/i2c/tda998x.h
 
@@ -44,10 +45,14 @@ struct tda998x_priv {
 
wait_queue_head_t wq_edid;
volatile int wq_edid_wait;
-   struct drm_encoder *encoder;
+   struct drm_encoder encoder;
+   struct drm_connector connector;
 };
 
-#define to_tda998x_priv(x)  ((struct tda998x_priv 
*)to_encoder_slave(x)-slave_priv)
+#define connector_priv(e) \
+   container_of(connector, struct tda998x_priv, connector)
+#define encoder_priv(e) \
+   container_of(encoder, struct tda998x_priv, encoder)
 
 /* The TDA9988 series of devices use a paged register scheme.. to simplify
  * things we encode the page # in upper bits of the register #.  To read/
@@ -559,9 +564,8 @@ static irqreturn_t tda998x_irq_thread(int irq, void *data)
if ((flag2  INT_FLAGS_2_EDID_BLK_RD)  priv-wq_edid_wait) {
priv-wq_edid_wait = 0;
wake_up(priv-wq_edid);
-   } else if (cec != 0) {  /* HPD change */
-   if (priv-encoder  priv-encoder-dev)
-   drm_helper_hpd_irq_event(priv-encoder-dev);
+   } else if (cec != 0  priv-encoder.dev) { /* HPD change */
+   drm_helper_hpd_irq_event(priv-encoder.dev);
}
return IRQ_HANDLED;
 }
@@ -731,9 +735,8 @@ tda998x_configure_audio(struct tda998x_priv *priv,
 /* DRM encoder functions */
 
 static void
-tda998x_encoder_set_config(struct drm_encoder *encoder, void *params)
+tda998x_encoder_set_config(struct tda998x_priv *priv, void *params)
 {
-   struct tda998x_priv *priv = to_tda998x_priv(encoder);
struct tda998x_encoder_params *p = params;
 
priv-vip_cntrl_0 = VIP_CNTRL_0_SWAP_A(p-swap_a) |
@@ -755,7 +758,7 @@ tda998x_encoder_set_config(struct drm_encoder *encoder, 
void *params)
 static void
 tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
 {
-   struct tda998x_priv *priv = to_tda998x_priv(encoder);
+   struct tda998x_priv *priv = encoder_priv(encoder);
 
/* we only care about on or off: */
if (mode != DRM_MODE_DPMS_ON)
@@ -786,18 +789,6 @@ tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
priv-dpms = mode;
 }
 
-static void
-tda998x_encoder_save(struct drm_encoder *encoder)
-{
-   DBG();
-}
-
-static void
-tda998x_encoder_restore(struct drm_encoder *encoder)
-{
-   DBG();
-}
-
 static bool
 tda998x_encoder_mode_fixup(struct drm_encoder *encoder,
  const struct drm_display_mode *mode,
@@ -806,11 +797,14 @@ tda998x_encoder_mode_fixup(struct drm_encoder *encoder,
return true;
 }
 
-static int
-tda998x_encoder_mode_valid(struct drm_encoder *encoder,
- struct drm_display_mode *mode)
+static void tda998x_encoder_prepare(struct drm_encoder *encoder)
 {
-   return MODE_OK;
+   tda998x_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+}
+
+static void tda998x_encoder_commit(struct drm_encoder *encoder)
+{
+   tda998x_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
 }
 
 static void
@@ -818,7 +812,7 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
 {
-   struct tda998x_priv *priv = to_tda998x_priv(encoder);
+   struct tda998x_priv *priv = encoder_priv(encoder);
uint16_t ref_pix, ref_line, n_pix, n_line;
uint16_t hs_pix_s, hs_pix_e;
uint16_t vs1_pix_s, vs1_pix_e, vs1_line_s, vs1_line_e;
@@ -1006,10 +1000,9 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,
 }
 
 static enum drm_connector_status
-tda998x_encoder_detect(struct drm_encoder *encoder,
- struct drm_connector *connector)
+tda998x_connector_detect(struct drm_connector *connector, bool force)
 {
-   struct tda998x_priv *priv = to_tda998x_priv(encoder);
+   struct tda998x_priv *priv = connector_priv(connector);
uint8_t val = cec_read(priv, REG_CEC_RXSHPDLEV);
 
return (val  CEC_RXSHPDLEV_HPD) ? connector_status_connected :
@@ -1017,9 +1010,8