[U-Boot] [PATCH 23/33] sound: x86: link: Add sound support

Bin Meng bmeng.cn at gmail.com
Wed Feb 13 09:39:19 UTC 2019


Hi Simon,

On Tue, Jan 22, 2019 at 9:14 AM Simon Glass <sjg at chromium.org> wrote:
>
> Add sound support for link, using the HDA codec implementation.
>
> Signed-off-by: Simon Glass <sjg at chromium.org>
> ---
>
>  arch/x86/cpu/ivybridge/Kconfig                |   1 +
>  arch/x86/cpu/ivybridge/northbridge.c          |  27 ++++
>  arch/x86/dts/chromebook_link.dts              |  91 ++++++++++++
>  .../include/asm/arch-ivybridge/sandybridge.h  |   3 +
>  configs/chromebook_link_defconfig             |   2 +
>  drivers/sound/Kconfig                         |  10 ++
>  drivers/sound/Makefile                        |   1 +
>  drivers/sound/ivybridge_sound.c               | 137 ++++++++++++++++++
>  8 files changed, 272 insertions(+)
>  create mode 100644 drivers/sound/ivybridge_sound.c
>
> diff --git a/arch/x86/cpu/ivybridge/Kconfig b/arch/x86/cpu/ivybridge/Kconfig
> index 5f0e60837c..2f42393786 100644
> --- a/arch/x86/cpu/ivybridge/Kconfig
> +++ b/arch/x86/cpu/ivybridge/Kconfig
> @@ -21,6 +21,7 @@ config NORTHBRIDGE_INTEL_IVYBRIDGE
>         imply USB_EHCI_HCD
>         imply USB_XHCI_HCD
>         imply VIDEO_VESA
> +       imply SOUND_IVYBRIDGE
>
>  if NORTHBRIDGE_INTEL_IVYBRIDGE
>
> diff --git a/arch/x86/cpu/ivybridge/northbridge.c b/arch/x86/cpu/ivybridge/northbridge.c
> index 39bab7bdf3..0ac0a34acc 100644
> --- a/arch/x86/cpu/ivybridge/northbridge.c
> +++ b/arch/x86/cpu/ivybridge/northbridge.c
> @@ -177,6 +177,30 @@ static void sandybridge_setup_northbridge_bars(struct udevice *dev)
>         dm_pci_write_config8(dev, PAM6, 0x33);
>  }
>
> +static void sandybridge_init_iommu(struct udevice *dev)
> +{
> +       u32 capid0_a;
> +
> +       dm_pci_read_config32(dev, 0xe4, &capid0_a);
> +       if (capid0_a & (1 << 23)) {
> +               log_debug("capid0_a not needed\n");
> +               return;
> +       }
> +
> +       /* setup BARs */
> +       writel(IOMMU_BASE1 >> 32, MCHBAR_REG(0x5404));
> +       writel(IOMMU_BASE1 | 1, MCHBAR_REG(0x5400));
> +       writel(IOMMU_BASE2 >> 32, MCHBAR_REG(0x5414));
> +       writel(IOMMU_BASE2 | 1, MCHBAR_REG(0x5410));
> +
> +       /* lock policies */
> +       writel(0x80000000, IOMMU_BASE1 + 0xff0);
> +
> +       /* Enable azalia sound */
> +       writel(0x20000000, IOMMU_BASE2 + 0xff0);
> +       writel(0xa0000000, IOMMU_BASE2 + 0xff0);
> +}

The function name looks it has something to do with IOMMU, but why
does enabling sound support need IOMMU which is mainly for hypervisor
stuff? Better providing some comments here, and if possible use macros
instead of hard-coded numbers.

