diff options
author | Álvaro Fernández Rojas <noltari@gmail.com> | 2021-08-21 10:54:34 +0200 |
---|---|---|
committer | Álvaro Fernández Rojas <noltari@gmail.com> | 2021-08-21 19:07:07 +0200 |
commit | 8299d1f057439f94c6a4412e2e5c5082b82a30c9 (patch) | |
tree | 1bf678d61f11f7394493be464c7876e496f7faed /target/linux/bcm27xx/patches-5.10/950-0636-drm-vc4-Register-HDMI-codec.patch | |
parent | 33b6885975ce376ff075362b7f0890326043111b (diff) | |
download | upstream-8299d1f057439f94c6a4412e2e5c5082b82a30c9.tar.gz upstream-8299d1f057439f94c6a4412e2e5c5082b82a30c9.tar.bz2 upstream-8299d1f057439f94c6a4412e2e5c5082b82a30c9.zip |
bcm27xx: add kernel 5.10 support
Rebased RPi foundation patches on linux 5.10.59, removed applied and reverted
patches, wireless patches and defconfig patches.
bcm2708: boot tested on RPi B+ v1.2
bcm2709: boot tested on RPi 4B v1.1 4G
bcm2711: boot tested on RPi 4B v1.1 4G
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
Diffstat (limited to 'target/linux/bcm27xx/patches-5.10/950-0636-drm-vc4-Register-HDMI-codec.patch')
-rw-r--r-- | target/linux/bcm27xx/patches-5.10/950-0636-drm-vc4-Register-HDMI-codec.patch | 492 |
1 files changed, 492 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-5.10/950-0636-drm-vc4-Register-HDMI-codec.patch b/target/linux/bcm27xx/patches-5.10/950-0636-drm-vc4-Register-HDMI-codec.patch new file mode 100644 index 0000000000..9a294b3f31 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.10/950-0636-drm-vc4-Register-HDMI-codec.patch @@ -0,0 +1,492 @@ +From 1e6a19ca5f275155a4dd1961d351306b589b11a0 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime@cerno.tech> +Date: Mon, 26 Apr 2021 14:42:26 +0200 +Subject: [PATCH] drm/vc4: Register HDMI codec + +The hdmi-codec brings a lot of advanced features, including the HDMI +channel mapping. Let's use it in our driver instead of our own codec. + +Signed-off-by: Maxime Ripard <maxime@cerno.tech> +--- + drivers/gpu/drm/vc4/Kconfig | 1 + + drivers/gpu/drm/vc4/vc4_hdmi.c | 311 +++++++++------------------------ + drivers/gpu/drm/vc4/vc4_hdmi.h | 3 +- + 3 files changed, 84 insertions(+), 231 deletions(-) + +--- a/drivers/gpu/drm/vc4/Kconfig ++++ b/drivers/gpu/drm/vc4/Kconfig +@@ -12,6 +12,7 @@ config DRM_VC4 + select SND_PCM + select SND_PCM_ELD + select SND_SOC_GENERIC_DMAENGINE_PCM ++ select SND_SOC_HDMI_CODEC + select DRM_MIPI_DSI + help + Choose this option if you have a system that has a Broadcom +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -47,6 +47,7 @@ + #include <linux/reset.h> + #include <sound/asoundef.h> + #include <sound/dmaengine_pcm.h> ++#include <sound/hdmi-codec.h> + #include <sound/pcm_drm_eld.h> + #include <sound/pcm_params.h> + #include <sound/soc.h> +@@ -95,6 +96,12 @@ + # define VC4_HD_M_ENABLE BIT(0) + + #define CEC_CLOCK_FREQ 40000 ++#define HDMI_14_MAX_TMDS_CLK (340 * 1000 * 1000) ++ ++static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode) ++{ ++ return (mode->clock * 1000) > HDMI_14_MAX_TMDS_CLK; ++} + + static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) + { +@@ -472,16 +479,10 @@ static void vc4_hdmi_set_spd_infoframe(s + static void vc4_hdmi_set_audio_infoframe(struct drm_encoder *encoder) + { + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); ++ struct hdmi_audio_infoframe *audio = &vc4_hdmi->audio.infoframe; + union hdmi_infoframe frame; +- int ret; +- +- ret = hdmi_audio_infoframe_init(&frame.audio); +- +- 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 = vc4_hdmi->audio.channels; + ++ memcpy(&frame.audio, audio, sizeof(*audio)); + vc4_hdmi_write_infoframe(encoder, &frame); + } + +@@ -1214,18 +1215,10 @@ static inline struct vc4_hdmi *dai_to_hd + return snd_soc_card_get_drvdata(card); + } + +-static int vc4_hdmi_audio_startup(struct snd_pcm_substream *substream, +- struct snd_soc_dai *dai) ++static int vc4_hdmi_audio_startup(struct device *dev, void *data) + { +- struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai); ++ struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); + struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; +- struct drm_connector *connector = &vc4_hdmi->connector; +- int ret; +- +- if (vc4_hdmi->audio.substream && vc4_hdmi->audio.substream != substream) +- return -EINVAL; +- +- vc4_hdmi->audio.substream = substream; + + /* + * If the HDMI encoder hasn't probed, or the encoder is +@@ -1235,15 +1228,18 @@ static int vc4_hdmi_audio_startup(struct + VC4_HDMI_RAM_PACKET_ENABLE)) + return -ENODEV; + +- ret = snd_pcm_hw_constraint_eld(substream->runtime, connector->eld); +- if (ret) +- return ret; ++ vc4_hdmi->audio.streaming = true; + +- return 0; +-} ++ HDMI_WRITE(HDMI_MAI_CTL, ++ VC4_HD_MAI_CTL_RESET | ++ VC4_HD_MAI_CTL_FLUSH | ++ VC4_HD_MAI_CTL_DLATE | ++ VC4_HD_MAI_CTL_ERRORE | ++ VC4_HD_MAI_CTL_ERRORF); ++ ++ if (vc4_hdmi->variant->phy_rng_enable) ++ vc4_hdmi->variant->phy_rng_enable(vc4_hdmi); + +-static int vc4_hdmi_audio_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +-{ + return 0; + } + +@@ -1263,17 +1259,20 @@ static void vc4_hdmi_audio_reset(struct + HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_FLUSH); + } + +-static void vc4_hdmi_audio_shutdown(struct snd_pcm_substream *substream, +- struct snd_soc_dai *dai) ++static void vc4_hdmi_audio_shutdown(struct device *dev, void *data) + { +- struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai); ++ struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); + +- if (substream != vc4_hdmi->audio.substream) +- return; ++ HDMI_WRITE(HDMI_MAI_CTL, ++ VC4_HD_MAI_CTL_DLATE | ++ VC4_HD_MAI_CTL_ERRORE | ++ VC4_HD_MAI_CTL_ERRORF); + +- vc4_hdmi_audio_reset(vc4_hdmi); ++ if (vc4_hdmi->variant->phy_rng_disable) ++ vc4_hdmi->variant->phy_rng_disable(vc4_hdmi); + +- vc4_hdmi->audio.substream = NULL; ++ vc4_hdmi->audio.streaming = false; ++ vc4_hdmi_audio_reset(vc4_hdmi); + } + + static int sample_rate_to_mai_fmt(int samplerate) +@@ -1315,42 +1314,35 @@ static int sample_rate_to_mai_fmt(int sa + } + + /* HDMI audio codec callbacks */ +-static int vc4_hdmi_audio_prepare(struct snd_pcm_substream *substream, +- struct snd_soc_dai *dai) ++static int vc4_hdmi_audio_prepare(struct device *dev, void *data, ++ struct hdmi_codec_daifmt *daifmt, ++ struct hdmi_codec_params *params) + { +- struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai); ++ struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); + struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; +- struct device *dev = &vc4_hdmi->pdev->dev; + u32 audio_packet_config, channel_mask; + u32 channel_map; + u32 mai_audio_format; + u32 mai_sample_rate; + +- if (substream != vc4_hdmi->audio.substream) +- return -EINVAL; ++ dev_dbg(dev, "%s: %u Hz, %d bit, %d channels\n", __func__, ++ params->sample_rate, params->sample_width, ++ params->channels); + +- dev_dbg(dev, "%s: %u Hz, %d bit, %d channels AES0=%02x\n", +- __func__, +- substream->runtime->rate, +- snd_pcm_format_width(substream->runtime->format), +- substream->runtime->channels, +- vc4_hdmi->audio.iec_status[0]); +- +- vc4_hdmi->audio.channels = substream->runtime->channels; +- vc4_hdmi->audio.samplerate = substream->runtime->rate; ++ vc4_hdmi->audio.channels = params->channels; ++ vc4_hdmi->audio.samplerate = params->sample_rate; + + HDMI_WRITE(HDMI_MAI_CTL, +- VC4_HD_MAI_CTL_RESET | +- VC4_HD_MAI_CTL_FLUSH | +- VC4_HD_MAI_CTL_DLATE | +- VC4_HD_MAI_CTL_ERRORE | +- VC4_HD_MAI_CTL_ERRORF); ++ VC4_SET_FIELD(params->channels, VC4_HD_MAI_CTL_CHNUM) | ++ VC4_HD_MAI_CTL_WHOLSMP | ++ VC4_HD_MAI_CTL_CHALIGN | ++ VC4_HD_MAI_CTL_ENABLE); + + vc4_hdmi_audio_set_mai_clock(vc4_hdmi); + + mai_sample_rate = sample_rate_to_mai_fmt(vc4_hdmi->audio.samplerate); +- if (vc4_hdmi->audio.iec_status[0] & IEC958_AES0_NONAUDIO && +- vc4_hdmi->audio.channels == 8) ++ if (params->iec.status[0] & IEC958_AES0_NONAUDIO && ++ params->channels == 8) + mai_audio_format = VC4_HDMI_MAI_FORMAT_HBR; + else + mai_audio_format = VC4_HDMI_MAI_FORMAT_PCM; +@@ -1387,148 +1379,12 @@ static int vc4_hdmi_audio_prepare(struct + HDMI_WRITE(HDMI_AUDIO_PACKET_CONFIG, audio_packet_config); + vc4_hdmi_set_n_cts(vc4_hdmi); + ++ memcpy(&vc4_hdmi->audio.infoframe, ¶ms->cea, sizeof(params->cea)); + vc4_hdmi_set_audio_infoframe(encoder); + + return 0; + } + +-static int vc4_hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd, +- struct snd_soc_dai *dai) +-{ +- struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai); +- +- switch (cmd) { +- case SNDRV_PCM_TRIGGER_START: +- vc4_hdmi->audio.streaming = true; +- +- if (vc4_hdmi->variant->phy_rng_enable) +- vc4_hdmi->variant->phy_rng_enable(vc4_hdmi); +- +- HDMI_WRITE(HDMI_MAI_CTL, +- VC4_SET_FIELD(vc4_hdmi->audio.channels, +- VC4_HD_MAI_CTL_CHNUM) | +- VC4_HD_MAI_CTL_WHOLSMP | +- VC4_HD_MAI_CTL_CHALIGN | +- VC4_HD_MAI_CTL_ENABLE); +- break; +- case SNDRV_PCM_TRIGGER_STOP: +- HDMI_WRITE(HDMI_MAI_CTL, +- VC4_HD_MAI_CTL_DLATE | +- VC4_HD_MAI_CTL_ERRORE | +- VC4_HD_MAI_CTL_ERRORF); +- +- if (vc4_hdmi->variant->phy_rng_disable) +- vc4_hdmi->variant->phy_rng_disable(vc4_hdmi); +- +- vc4_hdmi->audio.streaming = false; +- +- break; +- default: +- break; +- } +- +- return 0; +-} +- +-static inline struct vc4_hdmi * +-snd_component_to_hdmi(struct snd_soc_component *component) +-{ +- struct snd_soc_card *card = snd_soc_component_get_drvdata(component); +- +- return snd_soc_card_get_drvdata(card); +-} +- +-static int vc4_hdmi_audio_eld_ctl_info(struct snd_kcontrol *kcontrol, +- struct snd_ctl_elem_info *uinfo) +-{ +- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); +- struct vc4_hdmi *vc4_hdmi = snd_component_to_hdmi(component); +- struct drm_connector *connector = &vc4_hdmi->connector; +- +- uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; +- uinfo->count = sizeof(connector->eld); +- +- return 0; +-} +- +-static int vc4_hdmi_audio_eld_ctl_get(struct snd_kcontrol *kcontrol, +- struct snd_ctl_elem_value *ucontrol) +-{ +- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); +- struct vc4_hdmi *vc4_hdmi = snd_component_to_hdmi(component); +- struct drm_connector *connector = &vc4_hdmi->connector; +- +- memcpy(ucontrol->value.bytes.data, connector->eld, +- sizeof(connector->eld)); +- +- return 0; +-} +- +-static int vc4_spdif_info(struct snd_kcontrol *kcontrol, +- struct snd_ctl_elem_info *uinfo) +-{ +- uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; +- uinfo->count = 1; +- return 0; +-} +- +-static int vc4_spdif_playback_get(struct snd_kcontrol *kcontrol, +- struct snd_ctl_elem_value *ucontrol) +-{ +- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); +- struct vc4_hdmi *vc4_hdmi = snd_component_to_hdmi(component); +- +- memcpy(ucontrol->value.iec958.status, vc4_hdmi->audio.iec_status, +- sizeof(vc4_hdmi->audio.iec_status)); +- +- return 0; +-} +- +-static int vc4_spdif_playback_put(struct snd_kcontrol *kcontrol, +- struct snd_ctl_elem_value *ucontrol) +-{ +- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); +- struct vc4_hdmi *vc4_hdmi = snd_component_to_hdmi(component); +- +- memcpy(vc4_hdmi->audio.iec_status, ucontrol->value.iec958.status, +- sizeof(vc4_hdmi->audio.iec_status)); +- +- return 0; +-} +- +-static int vc4_spdif_mask_get(struct snd_kcontrol *kcontrol, +- struct snd_ctl_elem_value *ucontrol) +-{ +- memset(ucontrol->value.iec958.status, 0xff, +- sizeof_field(struct vc4_hdmi_audio, iec_status)); +- +- return 0; +-} +- +-static const struct snd_kcontrol_new vc4_hdmi_audio_controls[] = { +- { +- .access = SNDRV_CTL_ELEM_ACCESS_READ | +- SNDRV_CTL_ELEM_ACCESS_VOLATILE, +- .iface = SNDRV_CTL_ELEM_IFACE_PCM, +- .name = "ELD", +- .info = vc4_hdmi_audio_eld_ctl_info, +- .get = vc4_hdmi_audio_eld_ctl_get, +- }, +- { +- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, +- .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), +- .info = vc4_spdif_info, +- .get = vc4_spdif_playback_get, +- .put = vc4_spdif_playback_put, +- }, +- { +- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, +- .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), +- .info = vc4_spdif_info, +- .get = vc4_spdif_mask_get, +- }, +-}; +- + static const struct snd_soc_dapm_widget vc4_hdmi_audio_widgets[] = { + SND_SOC_DAPM_OUTPUT("TX"), + }; +@@ -1539,8 +1395,6 @@ static const struct snd_soc_dapm_route v + + static const struct snd_soc_component_driver vc4_hdmi_audio_component_drv = { + .name = "vc4-hdmi-codec-dai-component", +- .controls = vc4_hdmi_audio_controls, +- .num_controls = ARRAY_SIZE(vc4_hdmi_audio_controls), + .dapm_widgets = vc4_hdmi_audio_widgets, + .num_dapm_widgets = ARRAY_SIZE(vc4_hdmi_audio_widgets), + .dapm_routes = vc4_hdmi_audio_routes, +@@ -1551,28 +1405,6 @@ static const struct snd_soc_component_dr + .non_legacy_dai_naming = 1, + }; + +-static const struct snd_soc_dai_ops vc4_hdmi_audio_dai_ops = { +- .startup = vc4_hdmi_audio_startup, +- .shutdown = vc4_hdmi_audio_shutdown, +- .prepare = vc4_hdmi_audio_prepare, +- .set_fmt = vc4_hdmi_audio_set_fmt, +- .trigger = vc4_hdmi_audio_trigger, +-}; +- +-static struct snd_soc_dai_driver vc4_hdmi_audio_codec_dai_drv = { +- .name = "vc4-hdmi-hifi", +- .playback = { +- .stream_name = "Playback", +- .channels_min = 2, +- .channels_max = 8, +- .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | +- SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | +- SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | +- SNDRV_PCM_RATE_192000, +- .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE, +- }, +-}; +- + static const struct snd_soc_component_driver vc4_hdmi_audio_cpu_dai_comp = { + .name = "vc4-hdmi-cpu-dai-component", + }; +@@ -1599,7 +1431,6 @@ static struct snd_soc_dai_driver vc4_hdm + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE, + }, +- .ops = &vc4_hdmi_audio_dai_ops, + }; + + static const struct snd_dmaengine_pcm_config pcm_conf = { +@@ -1607,6 +1438,31 @@ static const struct snd_dmaengine_pcm_co + .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, + }; + ++ ++static int vc4_hdmi_audio_get_eld(struct device *dev, void *data, ++ uint8_t *buf, size_t len) ++{ ++ struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); ++ struct drm_connector *connector = &vc4_hdmi->connector; ++ ++ memcpy(buf, connector->eld, min(sizeof(connector->eld), len)); ++ ++ return 0; ++} ++ ++static const struct hdmi_codec_ops vc4_hdmi_codec_ops = { ++ .get_eld = vc4_hdmi_audio_get_eld, ++ .prepare = vc4_hdmi_audio_prepare, ++ .audio_shutdown = vc4_hdmi_audio_shutdown, ++ .audio_startup = vc4_hdmi_audio_startup, ++}; ++ ++struct hdmi_codec_pdata vc4_hdmi_codec_pdata = { ++ .ops = &vc4_hdmi_codec_ops, ++ .max_i2s_channels = 8, ++ .i2s = 1, ++}; ++ + static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) + { + const struct vc4_hdmi_register *mai_data = +@@ -1614,6 +1470,7 @@ static int vc4_hdmi_audio_init(struct vc + struct snd_soc_dai_link *dai_link = &vc4_hdmi->audio.link; + struct snd_soc_card *card = &vc4_hdmi->audio.card; + struct device *dev = &vc4_hdmi->pdev->dev; ++ struct platform_device *codec_pdev; + const __be32 *addr; + int index; + int ret; +@@ -1649,11 +1506,6 @@ static int vc4_hdmi_audio_init(struct vc + vc4_hdmi->audio.dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + vc4_hdmi->audio.dma_data.maxburst = 2; + +- vc4_hdmi->audio.iec_status[0] = IEC958_AES0_CON_NOT_COPYRIGHT; +- vc4_hdmi->audio.iec_status[1] = +- IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER; +- vc4_hdmi->audio.iec_status[3] = IEC958_AES3_CON_FS_48000; +- + ret = devm_snd_dmaengine_pcm_register(dev, &pcm_conf, 0); + if (ret) { + dev_err(dev, "Could not register PCM component: %d\n", ret); +@@ -1667,12 +1519,13 @@ static int vc4_hdmi_audio_init(struct vc + return ret; + } + +- /* register component and codec dai */ +- ret = devm_snd_soc_register_component(dev, &vc4_hdmi_audio_component_drv, +- &vc4_hdmi_audio_codec_dai_drv, 1); +- if (ret) { +- dev_err(dev, "Could not register component: %d\n", ret); +- return ret; ++ codec_pdev = platform_device_register_data(dev, HDMI_CODEC_DRV_NAME, ++ PLATFORM_DEVID_AUTO, ++ &vc4_hdmi_codec_pdata, ++ sizeof(vc4_hdmi_codec_pdata)); ++ if (IS_ERR(codec_pdev)) { ++ dev_err(dev, "Couldn't register the HDMI codec: %ld\n", PTR_ERR(codec_pdev)); ++ return PTR_ERR(codec_pdev); + } + + dai_link->cpus = &vc4_hdmi->audio.cpu; +@@ -1685,9 +1538,9 @@ static int vc4_hdmi_audio_init(struct vc + + dai_link->name = "MAI"; + dai_link->stream_name = "MAI PCM"; +- dai_link->codecs->dai_name = vc4_hdmi_audio_codec_dai_drv.name; ++ dai_link->codecs->dai_name = "i2s-hifi"; + dai_link->cpus->dai_name = dev_name(dev); +- dai_link->codecs->name = dev_name(dev); ++ dai_link->codecs->name = dev_name(&codec_pdev->dev); + dai_link->platforms->name = dev_name(dev); + + card->dai_link = dai_link; +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -114,8 +114,7 @@ struct vc4_hdmi_audio { + int samplerate; + int channels; + struct snd_dmaengine_dai_dma_data dma_data; +- struct snd_pcm_substream *substream; +- ++ struct hdmi_audio_infoframe infoframe; + bool streaming; + + unsigned char iec_status[4]; |