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