> +
>  static int bd82x6x_northbridge_early_init(struct udevice *dev)
>  {
>         const int chipset_type = SANDYBRIDGE_MOBILE;
> @@ -197,6 +221,9 @@ static int bd82x6x_northbridge_early_init(struct udevice *dev)
>
>         sandybridge_setup_northbridge_bars(dev);
>
> +       /* Setup IOMMU BARs */
> +       sandybridge_init_iommu(dev);
> +
>         /* Device Enable */
>         dm_pci_write_config32(dev, DEVEN, DEVEN_HOST | DEVEN_IGD);
>
> diff --git a/arch/x86/dts/chromebook_link.dts b/arch/x86/dts/chromebook_link.dts
> index f9f0979730..7e0a615a60 100644
> --- a/arch/x86/dts/chromebook_link.dts
> +++ b/arch/x86/dts/chromebook_link.dts
> @@ -1,6 +1,8 @@
>  /dts-v1/;
>
>  #include <dt-bindings/gpio/x86-gpio.h>
> +#include <dt-bindings/sound/azalia.h>
> +#include <pci_ids.h>
>
>  /include/ "skeleton.dtsi"
>  /include/ "keyboard.dtsi"
> @@ -372,6 +374,30 @@
>                         compatible = "ehci-pci";
>                 };
>
> +               hda at 1b,0 {
> +                       reg = <0x0000d800 0 0 0 0>;
> +                       compatible = "intel,bd82x6x-hda";
> +                       beep-verbs = <
> +                               0x00170500      /* power up codec */
> +                               0x00270500      /* power up DAC */
> +                               0x00b70500      /* power up speaker */
> +                               0x00b70740      /* enable speaker out */
> +                               0x00b78d00      /* enable EAPD pin */
> +                               0x00b70c02      /* set EAPD pin */
> +                               0x0143b013>;    /* beep volume */

Are these verbs from the chipset datasheet?

> +
> +                       codecs {
> +                               creative_codec: creative-ca0132 {
> +                                       vendor-id = <PCI_VENDOR_ID_CREATIVE>;
> +                                       device-id = <PCI_DEVICE_ID_CREATIVE_CA01322>;
> +                               };
> +                               intel_hdmi: hdmi {
> +                                       vendor-id = <PCI_VENDOR_ID_INTEL>;
> +                                       device-id = <PCI_DEVICE_ID_INTEL_COUGARPOINT_HDMI>;
> +                               };
> +                       };
> +               };
> +
>                 usb_0: usb at 1d,0 {
>                         reg = <0x0000e800 0 0 0 0>;
>                         compatible = "ehci-pci";
> @@ -492,3 +518,68 @@
>         };
>
>  };
> +
> +&creative_codec {
> +       verbs =  <
> +               /* Malcolm Setup */
> +               0x01570d09 0x01570c23 0x01570a01 0x01570df0
> +               0x01570efe 0x01570775 0x015707d3 0x01570709
> +               0x01570753 0x015707d4 0x015707ef 0x01570775
> +               0x015707d3 0x01570709 0x01570702 0x01570737
> +               0x01570778 0x01553cce 0x015575c9 0x01553dce
> +               0x0155b7c9 0x01570de8 0x01570efe 0x01570702
> +               0x01570768 0x01570762 0x01553ace 0x015546c9
> +               0x01553bce 0x0155e8c9 0x01570d49 0x01570c88
> +               0x01570d20 0x01570e19 0x01570700 0x01571a05
> +               0x01571b29 0x01571a04 0x01571b29 0x01570a01
> +

And here? Is this something one can easily get from the chipset
datasheet? If not, better adding some comments to point out the
sources of these magic numbers.

> +               /* Pin Widget Verb Table */
> +
> +               /* NID 0x01, HDA Codec Subsystem ID Verb Table: 0x144DC0C2 */
> +               AZALIA_SUBVENDOR(0x0, 0x144dc0c2)
> +
> +               /*
> +                * Pin Complex (NID 0x0B)  Port-G Analog Unknown
> +                * Speaker at Int N/A
> +                */
> +               AZALIA_PIN_CFG(0x0, 0x0b, 0x901700f0)
> +
> +               /* Pin Complex (NID 0x0C)  N/C */
> +               AZALIA_PIN_CFG(0x0, 0x0c, 0x70f000f0)
> +
> +               /* Pin Complex (NID 0x0D)  N/C */
> +               AZALIA_PIN_CFG(0x0, 0x0d, 0x70f000f0)
> +
> +               /* Pin Complex (NID 0x0E)  N/C */
> +               AZALIA_PIN_CFG(0x0, 0x0e, 0x70f000f0)
> +
> +               /* Pin Complex (NID 0x0F)  N/C */
> +               AZALIA_PIN_CFG(0x0, 0x0f, 0x70f000f0)
> +
> +               /* Pin Complex (NID 0x10) Port-D 1/8 Black HP Out at Ext Left */
> +               AZALIA_PIN_CFG(0x0, 0x10, 0x032110f0)
> +
> +               /* Pin Complex (NID 0x11) Port-B Click Mic */
> +               AZALIA_PIN_CFG(0x0, 0x11, 0x90a700f0)
> +
> +               /* Pin Complex (NID 0x12) Port-C Combo Jack Mic or D-Mic */
> +               AZALIA_PIN_CFG(0x0, 0x12, 0x03a110f0)
> +
> +               /* Pin Complex (NID 0x13) What you hear */
> +               AZALIA_PIN_CFG(0x0, 0x13, 0x90d600f0)>;
> +};
> +
> +&intel_hdmi {
> +       verbs = <
> +               /* NID 0x01, HDA Codec Subsystem ID Verb Table: 0x80860101 */
> +               AZALIA_SUBVENDOR(0x3, 0x80860101)
> +
> +               /* Pin Complex (NID 0x05) Digital Out at Int HDMI */
> +               AZALIA_PIN_CFG(0x3, 0x05, 0x18560010)
> +
> +               /* Pin Complex (NID 0x06) Digital Out at Int HDMI */
> +               AZALIA_PIN_CFG(0x3, 0x06, 0x18560020)
> +
> +               /* Pin Complex (NID 0x07) Digital Out at Int HDMI */
> +               AZALIA_PIN_CFG(0x3, 0x07, 0x18560030)>;
> +};
> diff --git a/arch/x86/include/asm/arch-ivybridge/sandybridge.h b/arch/x86/include/asm/arch-ivybridge/sandybridge.h
> index a96c951c85..a3a507f2b3 100644
> --- a/arch/x86/include/asm/arch-ivybridge/sandybridge.h
> +++ b/arch/x86/include/asm/arch-ivybridge/sandybridge.h
> @@ -43,6 +43,9 @@
>  /* 4 KB per PCIe device */
>  #define DEFAULT_PCIEXBAR       CONFIG_PCIE_ECAM_BASE
>
> +#define IOMMU_BASE1            0xfed90000ULL
> +#define IOMMU_BASE2            0xfed91000ULL
> +
>  /* Device 0:0.0 PCI configuration space (Host Bridge) */
>  #define EPBAR          0x40
>  #define MCHBAR         0x48
> diff --git a/configs/chromebook_link_defconfig b/configs/chromebook_link_defconfig
> index c402568c17..6058dfaf0f 100644
> --- a/configs/chromebook_link_defconfig
> +++ b/configs/chromebook_link_defconfig
> @@ -33,6 +33,7 @@ CONFIG_CMD_DHCP=y
>  # CONFIG_CMD_NFS is not set
>  CONFIG_CMD_PING=y
>  CONFIG_CMD_TIME=y
> +CONFIG_CMD_SOUND=y
>  CONFIG_CMD_BOOTSTAGE=y
>  CONFIG_CMD_TPM=y
>  CONFIG_CMD_TPM_TEST=y
> @@ -53,6 +54,7 @@ CONFIG_SYS_I2C_INTEL=y
>  CONFIG_CROS_EC=y
>  CONFIG_CROS_EC_LPC=y
>  CONFIG_SYS_NS16550=y
> +CONFIG_SOUND=y
>  CONFIG_SPI=y
>  CONFIG_TPM_TIS_LPC=y
>  CONFIG_USB_STORAGE=y
> diff --git a/drivers/sound/Kconfig b/drivers/sound/Kconfig
> index a03d3057e1..a414e8e712 100644
> --- a/drivers/sound/Kconfig
> +++ b/drivers/sound/Kconfig
> @@ -40,6 +40,16 @@ config SOUND_INTEL_HDA
>           Azalia which was the development code-name. It requires setup
>           information in the device tree (see intel-hda.txt).
>
> +config SOUND_IVYBRIDGE
> +       bool "Intel Ivybridge sound support"
> +       depends on SOUND
> +       select SOUND_INTEL_HDA
> +       help
> +         Enable sound output on supported Intel ivybridge-based boards. This

