bootstd: Update documentation
[platform/kernel/u-boot.git] / drivers / sound / ivybridge_sound.c
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
24 static 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
107 static int bd82x6x_azalia_setup(struct udevice *dev)
108 {
109         return 0;
110 }
111
112 int bd82x6x_azalia_start_beep(struct udevice *dev, int frequency_hz)
113 {
114         return hda_codec_start_beep(dev, frequency_hz);
115 }
116
117 int bd82x6x_azalia_stop_beep(struct udevice *dev)
118 {
119         return hda_codec_stop_beep(dev);
120 }
121
122 static 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
128 static const struct udevice_id bd82x6x_azalia_ids[] = {
129         { .compatible = "intel,hd-audio" },
130         { }
131 };
132
133 U_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 };