blob: 3f2243786da594886e79fdd69095dfbd613dbe54 [file] [log] [blame]
Stefan Reinauere2b53e12004-06-28 11:59:45 +00001#include <console/console.h>
2#include <arch/io.h>
Uwe Hermann74d1a6e2010-10-12 17:34:08 +00003#include <arch/ioapic.h>
Stefan Reinauere2b53e12004-06-28 11:59:45 +00004#include <stdint.h>
Stefan Reinauere2b53e12004-06-28 11:59:45 +00005#include <device/device.h>
6#include <device/pci.h>
Stefan Reinauere2b53e12004-06-28 11:59:45 +00007#include <stdlib.h>
8#include <string.h>
9#include <bitops.h>
10#include "chip.h"
Myles Watson2e672732009-11-12 16:38:03 +000011#include <delay.h>
Sven Schnelle164bcfd2011-08-14 20:56:34 +020012#include <smbios.h>
Stefan Reinauere2b53e12004-06-28 11:59:45 +000013
Myles Watsonb8e20272009-10-15 13:35:47 +000014#if CONFIG_WRITE_HIGH_TABLES==1
Rudolf Marek97be27e2010-12-13 19:50:25 +000015#include <cbmem.h>
Myles Watson0520d552009-05-11 22:44:14 +000016#endif
17
Valdimir Serbinenko7339f362010-05-03 16:21:52 +000018#define CMOS_ADDR_PORT 0x70
19#define CMOS_DATA_PORT 0x71
20#define HIGH_RAM_ADDR 0x35
21#define LOW_RAM_ADDR 0x34
22
Sven Schnelle164bcfd2011-08-14 20:56:34 +020023static unsigned long qemu_get_memory_size(void)
24{
25 unsigned long tomk;
26 outb (HIGH_RAM_ADDR, CMOS_ADDR_PORT);
27 tomk = ((unsigned long) inb(CMOS_DATA_PORT)) << 14;
28 outb (LOW_RAM_ADDR, CMOS_ADDR_PORT);
29 tomk |= ((unsigned long) inb(CMOS_DATA_PORT)) << 6;
30 tomk += 16 * 1024;
31 return tomk;
32}
33
Myles Watson29cc9ed2009-07-02 18:56:24 +000034static void cpu_pci_domain_set_resources(device_t dev)
Eric Biederman6e53f502004-10-27 08:53:57 +000035{
Myles Watson894a3472010-06-09 22:41:35 +000036 u32 pci_tolm = find_pci_tolm(dev->link_list);
Valdimir Serbinenko7339f362010-05-03 16:21:52 +000037 unsigned long tomk = 0, tolmk;
38 int idx;
Eric Biederman6e53f502004-10-27 08:53:57 +000039
Sven Schnelle164bcfd2011-08-14 20:56:34 +020040 tomk = qemu_get_memory_size();
Valdimir Serbinenko7339f362010-05-03 16:21:52 +000041 printk(BIOS_DEBUG, "Detected %lu Kbytes (%lu MiB) RAM.\n",
42 tomk, tomk / 1024);
Myles Watson032a9652009-05-11 22:24:53 +000043
Valdimir Serbinenko7339f362010-05-03 16:21:52 +000044 /* Compute the top of Low memory */
45 tolmk = pci_tolm >> 10;
46 if (tolmk >= tomk) {
47 /* The PCI hole does not overlap the memory. */
48 tolmk = tomk;
49 }
50
51 /* Report the memory regions. */
52 idx = 10;
53 ram_resource(dev, idx++, 0, 640);
54 ram_resource(dev, idx++, 768, tolmk - 768);
Myles Watson0520d552009-05-11 22:44:14 +000055
Myles Watsonb8e20272009-10-15 13:35:47 +000056#if CONFIG_WRITE_HIGH_TABLES==1
Valdimir Serbinenko7339f362010-05-03 16:21:52 +000057 /* Leave some space for ACPI, PIRQ and MP tables */
Rudolf Marek97be27e2010-12-13 19:50:25 +000058 high_tables_base = (tomk * 1024) - HIGH_MEMORY_SIZE;
59 high_tables_size = HIGH_MEMORY_SIZE;
Myles Watson0520d552009-05-11 22:44:14 +000060#endif
Valdimir Serbinenko7339f362010-05-03 16:21:52 +000061
Myles Watson894a3472010-06-09 22:41:35 +000062 assign_resources(dev->link_list);
Eric Biederman6e53f502004-10-27 08:53:57 +000063}
Stefan Reinauere2b53e12004-06-28 11:59:45 +000064
Myles Watson29cc9ed2009-07-02 18:56:24 +000065static void cpu_pci_domain_read_resources(struct device *dev)
Eric Biederman6e53f502004-10-27 08:53:57 +000066{
Myles Watson29cc9ed2009-07-02 18:56:24 +000067 struct resource *res;
68
69 pci_domain_read_resources(dev);
70
71 /* Reserve space for the IOAPIC. This should be in the Southbridge,
72 * but I couldn't tell which device to put it in. */
73 res = new_resource(dev, 2);
Uwe Hermann74d1a6e2010-10-12 17:34:08 +000074 res->base = IO_APIC_ADDR;
Myles Watson29cc9ed2009-07-02 18:56:24 +000075 res->size = 0x100000UL;
76 res->limit = 0xffffffffUL;
77 res->flags = IORESOURCE_MEM | IORESOURCE_FIXED | IORESOURCE_STORED |
78 IORESOURCE_ASSIGNED;
79
80 /* Reserve space for the LAPIC. There's one in every processor, but
81 * the space only needs to be reserved once, so we do it here. */
82 res = new_resource(dev, 3);
83 res->base = 0xfee00000UL;
84 res->size = 0x10000UL;
85 res->limit = 0xffffffffUL;
86 res->flags = IORESOURCE_MEM | IORESOURCE_FIXED | IORESOURCE_STORED |
87 IORESOURCE_ASSIGNED;
Eric Biederman6e53f502004-10-27 08:53:57 +000088}
89
Sven Schnelle164bcfd2011-08-14 20:56:34 +020090#if CONFIG_GENERATE_SMBIOS_TABLES
91static int qemu_get_smbios_data16(int handle, unsigned long *current)
92{
93 struct smbios_type16 *t = (struct smbios_type16 *)*current;
94 int len = sizeof(struct smbios_type16);
95
96 memset(t, 0, sizeof(struct smbios_type16));
97 t->type = SMBIOS_PHYS_MEMORY_ARRAY;
98 t->handle = handle;
99 t->length = len - 2;
100 t->location = 3; /* Location: System Board */
101 t->use = 3; /* System memory */
102 t->memory_error_correction = 3; /* No error correction */
103 t->maximum_capacity = qemu_get_memory_size();
104 *current += len;
105 return len;
106}
107
108static int qemu_get_smbios_data17(int handle, int parent_handle, unsigned long *current)
109{
110 struct smbios_type17 *t = (struct smbios_type17 *)*current;
111 int len;
112
113 memset(t, 0, sizeof(struct smbios_type17));
114 t->type = SMBIOS_MEMORY_DEVICE;
115 t->handle = handle;
116 t->phys_memory_array_handle = parent_handle;
117 t->length = sizeof(struct smbios_type17) - 2;
118 t->size = qemu_get_memory_size() / 1024;
119 t->data_width = 64;
120 t->total_width = 64;
121 t->form_factor = 9; /* DIMM */
122 t->device_locator = smbios_add_string(t->eos, "Virtual");
123 t->memory_type = 0x12; /* DDR */
124 t->type_detail = 0x80; /* Synchronous */
125 t->speed = 200;
126 t->clock_speed = 200;
127 t->manufacturer = smbios_add_string(t->eos, CONFIG_MAINBOARD_VENDOR);
128 len = t->length + smbios_string_table_len(t->eos);
129 *current += len;
130 return len;
131}
132
133static int qemu_get_smbios_data(device_t dev, int *handle, unsigned long *current)
134{
135 int len;
136 len = qemu_get_smbios_data16(*handle, current);
137 len += qemu_get_smbios_data17(*handle+1, *handle, current);
138 *handle += 2;
139 return len;
140}
141#endif
Eric Biederman6e53f502004-10-27 08:53:57 +0000142static struct device_operations pci_domain_ops = {
Myles Watson29cc9ed2009-07-02 18:56:24 +0000143 .read_resources = cpu_pci_domain_read_resources,
144 .set_resources = cpu_pci_domain_set_resources,
Myles Watson7eac4452010-06-17 16:16:56 +0000145 .enable_resources = NULL,
146 .init = NULL,
Myles Watson032a9652009-05-11 22:24:53 +0000147 .scan_bus = pci_domain_scan_bus,
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200148#if CONFIG_GENERATE_SMBIOS_TABLES
149 .get_smbios_data = qemu_get_smbios_data,
150#endif
Myles Watson032a9652009-05-11 22:24:53 +0000151};
Eric Biederman6e53f502004-10-27 08:53:57 +0000152
153static void enable_dev(struct device *dev)
154{
Eric Biederman018d8dd2004-11-04 11:04:33 +0000155 /* Set the operations if it is a special bus type */
156 if (dev->path.type == DEVICE_PATH_PCI_DOMAIN) {
157 dev->ops = &pci_domain_ops;
Eric Biedermana9e632c2004-11-18 22:38:08 +0000158 pci_set_method(dev);
Eric Biederman018d8dd2004-11-04 11:04:33 +0000159 }
Stefan Reinauere2b53e12004-06-28 11:59:45 +0000160}
161
Patrick Georgi35784b62010-04-08 12:47:35 +0000162struct chip_operations mainboard_emulation_qemu_x86_ops = {
Eric Biederman018d8dd2004-11-04 11:04:33 +0000163 CHIP_NAME("QEMU Northbridge")
Eric Biederman6e53f502004-10-27 08:53:57 +0000164 .enable_dev = enable_dev,
Stefan Reinauere2b53e12004-06-28 11:59:45 +0000165};