Re: [PATCH 1/3 v2] drm/i2c/adv7511: Add audio support

2016-03-29 Thread Archit Taneja

Hi,

On 03/28/2016 08:06 PM, Jose Abreu wrote:

This patch adds audio support for the ADV7511 HDMI transmitter
using ALSA SoC.

The code was ported from Analog Devices linux tree from
commit 1770c4a1e32b ("Merge remote-tracking branch
'xilinx/master' into xcomm_zynq"), which is available at:
- https://github.com/analogdevicesinc/linux/

The main core file was renamed from adv7511.c to adv7511_core.c
so that audio and video compile into a single adv7511.ko module
and to keep up with Analog Devices kernel tree.

The audio can be disabled using menu-config so it is possible
to use only video mode.

The HDMI mode is automatically started at boot and the audio
(when enabled) registers as a codec into ALSA.


Is there a reason why we set the mode to HDMI at probe itself?
Shouldn't it be okay to set the mode later once we read the
EDID off the panel?

Some more comments below.



SPDIF DAI format was also added to ASoC as it is required
by adv7511 audio.

Signed-off-by: Jose Abreu 
---

No changes v1 -> v2.

  drivers/gpu/drm/i2c/Kconfig |   11 +
  drivers/gpu/drm/i2c/Makefile|2 +
  drivers/gpu/drm/i2c/adv7511.c   | 1024 ---
  drivers/gpu/drm/i2c/adv7511.h   |   41 ++
  drivers/gpu/drm/i2c/adv7511_audio.c |  310 +++
  drivers/gpu/drm/i2c/adv7511_core.c  | 1005 ++
  include/sound/soc-dai.h |1 +
  7 files changed, 1370 insertions(+), 1024 deletions(-)
  delete mode 100644 drivers/gpu/drm/i2c/adv7511.c
  create mode 100644 drivers/gpu/drm/i2c/adv7511_audio.c
  create mode 100644 drivers/gpu/drm/i2c/adv7511_core.c





+
+static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id 
*id)
+{
+   struct adv7511_link_config link_config;
+   struct adv7511 *adv7511;
+   struct device *dev = &i2c->dev;
+   unsigned int val;
+   int ret;
+
+   if (!dev->of_node)
+   return -EINVAL;
+
+   adv7511 = devm_kzalloc(dev, sizeof(*adv7511), GFP_KERNEL);
+   if (!adv7511)
+   return -ENOMEM;
+
+   adv7511->powered = false;
+   adv7511->status = connector_status_disconnected;
+
+   ret = adv7511_parse_dt(dev->of_node, &link_config);
+   if (ret)
+   return ret;
+
+   /*
+* The power down GPIO is optional. If present, toggle it from active to
+* inactive to wake up the encoder.
+*/
+   adv7511->gpio_pd = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_HIGH);
+   if (IS_ERR(adv7511->gpio_pd))
+   return PTR_ERR(adv7511->gpio_pd);
+
+   if (adv7511->gpio_pd) {
+   mdelay(5);
+   gpiod_set_value_cansleep(adv7511->gpio_pd, 0);
+   }
+
+   adv7511->regmap = devm_regmap_init_i2c(i2c, &adv7511_regmap_config);
+   if (IS_ERR(adv7511->regmap))
+   return PTR_ERR(adv7511->regmap);
+
+   ret = regmap_read(adv7511->regmap, ADV7511_REG_CHIP_REVISION, &val);
+   if (ret)
+   return ret;
+   dev_dbg(dev, "Rev. %d\n", val);
+
+   ret = regmap_register_patch(adv7511->regmap, adv7511_fixed_registers,
+   ARRAY_SIZE(adv7511_fixed_registers));
+   if (ret)
+   return ret;
+
+   regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, edid_i2c_addr);
+   regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR,
+packet_i2c_addr);
+   regmap_write(adv7511->regmap, ADV7511_REG_CEC_I2C_ADDR, cec_i2c_addr);
+   adv7511_packet_disable(adv7511, 0x);
+
+   adv7511->i2c_main = i2c;
+   adv7511->i2c_edid = i2c_new_dummy(i2c->adapter, edid_i2c_addr >> 1);
+   if (!adv7511->i2c_edid)
+   return -ENOMEM;
+
+   if (i2c->irq) {
+   init_waitqueue_head(&adv7511->wq);
+
+   ret = devm_request_threaded_irq(dev, i2c->irq, NULL,
+   adv7511_irq_handler,
+   IRQF_ONESHOT, dev_name(dev),
+   adv7511);
+   if (ret)
+   goto err_i2c_unregister_device;
+   }
+
+   /* CEC is unused for now */
+   regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL,
+ADV7511_CEC_CTRL_POWER_DOWN);
+
+   adv7511_power_off(adv7511);
+
+   i2c_set_clientdata(i2c, adv7511);
+
+#ifdef CONFIG_DRM_I2C_ADV7511_AUDIO
+   adv7511_audio_init(&i2c->dev);
+#endif


