drm/rockchip: analogix_dp: Add audio support

Change-Id: Ib611037f497a0758bd2b6a312155562a719fe15f
Signed-off-by: Wyon Bi <bivvy.bi@rock-chips.com>
This commit is contained in:
Wyon Bi
2020-11-17 08:32:58 +08:00
committed by Tao Huang
parent 17e3503627
commit 962c917b1d
6 changed files with 186 additions and 2 deletions

View File

@@ -1499,6 +1499,48 @@ static ssize_t analogix_dpaux_transfer(struct drm_dp_aux *aux,
return analogix_dp_transfer(dp, msg);
}
int analogix_dp_audio_hw_params(struct analogix_dp_device *dp,
struct hdmi_codec_daifmt *daifmt,
struct hdmi_codec_params *params)
{
switch (daifmt->fmt) {
case HDMI_SPDIF:
analogix_dp_audio_config_spdif(dp);
break;
case HDMI_I2S:
analogix_dp_audio_config_i2s(dp);
break;
default:
DRM_DEV_ERROR(dp->dev, "invalid daifmt %d\n", daifmt->fmt);
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL_GPL(analogix_dp_audio_hw_params);
void analogix_dp_audio_shutdown(struct analogix_dp_device *dp)
{
analogix_dp_audio_disable(dp);
}
EXPORT_SYMBOL_GPL(analogix_dp_audio_shutdown);
int analogix_dp_audio_startup(struct analogix_dp_device *dp)
{
analogix_dp_audio_enable(dp);
return 0;
}
EXPORT_SYMBOL_GPL(analogix_dp_audio_enable);
int analogix_dp_audio_get_eld(struct analogix_dp_device *dp, u8 *buf, size_t len)
{
memcpy(buf, dp->connector.eld, min(sizeof(dp->connector.eld), len));
return 0;
}
EXPORT_SYMBOL_GPL(analogix_dp_audio_get_eld);
struct analogix_dp_device *
analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
struct analogix_dp_plat_data *plat_data)

View File

@@ -252,5 +252,9 @@ void analogix_dp_video_bist_enable(struct analogix_dp_device *dp);
bool analogix_dp_ssc_supported(struct analogix_dp_device *dp);
void analogix_dp_phy_power_on(struct analogix_dp_device *dp);
void analogix_dp_phy_power_off(struct analogix_dp_device *dp);
void analogix_dp_audio_config_spdif(struct analogix_dp_device *dp);
void analogix_dp_audio_config_i2s(struct analogix_dp_device *dp);
void analogix_dp_audio_enable(struct analogix_dp_device *dp);
void analogix_dp_audio_disable(struct analogix_dp_device *dp);
#endif /* _ANALOGIX_DP_CORE_H */

View File

@@ -1320,3 +1320,53 @@ void analogix_dp_video_bist_enable(struct analogix_dp_device *dp)
reg &= ~FORMAT_SEL;
analogix_dp_write(dp, ANALOGIX_DP_VIDEO_CTL_10, reg);
}
void analogix_dp_audio_config_i2s(struct analogix_dp_device *dp)
{
u32 reg;
reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_4);
reg &= ~FIX_M_AUD;
analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_4, reg);
reg = analogix_dp_read(dp, ANALOGIX_DP_I2S_CTRL);
reg |= I2S_EN;
analogix_dp_write(dp, ANALOGIX_DP_I2S_CTRL, reg);
}
void analogix_dp_audio_config_spdif(struct analogix_dp_device *dp)
{
u32 reg;
reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_4);
reg &= ~FIX_M_AUD;
analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_4, reg);
reg = analogix_dp_read(dp, ANALOGIX_DP_SPDIF_AUDIO_CTL_0);
reg |= AUD_SPDIF_EN;
analogix_dp_write(dp, ANALOGIX_DP_SPDIF_AUDIO_CTL_0, reg);
}
void analogix_dp_audio_enable(struct analogix_dp_device *dp)
{
u32 reg;
reg = analogix_dp_read(dp, ANALOGIX_DP_FUNC_EN_1);
reg &= ~(AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N);
analogix_dp_write(dp, ANALOGIX_DP_FUNC_EN_1, reg);
reg = analogix_dp_read(dp, ANALOGIX_DP_AUD_CTL);
reg |= MISC_CTRL_RESET | DP_AUDIO_EN;
analogix_dp_write(dp, ANALOGIX_DP_AUD_CTL, reg);
}
void analogix_dp_audio_disable(struct analogix_dp_device *dp)
{
u32 reg;
analogix_dp_write(dp, ANALOGIX_DP_AUD_CTL, 0);
reg = analogix_dp_read(dp, ANALOGIX_DP_FUNC_EN_1);
reg |= AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N;
analogix_dp_write(dp, ANALOGIX_DP_FUNC_EN_1, reg);
}

