1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Intel HDA audio (Azalia) for ivybridge 4 * 5 * Originally from coreboot file bd82x6x/azalia.c 6 * 7 * Copyright (C) 2008 Advanced Micro Devices, Inc. 8 * Copyright (C) 2008-2009 coresystems GmbH 9 * Copyright (C) 2011 The ChromiumOS Authors. 10 * Copyright 2018 Google LLC 11 */ 12 13 #define LOG_CATEGORY UCLASS_SOUND 14 15 #include <common.h> 16 #include <dm.h> 17 #include <hda_codec.h> 18 #include <pch.h> 19 #include <sound.h> 20 21 static int bd82x6x_azalia_probe(struct udevice *dev) 22 { 23 struct pci_child_platdata *plat; 24 struct hda_codec_priv *priv; 25 struct udevice *pch; 26 u32 codec_mask; 27 int conf; 28 int ret; 29 30 /* Only init after relocation */ 31 if (!(gd->flags & GD_FLG_RELOC)) 32 return 0; 33 34 ret = hda_codec_init(dev); 35 if (ret) { 36 log_debug("Cannot set up HDA codec (err=%d)\n", ret); 37 return ret; 38 } 39 priv = dev_get_priv(dev); 40 41 ret = uclass_first_device_err(UCLASS_PCH, &pch); 42 log_debug("PCH %p %s\n", pch, pch->name); 43 if (ret) 44 return ret; 45 46 conf = pch_ioctl(pch, PCH_REQ_HDA_CONFIG, NULL, 0); 47 log_debug("conf = %x\n", conf); 48 if (conf >= 0) { 49 dm_pci_clrset_config32(dev, 0x120, 7 << 24 | 0xfe, 50 1 << 24 | /* 2 << 24 for server */ 51 conf); 52 53 dm_pci_clrset_config16(dev, 0x78, 0, 1 << 1); 54 } else { 55 log_debug("V1CTL disabled\n"); 56 } 57 dm_pci_clrset_config32(dev, 0x114, 0xfe, 0); 58 59 /* Set VCi enable bit */ 60 dm_pci_clrset_config32(dev, 0x120, 0, 1U << 31); 61 62 /* Enable HDMI codec */ 63 dm_pci_clrset_config32(dev, 0xc4, 0, 1 << 1); 64 dm_pci_clrset_config8(dev, 0x43, 0, 1 << 6); 65 66 /* Additional programming steps */ 67 dm_pci_clrset_config32(dev, 0xc4, 0, 1 << 13); 68 dm_pci_clrset_config32(dev, 0xc4, 0, 1 << 10); 69 dm_pci_clrset_config32(dev, 0xd0, 1U << 31, 0); 70 71 /* Additional step on Panther Point */ 72 plat = dev_get_parent_platdata(dev); 73 if (plat->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_HDA) 74 dm_pci_clrset_config32(dev, 0xc4, 0, 1 << 17); 75 76 dm_pci_write_config8(dev, 0x3c, 0xa); /* unused? */ 77 78 /* Audio Control: Select Azalia mode */ 79 dm_pci_clrset_config8(dev, 0x40, 0, 1); 80 dm_pci_clrset_config8(dev, 0x4d, 1 << 7, 0); /* Docking not supported */ 81 codec_mask = hda_codec_detect(priv->regs); 82 log_debug("codec_mask = %02x\n", codec_mask); 83 84 if (codec_mask) { 85 ret = hda_codecs_init(dev, priv->regs, codec_mask); 86 if (ret) { 87 log_err("Codec init failed (err=%d)\n", ret); 88 return ret; 89 } 90 } 91 92 /* Enable dynamic clock gating */ 93 dm_pci_clrset_config8(dev, 0x43, 7, BIT(2) | BIT(0)); 94 95 ret = hda_codec_finish_init(dev); 96 if (ret) { 97 log_debug("Cannot set up HDA codec (err=%d)\n", ret); 98 return ret; 99 } 100 101 return 0; 102 } 103 104 static int bd82x6x_azalia_setup(struct udevice *dev) 105 { 106 return 0; 107 } 108 109 int bd82x6x_azalia_start_beep(struct udevice *dev, int frequency_hz) 110 { 111 return hda_codec_start_beep(dev, frequency_hz); 112 } 113 114 int bd82x6x_azalia_stop_beep(struct udevice *dev) 115 { 116 return hda_codec_stop_beep(dev); 117 } 118 119 static const struct sound_ops bd82x6x_azalia_ops = { 120 .setup = bd82x6x_azalia_setup, 121 .start_beep = bd82x6x_azalia_start_beep, 122 .stop_beep = bd82x6x_azalia_stop_beep, 123 }; 124 125 static const struct udevice_id bd82x6x_azalia_ids[] = { 126 { .compatible = "intel,hd-audio" }, 127 { } 128 }; 129 130 U_BOOT_DRIVER(bd82x6x_azalia_drv) = { 131 .name = "bd82x6x-hda", 132 .id = UCLASS_SOUND, 133 .of_match = bd82x6x_azalia_ids, 134 .probe = bd82x6x_azalia_probe, 135 .ops = &bd82x6x_azalia_ops, 136 .priv_auto_alloc_size = sizeof(struct hda_codec_priv), 137 }; 138