Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | // 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 <dm.h> #include <hda_codec.h> #include <log.h> #include <pch.h> #include <sound.h> #include <linux/bitops.h> #include <asm/global_data.h> 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), }; |