sound: x86: link: Add sound support

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>
diff --git a/arch/x86/cpu/ivybridge/Kconfig b/arch/x86/cpu/ivybridge/Kconfig
index 5f0e608..2f42393 100644
--- a/arch/x86/cpu/ivybridge/Kconfig
+++ b/arch/x86/cpu/ivybridge/Kconfig
@@ -21,6 +21,7 @@
 	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 39bab7b..a809b82 100644
--- a/arch/x86/cpu/ivybridge/northbridge.c
+++ b/arch/x86/cpu/ivybridge/northbridge.c
@@ -177,6 +177,35 @@
 	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 @@
 
 	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 f9f0979..c5653fe 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,32 @@
 			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";
@@ -491,4 +519,72 @@
 		};
 	};
 
+};
+
+&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)>;
 };
diff --git a/arch/x86/include/asm/arch-ivybridge/sandybridge.h b/arch/x86/include/asm/arch-ivybridge/sandybridge.h
index a96c951..a3a507f 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