blob: 396b7c448accfcff2f16750ca273fd6175f14dac [file] [log] [blame]
Eric Biederman52685572003-05-19 19:16:21 +00001#include <console/console.h>
2#include <device/device.h>
3#include <device/pci.h>
4#include <device/pci_ids.h>
5#include <device/pci_ops.h>
Eric Biedermandbec2d42004-10-21 10:44:08 +00006#include <device/smbus.h>
Eric Biederman83b991a2003-10-11 06:20:25 +00007#include <pc80/mc146818rtc.h>
Ronald G. Minnich5079a0d2012-11-27 11:32:38 -08008#include <lib.h>
Eric Biederman5cd81732004-03-11 15:01:31 +00009#include <arch/io.h>
Eric Biederman83b991a2003-10-11 06:20:25 +000010#include "amd8111.h"
Eric Biedermandbec2d42004-10-21 10:44:08 +000011#include "amd8111_smbus.h"
Eric Biederman83b991a2003-10-11 06:20:25 +000012
13#define PREVIOUS_POWER_STATE 0x43
14#define MAINBOARD_POWER_OFF 0
15#define MAINBOARD_POWER_ON 1
Eric Biederman5cd81732004-03-11 15:01:31 +000016#define SLOW_CPU_OFF 0
17#define SLOW_CPU__ON 1
Eric Biederman83b991a2003-10-11 06:20:25 +000018
Stefan Reinauer08670622009-06-30 15:17:49 +000019#ifndef CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL
20#define CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBOARD_POWER_ON
Eric Biederman83b991a2003-10-11 06:20:25 +000021#endif
22
Eric Biederman52685572003-05-19 19:16:21 +000023
Eric Biedermandbec2d42004-10-21 10:44:08 +000024static int lsmbus_recv_byte(device_t dev)
25{
26 unsigned device;
27 struct resource *res;
28
Stefan Reinauer2b34db82009-02-28 20:10:20 +000029 device = dev->path.i2c.device;
Yinghai Lu7213d0f2004-12-03 03:39:04 +000030 res = find_resource(get_pbus_smbus(dev)->dev, 0x58);
Stefan Reinauer14e22772010-04-27 06:56:47 +000031
Eric Biedermandbec2d42004-10-21 10:44:08 +000032 return do_smbus_recv_byte(res->base, device);
33}
34
35static int lsmbus_send_byte(device_t dev, uint8_t val)
36{
37 unsigned device;
38 struct resource *res;
39
Stefan Reinauer2b34db82009-02-28 20:10:20 +000040 device = dev->path.i2c.device;
Yinghai Lu7213d0f2004-12-03 03:39:04 +000041 res = find_resource(get_pbus_smbus(dev)->dev, 0x58);
Eric Biedermandbec2d42004-10-21 10:44:08 +000042
43 return do_smbus_send_byte(res->base, device, val);
44}
45
46
47static int lsmbus_read_byte(device_t dev, uint8_t address)
48{
49 unsigned device;
50 struct resource *res;
51
Stefan Reinauer2b34db82009-02-28 20:10:20 +000052 device = dev->path.i2c.device;
Yinghai Lu7213d0f2004-12-03 03:39:04 +000053 res = find_resource(get_pbus_smbus(dev)->dev, 0x58);
Stefan Reinauer14e22772010-04-27 06:56:47 +000054
Eric Biedermandbec2d42004-10-21 10:44:08 +000055 return do_smbus_read_byte(res->base, device, address);
56}
57
58static int lsmbus_write_byte(device_t dev, uint8_t address, uint8_t val)
59{
60 unsigned device;
61 struct resource *res;
62
Stefan Reinauer2b34db82009-02-28 20:10:20 +000063 device = dev->path.i2c.device;
Yinghai Lu7213d0f2004-12-03 03:39:04 +000064 res = find_resource(get_pbus_smbus(dev)->dev, 0x58);
Stefan Reinauer14e22772010-04-27 06:56:47 +000065
Eric Biedermandbec2d42004-10-21 10:44:08 +000066 return do_smbus_write_byte(res->base, device, address, val);
67}
68
Oskar Enoksson9bfa1c82011-10-14 02:16:48 +020069static int lsmbus_block_read(device_t dev, uint8_t cmd, u8 bytes, u8 *buffer)
70{
71 unsigned device;
72 struct resource *res;
73
74 device = dev->path.i2c.device;
75 res = find_resource(get_pbus_smbus(dev)->dev, 0x58);
76
77 return do_smbus_block_read(res->base, device, cmd, bytes, buffer);
78}
79
80static int lsmbus_block_write(device_t dev, uint8_t cmd, u8 bytes, const u8 *buffer)
81{
82 unsigned device;
83 struct resource *res;
84
85 device = dev->path.i2c.device;
86 res = find_resource(get_pbus_smbus(dev)->dev, 0x58);
87
88 return do_smbus_block_write(res->base, device, cmd, bytes, buffer);
89}
90
91
Vladimir Serbinenko822bc652014-01-03 15:55:40 +010092#if CONFIG_HAVE_ACPI_TABLES
Stefan Reinauerf622d592005-11-26 16:56:05 +000093unsigned pm_base;
94#endif
95
Eric Biederman52685572003-05-19 19:16:21 +000096static void acpi_init(struct device *dev)
97{
98 uint8_t byte;
Eric Biederman5cd81732004-03-11 15:01:31 +000099 uint16_t pm10_bar;
Luc Verhaegena9c5ea02009-06-03 14:19:33 +0000100 int on;
Eric Biederman52685572003-05-19 19:16:21 +0000101
102#if 0
Stefan Reinauer50776fa2010-03-17 04:40:15 +0000103 uint16_t word;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000104 printk(BIOS_DEBUG, "ACPI: disabling NMI watchdog.. ");
Eric Biedermandbec2d42004-10-21 10:44:08 +0000105 byte = pci_read_config8(dev, 0x49);
106 pci_write_config8(dev, 0x49, byte | (1<<2));
Eric Biederman52685572003-05-19 19:16:21 +0000107
108
Eric Biedermandbec2d42004-10-21 10:44:08 +0000109 byte = pci_read_config8(dev, 0x41);
110 pci_write_config8(dev, 0x41, byte | (1<<6)|(1<<2));
Eric Biederman52685572003-05-19 19:16:21 +0000111
112 /* added from sourceforge */
Eric Biedermandbec2d42004-10-21 10:44:08 +0000113 byte = pci_read_config8(dev, 0x48);
114 pci_write_config8(dev, 0x48, byte | (1<<3));
Eric Biederman52685572003-05-19 19:16:21 +0000115
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000116 printk(BIOS_DEBUG, "done.\n");
Eric Biederman52685572003-05-19 19:16:21 +0000117
118
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000119 printk(BIOS_DEBUG, "ACPI: Routing IRQ 12 to PS2 port.. ");
Eric Biedermandbec2d42004-10-21 10:44:08 +0000120 word = pci_read_config16(dev, 0x46);
121 pci_write_config16(dev, 0x46, word | (1<<9));
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000122 printk(BIOS_DEBUG, "done.\n");
Eric Biederman52685572003-05-19 19:16:21 +0000123#endif
Stefan Reinauer50776fa2010-03-17 04:40:15 +0000124
Stefan Reinauer6cc0e082005-11-26 00:10:10 +0000125 /* To enable the register 0xcf9 in the IO space
126 * bit [D5] is set in the amd8111 configuration register.
127 * The config. reg. is devBx41. Register 0xcf9 allows
128 * hard reset capability to the system. For the ACPI
129 * reset.reg values in fadt.c to work this register
130 * must be enabled.
131 */
132 byte = pci_read_config8(dev, 0x41);
133 pci_write_config8(dev, 0x41, byte | (1<<6)|(1<<5));
Stefan Reinauer14e22772010-04-27 06:56:47 +0000134
Jason Schildtab327a32005-10-13 00:44:34 +0000135 /* power on after power fail */
Stefan Reinauer08670622009-06-30 15:17:49 +0000136 on = CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
Luc Verhaegena9c5ea02009-06-03 14:19:33 +0000137 get_option(&on, "power_on_after_fail");
Eric Biederman83b991a2003-10-11 06:20:25 +0000138 byte = pci_read_config8(dev, PREVIOUS_POWER_STATE);
139 byte &= ~0x40;
140 if (!on) {
141 byte |= 0x40;
142 }
143 pci_write_config8(dev, PREVIOUS_POWER_STATE, byte);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000144 printk(BIOS_INFO, "set power %s after power fail\n", on?"on":"off");
Jason Schildt043b4092005-08-10 15:16:44 +0000145
Stefan Reinauer96f8fb52006-03-23 19:26:40 +0000146 /* switch serial irq logic from quiet mode to continuous
147 * mode for Winbond W83627HF Rev. 17
148 */
149 byte = pci_read_config8(dev, 0x4a);
150 pci_write_config8(dev, 0x4a, byte | (1<<6));
Stefan Reinauer14e22772010-04-27 06:56:47 +0000151
Eric Biederman5cd81732004-03-11 15:01:31 +0000152 /* Throttle the CPU speed down for testing */
153 on = SLOW_CPU_OFF;
Luc Verhaegena9c5ea02009-06-03 14:19:33 +0000154 get_option(&on, "slow_cpu");
Eric Biederman5cd81732004-03-11 15:01:31 +0000155 if(on) {
156 pm10_bar = (pci_read_config16(dev, 0x58)&0xff00);
157 outl(((on<<1)+0x10) ,(pm10_bar + 0x10));
Paul Menzel69813fe2014-03-01 12:49:57 +0100158 inl(pm10_bar + 0x10);
Eric Biederman5cd81732004-03-11 15:01:31 +0000159 on = 8-on;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000160 printk(BIOS_DEBUG, "Throttling CPU %2d.%1.1d percent.\n",
Eric Biederman5cd81732004-03-11 15:01:31 +0000161 (on*12)+(on>>1),(on&1)*5);
162 }
Stefan Reinauerf622d592005-11-26 16:56:05 +0000163
Vladimir Serbinenko822bc652014-01-03 15:55:40 +0100164#if CONFIG_HAVE_ACPI_TABLES
Stefan Reinauerf622d592005-11-26 16:56:05 +0000165 pm_base = pci_read_config16(dev, 0x58) & 0xff00;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000166 printk(BIOS_DEBUG, "pm_base: 0x%04x\n",pm_base);
Stefan Reinauerf622d592005-11-26 16:56:05 +0000167#endif
168
Eric Biederman5cd81732004-03-11 15:01:31 +0000169}
170
171static void acpi_read_resources(device_t dev)
172{
Eric Biedermandbec2d42004-10-21 10:44:08 +0000173 struct resource *resource;
174
Eric Biederman5cd81732004-03-11 15:01:31 +0000175 /* Handle the generic bars */
176 pci_dev_read_resources(dev);
177
Eric Biedermandbec2d42004-10-21 10:44:08 +0000178 /* Add the ACPI/SMBUS bar */
179 resource = new_resource(dev, 0x58);
180 resource->base = 0;
181 resource->size = 256;
182 resource->align = log2(256);
183 resource->gran = log2(256);
184 resource->limit = 65536;
185 resource->flags = IORESOURCE_IO;
186 resource->index = 0x58;
Eric Biederman52685572003-05-19 19:16:21 +0000187}
188
Eric Biedermandbec2d42004-10-21 10:44:08 +0000189static void acpi_enable_resources(device_t dev)
190{
191 uint8_t byte;
192 /* Enable the generic pci resources */
193 pci_dev_enable_resources(dev);
194
195 /* Enable the ACPI/SMBUS Bar */
196 byte = pci_read_config8(dev, 0x41);
197 byte |= (1 << 7);
198 pci_write_config8(dev, 0x41, byte);
199
200 /* Set the class code */
201 pci_write_config32(dev, 0x60, 0x06800000);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000202
Eric Biedermandbec2d42004-10-21 10:44:08 +0000203}
204
205static void lpci_set_subsystem(device_t dev, unsigned vendor, unsigned device)
206{
Stefan Reinauer14e22772010-04-27 06:56:47 +0000207 pci_write_config32(dev, 0x7c,
Eric Biedermandbec2d42004-10-21 10:44:08 +0000208 ((device & 0xffff) << 16) | (vendor & 0xffff));
209}
210
211static struct smbus_bus_operations lops_smbus_bus = {
212 .recv_byte = lsmbus_recv_byte,
213 .send_byte = lsmbus_send_byte,
214 .read_byte = lsmbus_read_byte,
215 .write_byte = lsmbus_write_byte,
Oskar Enoksson9bfa1c82011-10-14 02:16:48 +0200216 .block_read = lsmbus_block_read,
217 .block_write= lsmbus_block_write,
Eric Biedermandbec2d42004-10-21 10:44:08 +0000218};
Yinghai Lu7213d0f2004-12-03 03:39:04 +0000219
Eric Biedermandbec2d42004-10-21 10:44:08 +0000220static struct pci_operations lops_pci = {
221 .set_subsystem = lpci_set_subsystem,
222};
223
Eric Biederman52685572003-05-19 19:16:21 +0000224static struct device_operations acpi_ops = {
Eric Biederman5cd81732004-03-11 15:01:31 +0000225 .read_resources = acpi_read_resources,
Eric Biedermane9a271e32003-09-02 03:36:25 +0000226 .set_resources = pci_dev_set_resources,
Eric Biedermandbec2d42004-10-21 10:44:08 +0000227 .enable_resources = acpi_enable_resources,
Eric Biederman83b991a2003-10-11 06:20:25 +0000228 .init = acpi_init,
Kyösti Mälkkid0e212c2015-02-26 20:47:47 +0200229 .scan_bus = scan_smbus,
Jason Schildtab327a32005-10-13 00:44:34 +0000230 /* We don't need amd8111_enable, chip ops takes care of it.
Stefan Reinauer14e22772010-04-27 06:56:47 +0000231 * It could be useful if these devices were not
Jason Schildtab327a32005-10-13 00:44:34 +0000232 * enabled by default.
233 */
Jason Schildt043b4092005-08-10 15:16:44 +0000234// .enable = amd8111_enable,
Eric Biedermandbec2d42004-10-21 10:44:08 +0000235 .ops_pci = &lops_pci,
236 .ops_smbus_bus = &lops_smbus_bus,
Eric Biederman52685572003-05-19 19:16:21 +0000237};
238
Stefan Reinauerf1cf1f72007-10-24 09:08:58 +0000239static const struct pci_driver acpi_driver __pci_driver = {
Eric Biederman52685572003-05-19 19:16:21 +0000240 .ops = &acpi_ops,
241 .vendor = PCI_VENDOR_ID_AMD,
242 .device = PCI_DEVICE_ID_AMD_8111_ACPI,
243};