blob: d785bebbc4a8817156cef3d570e6c2713db9d0a4 [file] [log] [blame]
Stefan Reinauere2b53e12004-06-28 11:59:45 +00001#include <console/console.h>
Patrick Georgic8feedd2012-02-16 18:43:25 +01002#include <cpu/x86/lapic_def.h>
Stefan Reinauere2b53e12004-06-28 11:59:45 +00003#include <arch/io.h>
Uwe Hermann74d1a6e2010-10-12 17:34:08 +00004#include <arch/ioapic.h>
Stefan Reinauere2b53e12004-06-28 11:59:45 +00005#include <stdint.h>
Stefan Reinauere2b53e12004-06-28 11:59:45 +00006#include <device/device.h>
7#include <device/pci.h>
Stefan Reinauere2b53e12004-06-28 11:59:45 +00008#include <stdlib.h>
9#include <string.h>
Myles Watson2e672732009-11-12 16:38:03 +000010#include <delay.h>
Sven Schnelle164bcfd2011-08-14 20:56:34 +020011#include <smbios.h>
Rudolf Marek97be27e2010-12-13 19:50:25 +000012#include <cbmem.h>
Myles Watson0520d552009-05-11 22:44:14 +000013
Stefan Reinauer597ff872013-01-07 13:21:22 -080014#include "memory.c"
Sven Schnelle164bcfd2011-08-14 20:56:34 +020015
Myles Watson29cc9ed2009-07-02 18:56:24 +000016static void cpu_pci_domain_set_resources(device_t dev)
Eric Biederman6e53f502004-10-27 08:53:57 +000017{
Myles Watson894a3472010-06-09 22:41:35 +000018 u32 pci_tolm = find_pci_tolm(dev->link_list);
Valdimir Serbinenko7339f362010-05-03 16:21:52 +000019 unsigned long tomk = 0, tolmk;
20 int idx;
Eric Biederman6e53f502004-10-27 08:53:57 +000021
Sven Schnelle164bcfd2011-08-14 20:56:34 +020022 tomk = qemu_get_memory_size();
Valdimir Serbinenko7339f362010-05-03 16:21:52 +000023 printk(BIOS_DEBUG, "Detected %lu Kbytes (%lu MiB) RAM.\n",
24 tomk, tomk / 1024);
Myles Watson032a9652009-05-11 22:24:53 +000025
Valdimir Serbinenko7339f362010-05-03 16:21:52 +000026 /* Compute the top of Low memory */
27 tolmk = pci_tolm >> 10;
28 if (tolmk >= tomk) {
29 /* The PCI hole does not overlap the memory. */
30 tolmk = tomk;
31 }
32
33 /* Report the memory regions. */
34 idx = 10;
35 ram_resource(dev, idx++, 0, 640);
36 ram_resource(dev, idx++, 768, tolmk - 768);
Myles Watson0520d552009-05-11 22:44:14 +000037
Valdimir Serbinenko7339f362010-05-03 16:21:52 +000038 /* Leave some space for ACPI, PIRQ and MP tables */
Rudolf Marek97be27e2010-12-13 19:50:25 +000039 high_tables_base = (tomk * 1024) - HIGH_MEMORY_SIZE;
40 high_tables_size = HIGH_MEMORY_SIZE;
Valdimir Serbinenko7339f362010-05-03 16:21:52 +000041
Myles Watson894a3472010-06-09 22:41:35 +000042 assign_resources(dev->link_list);
Eric Biederman6e53f502004-10-27 08:53:57 +000043}
Stefan Reinauere2b53e12004-06-28 11:59:45 +000044
Myles Watson29cc9ed2009-07-02 18:56:24 +000045static void cpu_pci_domain_read_resources(struct device *dev)
Eric Biederman6e53f502004-10-27 08:53:57 +000046{
Myles Watson29cc9ed2009-07-02 18:56:24 +000047 struct resource *res;
48
49 pci_domain_read_resources(dev);
50
51 /* Reserve space for the IOAPIC. This should be in the Southbridge,
52 * but I couldn't tell which device to put it in. */
53 res = new_resource(dev, 2);
Uwe Hermann74d1a6e2010-10-12 17:34:08 +000054 res->base = IO_APIC_ADDR;
Myles Watson29cc9ed2009-07-02 18:56:24 +000055 res->size = 0x100000UL;
56 res->limit = 0xffffffffUL;
57 res->flags = IORESOURCE_MEM | IORESOURCE_FIXED | IORESOURCE_STORED |
58 IORESOURCE_ASSIGNED;
59
60 /* Reserve space for the LAPIC. There's one in every processor, but
61 * the space only needs to be reserved once, so we do it here. */
62 res = new_resource(dev, 3);
Patrick Georgic8feedd2012-02-16 18:43:25 +010063 res->base = LOCAL_APIC_ADDR;
Myles Watson29cc9ed2009-07-02 18:56:24 +000064 res->size = 0x10000UL;
65 res->limit = 0xffffffffUL;
66 res->flags = IORESOURCE_MEM | IORESOURCE_FIXED | IORESOURCE_STORED |
67 IORESOURCE_ASSIGNED;
Eric Biederman6e53f502004-10-27 08:53:57 +000068}
69
Sven Schnelle164bcfd2011-08-14 20:56:34 +020070#if CONFIG_GENERATE_SMBIOS_TABLES
71static int qemu_get_smbios_data16(int handle, unsigned long *current)
72{
73 struct smbios_type16 *t = (struct smbios_type16 *)*current;
74 int len = sizeof(struct smbios_type16);
75
76 memset(t, 0, sizeof(struct smbios_type16));
77 t->type = SMBIOS_PHYS_MEMORY_ARRAY;
78 t->handle = handle;
79 t->length = len - 2;
80 t->location = 3; /* Location: System Board */
81 t->use = 3; /* System memory */
82 t->memory_error_correction = 3; /* No error correction */
83 t->maximum_capacity = qemu_get_memory_size();
84 *current += len;
85 return len;
86}
87
88static int qemu_get_smbios_data17(int handle, int parent_handle, unsigned long *current)
89{
90 struct smbios_type17 *t = (struct smbios_type17 *)*current;
91 int len;
92
93 memset(t, 0, sizeof(struct smbios_type17));
94 t->type = SMBIOS_MEMORY_DEVICE;
95 t->handle = handle;
96 t->phys_memory_array_handle = parent_handle;
97 t->length = sizeof(struct smbios_type17) - 2;
98 t->size = qemu_get_memory_size() / 1024;
99 t->data_width = 64;
100 t->total_width = 64;
101 t->form_factor = 9; /* DIMM */
102 t->device_locator = smbios_add_string(t->eos, "Virtual");
103 t->memory_type = 0x12; /* DDR */
104 t->type_detail = 0x80; /* Synchronous */
105 t->speed = 200;
106 t->clock_speed = 200;
107 t->manufacturer = smbios_add_string(t->eos, CONFIG_MAINBOARD_VENDOR);
108 len = t->length + smbios_string_table_len(t->eos);
109 *current += len;
110 return len;
111}
112
113static int qemu_get_smbios_data(device_t dev, int *handle, unsigned long *current)
114{
115 int len;
116 len = qemu_get_smbios_data16(*handle, current);
117 len += qemu_get_smbios_data17(*handle+1, *handle, current);
118 *handle += 2;
119 return len;
120}
121#endif
Eric Biederman6e53f502004-10-27 08:53:57 +0000122static struct device_operations pci_domain_ops = {
Myles Watson29cc9ed2009-07-02 18:56:24 +0000123 .read_resources = cpu_pci_domain_read_resources,
124 .set_resources = cpu_pci_domain_set_resources,
Myles Watson7eac4452010-06-17 16:16:56 +0000125 .enable_resources = NULL,
126 .init = NULL,
Myles Watson032a9652009-05-11 22:24:53 +0000127 .scan_bus = pci_domain_scan_bus,
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200128#if CONFIG_GENERATE_SMBIOS_TABLES
129 .get_smbios_data = qemu_get_smbios_data,
130#endif
Myles Watson032a9652009-05-11 22:24:53 +0000131};
Eric Biederman6e53f502004-10-27 08:53:57 +0000132
Paul Menzel5f20b352013-02-24 14:27:03 +0100133static void northbridge_enable(struct device *dev)
Eric Biederman6e53f502004-10-27 08:53:57 +0000134{
Eric Biederman018d8dd2004-11-04 11:04:33 +0000135 /* Set the operations if it is a special bus type */
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800136 if (dev->path.type == DEVICE_PATH_DOMAIN) {
Eric Biederman018d8dd2004-11-04 11:04:33 +0000137 dev->ops = &pci_domain_ops;
Eric Biedermana9e632c2004-11-18 22:38:08 +0000138 pci_set_method(dev);
Eric Biederman018d8dd2004-11-04 11:04:33 +0000139 }
Stefan Reinauere2b53e12004-06-28 11:59:45 +0000140}
141
Patrick Georgi35784b62010-04-08 12:47:35 +0000142struct chip_operations mainboard_emulation_qemu_x86_ops = {
Eric Biederman018d8dd2004-11-04 11:04:33 +0000143 CHIP_NAME("QEMU Northbridge")
Paul Menzel5f20b352013-02-24 14:27:03 +0100144 .enable_dev = northbridge_enable,
Stefan Reinauere2b53e12004-06-28 11:59:45 +0000145};