blob: 20af2e76d7dd77f5e8cb96dc76852dcb9cde7067 [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.
zbao246e84b2012-07-13 18:47:03 +080014 */
15
16#include <console/console.h>
17
18#include <arch/io.h>
19#include <arch/acpi.h>
20
21#include <device/device.h>
22#include <device/pci.h>
23#include <device/pci_ids.h>
24#include <device/pci_ops.h>
25#include <cbmem.h>
26#include "hudson.h"
Kyösti Mälkki29d9c562014-10-16 21:35:48 +030027#include "imc.h"
zbao246e84b2012-07-13 18:47:03 +080028#include "smbus.h"
Alexandru Gagniuc86777e32014-04-20 14:36:29 -050029#include "smi.h"
zbao246e84b2012-07-13 18:47:03 +080030
Alexandru Gagniuc342ac642014-04-14 16:44:19 -050031/* Offsets from ACPI_MMIO_BASE
32 * This is defined by AGESA, but we don't include AGESA headers to avoid
Martin Roth3c3a50c2014-12-16 20:50:26 -070033 * polluting the namespace.
Alexandru Gagniuc342ac642014-04-14 16:44:19 -050034 */
35#define PM_MMIO_BASE 0xfed80300
36
Alexandru Gagniuc342ac642014-04-14 16:44:19 -050037void pm_write8(u8 reg, u8 value)
zbao246e84b2012-07-13 18:47:03 +080038{
Stefan Reinauer772029f2015-07-30 16:23:50 -070039 write8((void *)((uintptr_t)PM_MMIO_BASE + reg), value);
zbao246e84b2012-07-13 18:47:03 +080040}
41
Alexandru Gagniuc342ac642014-04-14 16:44:19 -050042u8 pm_read8(u8 reg)
zbao246e84b2012-07-13 18:47:03 +080043{
Stefan Reinauer772029f2015-07-30 16:23:50 -070044 return read8((void *)((uintptr_t)PM_MMIO_BASE + reg));
zbao246e84b2012-07-13 18:47:03 +080045}
46
Alexandru Gagniuc342ac642014-04-14 16:44:19 -050047void pm_write16(u8 reg, u16 value)
zbao246e84b2012-07-13 18:47:03 +080048{
Stefan Reinauer772029f2015-07-30 16:23:50 -070049 write16((void *)((uintptr_t)PM_MMIO_BASE + reg), value);
zbao246e84b2012-07-13 18:47:03 +080050}
51
Alexandru Gagniuc342ac642014-04-14 16:44:19 -050052u16 pm_read16(u16 reg)
zbao246e84b2012-07-13 18:47:03 +080053{
Stefan Reinauer772029f2015-07-30 16:23:50 -070054 return read16((void *)((uintptr_t)PM_MMIO_BASE + reg));
zbao246e84b2012-07-13 18:47:03 +080055}
56
Alexandru Gagniucd2e5f682014-04-16 16:33:03 -050057#define PM_REG_USB_ENABLE 0xef
58
59enum usb_enable {
60 USB_EN_DEVFN_12_0 = (1 << 0),
61 USB_EN_DEVFN_12_2 = (1 << 1),
62 USB_EN_DEVFN_13_0 = (1 << 2),
63 USB_EN_DEVFN_13_2 = (1 << 3),
64 USB_EN_DEVFN_16_0 = (1 << 4),
65 USB_EN_DEVFN_16_2 = (1 << 5),
66};
67
68static void hudson_disable_usb(u8 disable)
69{
70 u8 reg8;
71
72 /* Bit 7 handles routing, 6 is reserved. we don't mess with those */
73 disable &= 0x3f;
74
75 reg8 = pm_read8(PM_REG_USB_ENABLE);
76 reg8 &= ~disable;
77 pm_write8(PM_REG_USB_ENABLE, reg8);
78}
79
zbao246e84b2012-07-13 18:47:03 +080080void hudson_enable(device_t dev)
81{
Martin Rothf5726ea2013-01-18 12:55:40 -070082 printk(BIOS_DEBUG, "hudson_enable()\n");
Dave Frodinea909632013-05-31 08:15:57 -060083 switch (dev->path.pci.devfn) {
Tobias Diedrichae3adff2014-11-08 00:38:33 +010084 case PCI_DEVFN(0x14, 5):
85 if (dev->enabled == 0) {
86 // read the VENDEV ID
87 device_t usb_dev = dev_find_slot( 0, PCI_DEVFN( 0x14, 5));
88 u32 usb_device_id = pci_read_config32(usb_dev, 0) >> 16;
89 u8 reg8;
Kyösti Mälkki9d9a5522016-11-19 22:14:59 +020090 if (usb_device_id == PCI_DEVICE_ID_AMD_SB900_USB_20_5) {
Tobias Diedrichae3adff2014-11-08 00:38:33 +010091 /* turn off and remove device 0:14.5 from PCI space */
92 reg8 = pm_read8(0xef);
93 reg8 &= ~(1 << 6);
94 pm_write8(0xef, reg8);
95 }
96 }
97 break;
98
Alexandru Gagniucd2e5f682014-04-16 16:33:03 -050099 case PCI_DEVFN(0x14, 7):
Dave Frodinea909632013-05-31 08:15:57 -0600100 if (dev->enabled == 0) {
101 // read the VENDEV ID
102 device_t sd_dev = dev_find_slot( 0, PCI_DEVFN( 0x14, 7));
103 u32 sd_device_id = pci_read_config32( sd_dev, 0) >> 16;
104 /* turn off the SDHC controller in the PM reg */
Alexandru Gagniuc342ac642014-04-14 16:44:19 -0500105 u8 reg8;
Dave Frodinea909632013-05-31 08:15:57 -0600106 if (sd_device_id == PCI_DEVICE_ID_AMD_HUDSON_SD) {
Alexandru Gagniuc342ac642014-04-14 16:44:19 -0500107 reg8 = pm_read8(0xe7);
108 reg8 &= ~(1 << 0);
109 pm_write8(0xe7, reg8);
Dave Frodinea909632013-05-31 08:15:57 -0600110 }
111 else if (sd_device_id == PCI_DEVICE_ID_AMD_YANGTZE_SD) {
Alexandru Gagniuc342ac642014-04-14 16:44:19 -0500112 reg8 = pm_read8(0xe8);
113 reg8 &= ~(1 << 0);
114 pm_write8(0xe8, reg8);
Dave Frodinea909632013-05-31 08:15:57 -0600115 }
116 /* remove device 0:14.7 from PCI space */
Alexandru Gagniuc342ac642014-04-14 16:44:19 -0500117 reg8 = pm_read8(0xd3);
118 reg8 &= ~(1 << 6);
119 pm_write8(0xd3, reg8);
Dave Frodinea909632013-05-31 08:15:57 -0600120 }
121 break;
Alexandru Gagniucd2e5f682014-04-16 16:33:03 -0500122
123 /* Make sure to disable other functions if function 0 is disabled */
124 case PCI_DEVFN(0x12, 0):
125 if (dev->enabled == 0)
126 hudson_disable_usb(USB_EN_DEVFN_12_0);
127 case PCI_DEVFN(0x12, 2): /* Fall through */
128 if (dev->enabled == 0)
129 hudson_disable_usb(USB_EN_DEVFN_12_2);
130 break;
131 case PCI_DEVFN(0x13, 0):
132 if (dev->enabled == 0)
133 hudson_disable_usb(USB_EN_DEVFN_13_0);
134 case PCI_DEVFN(0x13, 2): /* Fall through */
135 if (dev->enabled == 0)
136 hudson_disable_usb(USB_EN_DEVFN_13_2);
137 break;
138 case PCI_DEVFN(0x16, 0):
139 if (dev->enabled == 0)
140 hudson_disable_usb(USB_EN_DEVFN_16_0);
141 case PCI_DEVFN(0x16, 2): /* Fall through */
142 if (dev->enabled == 0)
143 hudson_disable_usb(USB_EN_DEVFN_16_2);
144 break;
Dave Frodinea909632013-05-31 08:15:57 -0600145 default:
146 break;
147 }
zbao246e84b2012-07-13 18:47:03 +0800148}
149
zbao246e84b2012-07-13 18:47:03 +0800150
Alexandru Gagniuc86777e32014-04-20 14:36:29 -0500151static void hudson_init_acpi_ports(void)
152{
153 /* We use some of these ports in SMM regardless of whether or not
154 * ACPI tables are generated. Enable these ports indiscriminately.
155 */
156
157 pm_write16(0x60, ACPI_PM_EVT_BLK);
158 pm_write16(0x62, ACPI_PM1_CNT_BLK);
159 pm_write16(0x64, ACPI_PM_TMR_BLK);
160 pm_write16(0x68, ACPI_GPE0_BLK);
Timothy Pearson033bb4b2015-02-10 22:21:39 -0600161 /* CpuControl is in \_PR.CP00, 6 bytes */
Alexandru Gagniuc86777e32014-04-20 14:36:29 -0500162 pm_write16(0x66, ACPI_CPU_CONTROL);
163
164 if (IS_ENABLED(CONFIG_HAVE_SMI_HANDLER)) {
165 pm_write16(0x6a, ACPI_SMI_CTL_PORT);
166 hudson_enable_acpi_cmd_smi();
167 } else {
168 pm_write16(0x6a, 0);
169 }
170
171 /* AcpiDecodeEnable, When set, SB uses the contents of the PM registers
172 * at index 60-6B to decode ACPI I/O address. AcpiSmiEn & SmiCmdEn
173 */
174 pm_write8(0x74, 1<<0 | 1<<1 | 1<<4 | 1<<2);
175}
176
177static void hudson_init(void *chip_info)
178{
179 hudson_init_acpi_ports();
180}
181
Kyösti Mälkki29d9c562014-10-16 21:35:48 +0300182static void hudson_final(void *chip_info)
183{
WANG Siyuanb640fd32014-10-22 13:47:18 +0800184#if !CONFIG_ACPI_ENABLE_THERMAL_ZONE
Kyösti Mälkki29d9c562014-10-16 21:35:48 +0300185#if IS_ENABLED(CONFIG_HUDSON_IMC_FWM)
186 /* AMD AGESA does not enable thermal zone, so we enable it here. */
187 enable_imc_thermal_zone();
188#endif
WANG Siyuanb640fd32014-10-22 13:47:18 +0800189#endif
Kyösti Mälkki29d9c562014-10-16 21:35:48 +0300190}
191
zbao246e84b2012-07-13 18:47:03 +0800192struct chip_operations southbridge_amd_agesa_hudson_ops = {
193 CHIP_NAME("ATI HUDSON")
194 .enable_dev = hudson_enable,
Kyösti Mälkki29d9c562014-10-16 21:35:48 +0300195 .init = hudson_init,
196 .final = hudson_final
zbao246e84b2012-07-13 18:47:03 +0800197};