// 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 #include #include #include #include #include #include #include static int bd82x6x_azalia_probe(struct udevice *dev) { struct pci_child_plat *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_plat(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 = sizeof(struct hda_codec_priv), };