If we intend to have more audio funcs being used by the core in the
future, it would be nice to have NOP audio funcs rather than having
multiple #ifdef checks in the driver when CONFIG_DRM_I2C_ADV7511_AUDIO
isn't set.


+
+   adv7511_set_link_config(adv7511, &link_config);
+
+   /* Enable HDMI mode */
+   regmap_update_bits(adv7511->regmap, ADV7511_REG_HDCP_HDMI_CFG,
+   ADV7511_HDMI_CFG_MODE_MASK,
+   ADV7511_HDMI

Re: [PATCH 1/3 v2] drm/i2c/adv7511: Add audio support

2016-03-29 Thread Archit Taneja



On 3/29/2016 4:22 PM, Jose Abreu wrote:

Hi Archit,

On 29-03-2016 09:05, Archit Taneja wrote:

Hi,

On 03/28/2016 08:06 PM, Jose Abreu wrote:

This patch adds audio support for the ADV7511 HDMI transmitter
using ALSA SoC.

The code was ported from Analog Devices linux tree from
commit 1770c4a1e32b ("Merge remote-tracking branch
'xilinx/master' into xcomm_zynq"), which is available at:
 - https://github.com/analogdevicesinc/linux/

The main core file was renamed from adv7511.c to adv7511_core.c
so that audio and video compile into a single adv7511.ko module
and to keep up with Analog Devices kernel tree.

The audio can be disabled using menu-config so it is possible
to use only video mode.

The HDMI mode is automatically started at boot and the audio
(when enabled) registers as a codec into ALSA.


Is there a reason why we set the mode to HDMI at probe itself?
Shouldn't it be okay to set the mode later once we read the
EDID off the panel?

Some more comments below.



Well, when I was using this in kernel 3.18 (with an older version of the driver)
I noticed that DVI mode was being used even when HDMI was connected so I forced
the driver to start in HDMI mode. There were some changes in the driver so it is
possible that this is no longer needed. Should I drop it?


Mode selection works fine with ADV7533 on a 4.5 kernel. I'm assuming it
should work out of the box for ADV7511 too. We should drop this.






SPDIF DAI format was also added to ASoC as it is required
by adv7511 audio.

Signed-off-by: Jose Abreu 
---

No changes v1 -> v2.

   drivers/gpu/drm/i2c/Kconfig |   11 +
   drivers/gpu/drm/i2c/Makefile|2 +
   drivers/gpu/drm/i2c/adv7511.c   | 1024 
---
   drivers/gpu/drm/i2c/adv7511.h   |   41 ++
   drivers/gpu/drm/i2c/adv7511_audio.c |  310 +++
   drivers/gpu/drm/i2c/adv7511_core.c  | 1005 ++
   include/sound/soc-dai.h |1 +
   7 files changed, 1370 insertions(+), 1024 deletions(-)
   delete mode 100644 drivers/gpu/drm/i2c/adv7511.c
   create mode 100644 drivers/gpu/drm/i2c/adv7511_audio.c
   create mode 100644 drivers/gpu/drm/i2c/adv7511_core.c





+
+static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id
*id)
+{
+struct adv7511_link_config link_config;
+struct adv7511 *adv7511;
+struct device *dev = &i2c->dev;
+unsigned int val;
+int ret;
+
+if (!dev->of_node)
+return -EINVAL;
+
+adv7511 = devm_kzalloc(dev, sizeof(*adv7511), GFP_KERNEL);
+if (!adv7511)
+return -ENOMEM;
+
+adv7511->powered = false;
+adv7511->status = connector_status_disconnected;
+
+ret = adv7511_parse_dt(dev->of_node, &link_config);
+if (ret)
+return ret;
+
+/*
+ * The power down GPIO is optional. If present, toggle it from active to
+ * inactive to wake up the encoder.
+ */
+adv7511->gpio_pd = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_HIGH);
+if (IS_ERR(adv7511->gpio_pd))
+return PTR_ERR(adv7511->gpio_pd);
+
+if (adv7511->gpio_pd) {
+mdelay(5);
+gpiod_set_value_cansleep(adv7511->gpio_pd, 0);
+}
+
+adv7511->regmap = devm_regmap_init_i2c(i2c, &adv7511_regmap_config);
+if (IS_ERR(adv7511->regmap))
+return PTR_ERR(adv7511->regmap);
+
+ret = regmap_read(adv7511->regmap, ADV7511_REG_CHIP_REVISION, &val);
+if (ret)
+return ret;
+dev_dbg(dev, "Rev. %d\n", val);
+
+ret = regmap_register_patch(adv7511->regmap, adv7511_fixed_registers,
+ARRAY_SIZE(adv7511_fixed_registers));
+if (ret)
+return ret;
+
+regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, edid_i2c_addr);
+regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR,
+ packet_i2c_addr);
+regmap_write(adv7511->regmap, ADV7511_REG_CEC_I2C_ADDR, cec_i2c_addr);
+adv7511_packet_disable(adv7511, 0x);
+
+adv7511->i2c_main = i2c;
+adv7511->i2c_edid = i2c_new_dummy(i2c->adapter, edid_i2c_addr >> 1);
+if (!adv7511->i2c_edid)
+return -ENOMEM;
+
+if (i2c->irq) {
+init_waitqueue_head(&adv7511->wq);
+
+ret = devm_request_threaded_irq(dev, i2c->irq, NULL,
+adv7511_irq_handler,
+IRQF_ONESHOT, dev_name(dev),
+adv7511);
+if (ret)
+goto err_i2c_unregister_device;
+}
+
+/* CEC is unused for now */
+regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL,
+ ADV7511_CEC_CTRL_POWER_DOWN);
+
+adv7511_power_off(adv7511);
+
+i2c_set_clientdata(i2c, adv7511);
+
+#ifdef CONFIG_DRM_I2C_ADV7511_AUDIO
+adv7511_audio_init(&i2c->dev);
+#endif


