Merge branch 'drm-tda998x-mali' into drm-tda998x-devel
authorRussell King <rmk+kernel@armlinux.org.uk>
Tue, 1 Nov 2016 09:17:57 +0000 (09:17 +0000)
committerRussell King <rmk+kernel@armlinux.org.uk>
Tue, 1 Nov 2016 09:17:57 +0000 (09:17 +0000)
1  2 
arch/arm/boot/dts/am335x-boneblack.dts
drivers/gpu/drm/i2c/Kconfig
drivers/gpu/drm/i2c/tda998x_drv.c

index 6bbb1fee08689182dca4e113e9e37038c9a7b055,ca721670bd911a7f38e7516601576067981a3fc7..528559b33d8aeba9d0e4030d742e5434f1f00cf7
@@@ -9,7 -9,6 +9,7 @@@
  
  #include "am33xx.dtsi"
  #include "am335x-bone-common.dtsi"
 +#include <dt-bindings/display/tda998x.h>
  
  / {
        model = "TI AM335x BeagleBone Black";
        status = "okay";
  };
  
+ &cpu0_opp_table {
+       /*
+        * All PG 2.0 silicon may not support 1GHz but some of the early
+        * BeagleBone Blacks have PG 2.0 silicon which is guaranteed
+        * to support 1GHz OPP so enable it for PG 2.0 on this board.
+        */
+       oppnitro@1000000000 {
+               opp-supported-hw = <0x06 0x0100>;
+       };
+ };
  &am33xx_pinmux {
        nxp_hdmi_bonelt_pins: nxp_hdmi_bonelt_pins {
                pinctrl-single,pins = <
                        AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3)    /* xdma_event_intr0 */
                >;
        };
 +
 +      mcasp0_pins: mcasp0_pins {
 +              pinctrl-single,pins = <
 +                      AM33XX_IOPAD(0x9ac, PIN_INPUT_PULLUP | MUX_MODE0) /* mcasp0_ahcklx.mcasp0_ahclkx */
 +                      AM33XX_IOPAD(0x99c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mcasp0_ahclkr.mcasp0_axr2*/
 +                      AM33XX_IOPAD(0x994, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mcasp0_fsx.mcasp0_fsx */
 +                      AM33XX_IOPAD(0x990, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp0_aclkx.mcasp0_aclkx */
 +                      AM33XX_IOPAD(0x86c, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a11.GPIO1_27 */
 +              >;
 +      };
  };
  
  &lcdc {
  };
  
  &i2c0 {
 -      tda19988 {
 +      tda19988: tda19988 {
                compatible = "nxp,tda998x";
                reg = <0x70>;
 +
                pinctrl-names = "default", "off";
                pinctrl-0 = <&nxp_hdmi_bonelt_pins>;
                pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>;
  
 -              port {
 -                      hdmi_0: endpoint@0 {
 -                              remote-endpoint = <&lcdc_0>;
 +              #sound-dai-cells = <0>;
 +              audio-ports = < TDA998x_I2S     0x03>;
 +
 +              ports {
 +                      port@0 {
 +                              hdmi_0: endpoint@0 {
 +                                      remote-endpoint = <&lcdc_0>;
 +                              };
                        };
                };
        };
  &rtc {
        system-power-controller;
  };
 +
 +&mcasp0       {
 +      #sound-dai-cells = <0>;
 +      pinctrl-names = "default";
 +      pinctrl-0 = <&mcasp0_pins>;
 +      status = "okay";
 +      op-mode = <0>;  /* MCASP_IIS_MODE */
 +      tdm-slots = <2>;
 +      serial-dir = <  /* 0: INACTIVE, 1: TX, 2: RX */
 +                      0 0 1 0
 +              >;
 +      tx-num-evt = <32>;
 +      rx-num-evt = <32>;
 +};
 +
 +/ {
 +      clk_mcasp0_fixed: clk_mcasp0_fixed {
 +              #clock-cells = <0>;
 +              compatible = "fixed-clock";
 +              clock-frequency = <24576000>;
 +      };
 +
 +      clk_mcasp0: clk_mcasp0 {
 +              #clock-cells = <0>;
 +              compatible = "gpio-gate-clock";
 +              clocks = <&clk_mcasp0_fixed>;
 +              enable-gpios = <&gpio1 27 0>; /* BeagleBone Black Clk enable on GPIO1_27 */
 +      };
 +
 +      sound {
 +              compatible = "simple-audio-card";
 +              simple-audio-card,name = "TI BeagleBone Black";
 +              simple-audio-card,format = "i2s";
 +              simple-audio-card,bitclock-master = <&dailink0_master>;
 +              simple-audio-card,frame-master = <&dailink0_master>;
 +
 +              dailink0_master: simple-audio-card,cpu {
 +                      sound-dai = <&mcasp0>;
 +                      clocks = <&clk_mcasp0>;
 +              };
 +
 +              simple-audio-card,codec {
 +                      sound-dai = <&tda19988>;
 +              };
 +      };
 +};
index 088f2781d3036add3a252e8ba864e132087c7eec,4d341db462a2442878991e45a3438d770f1afe64..a6c92beb410a7d38f6eef7ee435c9014999018ac
@@@ -1,12 -1,6 +1,6 @@@
  menu "I2C encoder or helper chips"
       depends on DRM && DRM_KMS_HELPER && I2C
  
- config DRM_I2C_ADV7511
-       tristate "AV7511 encoder"
-       select REGMAP_I2C
-       help
-         Support for the Analog Device ADV7511(W) and ADV7513 HDMI encoders.
  config DRM_I2C_CH7006
        tristate "Chrontel ch7006 TV encoder"
        default m if DRM_NOUVEAU
@@@ -28,7 -22,6 +22,7 @@@ config DRM_I2C_SIL16
  config DRM_I2C_NXP_TDA998X
        tristate "NXP Semiconductors TDA998X HDMI encoder"
        default m if DRM_TILCDC
 +      select SND_SOC_HDMI_CODEC if SND_SOC
        help
          Support for NXP Semiconductors TDA998X HDMI encoders.
  
index 9798d400d8174750522b1704be66364fe9425318,6e6fca20ba8b46e1d51d99b5f1cc99f6cf24983e..088900d78ceb5c2946705c4252d3f5ec296a01ce
@@@ -20,7 -20,6 +20,7 @@@
  #include <linux/module.h>
  #include <linux/irq.h>
  #include <sound/asoundef.h>
 +#include <sound/hdmi-codec.h>
  
  #include <drm/drmP.h>
  #include <drm/drm_atomic_helper.h>
  
  #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
  
 +struct tda998x_audio_port {
 +      u8 format;              /* AFMT_xxx */
 +      u8 config;              /* AP value */
 +};
 +
  struct tda998x_priv {
        struct i2c_client *cec;
        struct i2c_client *hdmi;
        u8 vip_cntrl_0;
        u8 vip_cntrl_1;
        u8 vip_cntrl_2;
 -      struct tda998x_encoder_params params;
 +      struct tda998x_audio_params audio_params;
 +
 +      struct platform_device *audio_pdev;
 +      struct mutex audio_mutex;
  
        wait_queue_head_t wq_edid;
        volatile int wq_edid_wait;
@@@ -62,8 -53,6 +62,8 @@@
  
        struct drm_encoder encoder;
        struct drm_connector connector;
 +
 +      struct tda998x_audio_port audio_port[2];
  };
  
  #define conn_to_tda998x_priv(x) \
@@@ -677,16 -666,26 +677,16 @@@ tda998x_write_if(struct tda998x_priv *p
        reg_set(priv, REG_DIP_IF_FLAGS, bit);
  }
  
 -static void
 -tda998x_write_aif(struct tda998x_priv *priv, struct tda998x_encoder_params *p)
 +static int tda998x_write_aif(struct tda998x_priv *priv,
 +                           struct hdmi_audio_infoframe *cea)
  {
        union hdmi_infoframe frame;
  
 -      hdmi_audio_infoframe_init(&frame.audio);
 -
 -      frame.audio.channels = p->audio_frame[1] & 0x07;
 -      frame.audio.channel_allocation = p->audio_frame[4];
 -      frame.audio.level_shift_value = (p->audio_frame[5] & 0x78) >> 3;
 -      frame.audio.downmix_inhibit = (p->audio_frame[5] & 0x80) >> 7;
 -
 -      /*
 -       * L-PCM and IEC61937 compressed audio shall always set sample
 -       * frequency to "refer to stream".  For others, see the HDMI
 -       * specification.
 -       */
 -      frame.audio.sample_frequency = (p->audio_frame[2] & 0x1c) >> 2;
 +      frame.audio = *cea;
  
        tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, &frame);
 +
 +      return 0;
  }
  
  static void
@@@ -711,21 -710,20 +711,21 @@@ static void tda998x_audio_mute(struct t
        }
  }
  
 -static void
 +static int
  tda998x_configure_audio(struct tda998x_priv *priv,
 -              struct drm_display_mode *mode, struct tda998x_encoder_params *p)
 +                      struct tda998x_audio_params *params,
 +                      unsigned mode_clock)
  {
        u8 buf[6], clksel_aip, clksel_fs, cts_n, adiv;
        u32 n;
  
        /* Enable audio ports */
 -      reg_write(priv, REG_ENA_AP, p->audio_cfg);
 -      reg_write(priv, REG_ENA_ACLK, p->audio_clk_cfg);
 +      reg_write(priv, REG_ENA_AP, params->config);
  
        /* Set audio input source */
 -      switch (p->audio_format) {
 +      switch (params->format) {
        case AFMT_SPDIF:
 +              reg_write(priv, REG_ENA_ACLK, 0);
                reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_SPDIF);
                clksel_aip = AIP_CLKSEL_AIP_SPDIF;
                clksel_fs = AIP_CLKSEL_FS_FS64SPDIF;
                break;
  
        case AFMT_I2S:
 +              reg_write(priv, REG_ENA_ACLK, 1);
                reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_I2S);
                clksel_aip = AIP_CLKSEL_AIP_I2S;
                clksel_fs = AIP_CLKSEL_FS_ACLK;
 -              cts_n = CTS_N_M(3) | CTS_N_K(3);
 +              switch (params->sample_width) {
 +              case 16:
 +                      cts_n = CTS_N_M(3) | CTS_N_K(1);
 +                      break;
 +              case 18:
 +              case 20:
 +              case 24:
 +                      cts_n = CTS_N_M(3) | CTS_N_K(2);
 +                      break;
 +              default:
 +              case 32:
 +                      cts_n = CTS_N_M(3) | CTS_N_K(3);
 +                      break;
 +              }
                break;
  
        default:
 -              BUG();
 -              return;
 +              dev_err(&priv->hdmi->dev, "Unsupported I2S format\n");
 +              return -EINVAL;
        }
  
        reg_write(priv, REG_AIP_CLKSEL, clksel_aip);
         * assume 100MHz requires larger divider.
         */
        adiv = AUDIO_DIV_SERCLK_8;
 -      if (mode->clock > 100000)
 +      if (mode_clock > 100000)
                adiv++;                 /* AUDIO_DIV_SERCLK_16 */
  
        /* S/PDIF asks for a larger divider */
 -      if (p->audio_format == AFMT_SPDIF)
 +      if (params->format == AFMT_SPDIF)
                adiv++;                 /* AUDIO_DIV_SERCLK_16 or _32 */
  
        reg_write(priv, REG_AUDIO_DIV, adiv);
         * This is the approximate value of N, which happens to be
         * the recommended values for non-coherent clocks.
         */
 -      n = 128 * p->audio_sample_rate / 1000;
 +      n = 128 * params->sample_rate / 1000;
  
        /* Write the CTS and N values */
        buf[0] = 0x44;
        reg_set(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS);
        reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS);
  
 -      /* Write the channel status */
 -      buf[0] = IEC958_AES0_CON_NOT_COPYRIGHT;
 -      buf[1] = 0x00;
 -      buf[2] = IEC958_AES3_CON_FS_NOTID;
 -      buf[3] = IEC958_AES4_CON_ORIGFS_NOTID |
 -                      IEC958_AES4_CON_MAX_WORDLEN_24;
 +      /* Write the channel status
 +       * The REG_CH_STAT_B-registers skip IEC958 AES2 byte, because
 +       * there is a separate register for each I2S wire.
 +       */
 +      buf[0] = params->status[0];
 +      buf[1] = params->status[1];
 +      buf[2] = params->status[3];
 +      buf[3] = params->status[4];
        reg_write_range(priv, REG_CH_STAT_B(0), buf, 4);
  
        tda998x_audio_mute(priv, true);
        msleep(20);
        tda998x_audio_mute(priv, false);
  
 -      /* Write the audio information packet */
 -      tda998x_write_aif(priv, p);
 +      return tda998x_write_aif(priv, &params->cea);
  }
  
  /* DRM encoder functions */
@@@ -837,7 -820,7 +837,7 @@@ static void tda998x_encoder_set_config(
                            VIP_CNTRL_2_SWAP_F(p->swap_f) |
                            (p->mirr_f ? VIP_CNTRL_2_MIRR_F : 0);
  
 -      priv->params = *p;
 +      priv->audio_params = p->audio_params;
  }
  
  static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
@@@ -1074,13 -1057,9 +1074,13 @@@ tda998x_encoder_mode_set(struct drm_enc
  
                tda998x_write_avi(priv, adjusted_mode);
  
 -              if (priv->params.audio_cfg)
 -                      tda998x_configure_audio(priv, adjusted_mode,
 -                                              &priv->params);
 +              if (priv->audio_params.format != AFMT_UNUSED) {
 +                      mutex_lock(&priv->audio_mutex);
 +                      tda998x_configure_audio(priv,
 +                                              &priv->audio_params,
 +                                              adjusted_mode->clock);
 +                      mutex_unlock(&priv->audio_mutex);
 +              }
        }
  }
  
@@@ -1180,8 -1159,6 +1180,8 @@@ static int tda998x_connector_get_modes(
        drm_mode_connector_update_edid_property(connector, edid);
        n = drm_add_edid_modes(connector, edid);
        priv->is_hdmi_sink = drm_detect_hdmi_monitor(edid);
 +      drm_edid_to_eld(connector, edid);
 +
        kfree(edid);
  
        return n;
@@@ -1203,9 -1180,6 +1203,9 @@@ static void tda998x_destroy(struct tda9
        cec_write(priv, REG_CEC_RXSHPDINTENA, 0);
        reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
  
 +      if (priv->audio_pdev)
 +              platform_device_unregister(priv->audio_pdev);
 +
        if (priv->hdmi->irq)
                free_irq(priv->hdmi->irq, priv);
  
        i2c_unregister_device(priv->cec);
  }
  
 +static int tda998x_audio_hw_params(struct device *dev, void *data,
 +                                 struct hdmi_codec_daifmt *daifmt,
 +                                 struct hdmi_codec_params *params)
 +{
 +      struct tda998x_priv *priv = dev_get_drvdata(dev);
 +      int i, ret;
 +      struct tda998x_audio_params audio = {
 +              .sample_width = params->sample_width,
 +              .sample_rate = params->sample_rate,
 +              .cea = params->cea,
 +      };
 +
 +      if (!priv->encoder.crtc)
 +              return -ENODEV;
 +
 +      memcpy(audio.status, params->iec.status,
 +             min(sizeof(audio.status), sizeof(params->iec.status)));
 +
 +      switch (daifmt->fmt) {
 +      case HDMI_I2S:
 +              if (daifmt->bit_clk_inv || daifmt->frame_clk_inv ||
 +                  daifmt->bit_clk_master || daifmt->frame_clk_master) {
 +                      dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__,
 +                              daifmt->bit_clk_inv, daifmt->frame_clk_inv,
 +                              daifmt->bit_clk_master,
 +                              daifmt->frame_clk_master);
 +                      return -EINVAL;
 +              }
 +              for (i = 0; i < ARRAY_SIZE(priv->audio_port); i++)
 +                      if (priv->audio_port[i].format == AFMT_I2S)
 +                              audio.config = priv->audio_port[i].config;
 +              audio.format = AFMT_I2S;
 +              break;
 +      case HDMI_SPDIF:
 +              for (i = 0; i < ARRAY_SIZE(priv->audio_port); i++)
 +                      if (priv->audio_port[i].format == AFMT_SPDIF)
 +                              audio.config = priv->audio_port[i].config;
 +              audio.format = AFMT_SPDIF;
 +              break;
 +      default:
 +              dev_err(dev, "%s: Invalid format %d\n", __func__, daifmt->fmt);
 +              return -EINVAL;
 +      }
 +
 +      if (audio.config == 0) {
 +              dev_err(dev, "%s: No audio configutation found\n", __func__);
 +              return -EINVAL;
 +      }
 +
 +      mutex_lock(&priv->audio_mutex);
 +      ret = tda998x_configure_audio(priv,
 +                                    &audio,
 +                                    priv->encoder.crtc->hwmode.clock);
 +
 +      if (ret == 0)
 +              priv->audio_params = audio;
 +      mutex_unlock(&priv->audio_mutex);
 +
 +      return ret;
 +}
 +
 +static void tda998x_audio_shutdown(struct device *dev, void *data)
 +{
 +      struct tda998x_priv *priv = dev_get_drvdata(dev);
 +
 +      mutex_lock(&priv->audio_mutex);
 +
 +      reg_write(priv, REG_ENA_AP, 0);
 +
 +      priv->audio_params.format = AFMT_UNUSED;
 +
 +      mutex_unlock(&priv->audio_mutex);
 +}
 +
 +int tda998x_audio_digital_mute(struct device *dev, void *data, bool enable)
 +{
 +      struct tda998x_priv *priv = dev_get_drvdata(dev);
 +
 +      mutex_lock(&priv->audio_mutex);
 +
 +      tda998x_audio_mute(priv, enable);
 +
 +      mutex_unlock(&priv->audio_mutex);
 +      return 0;
 +}
 +
 +static int tda998x_audio_get_eld(struct device *dev, void *data,
 +                               uint8_t *buf, size_t len)
 +{
 +      struct tda998x_priv *priv = dev_get_drvdata(dev);
 +      struct drm_mode_config *config = &priv->encoder.dev->mode_config;
 +      struct drm_connector *connector;
 +      int ret = -ENODEV;
 +
 +      mutex_lock(&config->mutex);
 +      list_for_each_entry(connector, &config->connector_list, head) {
 +              if (&priv->encoder == connector->encoder) {
 +                      memcpy(buf, connector->eld,
 +                             min(sizeof(connector->eld), len));
 +                      ret = 0;
 +              }
 +      }
 +      mutex_unlock(&config->mutex);
 +
 +      return ret;
 +}
 +
 +static const struct hdmi_codec_ops audio_codec_ops = {
 +      .hw_params = tda998x_audio_hw_params,
 +      .audio_shutdown = tda998x_audio_shutdown,
 +      .digital_mute = tda998x_audio_digital_mute,
 +      .get_eld = tda998x_audio_get_eld,
 +};
 +
 +static int tda998x_audio_codec_init(struct tda998x_priv *priv,
 +                                  struct device *dev)
 +{
 +      struct hdmi_codec_pdata codec_data = {
 +              .ops = &audio_codec_ops,
 +              .max_i2s_channels = 2,
 +      };
 +      int i;
 +
 +      for (i = 0; i < ARRAY_SIZE(priv->audio_port); i++) {
 +              if (priv->audio_port[i].format == AFMT_I2S &&
 +                  priv->audio_port[i].config != 0)
 +                      codec_data.i2s = 1;
 +              if (priv->audio_port[i].format == AFMT_SPDIF &&
 +                  priv->audio_port[i].config != 0)
 +                      codec_data.spdif = 1;
 +      }
 +
 +      priv->audio_pdev = platform_device_register_data(
 +              dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO,
 +              &codec_data, sizeof(codec_data));
 +
 +      return PTR_ERR_OR_ZERO(priv->audio_pdev);
 +}
 +
  /* I2C driver functions */
  
 +static int tda998x_get_audio_ports(struct tda998x_priv *priv,
 +                                 struct device_node *np)
 +{
 +      const u32 *port_data;
 +      u32 size;
 +      int i;
 +
 +      port_data = of_get_property(np, "audio-ports", &size);
 +      if (!port_data)
 +              return 0;
 +
 +      size /= sizeof(u32);
 +      if (size > 2 * ARRAY_SIZE(priv->audio_port) || size % 2 != 0) {
 +              dev_err(&priv->hdmi->dev,
 +                      "Bad number of elements in audio-ports dt-property\n");
 +              return -EINVAL;
 +      }
 +
 +      size /= 2;
 +
 +      for (i = 0; i < size; i++) {
 +              u8 afmt = be32_to_cpup(&port_data[2*i]);
 +              u8 ena_ap = be32_to_cpup(&port_data[2*i+1]);
 +
 +              if (afmt != AFMT_SPDIF && afmt != AFMT_I2S) {
 +                      dev_err(&priv->hdmi->dev,
 +                              "Bad audio format %u\n", afmt);
 +                      return -EINVAL;
 +              }
 +
 +              priv->audio_port[i].format = afmt;
 +              priv->audio_port[i].config = ena_ap;
 +      }
 +
 +      if (priv->audio_port[0].format == priv->audio_port[1].format) {
 +              dev_err(&priv->hdmi->dev,
 +                      "There can only be on I2S port and one SPDIF port\n");
 +              return -EINVAL;
 +      }
 +      return 0;
 +}
 +
  static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv)
  {
        struct device_node *np = client->dev.of_node;
        if (!np)
                return 0;               /* non-DT */
  
 -      /* get the optional video properties */
 +      /* get the device tree parameters */
        ret = of_property_read_u32(np, "video-ports", &video);
        if (ret == 0) {
                priv->vip_cntrl_0 = video >> 16;
                priv->vip_cntrl_2 = video;
        }
  
 -      return 0;
 +      mutex_init(&priv->audio_mutex); /* Protect access from audio thread */
 +
 +      ret = tda998x_get_audio_ports(priv, np);
 +      if (ret)
 +              goto fail;
  
 +      if (priv->audio_port[0].format != AFMT_UNUSED)
 +              tda998x_audio_codec_init(priv, &client->dev);
 +
 +      return 0;
  fail:
        /* if encoder_init fails, the encoder slave is never registered,
         * so cleanup here:
@@@ -1584,7 -1369,6 +1584,6 @@@ const struct drm_connector_helper_func
  
  static void tda998x_connector_destroy(struct drm_connector *connector)
  {
-       drm_connector_unregister(connector);
        drm_connector_cleanup(connector);
  }
  
@@@ -1656,16 -1440,10 +1655,10 @@@ static int tda998x_bind(struct device *
        if (ret)
                goto err_connector;
  
-       ret = drm_connector_register(&priv->connector);
-       if (ret)
-               goto err_sysfs;
        drm_mode_connector_attach_encoder(&priv->connector, &priv->encoder);
  
        return 0;
  
- err_sysfs:
-       drm_connector_cleanup(&priv->connector);
  err_connector:
        drm_encoder_cleanup(&priv->encoder);
  err_encoder:
@@@ -1678,7 -1456,6 +1671,6 @@@ static void tda998x_unbind(struct devic
  {
        struct tda998x_priv *priv = dev_get_drvdata(dev);
  
-       drm_connector_unregister(&priv->connector);
        drm_connector_cleanup(&priv->connector);
        drm_encoder_cleanup(&priv->encoder);
        tda998x_destroy(priv);