blob: be8aa692643ab8c736948adeb546fce6ba06a321 [file] [log] [blame]
zbao246e84b2012-07-13 18:47:03 +08001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2010 Advanced Micro Devices, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
Paul Menzela46a7122013-02-23 18:37:27 +010017 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
zbao246e84b2012-07-13 18:47:03 +080018 */
19
20#include <console/console.h>
21
22#include <arch/io.h>
23#include <arch/acpi.h>
24
25#include <device/device.h>
26#include <device/pci.h>
27#include <device/pci_ids.h>
28#include <device/pci_ops.h>
29#include <cbmem.h>
30#include "hudson.h"
Kyösti Mälkki29d9c562014-10-16 21:35:48 +030031#include "imc.h"
zbao246e84b2012-07-13 18:47:03 +080032#include "smbus.h"
Alexandru Gagniuc86777e32014-04-20 14:36:29 -050033#include "smi.h"
zbao246e84b2012-07-13 18:47:03 +080034
Alexandru Gagniuc342ac642014-04-14 16:44:19 -050035/* Offsets from ACPI_MMIO_BASE
36 * This is defined by AGESA, but we don't include AGESA headers to avoid
Martin Roth3c3a50c2014-12-16 20:50:26 -070037 * polluting the namespace.
Alexandru Gagniuc342ac642014-04-14 16:44:19 -050038 */
39#define PM_MMIO_BASE 0xfed80300
40
41
Stefan Reinauer8ada1522012-11-16 13:34:48 -080042#if CONFIG_HAVE_ACPI_RESUME
zbao246e84b2012-07-13 18:47:03 +080043int acpi_get_sleep_type(void)
44{
Alexandru Gagniuccf1f9b62014-04-20 13:24:42 -050045 u16 tmp = inw(ACPI_PM1_CNT_BLK);
zbao246e84b2012-07-13 18:47:03 +080046 tmp = ((tmp & (7 << 10)) >> 10);
47 /* printk(BIOS_DEBUG, "SLP_TYP type was %x\n", tmp); */
48 return (int)tmp;
49}
50#endif
51
Kyösti Mälkkibc90e152013-09-04 13:26:11 +030052void backup_top_of_ram(uint64_t ramtop)
zbao246e84b2012-07-13 18:47:03 +080053{
Kyösti Mälkkibc90e152013-09-04 13:26:11 +030054 u32 dword = (u32) ramtop;
zbao246e84b2012-07-13 18:47:03 +080055 int nvram_pos = 0xf8, i; /* temp */
56 /* printk(BIOS_DEBUG, "dword=%x\n", dword); */
57 for (i = 0; i<4; i++) {
58 /* printk(BIOS_DEBUG, "nvram_pos=%x, dword>>(8*i)=%x\n", nvram_pos, (dword >>(8 * i)) & 0xff); */
59 outb(nvram_pos, BIOSRAM_INDEX);
60 outb((dword >>(8 * i)) & 0xff , BIOSRAM_DATA);
61 nvram_pos++;
62 }
63}
64
Alexandru Gagniuc342ac642014-04-14 16:44:19 -050065void pm_write8(u8 reg, u8 value)
zbao246e84b2012-07-13 18:47:03 +080066{
Alexandru Gagniuc342ac642014-04-14 16:44:19 -050067 write8(PM_MMIO_BASE + reg, value);
zbao246e84b2012-07-13 18:47:03 +080068}
69
Alexandru Gagniuc342ac642014-04-14 16:44:19 -050070u8 pm_read8(u8 reg)
zbao246e84b2012-07-13 18:47:03 +080071{
Alexandru Gagniuc342ac642014-04-14 16:44:19 -050072 return read8(PM_MMIO_BASE + reg);
zbao246e84b2012-07-13 18:47:03 +080073}
74
Alexandru Gagniuc342ac642014-04-14 16:44:19 -050075void pm_write16(u8 reg, u16 value)
zbao246e84b2012-07-13 18:47:03 +080076{
Alexandru Gagniuc342ac642014-04-14 16:44:19 -050077 write16(PM_MMIO_BASE + reg, value);
zbao246e84b2012-07-13 18:47:03 +080078}
79
Alexandru Gagniuc342ac642014-04-14 16:44:19 -050080u16 pm_read16(u16 reg)
zbao246e84b2012-07-13 18:47:03 +080081{
Alexandru Gagniuc342ac642014-04-14 16:44:19 -050082 return read16(PM_MMIO_BASE + reg);
zbao246e84b2012-07-13 18:47:03 +080083}
84
Alexandru Gagniucd2e5f682014-04-16 16:33:03 -050085#define PM_REG_USB_ENABLE 0xef
86
87enum usb_enable {
88 USB_EN_DEVFN_12_0 = (1 << 0),
89 USB_EN_DEVFN_12_2 = (1 << 1),
90 USB_EN_DEVFN_13_0 = (1 << 2),
91 USB_EN_DEVFN_13_2 = (1 << 3),
92 USB_EN_DEVFN_16_0 = (1 << 4),
93 USB_EN_DEVFN_16_2 = (1 << 5),
94};
95
96static void hudson_disable_usb(u8 disable)
97{
98 u8 reg8;
99
100 /* Bit 7 handles routing, 6 is reserved. we don't mess with those */
101 disable &= 0x3f;
102
103 reg8 = pm_read8(PM_REG_USB_ENABLE);
104 reg8 &= ~disable;
105 pm_write8(PM_REG_USB_ENABLE, reg8);
106}
107
zbao246e84b2012-07-13 18:47:03 +0800108void hudson_enable(device_t dev)
109{
Martin Rothf5726ea2013-01-18 12:55:40 -0700110 printk(BIOS_DEBUG, "hudson_enable()\n");
Dave Frodinea909632013-05-31 08:15:57 -0600111 switch (dev->path.pci.devfn) {
Alexandru Gagniucd2e5f682014-04-16 16:33:03 -0500112 case PCI_DEVFN(0x14, 7):
Dave Frodinea909632013-05-31 08:15:57 -0600113 if (dev->enabled == 0) {
114 // read the VENDEV ID
115 device_t sd_dev = dev_find_slot( 0, PCI_DEVFN( 0x14, 7));
116 u32 sd_device_id = pci_read_config32( sd_dev, 0) >> 16;
117 /* turn off the SDHC controller in the PM reg */
Alexandru Gagniuc342ac642014-04-14 16:44:19 -0500118 u8 reg8;
Dave Frodinea909632013-05-31 08:15:57 -0600119 if (sd_device_id == PCI_DEVICE_ID_AMD_HUDSON_SD) {
Alexandru Gagniuc342ac642014-04-14 16:44:19 -0500120 reg8 = pm_read8(0xe7);
121 reg8 &= ~(1 << 0);
122 pm_write8(0xe7, reg8);
Dave Frodinea909632013-05-31 08:15:57 -0600123 }
124 else if (sd_device_id == PCI_DEVICE_ID_AMD_YANGTZE_SD) {
Alexandru Gagniuc342ac642014-04-14 16:44:19 -0500125 reg8 = pm_read8(0xe8);
126 reg8 &= ~(1 << 0);
127 pm_write8(0xe8, reg8);
Dave Frodinea909632013-05-31 08:15:57 -0600128 }
129 /* remove device 0:14.7 from PCI space */
Alexandru Gagniuc342ac642014-04-14 16:44:19 -0500130 reg8 = pm_read8(0xd3);
131 reg8 &= ~(1 << 6);
132 pm_write8(0xd3, reg8);
Dave Frodinea909632013-05-31 08:15:57 -0600133 }
134 break;
Alexandru Gagniucd2e5f682014-04-16 16:33:03 -0500135
136 /* Make sure to disable other functions if function 0 is disabled */
137 case PCI_DEVFN(0x12, 0):
138 if (dev->enabled == 0)
139 hudson_disable_usb(USB_EN_DEVFN_12_0);
140 case PCI_DEVFN(0x12, 2): /* Fall through */
141 if (dev->enabled == 0)
142 hudson_disable_usb(USB_EN_DEVFN_12_2);
143 break;
144 case PCI_DEVFN(0x13, 0):
145 if (dev->enabled == 0)
146 hudson_disable_usb(USB_EN_DEVFN_13_0);
147 case PCI_DEVFN(0x13, 2): /* Fall through */
148 if (dev->enabled == 0)
149 hudson_disable_usb(USB_EN_DEVFN_13_2);
150 break;
151 case PCI_DEVFN(0x16, 0):
152 if (dev->enabled == 0)
153 hudson_disable_usb(USB_EN_DEVFN_16_0);
154 case PCI_DEVFN(0x16, 2): /* Fall through */
155 if (dev->enabled == 0)
156 hudson_disable_usb(USB_EN_DEVFN_16_2);
157 break;
Dave Frodinea909632013-05-31 08:15:57 -0600158 default:
159 break;
160 }
zbao246e84b2012-07-13 18:47:03 +0800161}
162
Kyösti Mälkkibc90e152013-09-04 13:26:11 +0300163#if CONFIG_HAVE_ACPI_RESUME
164unsigned long get_top_of_ram(void)
zbao246e84b2012-07-13 18:47:03 +0800165{
166 uint32_t xdata = 0;
167 int xnvram_pos = 0xf8, xi;
Kyösti Mälkkibc90e152013-09-04 13:26:11 +0300168 if (acpi_get_sleep_type() != 3)
169 return 0;
zbao246e84b2012-07-13 18:47:03 +0800170 for (xi = 0; xi<4; xi++) {
171 outb(xnvram_pos, BIOSRAM_INDEX);
172 xdata &= ~(0xff << (xi * 8));
173 xdata |= inb(BIOSRAM_DATA) << (xi *8);
174 xnvram_pos++;
175 }
Kyösti Mälkkibc90e152013-09-04 13:26:11 +0300176 return (unsigned long) xdata;
zbao246e84b2012-07-13 18:47:03 +0800177}
Kyösti Mälkkibc90e152013-09-04 13:26:11 +0300178#endif
zbao246e84b2012-07-13 18:47:03 +0800179
Alexandru Gagniuc86777e32014-04-20 14:36:29 -0500180static void hudson_init_acpi_ports(void)
181{
182 /* We use some of these ports in SMM regardless of whether or not
183 * ACPI tables are generated. Enable these ports indiscriminately.
184 */
185
186 pm_write16(0x60, ACPI_PM_EVT_BLK);
187 pm_write16(0x62, ACPI_PM1_CNT_BLK);
188 pm_write16(0x64, ACPI_PM_TMR_BLK);
189 pm_write16(0x68, ACPI_GPE0_BLK);
190 /* CpuControl is in \_PR.CPU0, 6 bytes */
191 pm_write16(0x66, ACPI_CPU_CONTROL);
192
193 if (IS_ENABLED(CONFIG_HAVE_SMI_HANDLER)) {
194 pm_write16(0x6a, ACPI_SMI_CTL_PORT);
195 hudson_enable_acpi_cmd_smi();
196 } else {
197 pm_write16(0x6a, 0);
198 }
199
200 /* AcpiDecodeEnable, When set, SB uses the contents of the PM registers
201 * at index 60-6B to decode ACPI I/O address. AcpiSmiEn & SmiCmdEn
202 */
203 pm_write8(0x74, 1<<0 | 1<<1 | 1<<4 | 1<<2);
204}
205
206static void hudson_init(void *chip_info)
207{
208 hudson_init_acpi_ports();
209}
210
Kyösti Mälkki29d9c562014-10-16 21:35:48 +0300211static void hudson_final(void *chip_info)
212{
WANG Siyuanb640fd32014-10-22 13:47:18 +0800213#if !CONFIG_ACPI_ENABLE_THERMAL_ZONE
Kyösti Mälkki29d9c562014-10-16 21:35:48 +0300214#if IS_ENABLED(CONFIG_HUDSON_IMC_FWM)
215 /* AMD AGESA does not enable thermal zone, so we enable it here. */
216 enable_imc_thermal_zone();
217#endif
WANG Siyuanb640fd32014-10-22 13:47:18 +0800218#endif
Kyösti Mälkki29d9c562014-10-16 21:35:48 +0300219}
220
zbao246e84b2012-07-13 18:47:03 +0800221struct chip_operations southbridge_amd_agesa_hudson_ops = {
222 CHIP_NAME("ATI HUDSON")
223 .enable_dev = hudson_enable,
Kyösti Mälkki29d9c562014-10-16 21:35:48 +0300224 .init = hudson_init,
225 .final = hudson_final
zbao246e84b2012-07-13 18:47:03 +0800226};