View File

@@ -91,7 +91,7 @@
#define ANALOGIX_DP_SYS_CTL_2 0x604
#define ANALOGIX_DP_SYS_CTL_3 0x608
#define ANALOGIX_DP_SYS_CTL_4 0x60C
#define ANALOGIX_DP_AUD_CTL 0x618
#define ANALOGIX_DP_PKT_SEND_CTL 0x640
#define ANALOGIX_DP_HDCP_CTL 0x648
@@ -137,8 +137,9 @@
#define ANALOGIX_DP_BUF_DATA_0 0x7C0
#define ANALOGIX_DP_SOC_GENERAL_CTL 0x800
#define ANALOGIX_DP_AUD_CHANNEL_CTL 0x834
#define ANALOGIX_DP_CRC_CON 0x890
#define ANALOGIX_DP_I2S_CTRL 0x9C8
/* ANALOGIX_DP_TX_SW_RESET */
#define RESET_DP_TX (0x1 << 0)
@@ -258,6 +259,9 @@
/* ANALOGIX_DP_H_B_PORCH_CFG_H */
#define H_B_PORCH_CFG_H(x) (((x) & 0xf) << 0)
/* ANALOGIX_DP_SPDIF_AUDIO_CTL_0 */
#define AUD_SPDIF_EN (0x1 << 7)
/* ANALOGIX_DP_PLL_REG_1 */
#define REF_CLK_24M (0x1 << 0)
#define REF_CLK_27M (0x0 << 0)
@@ -386,6 +390,10 @@
#define FIX_M_VID (0x1 << 2)
#define M_VID_UPDATE_CTRL (0x3 << 0)
/* ANALOGIX_DP_AUD_CTL */
#define MISC_CTRL_RESET (0x1 << 4)
#define DP_AUDIO_EN (0x1 << 0)
/* ANALOGIX_DP_TRAINING_PTN_SET */
#define SCRAMBLER_TYPE (0x1 << 9)
#define HW_LINK_TRAINING_PATTERN (0x1 << 8)
@@ -483,6 +491,11 @@
#define VIDEO_MODE_SLAVE_MODE (0x1 << 0)
#define VIDEO_MODE_MASTER_MODE (0x0 << 0)
/* ANALOGIX_DP_AUD_CHANNEL_CTL */
#define AUD_CHANNEL_COUNT_6 (0x5 << 0)
#define AUD_CHANNEL_COUNT_4 (0x3 << 0)
#define AUD_CHANNEL_COUNT_2 (0x1 << 0)
/* ANALOGIX_DP_PKT_SEND_CTL */
#define IF_UP (0x1 << 4)
#define IF_EN (0x1 << 0)
@@ -491,4 +504,7 @@
#define PSR_VID_CRC_FLUSH (0x1 << 2)
#define PSR_VID_CRC_ENABLE (0x1 << 0)
/* ANALOGIX_DP_I2S_CTRL */
#define I2S_EN (0x1 << 4)
#endif /* _ANALOGIX_DP_REG_H */

View File

