From 1a2cbb05f9edfcfe189d107d1d6bd7126f8e6bdf Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Mon, 26 Feb 2018 15:12:32 +0800 Subject: MLK-17620-1: hdp: register generic hdmi codec driver Register generic hdmi codec driver, and move audio related code to an independent file. Signed-off-by: Shengjiu Wang Reviewed-by: Daniel Baluta Reviewed-by: Sandor Yu --- drivers/gpu/drm/imx/hdp/Makefile | 3 +- drivers/gpu/drm/imx/hdp/imx-hdp-audio.c | 212 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/imx/hdp/imx-hdp.c | 115 +---------------- drivers/gpu/drm/imx/hdp/imx-hdp.h | 2 +- 4 files changed, 218 insertions(+), 114 deletions(-) create mode 100644 drivers/gpu/drm/imx/hdp/imx-hdp-audio.c diff --git a/drivers/gpu/drm/imx/hdp/Makefile b/drivers/gpu/drm/imx/hdp/Makefile index 20bdab899cef..d289e041492a 100644 --- a/drivers/gpu/drm/imx/hdp/Makefile +++ b/drivers/gpu/drm/imx/hdp/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_DRM_IMX_HDP) += imx-hdp.o \ API_AFE_ss28fdsoi_kiran_hdmitx.o \ API_AFE_t28hpc_hdmitx.o \ ss28fdsoi_hdmitx_table.o \ - API_AFE_mcu1_dp.o + API_AFE_mcu1_dp.o \ + imx-hdp-audio.o obj-$(CONFIG_IMX_HDP_CEC) += imx-cec.o \ diff --git a/drivers/gpu/drm/imx/hdp/imx-hdp-audio.c b/drivers/gpu/drm/imx/hdp/imx-hdp-audio.c new file mode 100644 index 000000000000..afc5c6b79286 --- /dev/null +++ b/drivers/gpu/drm/imx/hdp/imx-hdp-audio.c @@ -0,0 +1,212 @@ +/* + * Copyright 2018 NXP + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "imx-hdp.h" +#include "imx-hdmi.h" +#include "imx-dp.h" +#include "../imx-drm.h" + +static u32 TMDS_rate_table[7] = { +25200, 27000, 54000, 74250, 148500, 297000, 594000, +}; + +static u32 N_table_32k[8] = { +/*25200, 27000, 54000, 74250, 148500, 297000, 594000,*/ +4096, 4096, 4096, 4096, 4096, 3072, 3072, 4096, +}; + +static u32 N_table_44k[8] = { +6272, 6272, 6272, 6272, 6272, 4704, 9408, 6272, +}; + +static u32 N_table_48k[8] = { +6144, 6144, 6144, 6144, 6144, 5120, 6144, 6144, +}; + +static int select_N_index(int vmode_index) +{ + + int i = 0, j = 0; + + for (i = 0; i < VIC_MODE_COUNT; i++) { + if (vic_table[i][23] == vmode_index) + break; + } + + if (i == VIC_MODE_COUNT) { + DRM_ERROR("vmode is wrong!\n"); + j = 7; + return j; + } + + for (j = 0; j < 7; j++) { + if (vic_table[i][13] == TMDS_rate_table[j]) + break; + } + + return j; +} + +static u32 imx_hdp_audio(struct imx_hdp *hdmi, AUDIO_TYPE type, u32 sample_rate, u32 channels, u32 width) +{ + AUDIO_FREQ freq; + AUDIO_WIDTH bits; + int ncts_n; + state_struct *state = &hdmi->state; + int idx_n = select_N_index(hdmi->vic); + + switch (sample_rate) { + case 32000: + freq = AUDIO_FREQ_32; + ncts_n = N_table_32k[idx_n]; + break; + case 44100: + freq = AUDIO_FREQ_44_1; + ncts_n = N_table_44k[idx_n]; + break; + case 48000: + freq = AUDIO_FREQ_48; + ncts_n = N_table_48k[idx_n]; + break; + case 88200: + freq = AUDIO_FREQ_88_2; + ncts_n = N_table_44k[idx_n] * 2; + break; + case 96000: + freq = AUDIO_FREQ_96; + ncts_n = N_table_48k[idx_n] * 2; + break; + case 176400: + freq = AUDIO_FREQ_176_4; + ncts_n = N_table_44k[idx_n] * 4; + break; + case 192000: + freq = AUDIO_FREQ_192; + ncts_n = N_table_48k[idx_n] * 4; + break; + default: + return -EINVAL; + } + + switch (width) { + case 16: + bits = AUDIO_WIDTH_16; + break; + case 24: + bits = AUDIO_WIDTH_24; + break; + case 32: + bits = AUDIO_WIDTH_32; + break; + default: + return -EINVAL; + } + + + CDN_API_AudioOff_blocking(state, type); + CDN_API_AudioAutoConfig_blocking(state, + type, + channels, + freq, + 0, + bits, + hdmi->audio_type, + ncts_n, + AUDIO_MUTE_MODE_UNMUTE); + return 0; +} + +/* + * HDMI audio codec callbacks + */ +static int imx_hdp_audio_hw_params(struct device *dev, void *data, + struct hdmi_codec_daifmt *daifmt, + struct hdmi_codec_params *params) +{ + struct imx_hdp *hdmi = dev_get_drvdata(dev); + unsigned int chan = params->cea.channels; + + dev_dbg(hdmi->dev, "%s: %u Hz, %d bit, %d channels\n", __func__, + params->sample_rate, params->sample_width, chan); + + if (!hdmi->bridge.encoder) + return -ENODEV; + + if (daifmt->fmt == HDMI_I2S) + imx_hdp_audio(hdmi, + AUDIO_TYPE_I2S, + params->sample_rate, + chan, + params->sample_width); + else if (daifmt->fmt == HDMI_SPDIF) + imx_hdp_audio(hdmi, + AUDIO_TYPE_SPIDIF_EXTERNAL, + params->sample_rate, + chan, + params->sample_width); + else + return -EINVAL; + + return 0; +} + +static void imx_hdp_audio_shutdown(struct device *dev, void *data) +{ +} + +static int imx_hdp_audio_get_eld(struct device *dev, void *data, uint8_t *buf, size_t len) +{ + struct imx_hdp *hdmi = dev_get_drvdata(dev); + + memcpy(buf, hdmi->connector.eld, min(sizeof(hdmi->connector.eld), len)); + + return 0; +} + +static const struct hdmi_codec_ops imx_hdp_audio_codec_ops = { + .hw_params = imx_hdp_audio_hw_params, + .audio_shutdown = imx_hdp_audio_shutdown, + .get_eld = imx_hdp_audio_get_eld, +}; + +void imx_hdp_register_audio_driver(struct device *dev) +{ + struct hdmi_codec_pdata codec_data = { + .ops = &imx_hdp_audio_codec_ops, + .max_i2s_channels = 8, + .i2s = 1, + }; + struct platform_device *pdev; + + pdev = platform_device_register_data(dev, HDMI_CODEC_DRV_NAME, + PLATFORM_DEVID_NONE, &codec_data, + sizeof(codec_data)); + if (IS_ERR(pdev)) + return; + + DRM_INFO("%s driver bound to HDMI\n", HDMI_CODEC_DRV_NAME); +} + + diff --git a/drivers/gpu/drm/imx/hdp/imx-hdp.c b/drivers/gpu/drm/imx/hdp/imx-hdp.c index 3a9f9cbe4618..ccf568775ee5 100644 --- a/drivers/gpu/drm/imx/hdp/imx-hdp.c +++ b/drivers/gpu/drm/imx/hdp/imx-hdp.c @@ -26,7 +26,6 @@ #include "imx-dp.h" #include "../imx-drm.h" -struct imx_hdp *g_hdp; struct drm_display_mode *g_mode; static const struct drm_display_mode edid_cea_modes[] = { @@ -64,116 +63,6 @@ static inline struct imx_hdp *enc_to_imx_hdp(struct drm_encoder *e) return container_of(e, struct imx_hdp, encoder); } -static u32 TMDS_rate_table[7] = { -25200, 27000, 54000, 74250, 148500, 297000, 594000, -}; - -static u32 N_table_32k[8] = { -/*25200, 27000, 54000, 74250, 148500, 297000, 594000,*/ -4096, 4096, 4096, 4096, 4096, 3072, 3072, 4096, -}; - -static u32 N_table_44k[8] = { -6272, 6272, 6272, 6272, 6272, 4704, 9408, 6272, -}; - -static u32 N_table_48k[8] = { -6144, 6144, 6144, 6144, 6144, 5120, 6144, 6144, -}; - -static int select_N_index(int vmode_index) -{ - - int i = 0, j = 0; - - for (i = 0; i < VIC_MODE_COUNT; i++) { - if (vic_table[i][23] == vmode_index) - break; - } - - if (i == VIC_MODE_COUNT) { - DRM_ERROR("vmode is wrong!\n"); - j = 7; - return j; - } - - for (j = 0; j < 7; j++) { - if (vic_table[i][13] == TMDS_rate_table[j]) - break; - } - - return j; -} - -u32 imx_hdp_audio(AUDIO_TYPE type, u32 sample_rate, u32 channels, u32 width) -{ - AUDIO_FREQ freq; - AUDIO_WIDTH bits; - int ncts_n; - state_struct *state = &g_hdp->state; - int idx_n = select_N_index(g_hdp->vic); - - switch (sample_rate) { - case 32000: - freq = AUDIO_FREQ_32; - ncts_n = N_table_32k[idx_n]; - break; - case 44100: - freq = AUDIO_FREQ_44_1; - ncts_n = N_table_44k[idx_n]; - break; - case 48000: - freq = AUDIO_FREQ_48; - ncts_n = N_table_48k[idx_n]; - break; - case 88200: - freq = AUDIO_FREQ_88_2; - ncts_n = N_table_44k[idx_n] * 2; - break; - case 96000: - freq = AUDIO_FREQ_96; - ncts_n = N_table_48k[idx_n] * 2; - break; - case 176400: - freq = AUDIO_FREQ_176_4; - ncts_n = N_table_44k[idx_n] * 4; - break; - case 192000: - freq = AUDIO_FREQ_192; - ncts_n = N_table_48k[idx_n] * 4; - break; - default: - return -EINVAL; - } - - switch (width) { - case 16: - bits = AUDIO_WIDTH_16; - break; - case 24: - bits = AUDIO_WIDTH_24; - break; - case 32: - bits = AUDIO_WIDTH_32; - break; - default: - return -EINVAL; - } - - - CDN_API_AudioOff_blocking(state, type); - CDN_API_AudioAutoConfig_blocking(state, - type, - channels, - freq, - 0, - bits, - g_hdp->audio_type, - ncts_n, - AUDIO_MUTE_MODE_UNMUTE); - return 0; -} - static void imx_hdp_state_init(struct imx_hdp *hdp) { state_struct *state = &hdp->state; @@ -1043,7 +932,6 @@ static int imx_hdp_imx_bind(struct device *dev, struct device *master, bridge = &hdp->bridge; connector = &hdp->connector; - g_hdp = hdp; mutex_init(&hdp->mutex); hdp->irq[HPD_IRQ_IN] = platform_get_irq_byname(pdev, "plug_in"); @@ -1140,6 +1028,7 @@ static int imx_hdp_imx_bind(struct device *dev, struct device *master, DRM_MODE_ENCODER_TMDS, NULL); /* bridge */ + bridge->encoder = encoder; bridge->driver_private = hdp; bridge->funcs = &imx_hdp_bridge_funcs; ret = drm_bridge_attach(encoder, bridge, NULL); @@ -1202,6 +1091,8 @@ static int imx_hdp_imx_bind(struct device *dev, struct device *master, imx_cec_register(&hdp->cec); #endif + imx_hdp_register_audio_driver(dev); + return 0; err_irq: drm_encoder_cleanup(encoder); diff --git a/drivers/gpu/drm/imx/hdp/imx-hdp.h b/drivers/gpu/drm/imx/hdp/imx-hdp.h index d2bb902ac970..7b5cfd8bd9f2 100644 --- a/drivers/gpu/drm/imx/hdp/imx-hdp.h +++ b/drivers/gpu/drm/imx/hdp/imx-hdp.h @@ -225,7 +225,7 @@ struct imx_hdp { struct imx_cec_dev cec; }; -u32 imx_hdp_audio(AUDIO_TYPE type, u32 sample_rate, u32 channels, u32 width); +void imx_hdp_register_audio_driver(struct device *dev); void imx_arc_power_up(state_struct *state); void imx_arc_calibrate(state_struct *state); void imx_arc_config(state_struct *state); -- cgit v1.2.3