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 
bd82x6x_azalia_probe(struct udevice * dev)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 
bd82x6x_azalia_setup(struct udevice * dev)104 static int bd82x6x_azalia_setup(struct udevice *dev)
105 {
106 	return 0;
107 }
108 
bd82x6x_azalia_start_beep(struct udevice * dev,int frequency_hz)109 int bd82x6x_azalia_start_beep(struct udevice *dev, int frequency_hz)
110 {
111 	return hda_codec_start_beep(dev, frequency_hz);
112 }
113 
bd82x6x_azalia_stop_beep(struct udevice * dev)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