blob: 101046f9c20152017f57e19c020988a6c715317f [file] [log] [blame]
Simon Glass6744c0d2019-02-16 20:24:57 -07001// 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
21static 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
104static int bd82x6x_azalia_setup(struct udevice *dev)
105{
106 return 0;
107}
108
109int bd82x6x_azalia_start_beep(struct udevice *dev, int frequency_hz)
110{
111 return hda_codec_start_beep(dev, frequency_hz);
112}
113
114int bd82x6x_azalia_stop_beep(struct udevice *dev)
115{
116 return hda_codec_stop_beep(dev);
117}
118
119static 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
125static const struct udevice_id bd82x6x_azalia_ids[] = {
126 { .compatible = "intel,hd-audio" },
127 { }
128};
129
130U_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};