@@ -57,6 +57,7 @@
* @lcdsel_lit: reg value of selecting vop little for eDP
* @chip_type: specific chip type
* @ssc: check if SSC is supported by source
* @audio: check if audio is supported by source
*/
struct rockchip_dp_chip_data {
u32 lcdsel_grf_reg;
@@ -64,6 +65,7 @@ struct rockchip_dp_chip_data {
u32 lcdsel_lit;
u32 chip_type;
bool ssc;
bool audio;
};
struct rockchip_dp_device {
@@ -80,6 +82,7 @@ struct rockchip_dp_device {
struct regulator *vcc_supply;
struct regulator *vccio_supply;
struct platform_device *audio_pdev;
const struct rockchip_dp_chip_data *data;
struct analogix_dp_device *adp;
@@ -87,6 +90,44 @@ struct rockchip_dp_device {
struct rockchip_drm_sub_dev sub_dev;
};
static int rockchip_dp_audio_hw_params(struct device *dev, void *data,
struct hdmi_codec_daifmt *daifmt,
struct hdmi_codec_params *params)
{
struct rockchip_dp_device *dp = dev_get_drvdata(dev);
return analogix_dp_audio_hw_params(dp->adp, daifmt, params);
}
static void rockchip_dp_audio_shutdown(struct device *dev, void *data)
{
struct rockchip_dp_device *dp = dev_get_drvdata(dev);
analogix_dp_audio_shutdown(dp->adp);
}
static int rockchip_dp_audio_startup(struct device *dev, void *data)
{
struct rockchip_dp_device *dp = dev_get_drvdata(dev);
return analogix_dp_audio_startup(dp->adp);
}
static int rockchip_dp_audio_get_eld(struct device *dev, void *data,
u8 *buf, size_t len)
{
struct rockchip_dp_device *dp = dev_get_drvdata(dev);
return analogix_dp_audio_get_eld(dp->adp, buf, len);
}
static const struct hdmi_codec_ops rockchip_dp_audio_codec_ops = {
.hw_params = rockchip_dp_audio_hw_params,
.audio_startup = rockchip_dp_audio_startup,
.audio_shutdown = rockchip_dp_audio_shutdown,
.get_eld = rockchip_dp_audio_get_eld,
};
static int analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
{
struct rockchip_dp_device *dp = to_dp(encoder);
@@ -439,6 +480,25 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
goto err_unreg_psr;
}
if (dp->data->audio) {
struct hdmi_codec_pdata codec_data = {
.ops = &rockchip_dp_audio_codec_ops,
.spdif = 1,
.i2s = 1,
.max_i2s_channels = 2,
};
dp->audio_pdev =
platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
PLATFORM_DEVID_AUTO,
&codec_data,
sizeof(codec_data));
if (IS_ERR(dp->audio_pdev)) {
ret = PTR_ERR(dp->audio_pdev);
goto err_unreg_psr;
}
}
dp->sub_dev.connector = &dp->adp->connector;
dp->sub_dev.of_node = dev->of_node;
rockchip_drm_register_sub_dev(&dp->sub_dev);
@@ -457,6 +517,8 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
struct rockchip_dp_device *dp = dev_get_drvdata(dev);
rockchip_drm_unregister_sub_dev(&dp->sub_dev);
if (dp->audio_pdev)
platform_device_unregister(dp->audio_pdev);
analogix_dp_unbind(dp->adp);
rockchip_drm_psr_unregister(&dp->encoder);
dp->encoder.funcs->destroy(&dp->encoder);
@@ -572,6 +634,7 @@ static const struct rockchip_dp_chip_data rk3288_dp = {
static const struct rockchip_dp_chip_data rk3568_edp = {
.chip_type = RK3568_EDP,
.ssc = true,
.audio = true,
};
static const struct of_device_id rockchip_dp_dt_ids[] = {

View File

@@ -12,6 +12,7 @@
#define _ANALOGIX_DP_H_
#include <drm/drm_crtc.h>
#include <sound/hdmi-codec.h>
struct analogix_dp_device;
@@ -68,4 +69,12 @@ void analogix_dp_unbind(struct analogix_dp_device *dp);
int analogix_dp_start_crc(struct drm_connector *connector);
int analogix_dp_stop_crc(struct drm_connector *connector);
int analogix_dp_audio_hw_params(struct analogix_dp_device *dp,
struct hdmi_codec_daifmt *daifmt,
struct hdmi_codec_params *params);
void analogix_dp_audio_shutdown(struct analogix_dp_device *dp);
int analogix_dp_audio_startup(struct analogix_dp_device *dp);
int analogix_dp_audio_get_eld(struct analogix_dp_device *dp,
u8 *buf, size_t len);
#endif /* _ANALOGIX_DP_H_ */