Re: [PATCH v6 2/5] drm: rockchip: add sound support to rk3066 hdmi driver

2021-03-22 Thread Johan Jonker
ping

On 12/6/20 2:33 PM, Johan Jonker wrote:
> From: Zheng Yang 
> 
> Add sound support to the rk3066 HDMI driver.
> 
> The I2S input of the HDMI TX allows transmission of
> DVD-Audio and decoded Dolby Digital
> to A/V Receivers and high-end displays.
> The interface supports 2 to 8 channels audio up to 192 kHz.
> The HDMI TX supports variable word length of
> 16bits to 32bits for I2S audio inputs.(This driver 24bit max)
> There are three I2S input modes supported.(This driver HDMI_I2S only)
> On RK3066/PX2 the HDMI TX audio source is connected to I2S_8CH.
> 
> Signed-off-by: Zheng Yang 
> Signed-off-by: Johan Jonker 
> ---
>  drivers/gpu/drm/rockchip/Kconfig   |   2 +
>  drivers/gpu/drm/rockchip/rk3066_hdmi.c | 277 
> -
>  2 files changed, 278 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/Kconfig 
> b/drivers/gpu/drm/rockchip/Kconfig
> index 310aa1546..4c20445dc 100644
> --- a/drivers/gpu/drm/rockchip/Kconfig
> +++ b/drivers/gpu/drm/rockchip/Kconfig
> @@ -11,6 +11,8 @@ config DRM_ROCKCHIP
>   select DRM_DW_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI
>   select DRM_RGB if ROCKCHIP_RGB
>   select SND_SOC_HDMI_CODEC if ROCKCHIP_CDN_DP && SND_SOC
> + select SND_SOC_HDMI_CODEC if ROCKCHIP_RK3066_HDMI && SND_SOC
> + select SND_SOC_ROCKCHIP_I2S if ROCKCHIP_RK3066_HDMI && SND_SOC
>   help
> Choose this option if you have a Rockchip soc chipset.
> This driver provides kernel mode setting and buffer
> diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c 
> b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
> index 1c546c3a8..2f8654023 100644
> --- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c
> +++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
> @@ -13,6 +13,8 @@
>  #include 
>  #include 
>  
> +#include 
> +
>  #include "rk3066_hdmi.h"
>  
>  #include "rockchip_drm_drv.h"
> @@ -20,9 +22,16 @@
>  
>  #define DEFAULT_PLLA_RATE 3000
>  
> +struct audio_info {
> + int channels;
> + int sample_rate;
> + int sample_width;
> +};
> +
>  struct hdmi_data_info {
>   int vic; /* The CEA Video ID (VIC) of the current drm display mode. */
>   bool sink_is_hdmi;
> + bool sink_has_audio;
>   unsigned int enc_out_format;
>   unsigned int colorimetry;
>  };
> @@ -54,12 +63,19 @@ struct rk3066_hdmi {
>  
>   unsigned int tmdsclk;
>  
> + struct platform_device *audio_pdev;
> + struct audio_info audio;
> + bool audio_enable;
> +
>   struct hdmi_data_info hdmi_data;
>   struct drm_display_mode previous_mode;
>  };
>  
>  #define to_rk3066_hdmi(x) container_of(x, struct rk3066_hdmi, x)
>  
> +static int
> +rk3066_hdmi_config_audio(struct rk3066_hdmi *hdmi, struct audio_info *audio);
> +
>  static inline u8 hdmi_readb(struct rk3066_hdmi *hdmi, u16 offset)
>  {
>   return readl_relaxed(hdmi->regs + offset);
> @@ -205,6 +221,23 @@ static int rk3066_hdmi_config_avi(struct rk3066_hdmi 
> *hdmi,
>   HDMI_INFOFRAME_AVI, 0, 0, 0);
>  }
>  
> +static int rk3066_hdmi_config_aai(struct rk3066_hdmi *hdmi,
> +   struct audio_info *audio)
> +{
> + union hdmi_infoframe frame;
> + int rc;
> +
> + rc = hdmi_audio_infoframe_init();
> +
> + frame.audio.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
> + frame.audio.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM;
> + frame.audio.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
> + frame.audio.channels = hdmi->audio.channels;
> +
> + return rk3066_hdmi_upload_frame(hdmi, rc, ,
> + HDMI_INFOFRAME_AAI, 0, 0, 0);
> +}
> +
>  static int rk3066_hdmi_config_video_timing(struct rk3066_hdmi *hdmi,
>  struct drm_display_mode *mode)
>  {
> @@ -353,6 +386,7 @@ static int rk3066_hdmi_setup(struct rk3066_hdmi *hdmi,
>   hdmi_modb(hdmi, HDMI_HDCP_CTRL, HDMI_VIDEO_MODE_MASK,
> HDMI_VIDEO_MODE_HDMI);
>   rk3066_hdmi_config_avi(hdmi, mode);
> + rk3066_hdmi_config_audio(hdmi, >audio);
>   } else {
>   hdmi_modb(hdmi, HDMI_HDCP_CTRL, HDMI_VIDEO_MODE_MASK, 0);
>   }
> @@ -369,9 +403,20 @@ static int rk3066_hdmi_setup(struct rk3066_hdmi *hdmi,
>*/
>   rk3066_hdmi_i2c_init(hdmi);
>  
> - /* Unmute video output. */
> + /* Unmute video and audio output. */
>   hdmi_modb(hdmi, HDMI_VIDEO_CTRL2,
> HDMI_VIDEO_AUDIO_DISABLE_MASK, HDMI_AUDIO_DISABLE);
> + if (hdmi->audio_enable) {
> + hdmi_modb(hdmi, HDMI_VIDEO_CTRL2, HDMI_AUDIO_DISABLE, 0);
> + /* Reset audio capture logic. */
> + hdmi_modb(hdmi, HDMI_VIDEO_CTRL2,
> +   HDMI_AUDIO_CP_LOGIC_RESET_MASK,
> +   HDMI_AUDIO_CP_LOGIC_RESET);
> + usleep_range(900, 1000);
> + hdmi_modb(hdmi, HDMI_VIDEO_CTRL2,
> +   HDMI_AUDIO_CP_LOGIC_RESET_MASK, 0);

[PATCH v6 2/5] drm: rockchip: add sound support to rk3066 hdmi driver

2020-12-07 Thread Johan Jonker
From: Zheng Yang 

Add sound support to the rk3066 HDMI driver.

The I2S input of the HDMI TX allows transmission of
DVD-Audio and decoded Dolby Digital
to A/V Receivers and high-end displays.
The interface supports 2 to 8 channels audio up to 192 kHz.
The HDMI TX supports variable word length of
16bits to 32bits for I2S audio inputs.(This driver 24bit max)
There are three I2S input modes supported.(This driver HDMI_I2S only)
On RK3066/PX2 the HDMI TX audio source is connected to I2S_8CH.

Signed-off-by: Zheng Yang 
Signed-off-by: Johan Jonker 
---
 drivers/gpu/drm/rockchip/Kconfig   |   2 +
 drivers/gpu/drm/rockchip/rk3066_hdmi.c | 277 -
 2 files changed, 278 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 310aa1546..4c20445dc 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -11,6 +11,8 @@ config DRM_ROCKCHIP
select DRM_DW_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI
select DRM_RGB if ROCKCHIP_RGB
select SND_SOC_HDMI_CODEC if ROCKCHIP_CDN_DP && SND_SOC
+   select SND_SOC_HDMI_CODEC if ROCKCHIP_RK3066_HDMI && SND_SOC
+   select SND_SOC_ROCKCHIP_I2S if ROCKCHIP_RK3066_HDMI && SND_SOC
help
  Choose this option if you have a Rockchip soc chipset.
  This driver provides kernel mode setting and buffer
diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c 
b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
index 1c546c3a8..2f8654023 100644
--- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c
+++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
@@ -13,6 +13,8 @@
 #include 
 #include 
 
+#include 
+
 #include "rk3066_hdmi.h"
 
 #include "rockchip_drm_drv.h"
@@ -20,9 +22,16 @@
 
 #define DEFAULT_PLLA_RATE 3000
 
+struct audio_info {
+   int channels;
+   int sample_rate;
+   int sample_width;
+};
+
 struct hdmi_data_info {
int vic; /* The CEA Video ID (VIC) of the current drm display mode. */
bool sink_is_hdmi;
+   bool sink_has_audio;
unsigned int enc_out_format;
unsigned int colorimetry;
 };
@@ -54,12 +63,19 @@ struct rk3066_hdmi {
 
unsigned int tmdsclk;
 
+   struct platform_device *audio_pdev;
+   struct audio_info audio;
+   bool audio_enable;
+
struct hdmi_data_info hdmi_data;
struct drm_display_mode previous_mode;
 };
 
 #define to_rk3066_hdmi(x) container_of(x, struct rk3066_hdmi, x)
 
+static int
+rk3066_hdmi_config_audio(struct rk3066_hdmi *hdmi, struct audio_info *audio);
+
 static inline u8 hdmi_readb(struct rk3066_hdmi *hdmi, u16 offset)
 {
return readl_relaxed(hdmi->regs + offset);
@@ -205,6 +221,23 @@ static int rk3066_hdmi_config_avi(struct rk3066_hdmi *hdmi,
HDMI_INFOFRAME_AVI, 0, 0, 0);
 }
 
+static int rk3066_hdmi_config_aai(struct rk3066_hdmi *hdmi,
+ struct audio_info *audio)
+{
+   union hdmi_infoframe frame;
+   int rc;
+
+   rc = hdmi_audio_infoframe_init();
+
+   frame.audio.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
+   frame.audio.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM;
+   frame.audio.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
+   frame.audio.channels = hdmi->audio.channels;
+
+   return rk3066_hdmi_upload_frame(hdmi, rc, ,
+   HDMI_INFOFRAME_AAI, 0, 0, 0);
+}
+
 static int rk3066_hdmi_config_video_timing(struct rk3066_hdmi *hdmi,
   struct drm_display_mode *mode)
 {
@@ -353,6 +386,7 @@ static int rk3066_hdmi_setup(struct rk3066_hdmi *hdmi,
hdmi_modb(hdmi, HDMI_HDCP_CTRL, HDMI_VIDEO_MODE_MASK,
  HDMI_VIDEO_MODE_HDMI);
rk3066_hdmi_config_avi(hdmi, mode);
+   rk3066_hdmi_config_audio(hdmi, >audio);
} else {
hdmi_modb(hdmi, HDMI_HDCP_CTRL, HDMI_VIDEO_MODE_MASK, 0);
}
@@ -369,9 +403,20 @@ static int rk3066_hdmi_setup(struct rk3066_hdmi *hdmi,
 */
rk3066_hdmi_i2c_init(hdmi);
 
-   /* Unmute video output. */
+   /* Unmute video and audio output. */
hdmi_modb(hdmi, HDMI_VIDEO_CTRL2,
  HDMI_VIDEO_AUDIO_DISABLE_MASK, HDMI_AUDIO_DISABLE);
+   if (hdmi->audio_enable) {
+   hdmi_modb(hdmi, HDMI_VIDEO_CTRL2, HDMI_AUDIO_DISABLE, 0);
+   /* Reset audio capture logic. */
+   hdmi_modb(hdmi, HDMI_VIDEO_CTRL2,
+ HDMI_AUDIO_CP_LOGIC_RESET_MASK,
+ HDMI_AUDIO_CP_LOGIC_RESET);
+   usleep_range(900, 1000);
+   hdmi_modb(hdmi, HDMI_VIDEO_CTRL2,
+ HDMI_AUDIO_CP_LOGIC_RESET_MASK, 0);
+   }
+
return 0;
 }
 
@@ -473,9 +518,13 @@ static int rk3066_hdmi_connector_get_modes(struct 
drm_connector *connector)
edid = drm_get_edid(connector, hdmi->ddc);
if (edid) {