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 
bd82x6x_azalia_probe(struct udevice * dev)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 
bd82x6x_azalia_setup(struct udevice * dev)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 
bd82x6x_azalia_start_beep(struct udevice * dev,int frequency_hz)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 
bd82x6x_azalia_stop_beep(struct udevice * dev)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