blob: eb505ed42e224200ee301d6024d7eb5a7674606f [file] [log] [blame]
Aaron Durbin76c37002012-10-30 09:03:43 -05001/*
2 * This file is part of the coreboot project.
3 *
Aaron Durbin76c37002012-10-30 09:03:43 -05004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
Aaron Durbin76c37002012-10-30 09:03:43 -050013 */
14
15#include <console/console.h>
16#include <device/device.h>
17#include <device/pci.h>
18#include <device/pci_ids.h>
19#include <device/pci_ops.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020020#include <device/mmio.h>
Vladimir Serbinenko75c83872014-09-05 01:01:31 +020021#include <device/azalia_device.h>
Elyes HAOUASbf0970e2019-03-21 11:10:03 +010022
Aaron Durbin76c37002012-10-30 09:03:43 -050023#include "pch.h"
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070024#include "hda_verb.h"
Aaron Durbin76c37002012-10-30 09:03:43 -050025
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080026static void codecs_init(u8 *base, u32 codec_mask)
Aaron Durbin76c37002012-10-30 09:03:43 -050027{
28 int i;
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070029
30 /* Can support up to 4 codecs */
Aaron Durbin76c37002012-10-30 09:03:43 -050031 for (i = 3; i >= 0; i--) {
32 if (codec_mask & (1 << i))
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070033 hda_codec_init(base, i,
34 cim_verb_data_size,
35 cim_verb_data);
Aaron Durbin76c37002012-10-30 09:03:43 -050036 }
37
Vladimir Serbinenko75c83872014-09-05 01:01:31 +020038 if (pc_beep_verbs_size)
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070039 hda_codec_write(base, pc_beep_verbs_size, pc_beep_verbs);
Aaron Durbin76c37002012-10-30 09:03:43 -050040}
41
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080042static void azalia_pch_init(struct device *dev, u8 *base)
Aaron Durbin76c37002012-10-30 09:03:43 -050043{
Aaron Durbin76c37002012-10-30 09:03:43 -050044 u8 reg8;
45 u16 reg16;
46 u32 reg32;
47
Ryan Salsamendi0d9b3602017-06-30 17:15:57 -070048 if (RCBA32(0x2030) & (1UL << 31)) {
Kyösti Mälkki386b3e62013-07-26 08:52:49 +030049 reg32 = pci_read_config32(dev, 0x120);
Aaron Durbin76c37002012-10-30 09:03:43 -050050 reg32 &= 0xf8ffff01;
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070051 reg32 |= (1 << 25);
Aaron Durbin76c37002012-10-30 09:03:43 -050052 reg32 |= RCBA32(0x2030) & 0xfe;
Kyösti Mälkki386b3e62013-07-26 08:52:49 +030053 pci_write_config32(dev, 0x120, reg32);
Aaron Durbin76c37002012-10-30 09:03:43 -050054
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070055 if (!pch_is_lp()) {
56 reg16 = pci_read_config16(dev, 0x78);
57 reg16 &= ~(1 << 11);
58 pci_write_config16(dev, 0x78, reg16);
59 }
Aaron Durbin76c37002012-10-30 09:03:43 -050060 } else
61 printk(BIOS_DEBUG, "Azalia: V1CTL disabled.\n");
62
Kyösti Mälkki386b3e62013-07-26 08:52:49 +030063 reg32 = pci_read_config32(dev, 0x114);
Aaron Durbin76c37002012-10-30 09:03:43 -050064 reg32 &= ~0xfe;
Kyösti Mälkki386b3e62013-07-26 08:52:49 +030065 pci_write_config32(dev, 0x114, reg32);
Aaron Durbin76c37002012-10-30 09:03:43 -050066
67 // Set VCi enable bit
Kyösti Mälkki386b3e62013-07-26 08:52:49 +030068 if (pci_read_config32(dev, 0x120) & ((1 << 24) |
Aaron Durbin76c37002012-10-30 09:03:43 -050069 (1 << 25) | (1 << 26))) {
Kyösti Mälkki386b3e62013-07-26 08:52:49 +030070 reg32 = pci_read_config32(dev, 0x120);
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070071 if (pch_is_lp())
Ryan Salsamendi0d9b3602017-06-30 17:15:57 -070072 reg32 &= ~(1UL << 31);
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070073 else
Ryan Salsamendi0d9b3602017-06-30 17:15:57 -070074 reg32 |= (1UL << 31);
Kyösti Mälkki386b3e62013-07-26 08:52:49 +030075 pci_write_config32(dev, 0x120, reg32);
Aaron Durbin76c37002012-10-30 09:03:43 -050076 }
77
Aaron Durbin76c37002012-10-30 09:03:43 -050078 reg8 = pci_read_config8(dev, 0x43);
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070079 if (pch_is_lp())
80 reg8 &= ~(1 << 6);
81 else
82 reg8 |= (1 << 4);
Aaron Durbin76c37002012-10-30 09:03:43 -050083 pci_write_config8(dev, 0x43, reg8);
84
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070085 if (!pch_is_lp()) {
86 reg32 = pci_read_config32(dev, 0xc0);
87 reg32 |= (1 << 17);
88 pci_write_config32(dev, 0xc0, reg32);
89 }
Aaron Durbin76c37002012-10-30 09:03:43 -050090
91 /* Additional programming steps */
92 reg32 = pci_read_config32(dev, 0xc4);
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070093 if (pch_is_lp())
94 reg32 |= (1 << 24);
95 else
96 reg32 |= (1 << 14);
Aaron Durbin76c37002012-10-30 09:03:43 -050097 pci_write_config32(dev, 0xc4, reg32);
98
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070099 if (!pch_is_lp()) {
100 reg32 = pci_read_config32(dev, 0xd0);
Ryan Salsamendi0d9b3602017-06-30 17:15:57 -0700101 reg32 &= ~(1UL << 31);
Duncan Laurie0a7c49e2013-06-20 12:40:55 -0700102 pci_write_config32(dev, 0xd0, reg32);
103 }
Aaron Durbin76c37002012-10-30 09:03:43 -0500104
Aaron Durbin76c37002012-10-30 09:03:43 -0500105 reg8 = pci_read_config8(dev, 0x40); // Audio Control
Duncan Laurie0a7c49e2013-06-20 12:40:55 -0700106 reg8 |= 1; // Select Azalia mode
Aaron Durbin76c37002012-10-30 09:03:43 -0500107 pci_write_config8(dev, 0x40, reg8);
108
109 reg8 = pci_read_config8(dev, 0x4d); // Docking Status
110 reg8 &= ~(1 << 7); // Docking not supported
111 pci_write_config8(dev, 0x4d, reg8);
112
Duncan Laurie0a7c49e2013-06-20 12:40:55 -0700113 if (pch_is_lp()) {
114 reg16 = read32(base + 0x0012);
115 reg16 |= (1 << 0);
116 write32(base + 0x0012, reg16);
117
118 /* disable Auto Voltage Detector */
119 reg8 = pci_read_config8(dev, 0x42);
120 reg8 |= (1 << 2);
121 pci_write_config8(dev, 0x42, reg8);
122 }
123}
124
125static void azalia_init(struct device *dev)
126{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800127 u8 *base;
Duncan Laurie0a7c49e2013-06-20 12:40:55 -0700128 struct resource *res;
129 u32 codec_mask;
130 u32 reg32;
131
132 /* Find base address */
133 res = find_resource(dev, PCI_BASE_ADDRESS_0);
134 if (!res)
135 return;
136
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800137 base = res2mmio(res, 0, 0);
138 printk(BIOS_DEBUG, "Azalia: base = %p\n", base);
Duncan Laurie0a7c49e2013-06-20 12:40:55 -0700139
140 /* Set Bus Master */
141 reg32 = pci_read_config32(dev, PCI_COMMAND);
142 pci_write_config32(dev, PCI_COMMAND, reg32 | PCI_COMMAND_MASTER);
143
144 azalia_pch_init(dev, base);
145
146 codec_mask = hda_codec_detect(base);
Aaron Durbin76c37002012-10-30 09:03:43 -0500147
148 if (codec_mask) {
149 printk(BIOS_DEBUG, "Azalia: codec_mask = %02x\n", codec_mask);
Duncan Laurie0a7c49e2013-06-20 12:40:55 -0700150 codecs_init(base, codec_mask);
Aaron Durbin76c37002012-10-30 09:03:43 -0500151 }
Aaron Durbin76c37002012-10-30 09:03:43 -0500152}
153
Aaron Durbin76c37002012-10-30 09:03:43 -0500154static struct pci_operations azalia_pci_ops = {
Subrata Banik4a0f0712019-03-20 14:29:47 +0530155 .set_subsystem = pci_dev_set_subsystem,
Aaron Durbin76c37002012-10-30 09:03:43 -0500156};
157
158static struct device_operations azalia_ops = {
159 .read_resources = pci_dev_read_resources,
160 .set_resources = pci_dev_set_resources,
161 .enable_resources = pci_dev_enable_resources,
162 .init = azalia_init,
163 .scan_bus = 0,
164 .ops_pci = &azalia_pci_ops,
165};
166
Aaron Durbined095ca2013-05-20 15:57:16 -0500167static const unsigned short pci_device_ids[] = { 0x8c20, 0x9c20, 0 };
Aaron Durbin76c37002012-10-30 09:03:43 -0500168
169static const struct pci_driver pch_azalia __pci_driver = {
170 .ops = &azalia_ops,
171 .vendor = PCI_VENDOR_ID_INTEL,
172 .devices = pci_device_ids,
173};