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 ada06fcdb5
commit 0d0f8a70ae
6 changed files with 186 additions and 2 deletions

View File

@@ -1600,6 +1600,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_startup);
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_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
{

View File

@@ -249,5 +249,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

@@ -1228,3 +1228,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

@@ -88,7 +88,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
@@ -134,8 +134,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)
@@ -255,6 +256,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)
@@ -383,6 +387,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)
@@ -480,6 +488,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)
@@ -488,4 +501,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

@@ -50,6 +50,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;
@@ -57,6 +58,7 @@ struct rockchip_dp_chip_data {
u32 lcdsel_lit;
u32 chip_type;
bool ssc;
bool audio;
};
struct rockchip_dp_device {
@@ -69,12 +71,51 @@ struct rockchip_dp_device {
struct reset_control *rst;
struct reset_control *apb_reset;
struct platform_device *audio_pdev;
const struct rockchip_dp_chip_data *data;
struct analogix_dp_device *adp;
struct analogix_dp_plat_data plat_data;
};
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 rockchip_dp_pre_init(struct rockchip_dp_device *dp)
{
reset_control_assert(dp->rst);
@@ -331,6 +372,25 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
if (ret)
goto err_cleanup_encoder;
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_cleanup_encoder;
}
}
return 0;
err_cleanup_encoder:
dp->encoder.funcs->destroy(&dp->encoder);
@@ -342,6 +402,8 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
{
struct rockchip_dp_device *dp = dev_get_drvdata(dev);
if (dp->audio_pdev)
platform_device_unregister(dp->audio_pdev);
analogix_dp_unbind(dp->adp);
dp->encoder.funcs->destroy(&dp->encoder);
}
@@ -446,6 +508,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

@@ -8,6 +8,7 @@
#define _ANALOGIX_DP_H_
#include <drm/drm_crtc.h>
#include <sound/hdmi-codec.h>
struct analogix_dp_device;
@@ -59,4 +60,12 @@ void analogix_dp_remove(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_ */