nits: Ivybridge-based

> +         driver uses Intel's High-definition Audio (HDA) architecture,
> +         sometimes called Azalia. The audio codec is detected using a
> +         semi-automatic mechanism.
> +
>  config SOUND_MAX98088
>         bool "Support Maxim max98088 audio codec"
>         depends on I2S
> diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile
> index 705a09464d..23893947be 100644
> --- a/drivers/sound/Makefile
> +++ b/drivers/sound/Makefile
> @@ -15,3 +15,4 @@ obj-$(CONFIG_SOUND_MAX98088)  += max98088.o maxim_codec.o
>  obj-$(CONFIG_SOUND_MAX98090)   += max98090.o maxim_codec.o
>  obj-$(CONFIG_SOUND_MAX98095)   += max98095.o maxim_codec.o
>  obj-$(CONFIG_SOUND_INTEL_HDA)  += hda_codec.o
> +obj-$(CONFIG_SOUND_IVYBRIDGE)  += ivybridge_sound.o
> diff --git a/drivers/sound/ivybridge_sound.c b/drivers/sound/ivybridge_sound.c
> new file mode 100644
> index 0000000000..49071b323c
> --- /dev/null
> +++ b/drivers/sound/ivybridge_sound.c
> @@ -0,0 +1,137 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Intel HDA audio (Azalia) for ivybridge
> + *
> + * Originally from coreboot file bd82x6x/azalia.c
> + *
> + * Copyright (C) 2008 Advanced Micro Devices, Inc.
> + * Copyright (C) 2008-2009 coresystems GmbH
> + * Copyright (C) 2011 The ChromiumOS Authors.
> + * Copyright 2018 Google LLC
> + */
> +
> +#define LOG_CATEGORY UCLASS_SOUND
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <hda_codec.h>
> +#include <pch.h>
> +#include <sound.h>
> +
> +static int bd82x6x_azalia_probe(struct udevice *dev)
> +{
> +       struct pci_child_platdata *plat;
> +       struct hda_codec_priv *priv;
> +       struct udevice *pch;
> +       u32 codec_mask;
> +       int conf;
> +       int ret;
> +
> +       /* Only init after relocation */
> +       if (!(gd->flags & GD_FLG_RELOC))
> +               return 0;
> +
> +       ret = hda_codec_init(dev);
> +       if (ret) {
> +               log_debug("Cannot set up HDA codec (err=%d)\n", ret);
> +               return ret;
> +       }
> +       priv = dev_get_priv(dev);
> +
> +       ret = uclass_first_device_err(UCLASS_PCH, &pch);
> +       log_debug("PCH %p %s\n", pch, pch->name);
> +       if (ret)
> +               return ret;
> +
> +       conf = pch_ioctl(pch, PCH_REQ_HDA_CONFIG, NULL, 0);
> +       log_debug("conf = %x\n", conf);
> +       if (conf >= 0) {
> +               dm_pci_clrset_config32(dev, 0x120, 7 << 24 | 0xfe,
> +                                      1 << 24 | // 2 << 24 for server
> +                                      conf);
> +
> +               dm_pci_clrset_config16(dev, 0x78, 0, 1 << 1);
> +       } else {
> +               log_debug("V1CTL disabled\n");
> +       }
> +       dm_pci_clrset_config32(dev, 0x114, 0xfe, 0);
> +
> +       // Set VCi enable bit

nits: Use /* */

> +       dm_pci_clrset_config32(dev, 0x120, 0, 1U << 31);
> +
> +       /* Enable HDMI codec */
> +       dm_pci_clrset_config32(dev, 0xc4, 0, 1 << 1);
> +       dm_pci_clrset_config8(dev, 0x43, 0, 1 << 6);
> +
> +       /* Additional programming steps */
> +       dm_pci_clrset_config32(dev, 0xc4, 0, 1 << 13);
> +       dm_pci_clrset_config32(dev, 0xc4, 0, 1 << 10);
> +       dm_pci_clrset_config32(dev, 0xd0, 1U << 31, 0);
> +
> +       /* Additional step on Panther Point */
> +       plat = dev_get_parent_platdata(dev);
> +       if (plat->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_HDA)
> +               dm_pci_clrset_config32(dev, 0xc4, 0, 1 << 17);
> +
> +       dm_pci_write_config8(dev, 0x3c, 0xa); /* unused? */
> +
> +       /* Audio Control: Select Azalia mode */
> +       dm_pci_clrset_config8(dev, 0x40, 0, 1);
> +       dm_pci_clrset_config8(dev, 0x4d, 1 << 7, 0); /* Docking not supported */
> +       codec_mask = hda_codec_detect(priv->regs);
> +       log_debug("codec_mask = %02x\n", codec_mask);
> +
> +       if (codec_mask) {
> +               ret = hda_codecs_init(dev, priv->regs, codec_mask);
> +               if (ret) {
> +                       log_err("Codec init failed (err=%d)\n", ret);
> +                       return ret;
> +               }
> +       }
> +
> +       /* Enable dynamic clock gating */
> +       dm_pci_clrset_config8(dev, 0x43, 7, BIT(2) | BIT(0));
> +
> +       ret = hda_codec_finish_init(dev);
> +       if (ret) {
> +               log_debug("Cannot set up HDA codec (err=%d)\n", ret);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static int bd82x6x_azalia_setup(struct udevice *dev)
> +{
> +       return 0;
> +}
> +
> +int bd82x6x_azalia_start_beep(struct udevice *dev, int frequency_hz)
> +{
> +       return hda_codec_start_beep(dev, frequency_hz);
> +}
> +
> +int bd82x6x_azalia_stop_beep(struct udevice *dev)
> +{
> +       return hda_codec_stop_beep(dev);
> +}
> +
> +static const struct sound_ops bd82x6x_azalia_ops = {
> +       .setup          = bd82x6x_azalia_setup,
> +       .start_beep     = bd82x6x_azalia_start_beep,
> +       .stop_beep      = bd82x6x_azalia_stop_beep,
> +};
> +
> +static const struct udevice_id bd82x6x_azalia_ids[] = {
> +       { .compatible = "intel,bd82x6x-hda" },
> +       { }
> +};
> +
> +U_BOOT_DRIVER(bd82x6x_azalia_drv) = {
> +       .name           = "bd82x6x",

The driver name is too generic. Could be "bd82x6x-hda"?

> +       .id             = UCLASS_SOUND,
> +       .of_match       = bd82x6x_azalia_ids,
> +       .probe          = bd82x6x_azalia_probe,
> +       .ops            = &bd82x6x_azalia_ops,
> +       .priv_auto_alloc_size   = sizeof(struct hda_codec_priv),
> +};
> --

Regards,
Bin


More information about the U-Boot mailing list