blob: 2deb92976ec218fbd67d101b1dd5825acb010346 [file] [log] [blame]
Aaron Durbin76c37002012-10-30 09:03:43 -05001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2008 Advanced Micro Devices, Inc.
5 * Copyright (C) 2008-2009 coresystems GmbH
6 * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
Aaron Durbin76c37002012-10-30 09:03:43 -050016 */
17
18#include <console/console.h>
19#include <device/device.h>
20#include <device/pci.h>
21#include <device/pci_ids.h>
22#include <device/pci_ops.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020023#include <device/mmio.h>
Aaron Durbin76c37002012-10-30 09:03:43 -050024#include <delay.h>
Vladimir Serbinenko75c83872014-09-05 01:01:31 +020025#include <device/azalia_device.h>
Aaron Durbin76c37002012-10-30 09:03:43 -050026#include "pch.h"
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070027#include "hda_verb.h"
Aaron Durbin76c37002012-10-30 09:03:43 -050028
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080029static void codecs_init(u8 *base, u32 codec_mask)
Aaron Durbin76c37002012-10-30 09:03:43 -050030{
31 int i;
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070032
33 /* Can support up to 4 codecs */
Aaron Durbin76c37002012-10-30 09:03:43 -050034 for (i = 3; i >= 0; i--) {
35 if (codec_mask & (1 << i))
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070036 hda_codec_init(base, i,
37 cim_verb_data_size,
38 cim_verb_data);
Aaron Durbin76c37002012-10-30 09:03:43 -050039 }
40
Vladimir Serbinenko75c83872014-09-05 01:01:31 +020041 if (pc_beep_verbs_size)
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070042 hda_codec_write(base, pc_beep_verbs_size, pc_beep_verbs);
Aaron Durbin76c37002012-10-30 09:03:43 -050043}
44
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080045static void azalia_pch_init(struct device *dev, u8 *base)
Aaron Durbin76c37002012-10-30 09:03:43 -050046{
Aaron Durbin76c37002012-10-30 09:03:43 -050047 u8 reg8;
48 u16 reg16;
49 u32 reg32;
50
Ryan Salsamendi0d9b3602017-06-30 17:15:57 -070051 if (RCBA32(0x2030) & (1UL << 31)) {
Kyösti Mälkki386b3e62013-07-26 08:52:49 +030052 reg32 = pci_read_config32(dev, 0x120);
Aaron Durbin76c37002012-10-30 09:03:43 -050053 reg32 &= 0xf8ffff01;
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070054 reg32 |= (1 << 25);
Aaron Durbin76c37002012-10-30 09:03:43 -050055 reg32 |= RCBA32(0x2030) & 0xfe;
Kyösti Mälkki386b3e62013-07-26 08:52:49 +030056 pci_write_config32(dev, 0x120, reg32);
Aaron Durbin76c37002012-10-30 09:03:43 -050057
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070058 if (!pch_is_lp()) {
59 reg16 = pci_read_config16(dev, 0x78);
60 reg16 &= ~(1 << 11);
61 pci_write_config16(dev, 0x78, reg16);
62 }
Aaron Durbin76c37002012-10-30 09:03:43 -050063 } else
64 printk(BIOS_DEBUG, "Azalia: V1CTL disabled.\n");
65
Kyösti Mälkki386b3e62013-07-26 08:52:49 +030066 reg32 = pci_read_config32(dev, 0x114);
Aaron Durbin76c37002012-10-30 09:03:43 -050067 reg32 &= ~0xfe;
Kyösti Mälkki386b3e62013-07-26 08:52:49 +030068 pci_write_config32(dev, 0x114, reg32);
Aaron Durbin76c37002012-10-30 09:03:43 -050069
70 // Set VCi enable bit
Kyösti Mälkki386b3e62013-07-26 08:52:49 +030071 if (pci_read_config32(dev, 0x120) & ((1 << 24) |
Aaron Durbin76c37002012-10-30 09:03:43 -050072 (1 << 25) | (1 << 26))) {
Kyösti Mälkki386b3e62013-07-26 08:52:49 +030073 reg32 = pci_read_config32(dev, 0x120);
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070074 if (pch_is_lp())
Ryan Salsamendi0d9b3602017-06-30 17:15:57 -070075 reg32 &= ~(1UL << 31);
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070076 else
Ryan Salsamendi0d9b3602017-06-30 17:15:57 -070077 reg32 |= (1UL << 31);
Kyösti Mälkki386b3e62013-07-26 08:52:49 +030078 pci_write_config32(dev, 0x120, reg32);
Aaron Durbin76c37002012-10-30 09:03:43 -050079 }
80
Aaron Durbin76c37002012-10-30 09:03:43 -050081 reg8 = pci_read_config8(dev, 0x43);
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070082 if (pch_is_lp())
83 reg8 &= ~(1 << 6);
84 else
85 reg8 |= (1 << 4);
Aaron Durbin76c37002012-10-30 09:03:43 -050086 pci_write_config8(dev, 0x43, reg8);
87
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070088 if (!pch_is_lp()) {
89 reg32 = pci_read_config32(dev, 0xc0);
90 reg32 |= (1 << 17);
91 pci_write_config32(dev, 0xc0, reg32);
92 }
Aaron Durbin76c37002012-10-30 09:03:43 -050093
94 /* Additional programming steps */
95 reg32 = pci_read_config32(dev, 0xc4);
Duncan Laurie0a7c49e2013-06-20 12:40:55 -070096 if (pch_is_lp())
97 reg32 |= (1 << 24);
98 else
99 reg32 |= (1 << 14);
Aaron Durbin76c37002012-10-30 09:03:43 -0500100 pci_write_config32(dev, 0xc4, reg32);
101
Duncan Laurie0a7c49e2013-06-20 12:40:55 -0700102 if (!pch_is_lp()) {
103 reg32 = pci_read_config32(dev, 0xd0);
Ryan Salsamendi0d9b3602017-06-30 17:15:57 -0700104 reg32 &= ~(1UL << 31);
Duncan Laurie0a7c49e2013-06-20 12:40:55 -0700105 pci_write_config32(dev, 0xd0, reg32);
106 }
Aaron Durbin76c37002012-10-30 09:03:43 -0500107
Aaron Durbin76c37002012-10-30 09:03:43 -0500108 reg8 = pci_read_config8(dev, 0x40); // Audio Control
Duncan Laurie0a7c49e2013-06-20 12:40:55 -0700109 reg8 |= 1; // Select Azalia mode
Aaron Durbin76c37002012-10-30 09:03:43 -0500110 pci_write_config8(dev, 0x40, reg8);
111
112 reg8 = pci_read_config8(dev, 0x4d); // Docking Status
113 reg8 &= ~(1 << 7); // Docking not supported
114 pci_write_config8(dev, 0x4d, reg8);
115
Duncan Laurie0a7c49e2013-06-20 12:40:55 -0700116 if (pch_is_lp()) {
117 reg16 = read32(base + 0x0012);
118 reg16 |= (1 << 0);
119 write32(base + 0x0012, reg16);
120
121 /* disable Auto Voltage Detector */
122 reg8 = pci_read_config8(dev, 0x42);
123 reg8 |= (1 << 2);
124 pci_write_config8(dev, 0x42, reg8);
125 }
126}
127
128static void azalia_init(struct device *dev)
129{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800130 u8 *base;
Duncan Laurie0a7c49e2013-06-20 12:40:55 -0700131 struct resource *res;
132 u32 codec_mask;
133 u32 reg32;
134
135 /* Find base address */
136 res = find_resource(dev, PCI_BASE_ADDRESS_0);
137 if (!res)
138 return;
139
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800140 base = res2mmio(res, 0, 0);
141 printk(BIOS_DEBUG, "Azalia: base = %p\n", base);
Duncan Laurie0a7c49e2013-06-20 12:40:55 -0700142
143 /* Set Bus Master */
144 reg32 = pci_read_config32(dev, PCI_COMMAND);
145 pci_write_config32(dev, PCI_COMMAND, reg32 | PCI_COMMAND_MASTER);
146
147 azalia_pch_init(dev, base);
148
149 codec_mask = hda_codec_detect(base);
Aaron Durbin76c37002012-10-30 09:03:43 -0500150
151 if (codec_mask) {
152 printk(BIOS_DEBUG, "Azalia: codec_mask = %02x\n", codec_mask);
Duncan Laurie0a7c49e2013-06-20 12:40:55 -0700153 codecs_init(base, codec_mask);
Aaron Durbin76c37002012-10-30 09:03:43 -0500154 }
Aaron Durbin76c37002012-10-30 09:03:43 -0500155}
156
Aaron Durbin76c37002012-10-30 09:03:43 -0500157static struct pci_operations azalia_pci_ops = {
Subrata Banik4a0f0712019-03-20 14:29:47 +0530158 .set_subsystem = pci_dev_set_subsystem,
Aaron Durbin76c37002012-10-30 09:03:43 -0500159};
160
161static struct device_operations azalia_ops = {
162 .read_resources = pci_dev_read_resources,
163 .set_resources = pci_dev_set_resources,
164 .enable_resources = pci_dev_enable_resources,
165 .init = azalia_init,
166 .scan_bus = 0,
167 .ops_pci = &azalia_pci_ops,
168};
169
Aaron Durbined095ca2013-05-20 15:57:16 -0500170static const unsigned short pci_device_ids[] = { 0x8c20, 0x9c20, 0 };
Aaron Durbin76c37002012-10-30 09:03:43 -0500171
172static const struct pci_driver pch_azalia __pci_driver = {
173 .ops = &azalia_ops,
174 .vendor = PCI_VENDOR_ID_INTEL,
175 .devices = pci_device_ids,
176};