If we intend to have more audio funcs being used by the core in the
futur

Re: [PATCH] drm/arcpgu: Accommodate adv7511 switch to DRM bridge

2016-10-15 Thread Archit Taneja

Hi,

On 10/14/2016 6:57 PM, Eugeniy Paltsev wrote:

ARC PGU driver starts crashing on initialization after
'commit e12c2f645557 ("drm/i2c: adv7511: Convert to drm_bridge")'
This happenes because in "arcpgu_drm_hdmi_init" function we get pointer
of "drm_i2c_encoder_driver" structure, which doesn't exist after
adv7511 hdmi encoder interface changed from slave encoder to drm bridge.
So, when we call "encoder_init" function from this structure driver
crashes.



The conversion doesn't seem entirely correct. Some comments below.



Bootlog:
->8
[drm] Initialized drm 1.1.0 20060810
arcpgu e0017000.pgu: arc_pgu ID: 0xabbabaab
arcpgu e0017000.pgu: assigned reserved memory node frame_buffer@9e00
Path: (null)
CPU: 0 PID: 1 Comm: swapper Not tainted 4.8.0-1-gb5642252fa01-dirty #8
task: 9a058000 task.stack: 9a032000

[ECR   ]: 0x00220100 => Invalid Read @ 0x0004 by insn @ 0x803934e8
[EFA   ]: 0x0004
[BLINK ]: drm_atomic_helper_connector_dpms+0xa6/0x230
[ERET  ]: drm_atomic_helper_connector_dpms+0xa4/0x230
[STAT32]: 0x0846 : K DE   E2 E1
BTA: 0x8016d949  SP: 0x9a033e34  FP: 0x
LPS: 0x8036f6fc LPE: 0x8036f700 LPC: 0x
r00: 0x8063c118 r01: 0x805b98ac r02: 0x0b11
r03: 0x r04: 0x9a010f54 r05: 0x
r06: 0x0001 r07: 0x r08: 0x0028
r09: 0x0001 r10: 0x0007 r11: 0x0054
r12: 0x720a3033

Stack Trace:
  drm_atomic_helper_connector_dpms+0xa4/0x230
  arcpgu_drm_hdmi_init+0xbc/0x228
  arcpgu_probe+0x168/0x244
  platform_drv_probe+0x26/0x64
  really_probe+0x1f0/0x32c
  __driver_attach+0xa8/0xd0
  bus_for_each_dev+0x3c/0x74
  bus_add_driver+0xc2/0x184
  driver_register+0x50/0xec
  do_one_initcall+0x3a/0x120
  kernel_init_freeable+0x108/0x1a0
->8

Fix ARC PGU driver to be able work with drm bridge hdmi encoder
interface. The hdmi connector code isn't needed anymore as we expect
the adv7511 bridge driver to create/manage the connector.

