|
@@ -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),
|
|
|
+};
|