From 46e3e82a547b78ca5db11a8444f787fd15f8e8ce Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Wed, 7 Sep 2016 14:30:21 +0800 Subject: [PATCH] UPSTREAM: ASoC: rockchip: spdif: restore register during runtime_suspend/resume cycle when step into runtime_suspend, spdif pd will be disabled and loss state. so need to restore register when runtime_resume. Signed-off-by: Sugar Zhang Signed-off-by: Mark Brown (cherry picked from commit 3628c6987fb45d719cd963805bbba9f15017290e) --- sound/soc/rockchip/rockchip_spdif.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c index 784941ca2408..831e4caf29d3 100644 --- a/sound/soc/rockchip/rockchip_spdif.c +++ b/sound/soc/rockchip/rockchip_spdif.c @@ -69,6 +69,7 @@ static int __maybe_unused rk_spdif_runtime_suspend(struct device *dev) { struct rk_spdif_dev *spdif = dev_get_drvdata(dev); + regcache_cache_only(spdif->regmap, true); clk_disable_unprepare(spdif->mclk); clk_disable_unprepare(spdif->hclk); @@ -92,7 +93,16 @@ static int __maybe_unused rk_spdif_runtime_resume(struct device *dev) return ret; } - return 0; + regcache_cache_only(spdif->regmap, false); + regcache_mark_dirty(spdif->regmap); + + ret = regcache_sync(spdif->regmap); + if (ret) { + clk_disable_unprepare(spdif->mclk); + clk_disable_unprepare(spdif->hclk); + } + + return ret; } static int rk_spdif_hw_params(struct snd_pcm_substream *substream, From d8a8c9964022565ecf7b5ea7249262c3ac381a1b Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Tue, 3 Jan 2017 16:52:50 +0100 Subject: [PATCH] UPSTREAM: DRM: add help to get ELD speaker allocation Add helper to allow users to retrieve the speaker allocations without knowledge of the ELD structure. Signed-off-by: Arnaud Pouliquen Reviewed-by: Jani Nikula Signed-off-by: Mark Brown (cherry picked from commit c82dbe5c055e4d246bd07c4d7b24801c9445c241) --- include/drm/drm_edid.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 85861b63e77a..55201e7e2ede 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -254,6 +254,7 @@ struct detailed_timing { # define DRM_ELD_AUD_SYNCH_DELAY_MAX 0xfa /* 500 ms */ #define DRM_ELD_SPEAKER 7 +# define DRM_ELD_SPEAKER_MASK 0x7f # define DRM_ELD_SPEAKER_RLRC (1 << 6) # define DRM_ELD_SPEAKER_FLRC (1 << 5) # define DRM_ELD_SPEAKER_RC (1 << 4) @@ -417,6 +418,18 @@ static inline int drm_eld_size(const uint8_t *eld) return DRM_ELD_HEADER_BLOCK_SIZE + eld[DRM_ELD_BASELINE_ELD_LEN] * 4; } +/** + * drm_eld_get_spk_alloc - Get speaker allocation + * @eld: pointer to an ELD memory structure + * + * The returned value is the speakers mask. User has to use %DRM_ELD_SPEAKER + * field definitions to identify speakers. + */ +static inline u8 drm_eld_get_spk_alloc(const uint8_t *eld) +{ + return eld[DRM_ELD_SPEAKER] & DRM_ELD_SPEAKER_MASK; +} + struct edid *drm_do_get_edid(struct drm_connector *connector, int (*get_edid_block)(void *data, u8 *buf, unsigned int block, size_t len), From e622344ce58345eda1ce7372bf7e91e4e90ece5f Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Tue, 3 Jan 2017 16:52:51 +0100 Subject: [PATCH] UPSTREAM: ASoC: core: add optional pcm_new callback for DAI driver During probe, DAIs can need to perform some actions that requests the knowledge of the pcm runtime handle. The callback is called during DAIs linking, after PCM device creation. For instance this can be used to add relationship between a DAI pcm control and the pcm device. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown (cherry picked from commit 25f7b701c20db3e9ae09e28dd652949bd977e5cd) --- include/sound/soc-dai.h | 3 +++ sound/soc/soc-core.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 212eaaf172ed..345e4f8ee93f 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -230,6 +230,9 @@ struct snd_soc_dai_driver { int (*resume)(struct snd_soc_dai *dai); /* compress dai */ int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num); + /* Optional Callback used at pcm creation*/ + int (*pcm_new)(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_dai *dai); /* DAI is also used for the control bus */ bool bus_control; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3c6713da3ad9..e46e80c0e07d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1289,6 +1289,27 @@ static int soc_probe_dai(struct snd_soc_dai *dai, int order) return 0; } +static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, + struct snd_soc_pcm_runtime *rtd) +{ + int i, ret = 0; + + for (i = 0; i < num_dais; ++i) { + struct snd_soc_dai_driver *drv = dais[i]->driver; + + if (!rtd->dai_link->no_pcm && drv->pcm_new) + ret = drv->pcm_new(rtd, dais[i]); + if (ret < 0) { + dev_err(dais[i]->dev, + "ASoC: Failed to bind %s with pcm device\n", + dais[i]->name); + return ret; + } + } + + return 0; +} + static int soc_link_dai_widgets(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link, struct snd_soc_pcm_runtime *rtd) @@ -1400,6 +1421,13 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) dai_link->stream_name, ret); return ret; } + ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd); + if (ret < 0) + return ret; + ret = soc_link_dai_pcm_new(rtd->codec_dais, + rtd->num_codecs, rtd); + if (ret < 0) + return ret; } else { INIT_DELAYED_WORK(&rtd->delayed_work, codec2codec_close_delayed_work); From 3877e4beac5a5efc2898185fe75555e21cf6b090 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Tue, 3 Jan 2017 16:52:52 +0100 Subject: [PATCH] UPSTREAM: ASoC: hdmi-codec: add channel mapping control Add user interface to provide channel mapping. In a first step this control is read only. As TLV type, the control provides all configuration available for HDMI sink(ELD), and provides current channel mapping selected by codec based on ELD and number of channels specified by user on open. When control is called before the number of the channel is specified (i.e. hw_params is set), it returns all channels set to UNKNOWN. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown (cherry picked from commit cd6111b26280a2f38a9fb8e6630c63a96477e4bf) --- sound/soc/codecs/hdmi-codec.c | 377 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 376 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 028d60c196ae..cb78d8971b41 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -21,12 +21,264 @@ #include #include #include +#include #include #include #include #include /* This is only to get MAX_ELD_BYTES */ +#define HDMI_CODEC_CHMAP_IDX_UNKNOWN -1 + +struct hdmi_codec_channel_map_table { + unsigned char map; /* ALSA API channel map position */ + unsigned long spk_mask; /* speaker position bit mask */ +}; + +/* + * CEA speaker placement for HDMI 1.4: + * + * FL FLC FC FRC FR FRW + * + * LFE + * + * RL RLC RC RRC RR + * + * Speaker placement has to be extended to support HDMI 2.0 + */ +enum hdmi_codec_cea_spk_placement { + FL = BIT(0), /* Front Left */ + FC = BIT(1), /* Front Center */ + FR = BIT(2), /* Front Right */ + FLC = BIT(3), /* Front Left Center */ + FRC = BIT(4), /* Front Right Center */ + RL = BIT(5), /* Rear Left */ + RC = BIT(6), /* Rear Center */ + RR = BIT(7), /* Rear Right */ + RLC = BIT(8), /* Rear Left Center */ + RRC = BIT(9), /* Rear Right Center */ + LFE = BIT(10), /* Low Frequency Effect */ +}; + +/* + * cea Speaker allocation structure + */ +struct hdmi_codec_cea_spk_alloc { + const int ca_id; + unsigned int n_ch; + unsigned long mask; +}; + +/* Channel maps stereo HDMI */ +const struct snd_pcm_chmap_elem hdmi_codec_stereo_chmaps[] = { + { .channels = 2, + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } }, + { } +}; + +/* Channel maps for multi-channel playbacks, up to 8 n_ch */ +const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = { + { .channels = 2, /* CA_ID 0x00 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } }, + { .channels = 4, /* CA_ID 0x01 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA } }, + { .channels = 4, /* CA_ID 0x02 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC } }, + { .channels = 4, /* CA_ID 0x03 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC } }, + { .channels = 6, /* CA_ID 0x04 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 6, /* CA_ID 0x05 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 6, /* CA_ID 0x06 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 6, /* CA_ID 0x07 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 6, /* CA_ID 0x08 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, + { .channels = 6, /* CA_ID 0x09 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, + { .channels = 6, /* CA_ID 0x0A */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, + { .channels = 6, /* CA_ID 0x0B */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, + { .channels = 8, /* CA_ID 0x0C */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 8, /* CA_ID 0x0D */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 8, /* CA_ID 0x0E */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 8, /* CA_ID 0x0F */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 8, /* CA_ID 0x10 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } }, + { .channels = 8, /* CA_ID 0x11 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } }, + { .channels = 8, /* CA_ID 0x12 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } }, + { .channels = 8, /* CA_ID 0x13 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } }, + { .channels = 8, /* CA_ID 0x14 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x15 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x16 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x17 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x18 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x19 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x1A */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x1B */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x1C */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x1D */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x1E */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x1F */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { } +}; + +/* + * hdmi_codec_channel_alloc: speaker configuration available for CEA + * + * This is an ordered list that must match with hdmi_codec_8ch_chmaps struct + * The preceding ones have better chances to be selected by + * hdmi_codec_get_ch_alloc_table_idx(). + */ +static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = { + { .ca_id = 0x00, .n_ch = 2, + .mask = FL | FR}, + /* 2.1 */ + { .ca_id = 0x01, .n_ch = 4, + .mask = FL | FR | LFE}, + /* Dolby Surround */ + { .ca_id = 0x02, .n_ch = 4, + .mask = FL | FR | FC }, + /* surround51 */ + { .ca_id = 0x0b, .n_ch = 6, + .mask = FL | FR | LFE | FC | RL | RR}, + /* surround40 */ + { .ca_id = 0x08, .n_ch = 6, + .mask = FL | FR | RL | RR }, + /* surround41 */ + { .ca_id = 0x09, .n_ch = 6, + .mask = FL | FR | LFE | RL | RR }, + /* surround50 */ + { .ca_id = 0x0a, .n_ch = 6, + .mask = FL | FR | FC | RL | RR }, + /* 6.1 */ + { .ca_id = 0x0f, .n_ch = 8, + .mask = FL | FR | LFE | FC | RL | RR | RC }, + /* surround71 */ + { .ca_id = 0x13, .n_ch = 8, + .mask = FL | FR | LFE | FC | RL | RR | RLC | RRC }, + /* others */ + { .ca_id = 0x03, .n_ch = 8, + .mask = FL | FR | LFE | FC }, + { .ca_id = 0x04, .n_ch = 8, + .mask = FL | FR | RC}, + { .ca_id = 0x05, .n_ch = 8, + .mask = FL | FR | LFE | RC }, + { .ca_id = 0x06, .n_ch = 8, + .mask = FL | FR | FC | RC }, + { .ca_id = 0x07, .n_ch = 8, + .mask = FL | FR | LFE | FC | RC }, + { .ca_id = 0x0c, .n_ch = 8, + .mask = FL | FR | RC | RL | RR }, + { .ca_id = 0x0d, .n_ch = 8, + .mask = FL | FR | LFE | RL | RR | RC }, + { .ca_id = 0x0e, .n_ch = 8, + .mask = FL | FR | FC | RL | RR | RC }, + { .ca_id = 0x10, .n_ch = 8, + .mask = FL | FR | RL | RR | RLC | RRC }, + { .ca_id = 0x11, .n_ch = 8, + .mask = FL | FR | LFE | RL | RR | RLC | RRC }, + { .ca_id = 0x12, .n_ch = 8, + .mask = FL | FR | FC | RL | RR | RLC | RRC }, + { .ca_id = 0x14, .n_ch = 8, + .mask = FL | FR | FLC | FRC }, + { .ca_id = 0x15, .n_ch = 8, + .mask = FL | FR | LFE | FLC | FRC }, + { .ca_id = 0x16, .n_ch = 8, + .mask = FL | FR | FC | FLC | FRC }, + { .ca_id = 0x17, .n_ch = 8, + .mask = FL | FR | LFE | FC | FLC | FRC }, + { .ca_id = 0x18, .n_ch = 8, + .mask = FL | FR | RC | FLC | FRC }, + { .ca_id = 0x19, .n_ch = 8, + .mask = FL | FR | LFE | RC | FLC | FRC }, + { .ca_id = 0x1a, .n_ch = 8, + .mask = FL | FR | RC | FC | FLC | FRC }, + { .ca_id = 0x1b, .n_ch = 8, + .mask = FL | FR | LFE | RC | FC | FLC | FRC }, + { .ca_id = 0x1c, .n_ch = 8, + .mask = FL | FR | RL | RR | FLC | FRC }, + { .ca_id = 0x1d, .n_ch = 8, + .mask = FL | FR | LFE | RL | RR | FLC | FRC }, + { .ca_id = 0x1e, .n_ch = 8, + .mask = FL | FR | FC | RL | RR | FLC | FRC }, + { .ca_id = 0x1f, .n_ch = 8, + .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC }, +}; + struct hdmi_codec_priv { struct hdmi_codec_pdata hcd; struct snd_soc_dai_driver *daidrv; @@ -41,6 +293,8 @@ struct hdmi_codec_priv { struct notifier_block nb; unsigned int jack_status; unsigned int mode; + struct snd_pcm_chmap *chmap_info; + unsigned int chmap_idx; }; static const struct snd_soc_dapm_widget hdmi_widgets[] = { @@ -109,6 +363,83 @@ static int hdmi_audio_mode_put(struct snd_kcontrol *kcontrol, return 0; } +static unsigned long hdmi_codec_spk_mask_from_alloc(int spk_alloc) +{ + int i; + const unsigned long hdmi_codec_eld_spk_alloc_bits[] = { + [0] = FL | FR, [1] = LFE, [2] = FC, [3] = RL | RR, + [4] = RC, [5] = FLC | FRC, [6] = RLC | RRC, + }; + unsigned long spk_mask = 0; + + for (i = 0; i < ARRAY_SIZE(hdmi_codec_eld_spk_alloc_bits); i++) { + if (spk_alloc & (1 << i)) + spk_mask |= hdmi_codec_eld_spk_alloc_bits[i]; + } + + return spk_mask; +} + +void hdmi_codec_eld_chmap(struct hdmi_codec_priv *hcp) +{ + u8 spk_alloc; + unsigned long spk_mask; + + spk_alloc = drm_eld_get_spk_alloc(hcp->eld); + spk_mask = hdmi_codec_spk_mask_from_alloc(spk_alloc); + + /* Detect if only stereo supported, else return 8 channels mappings */ + if ((spk_mask & ~(FL | FR)) && hcp->chmap_info->max_channels > 2) + hcp->chmap_info->chmap = hdmi_codec_8ch_chmaps; + else + hcp->chmap_info->chmap = hdmi_codec_stereo_chmaps; +} + +static int hdmi_codec_get_ch_alloc_table_idx(struct hdmi_codec_priv *hcp, + unsigned char channels) +{ + int i; + u8 spk_alloc; + unsigned long spk_mask; + const struct hdmi_codec_cea_spk_alloc *cap = hdmi_codec_channel_alloc; + + spk_alloc = drm_eld_get_spk_alloc(hcp->eld); + spk_mask = hdmi_codec_spk_mask_from_alloc(spk_alloc); + + for (i = 0; i < ARRAY_SIZE(hdmi_codec_channel_alloc); i++, cap++) { + /* If spk_alloc == 0, HDMI is unplugged return stereo config*/ + if (!spk_alloc && cap->ca_id == 0) + return i; + if (cap->n_ch != channels) + continue; + if (!(cap->mask == (spk_mask & cap->mask))) + continue; + return i; + } + + return -EINVAL; +} +static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + unsigned const char *map; + unsigned int i; + struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); + struct hdmi_codec_priv *hcp = info->private_data; + + map = info->chmap[hcp->chmap_idx].map; + + for (i = 0; i < info->max_channels; i++) { + if (hcp->chmap_idx == HDMI_CODEC_CHMAP_IDX_UNKNOWN) + ucontrol->value.integer.value[i] = 0; + else + ucontrol->value.integer.value[i] = map[i]; + } + + return 0; +} + + static const struct snd_kcontrol_new hdmi_controls[] = { { .access = SNDRV_CTL_ELEM_ACCESS_READ | @@ -184,6 +515,9 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, ret = snd_pcm_hw_constraint_eld(substream->runtime, hcp->eld); mutex_unlock(&hcp->eld_lock); + + /* Select chmap supported */ + hdmi_codec_eld_chmap(hcp); } return ret; } @@ -201,6 +535,7 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, WARN_ON(hcp->current_stream != substream); + hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data); mutex_lock(&hcp->current_stream_lock); @@ -221,7 +556,7 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, .dig_subframe = { 0 }, } }; - int ret; + int ret, idx; dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__, params_width(params), params_rate(params), @@ -248,6 +583,17 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, hp.cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; hp.cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; + /* Select a channel allocation that matches with ELD and pcm channels */ + idx = hdmi_codec_get_ch_alloc_table_idx(hcp, hp.cea.channels); + if (idx < 0) { + dev_err(dai->dev, "Not able to map channels to speakers (%d)\n", + idx); + hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; + return idx; + } + hp.cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id; + hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id; + hp.sample_width = params_width(params); hp.sample_rate = params_rate(params); hp.channels = params_channels(params); @@ -377,6 +723,32 @@ static const struct snd_soc_dai_ops hdmi_dai_ops = { SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE) +static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_dai *dai) +{ + struct snd_soc_dai_driver *drv = dai->driver; + struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); + int ret; + + dev_dbg(dai->dev, "%s()\n", __func__); + + ret = snd_pcm_add_chmap_ctls(rtd->pcm, SNDRV_PCM_STREAM_PLAYBACK, + NULL, drv->playback.channels_max, 0, + &hcp->chmap_info); + if (ret < 0) + return ret; + + /* override handlers */ + hcp->chmap_info->private_data = hcp; + hcp->chmap_info->kctl->get = hdmi_codec_chmap_ctl_get; + + /* default chmap supported is stereo */ + hcp->chmap_info->chmap = hdmi_codec_stereo_chmaps; + hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; + + return 0; +} + static struct snd_soc_dai_driver hdmi_i2s_dai = { .name = "i2s-hifi", .id = DAI_ID_I2S, @@ -389,6 +761,7 @@ static struct snd_soc_dai_driver hdmi_i2s_dai = { .sig_bits = 24, }, .ops = &hdmi_dai_ops, + .pcm_new = hdmi_codec_pcm_new, }; static const struct snd_soc_dai_driver hdmi_spdif_dai = { @@ -402,6 +775,7 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = { .formats = SPDIF_FORMATS, }, .ops = &hdmi_dai_ops, + .pcm_new = hdmi_codec_pcm_new, }; static struct snd_soc_codec_driver hdmi_codec = { @@ -534,6 +908,7 @@ static int hdmi_codec_remove(struct platform_device *pdev) { struct hdmi_codec_priv *hcp = platform_get_drvdata(pdev); + kfree(hcp->chmap_info); hdmi_unregister_notifier(&hcp->nb); snd_soc_unregister_codec(&pdev->dev); return 0; From 52c48ffd0956821dd3f1315b9ec3fd2a677b2b63 Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Thu, 15 Jun 2017 07:53:11 +0200 Subject: [PATCH] UPSTREAM: ASoC: rockchip: Fix an error handling in 'rockchip_i2s_probe' If this memory allocation fail, we must disable what has been enabled. Do not return immediately but go thrue the error handling path instead. Also use 'devm_kmemdup' instead of 'devm_kzalloc+memcpy' to simplify code. Signed-off-by: Christophe JAILLET Signed-off-by: Mark Brown (cherry picked from commit c3a3d3c41b74b05267bab6173f2a8224a1443ba6) --- sound/soc/rockchip/rockchip_i2s.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index b359639c1038..02ff642499bf 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -658,12 +658,13 @@ static int rockchip_i2s_probe(struct platform_device *pdev) goto err_pm_disable; } - soc_dai = devm_kzalloc(&pdev->dev, + soc_dai = devm_kmemdup(&pdev->dev, &rockchip_i2s_dai, sizeof(*soc_dai), GFP_KERNEL); - if (!soc_dai) - return -ENOMEM; + if (!soc_dai) { + ret = -ENOMEM; + goto err_pm_disable; + } - memcpy(soc_dai, &rockchip_i2s_dai, sizeof(*soc_dai)); if (!of_property_read_u32(node, "rockchip,playback-channels", &val)) { if (val >= 2 && val <= 8) soc_dai->playback.channels_max = val; From 7b9368e1f2d50d7ca5b07ea50240fd8f45d884fe Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 10 Aug 2017 18:38:09 +0200 Subject: [PATCH] UPSTREAM: ASoC: rockchip: Delete an error message for a failed memory allocation in rockchip_i2s_probe() Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Link: http://events.linuxfoundation.org/sites/events/files/slides/LCJ16-Refactor_Strings-WSang_0.pdf Signed-off-by: Markus Elfring Signed-off-by: Mark Brown (cherry picked from commit b48b2710913d583ff93c365413532e1a7cd60d84) --- sound/soc/rockchip/rockchip_i2s.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 02ff642499bf..16ff8d5e0033 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -594,10 +594,8 @@ static int rockchip_i2s_probe(struct platform_device *pdev) int val; i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); - if (!i2s) { - dev_err(&pdev->dev, "Can't allocate rk_i2s_dev\n"); + if (!i2s) return -ENOMEM; - } i2s->dev = &pdev->dev; From f217d206adafde4eb886ffbd5ecd7779c37438ef Mon Sep 17 00:00:00 2001 From: John Keeping Date: Thu, 14 Sep 2017 16:58:55 +0100 Subject: [PATCH] UPSTREAM: ASoC: rockchip: i2s: fix unbalanced clk_disable mclk is enabled and disabled only in i2s_runtime_{resume,suspend}() and we ensure that the device is runtime suspended before reaching this clk_disable_unprepare() call, so it is wrong to call it again here. Signed-off-by: John Keeping Signed-off-by: Mark Brown (cherry picked from commit 32debfcd3ff0939c93238ddde03ffcc96cca5c60) --- sound/soc/rockchip/rockchip_i2s.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 16ff8d5e0033..986ad2efc8e9 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -727,7 +727,6 @@ static int rockchip_i2s_remove(struct platform_device *pdev) if (!pm_runtime_status_suspended(&pdev->dev)) i2s_runtime_suspend(&pdev->dev); - clk_disable_unprepare(i2s->mclk); clk_disable_unprepare(i2s->hclk); return 0; From 8b1551df18617eba99d59f89724191954a7213a4 Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Thu, 20 Apr 2017 14:34:34 +0530 Subject: [PATCH] UPSTREAM: drm: dw-hdmi: gate audio clock from the I2S enablement callbacks Currently, the audio sampler clock is enabled from dw_hdmi_setup() at step E. and is kept enabled for later use. This clock should be enabled and disabled along with the actual audio stream and not always on (that is bad for PM). Furthermore, as described by the datasheet, the I2S variant needs to gate/ungate the clock when the stream is enabled/disabled. This commit adds a parameter to hdmi_audio_enable_clk() that controls when the audio sample clock must be enabled or disabled. Then, it adds the call to this function from dw_hdmi_i2s_audio_enable() and dw_hdmi_i2s_audio_disable(). Reviewed-by: Neil Armstrong Signed-off-by: Romain Perier Link: http://patchwork.freedesktop.org/patch/msgid/20170414083113.4255-3-romain.perier@collabora.com Signed-off-by: Archit Taneja (cherry picked from commit 57fbc05585a9c841c910677228f1e3f8a3a62801) --- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 8726498e9f73..17c182cb07b5 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -824,6 +824,15 @@ void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate) } EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_rate); +static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi, bool enable) +{ + if (enable) + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE; + else + hdmi->mc_clkdis |= HDMI_MC_CLKDIS_AUDCLK_DISABLE; + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); +} + static void dw_hdmi_ahb_audio_enable(struct dw_hdmi *hdmi) { hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n); @@ -837,6 +846,12 @@ static void dw_hdmi_ahb_audio_disable(struct dw_hdmi *hdmi) static void dw_hdmi_i2s_audio_enable(struct dw_hdmi *hdmi) { hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n); + hdmi_enable_audio_clk(hdmi, true); +} + +static void dw_hdmi_i2s_audio_disable(struct dw_hdmi *hdmi) +{ + hdmi_enable_audio_clk(hdmi, false); } void dw_hdmi_audio_enable(struct dw_hdmi *hdmi) @@ -2149,12 +2164,6 @@ static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi) HDMI_MC_FLOWCTRL); } -static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi) -{ - hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE; - hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); -} - /* Workaround to clear the overflow condition */ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi) { @@ -2306,7 +2315,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) /* HDMI Initialization Step E - Configure audio */ hdmi_clk_regenerator_update_pixel_clock(hdmi); - hdmi_enable_audio_clk(hdmi); + hdmi_enable_audio_clk(hdmi, true); } /* not for DVI mode */ @@ -3742,6 +3751,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master, audio.read = hdmi_readb; audio.mod = hdmi_modb; hdmi->enable_audio = dw_hdmi_i2s_audio_enable; + hdmi->disable_audio = dw_hdmi_i2s_audio_disable; pdevinfo.name = "dw-hdmi-i2s-audio"; pdevinfo.data = &audio; From 442b913082d21de7a8364344feb520946413da5b Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Mon, 7 Aug 2017 22:24:15 +0200 Subject: [PATCH] drm: dw-hdmi-i2s: sync with upstream --- drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h | 1 - drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 20 +++++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h index 3930ba04977b..af7f39c85ba4 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h @@ -14,7 +14,6 @@ struct dw_hdmi_audio_data { struct dw_hdmi_i2s_audio_data { struct dw_hdmi *hdmi; - struct platform_device *pdev; void (*write)(struct dw_hdmi *hdmi, u8 val, int offset); u8 (*read)(struct dw_hdmi *hdmi, int offset); diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c index f1f62d8c1d16..5ff993a35ab6 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c @@ -16,7 +16,8 @@ #define DRIVER_NAME "dw-hdmi-i2s-audio" -static inline void hdmi_write(struct dw_hdmi_i2s_audio_data *audio, u8 val, int offset) +static inline void hdmi_write(struct dw_hdmi_i2s_audio_data *audio, + u8 val, int offset) { struct dw_hdmi *hdmi = audio->hdmi; @@ -220,6 +221,7 @@ static int snd_dw_hdmi_probe(struct platform_device *pdev) struct dw_hdmi_i2s_audio_data *audio = pdev->dev.platform_data; struct platform_device_info pdevinfo; struct hdmi_codec_pdata pdata; + struct platform_device *platform; pdata.ops = &dw_hdmi_i2s_ops; pdata.i2s = 1; @@ -234,23 +236,27 @@ static int snd_dw_hdmi_probe(struct platform_device *pdev) pdevinfo.size_data = sizeof(pdata); pdevinfo.dma_mask = DMA_BIT_MASK(32); - audio->pdev = platform_device_register_full(&pdevinfo); - return IS_ERR_OR_NULL(audio->pdev); + platform = platform_device_register_full(&pdevinfo); + if (IS_ERR(platform)) + return PTR_ERR(platform); + + dev_set_drvdata(&pdev->dev, platform); + + return 0; } static int snd_dw_hdmi_remove(struct platform_device *pdev) { - struct dw_hdmi_i2s_audio_data *audio = pdev->dev.platform_data; + struct platform_device *platform = dev_get_drvdata(&pdev->dev); - if (!IS_ERR_OR_NULL(audio->pdev)) - platform_device_unregister(audio->pdev); + platform_device_unregister(platform); return 0; } static struct platform_driver snd_dw_hdmi_driver = { .probe = snd_dw_hdmi_probe, - .remove = snd_dw_hdmi_remove, + .remove = snd_dw_hdmi_remove, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, From 1d3de24bd61e0bfba1a9e042e040fa65346ccd9d Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Sun, 2 Apr 2017 11:33:39 +0200 Subject: [PATCH] drm: dw-hdmi-i2s: implement get_eld --- drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h | 1 + drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 12 ++++++++++++ drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 1 + 3 files changed, 14 insertions(+) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h index af7f39c85ba4..c5ace7808fdf 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h @@ -14,6 +14,7 @@ struct dw_hdmi_audio_data { struct dw_hdmi_i2s_audio_data { struct dw_hdmi *hdmi; + u8 *eld; void (*write)(struct dw_hdmi *hdmi, u8 val, int offset); u8 (*read)(struct dw_hdmi *hdmi, int offset); diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c index 5ff993a35ab6..e7312571e2cb 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c @@ -11,6 +11,8 @@ #include +#include /* This is only to get MAX_ELD_BYTES */ + #include "dw-hdmi.h" #include "dw-hdmi-audio.h" @@ -211,9 +213,19 @@ static void dw_hdmi_i2s_audio_shutdown(struct device *dev, void *data) hdmi_write(audio, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0); } +static int dw_hdmi_i2s_get_eld(struct device *dev, void *data, u8 *buf, size_t len) +{ + struct dw_hdmi_i2s_audio_data *audio = data; + + memcpy(buf, audio->eld, min(len, (size_t)MAX_ELD_BYTES)); + + return 0; +} + static struct hdmi_codec_ops dw_hdmi_i2s_ops = { .hw_params = dw_hdmi_i2s_hw_params, .audio_shutdown = dw_hdmi_i2s_audio_shutdown, + .get_eld = dw_hdmi_i2s_get_eld, }; static int snd_dw_hdmi_probe(struct platform_device *pdev) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 17c182cb07b5..df1ea752ac3d 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -3750,6 +3750,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master, audio.write = hdmi_writeb; audio.read = hdmi_readb; audio.mod = hdmi_modb; + audio.eld = hdmi->connector.eld; hdmi->enable_audio = dw_hdmi_i2s_audio_enable; hdmi->disable_audio = dw_hdmi_i2s_audio_disable; From 1e16f2f6b861a7273d922c9251665acec542eed9 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Mon, 17 Apr 2017 13:09:16 +0200 Subject: [PATCH] drm: dw-hdmi-i2s: configure channel allocation --- drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c index e7312571e2cb..1d4570e3fbed 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c @@ -188,7 +188,7 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, hdmi_write(audio, 0x00, HDMI_FC_AUDICONF1); /* Set Channel Allocation */ - hdmi_write(audio, 0x00, HDMI_FC_AUDICONF2); + hdmi_write(audio, hparms->cea.channel_allocation, HDMI_FC_AUDICONF2); /* Set LFEPBLDOWN-MIX INH and LSV */ hdmi_write(audio, 0x00, HDMI_FC_AUDICONF3); From 747742580e282f4374100909906f6957c997c4a3 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Mon, 14 Aug 2017 00:14:05 +0200 Subject: [PATCH] ASoC: hdmi-codec: reorder channel map --- sound/soc/codecs/hdmi-codec.c | 113 +++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 61 deletions(-) diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index cb78d8971b41..b74659bc3bbc 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -205,78 +205,69 @@ const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = { */ static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = { { .ca_id = 0x00, .n_ch = 2, - .mask = FL | FR}, - /* 2.1 */ - { .ca_id = 0x01, .n_ch = 4, - .mask = FL | FR | LFE}, - /* Dolby Surround */ + .mask = FL | FR }, + { .ca_id = 0x03, .n_ch = 4, + .mask = FL | FR | LFE | FC }, { .ca_id = 0x02, .n_ch = 4, .mask = FL | FR | FC }, - /* surround51 */ + { .ca_id = 0x01, .n_ch = 4, + .mask = FL | FR | LFE }, { .ca_id = 0x0b, .n_ch = 6, - .mask = FL | FR | LFE | FC | RL | RR}, - /* surround40 */ - { .ca_id = 0x08, .n_ch = 6, - .mask = FL | FR | RL | RR }, - /* surround41 */ - { .ca_id = 0x09, .n_ch = 6, - .mask = FL | FR | LFE | RL | RR }, - /* surround50 */ + .mask = FL | FR | LFE | FC | RL | RR }, { .ca_id = 0x0a, .n_ch = 6, .mask = FL | FR | FC | RL | RR }, - /* 6.1 */ - { .ca_id = 0x0f, .n_ch = 8, - .mask = FL | FR | LFE | FC | RL | RR | RC }, - /* surround71 */ + { .ca_id = 0x09, .n_ch = 6, + .mask = FL | FR | LFE | RL | RR }, + { .ca_id = 0x08, .n_ch = 6, + .mask = FL | FR | RL | RR }, + { .ca_id = 0x07, .n_ch = 6, + .mask = FL | FR | LFE | FC | RC }, + { .ca_id = 0x06, .n_ch = 6, + .mask = FL | FR | FC | RC }, + { .ca_id = 0x05, .n_ch = 6, + .mask = FL | FR | LFE | RC }, + { .ca_id = 0x04, .n_ch = 6, + .mask = FL | FR | RC }, { .ca_id = 0x13, .n_ch = 8, .mask = FL | FR | LFE | FC | RL | RR | RLC | RRC }, - /* others */ - { .ca_id = 0x03, .n_ch = 8, - .mask = FL | FR | LFE | FC }, - { .ca_id = 0x04, .n_ch = 8, - .mask = FL | FR | RC}, - { .ca_id = 0x05, .n_ch = 8, - .mask = FL | FR | LFE | RC }, - { .ca_id = 0x06, .n_ch = 8, - .mask = FL | FR | FC | RC }, - { .ca_id = 0x07, .n_ch = 8, - .mask = FL | FR | LFE | FC | RC }, - { .ca_id = 0x0c, .n_ch = 8, - .mask = FL | FR | RC | RL | RR }, - { .ca_id = 0x0d, .n_ch = 8, - .mask = FL | FR | LFE | RL | RR | RC }, - { .ca_id = 0x0e, .n_ch = 8, - .mask = FL | FR | FC | RL | RR | RC }, - { .ca_id = 0x10, .n_ch = 8, - .mask = FL | FR | RL | RR | RLC | RRC }, - { .ca_id = 0x11, .n_ch = 8, - .mask = FL | FR | LFE | RL | RR | RLC | RRC }, + { .ca_id = 0x1f, .n_ch = 8, + .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC }, { .ca_id = 0x12, .n_ch = 8, .mask = FL | FR | FC | RL | RR | RLC | RRC }, - { .ca_id = 0x14, .n_ch = 8, - .mask = FL | FR | FLC | FRC }, - { .ca_id = 0x15, .n_ch = 8, - .mask = FL | FR | LFE | FLC | FRC }, - { .ca_id = 0x16, .n_ch = 8, - .mask = FL | FR | FC | FLC | FRC }, - { .ca_id = 0x17, .n_ch = 8, - .mask = FL | FR | LFE | FC | FLC | FRC }, - { .ca_id = 0x18, .n_ch = 8, - .mask = FL | FR | RC | FLC | FRC }, - { .ca_id = 0x19, .n_ch = 8, - .mask = FL | FR | LFE | RC | FLC | FRC }, - { .ca_id = 0x1a, .n_ch = 8, - .mask = FL | FR | RC | FC | FLC | FRC }, - { .ca_id = 0x1b, .n_ch = 8, - .mask = FL | FR | LFE | RC | FC | FLC | FRC }, - { .ca_id = 0x1c, .n_ch = 8, - .mask = FL | FR | RL | RR | FLC | FRC }, - { .ca_id = 0x1d, .n_ch = 8, - .mask = FL | FR | LFE | RL | RR | FLC | FRC }, { .ca_id = 0x1e, .n_ch = 8, .mask = FL | FR | FC | RL | RR | FLC | FRC }, - { .ca_id = 0x1f, .n_ch = 8, - .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC }, + { .ca_id = 0x11, .n_ch = 8, + .mask = FL | FR | LFE | RL | RR | RLC | RRC }, + { .ca_id = 0x1d, .n_ch = 8, + .mask = FL | FR | LFE | RL | RR | FLC | FRC }, + { .ca_id = 0x10, .n_ch = 8, + .mask = FL | FR | RL | RR | RLC | RRC }, + { .ca_id = 0x1c, .n_ch = 8, + .mask = FL | FR | RL | RR | FLC | FRC }, + { .ca_id = 0x0f, .n_ch = 8, + .mask = FL | FR | LFE | FC | RL | RR | RC }, + { .ca_id = 0x1b, .n_ch = 8, + .mask = FL | FR | LFE | RC | FC | FLC | FRC }, + { .ca_id = 0x0e, .n_ch = 8, + .mask = FL | FR | FC | RL | RR | RC }, + { .ca_id = 0x1a, .n_ch = 8, + .mask = FL | FR | RC | FC | FLC | FRC }, + { .ca_id = 0x0d, .n_ch = 8, + .mask = FL | FR | LFE | RL | RR | RC }, + { .ca_id = 0x19, .n_ch = 8, + .mask = FL | FR | LFE | RC | FLC | FRC }, + { .ca_id = 0x0c, .n_ch = 8, + .mask = FL | FR | RC | RL | RR }, + { .ca_id = 0x18, .n_ch = 8, + .mask = FL | FR | RC | FLC | FRC }, + { .ca_id = 0x17, .n_ch = 8, + .mask = FL | FR | LFE | FC | FLC | FRC }, + { .ca_id = 0x16, .n_ch = 8, + .mask = FL | FR | FC | FLC | FRC }, + { .ca_id = 0x15, .n_ch = 8, + .mask = FL | FR | LFE | FLC | FRC }, + { .ca_id = 0x14, .n_ch = 8, + .mask = FL | FR | FLC | FRC }, }; struct hdmi_codec_priv { From 1cdb1f115b4bc9781c90d01d914dd4bbac6d0977 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Sun, 27 Aug 2017 23:32:40 +0200 Subject: [PATCH] ASoC: codecs: rk3328: limit to working rates --- sound/soc/codecs/rk3328_codec.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rk3328_codec.c b/sound/soc/codecs/rk3328_codec.c index af1b7429b6d4..d0b4578ffa0e 100644 --- a/sound/soc/codecs/rk3328_codec.c +++ b/sound/soc/codecs/rk3328_codec.c @@ -354,7 +354,12 @@ static struct snd_soc_dai_driver rk3328_dai[] = { .stream_name = "HIFI Playback", .channels_min = 1, .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_96000, + .rates = (SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_64000 | + SNDRV_PCM_RATE_96000), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | --- a/sound/soc/codecs/rk3228_codec.c +++ b/sound/soc/codecs/rk3228_codec.c @@ -352,7 +352,12 @@ .stream_name = "HIFI Playback", .channels_min = 1, .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_96000, + .rates = (SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_64000 | + SNDRV_PCM_RATE_96000), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | From 878d789ff5faa02f0da5e68126e2276124611eeb Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Sun, 8 Jul 2018 12:34:43 +0200 Subject: [PATCH] drm: dw-hdmi: change audio config --- drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 9 ++------- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c index 1d4570e3fbed..d0904f6b7a82 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c @@ -110,8 +110,7 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, HDMI_AUD_INT_FIFO_FULL_MSK, HDMI_AUD_INT); hdmi_update_bits(audio, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0); - hdmi_update_bits(audio, HDMI_MC_SWRSTZ_I2S_RESET_MSK, - HDMI_MC_SWRSTZ_I2S_RESET_MSK, HDMI_MC_SWRSTZ); + hdmi_write(audio, (u8)~HDMI_MC_SWRSTZ_I2S_RESET_MSK, HDMI_MC_SWRSTZ); switch (hparms->mode) { case NLPCM: @@ -193,11 +192,6 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, /* Set LFEPBLDOWN-MIX INH and LSV */ hdmi_write(audio, 0x00, HDMI_FC_AUDICONF3); - hdmi_update_bits(audio, HDMI_AUD_CONF0_SW_RESET, - HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0); - hdmi_update_bits(audio, HDMI_MC_SWRSTZ_I2S_RESET_MSK, - HDMI_MC_SWRSTZ_I2S_RESET_MSK, HDMI_MC_SWRSTZ); - dw_hdmi_audio_enable(hdmi); return 0; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index df1ea752ac3d..4bf4ff0fd741 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -89,6 +89,7 @@ static const struct dw_hdmi_audio_tmds_n common_tmds_n_table[] = { { .tmds = 71000000, .n_32k = 4096, .n_44k1 = 7056, .n_48k = 6144, }, { .tmds = 72000000, .n_32k = 4096, .n_44k1 = 5635, .n_48k = 6144, }, { .tmds = 73250000, .n_32k = 4096, .n_44k1 = 14112, .n_48k = 6144, }, + { .tmds = 74176000, .n_32k = 11648, .n_44k1 = 17836, .n_48k = 11648, }, { .tmds = 74250000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, }, { .tmds = 75000000, .n_32k = 4096, .n_44k1 = 5880, .n_48k = 6144, }, { .tmds = 78750000, .n_32k = 4096, .n_44k1 = 5600, .n_48k = 6144, }, @@ -105,13 +106,16 @@ static const struct dw_hdmi_audio_tmds_n common_tmds_n_table[] = { { .tmds = 119000000, .n_32k = 4096, .n_44k1 = 5544, .n_48k = 6144, }, { .tmds = 135000000, .n_32k = 4096, .n_44k1 = 5488, .n_48k = 6144, }, { .tmds = 146250000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, }, - { .tmds = 148500000, .n_32k = 4096, .n_44k1 = 5488, .n_48k = 6144, }, + { .tmds = 148352000, .n_32k = 11648, .n_44k1 = 8918, .n_48k = 5824, }, + { .tmds = 148500000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, }, { .tmds = 154000000, .n_32k = 4096, .n_44k1 = 5544, .n_48k = 6144, }, { .tmds = 162000000, .n_32k = 4096, .n_44k1 = 5684, .n_48k = 6144, }, /* For 297 MHz+ HDMI spec have some other rule for setting N */ - { .tmds = 297000000, .n_32k = 3073, .n_44k1 = 4704, .n_48k = 5120, }, - { .tmds = 594000000, .n_32k = 3073, .n_44k1 = 9408, .n_48k = 10240, }, + { .tmds = 296703000, .n_32k = 5824, .n_44k1 = 4459, .n_48k = 5824, }, + { .tmds = 297000000, .n_32k = 3072, .n_44k1 = 4704, .n_48k = 5120, }, + { .tmds = 593407000, .n_32k = 5824, .n_44k1 = 8918, .n_48k = 5824, }, + { .tmds = 594000000, .n_32k = 3072, .n_44k1 = 9408, .n_48k = 6144, }, /* End of table */ { .tmds = 0, .n_32k = 0, .n_44k1 = 0, .n_48k = 0, }, @@ -831,6 +835,11 @@ static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi, bool enable) else hdmi->mc_clkdis |= HDMI_MC_CLKDIS_AUDCLK_DISABLE; hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); + + if (enable) { + hdmi_set_cts_n(hdmi, 0, 0); + hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n); + } } static void dw_hdmi_ahb_audio_enable(struct dw_hdmi *hdmi) From 6bf23972f26fde1abad52cd1a65d1223d51d47c2 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Sun, 8 Jul 2018 12:56:51 +0200 Subject: [PATCH] WIP: drm: dw-hdmi: use Auto CTS mode --- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 52 ++++++++++++++++++------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 4bf4ff0fd741..2583320f3289 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -643,14 +643,18 @@ static struct i2c_adapter *dw_hdmi_i2c_adapter(struct dw_hdmi *hdmi) static void hdmi_set_cts_n(struct dw_hdmi *hdmi, unsigned int cts, unsigned int n) { - /* Must be set/cleared first */ - hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); - - /* nshift factor = 0 */ - hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3); - - hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) | - HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); + /* Use Auto CTS mode with CTS is unknown */ + if (cts) { + /* Must be set/cleared first */ + hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); + + /* nshift factor = 0 */ + hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3); + + hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) | + HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); + } else + hdmi_writeb(hdmi, 0, HDMI_AUD_CTS3); hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2); hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1); @@ -777,24 +781,30 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi, { unsigned long ftdms = pixel_clk; unsigned int n, cts; + u8 config3; u64 tmp; n = hdmi_find_n(hdmi, pixel_clk, sample_rate); - /* - * Compute the CTS value from the N value. Note that CTS and N - * can be up to 20 bits in total, so we need 64-bit math. Also - * note that our TDMS clock is not fully accurate; it is accurate - * to kHz. This can introduce an unnecessary remainder in the - * calculation below, so we don't try to warn about that. - */ - tmp = (u64)ftdms * n; - do_div(tmp, 128 * sample_rate); - cts = tmp; + config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID); - dev_dbg(hdmi->dev, "%s: fs=%uHz ftdms=%lu.%03luMHz N=%d cts=%d\n", - __func__, sample_rate, ftdms / 1000000, (ftdms / 1000) % 1000, - n, cts); + if (config3 & HDMI_CONFIG3_AHBAUDDMA) { + /* + * Compute the CTS value from the N value. Note that CTS and N + * can be up to 20 bits in total, so we need 64-bit math. Also + * note that our TDMS clock is not fully accurate; it is accurate + * to kHz. This can introduce an unnecessary remainder in the + * calculation below, so we don't try to warn about that. + */ + tmp = (u64)ftdms * n; + do_div(tmp, 128 * sample_rate); + cts = tmp; + + dev_dbg(hdmi->dev, "%s: fs=%uHz ftdms=%lu.%03luMHz N=%d cts=%d\n", + __func__, sample_rate, ftdms / 1000000, (ftdms / 1000) % 1000, + n, cts); + } else + cts = 0; spin_lock_irq(&hdmi->audio_lock); hdmi->audio_n = n;