Signed-off-by: Eugeniy Paltsev 
---
 drivers/gpu/drm/arc/arcpgu_hdmi.c | 144 +-
 1 file changed, 35 insertions(+), 109 deletions(-)

diff --git a/drivers/gpu/drm/arc/arcpgu_hdmi.c 
b/drivers/gpu/drm/arc/arcpgu_hdmi.c
index b7a8b2a..48a6c63 100644
--- a/drivers/gpu/drm/arc/arcpgu_hdmi.c
+++ b/drivers/gpu/drm/arc/arcpgu_hdmi.c
@@ -14,104 +14,54 @@
  *
  */

+#include 
 #include 
 #include 
 #include 

 #include "arcpgu.h"

-struct arcpgu_drm_connector {
-   struct drm_connector connector;
-   struct drm_encoder_slave *encoder_slave;
-};
-
-static int arcpgu_drm_connector_get_modes(struct drm_connector *connector)
+static void arcpgu_drm_i2c_encoder_mode_set(struct drm_encoder *encoder,
+   struct drm_display_mode *mode,
+   struct drm_display_mode *adjusted_mode)
 {
-   const struct drm_encoder_slave_funcs *sfuncs;
-   struct drm_encoder_slave *slave;
-   struct arcpgu_drm_connector *con =
-   container_of(connector, struct arcpgu_drm_connector, connector);
-
-   slave = con->encoder_slave;
-   if (slave == NULL) {
-   dev_err(connector->dev->dev,
-   "connector_get_modes: cannot find slave encoder for 
connector\n");
-   return 0;
-   }
-
-   sfuncs = slave->slave_funcs;
-   if (sfuncs->get_modes == NULL)
-   return 0;
-
-   return sfuncs->get_modes(&slave->base, connector);
-}
-
-static enum drm_connector_status
-arcpgu_drm_connector_detect(struct drm_connector *connector, bool force)
-{
-   enum drm_connector_status status = connector_status_unknown;
-   const struct drm_encoder_slave_funcs *sfuncs;
-   struct drm_encoder_slave *slave;
-
-   struct arcpgu_drm_connector *con =
-   container_of(connector, struct arcpgu_drm_connector, connector);
-
-   slave = con->encoder_slave;
-   if (slave == NULL) {
-   dev_err(connector->dev->dev,
-   "connector_detect: cannot find slave encoder for 
connector\n");
-   return status;
-   }
+   struct drm_bridge *bridge = encoder->bridge;

-   sfuncs = slave->slave_funcs;
-   if (sfuncs && sfuncs->detect)
-   return sfuncs->detect(&slave->base, connector);
-
-   dev_err(connector->dev->dev, "connector_detect: could not detect slave 
funcs\n");
-   return status;
+   bridge->funcs->mode_set(bridge, mode, adjusted_mode);


The bridge functions shouldn't really be called by the kms driver.
They're called automatically by the drm core for the bridge attached
to the encoder. See mode_fixup in drivers/gpu/drm/drm_atomic_helper.c


 }

-static void arcpgu_drm_connector_destroy(struct drm_connector *connector)
-{
-   drm_connector_unregister(connector);
-   drm_connector_cleanup(connector);
-}
-
-static const struct drm_connector_hel

Re: [PATCH v2] drm/arcpgu: Accommodate adv7511 switch to DRM bridge

2016-10-19 Thread Archit Taneja



On 10/19/2016 01:16 PM, Eugeniy Paltsev wrote:

ARC PGU driver starts crashing on initialization after
'commit e12c2f645557 ("drm/i2c: adv7511: Convert to drm_bridge")'
This happenes because in "arcpgu_drm_hdmi_init" function we get pointer
of "drm_i2c_encoder_driver" structure, which doesn't exist after
adv7511 hdmi encoder interface changed from slave encoder to drm bridge.
So, when we call "encoder_init" function from this structure driver
crashes.

Bootlog:
->8
[drm] Initialized drm 1.1.0 20060810
arcpgu e0017000.pgu: arc_pgu ID: 0xabbabaab
arcpgu e0017000.pgu: assigned reserved memory node frame_buffer@9e00
Path: (null)
CPU: 0 PID: 1 Comm: swapper Not tainted 4.8.0-1-gb5642252fa01-dirty #8
task: 9a058000 task.stack: 9a032000

[ECR   ]: 0x00220100 => Invalid Read @ 0x0004 by insn @ 0x803934e8
[EFA   ]: 0x0004
[BLINK ]: drm_atomic_helper_connector_dpms+0xa6/0x230
[ERET  ]: drm_atomic_helper_connector_dpms+0xa4/0x230
[STAT32]: 0x0846 : K DE   E2 E1
BTA: 0x8016d949  SP: 0x9a033e34  FP: 0x
LPS: 0x8036f6fc LPE: 0x8036f700 LPC: 0x
r00: 0x8063c118 r01: 0x805b98ac r02: 0x0b11
r03: 0x r04: 0x9a010f54 r05: 0x
r06: 0x0001 r07: 0x r08: 0x0028
r09: 0x0001 r10: 0x0007 r11: 0x0054
r12: 0x720a3033

Stack Trace:
  drm_atomic_helper_connector_dpms+0xa4/0x230
  arcpgu_drm_hdmi_init+0xbc/0x228
  arcpgu_probe+0x168/0x244
  platform_drv_probe+0x26/0x64
  really_probe+0x1f0/0x32c
  __driver_attach+0xa8/0xd0
  bus_for_each_dev+0x3c/0x74
  bus_add_driver+0xc2/0x184
  driver_register+0x50/0xec
  do_one_initcall+0x3a/0x120
  kernel_init_freeable+0x108/0x1a0
->8

Fix ARC PGU driver to be able work with drm bridge hdmi encoder
interface. The hdmi connector code isn't needed anymore as we expect
the adv7511 bridge driver to create/manage the connector.


Looks good now.

Reviewed-by: Archit Taneja 



Signed-off-by: Eugeniy Paltsev 
---
Changes for v2:
   - remove bridge functions call from kms driver
   - get rid of drm_encoder_slave interface
   - coding style cleanup

 drivers/gpu/drm/arc/arcpgu_hdmi.c | 159 --
 1 file changed, 17 insertions(+), 142 deletions(-)

diff --git a/drivers/gpu/drm/arc/arcpgu_hdmi.c 
b/drivers/gpu/drm/arc/arcpgu_hdmi.c
index b7a8b2a..b69c66b 100644
--- a/drivers/gpu/drm/arc/arcpgu_hdmi.c
+++ b/drivers/gpu/drm/arc/arcpgu_hdmi.c
@@ -14,170 +14,45 @@
  *
  */

-#include 
+#include 
 #include 
-#include 

 #include "arcpgu.h"

-struct arcpgu_drm_connector {
-   struct drm_connector connector;
-   struct drm_encoder_slave *encoder_slave;
-};
-
-static int arcpgu_drm_connector_get_modes(struct drm_connector *connector)
-{
-   const struct drm_encoder_slave_funcs *sfuncs;
-   struct drm_encoder_slave *slave;
-   struct arcpgu_drm_connector *con =
-   container_of(connector, struct arcpgu_drm_connector, connector);
-
-   slave = con->encoder_slave;
-   if (slave == NULL) {
-   dev_err(connector->dev->dev,
-   "connector_get_modes: cannot find slave encoder for 
connector\n");
-   return 0;
-   }
-
-   sfuncs = slave->slave_funcs;
-   if (sfuncs->get_modes == NULL)
-   return 0;
-
-   return sfuncs->get_modes(&slave->base, connector);
-}
-
-static enum drm_connector_status
-arcpgu_drm_connector_detect(struct drm_connector *connector, bool force)
-{
-   enum drm_connector_status status = connector_status_unknown;
-   const struct drm_encoder_slave_funcs *sfuncs;
-   struct drm_encoder_slave *slave;
-
-   struct arcpgu_drm_connector *con =
-   container_of(connector, struct arcpgu_drm_connector, connector);
-
-   slave = con->encoder_slave;
-   if (slave == NULL) {
-   dev_err(connector->dev->dev,
-   "connector_detect: cannot find slave encoder for 
connector\n");
-   return status;
-   }
-
-   sfuncs = slave->slave_funcs;
-   if (sfuncs && sfuncs->detect)
-   return sfuncs->detect(&slave->base, connector);
-
-   dev_err(connector->dev->dev, "connector_detect: could not detect slave 
funcs\n");
-   return status;
-}
-
-static void arcpgu_drm_connector_destroy(struct drm_connector *connector)
-{
-   drm_connector_unregister(connector);
-   drm_connector_cleanup(connector);
-}
-
-static const struct drm_connector_helper_funcs
-arcpgu_drm_connector_helper_funcs = {
-   .get_modes = arcpgu_drm_connector_get_modes,
-};
-
-static const struct drm_connector_funcs arcpgu_drm_connector_funcs = {
-   .dpms = drm_helper_connector_dpms,
-