sound: x86: link: Add sound support
authorSimon Glass <sjg@chromium.org>
Sun, 17 Feb 2019 03:24:57 +0000 (20:24 -0700)
committerBin Meng <bmeng.cn@gmail.com>
Wed, 20 Feb 2019 07:27:09 +0000 (15:27 +0800)
Add sound support for link, using the HDA codec implementation.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
arch/x86/cpu/ivybridge/Kconfig
arch/x86/cpu/ivybridge/northbridge.c
arch/x86/dts/chromebook_link.dts
arch/x86/include/asm/arch-ivybridge/sandybridge.h
configs/chromebook_link_defconfig
drivers/sound/Kconfig
drivers/sound/Makefile
drivers/sound/ivybridge_sound.c [new file with mode: 0644]

index 5f0e60837ca18a8f2ce2e4072d6ba6b130969de9..2f423937864230cc866fa8cdf593262eec247bb1 100644 (file)
@@ -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
 
index 39bab7bdf34e32f278fa2af2804fe1745f7f35b6..a809b823b3bcf8997756527c09834d32b5c4be2b 100644 (file)
@@ -177,6 +177,35 @@ static void sandybridge_setup_northbridge_bars(struct udevice *dev)
        dm_pci_write_config8(dev, PAM6, 0x33);
 }
 
+/**
+ * sandybridge_init_iommu() - Set up IOMMU so that azalia can be used
+ *
+ * It is not obvious where these values come from. They may be undocumented.
+ */
+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);
+}
+
 static int bd82x6x_northbridge_early_init(struct udevice *dev)
 {
        const int chipset_type = SANDYBRIDGE_MOBILE;
@@ -197,6 +226,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);
 
index f9f097973026a7de3d8ea3cab862cc9f2bfe53a1..c5653feac7241eb83eec7132bd65485bf2441310 100644 (file)
@@ -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"
                        compatible = "ehci-pci";
                };
 
+               hda@1b,0 {
+                       reg = <0x0000d800 0 0 0 0>;
+                       compatible = "intel,bd82x6x-hda";
+
+                       /* These correspond to the Intel HDA specification */
+                       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 */
+
+                       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@1d,0 {
                        reg = <0x0000e800 0 0 0 0>;
                        compatible = "ehci-pci";
        };
 
 };
+
+&creative_codec {
+       verbs =  <
+               /**
+                * Malcolm Setup. These correspond to the Intel HDA
+                * specification.
+                */
+               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
+
+               /* 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)>;
+};
index a96c951c85ea8d5765cdf924eb9d858285842b1b..a3a507f2b368d2f882fee4209cc3d6e368d01b8e 100644 (file)
@@ -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
index c402568c17e204cb452d1015c4cc3521b376159e..6058dfaf0f24b284a8007a5d160e3033445a29b6 100644 (file)
@@ -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
index 0dca6ffe88cee105aa3968f514b82b1df87b4673..4b893f035b0284b8905205d3c84dfd2875293507 100644 (file)
@@ -49,6 +49,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
+         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
index 2e21a0d06741b661885690b1adf7e5edce55a690..771c11651673d6429f129e9774a6dad9e88151d7 100644 (file)
@@ -16,3 +16,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 (file)
index 0000000..101046f
--- /dev/null
@@ -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 */
+       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,hd-audio" },
+       { }
+};
+
+U_BOOT_DRIVER(bd82x6x_azalia_drv) = {
+       .name           = "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),
+};