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