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