blob: 141ad150ad35198ffb76f93cd7f3a08c68ae1d07 [file] [log] [blame]
Corey Osgoodbd3f93e2008-02-21 00:56:14 +00001/*
2 * This file is part of the coreboot project.
3 *
Aaron Lwefcb2a312008-05-19 12:17:43 +00004 * Copyright (C) 2008 VIA Technologies, Inc.
5 * (Written by Aaron Lwe <aaron.lwe@gmail.com> for VIA)
Corey Osgoodbd3f93e2008-02-21 00:56:14 +00006 * Copyright (C) 2007 Corey Osgood <corey.osgood@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000017 */
18
19#include <console/console.h>
20#include <arch/io.h>
21#include <stdint.h>
22#include <device/device.h>
23#include <device/pci.h>
24#include <device/pci_ids.h>
25#include <stdlib.h>
26#include <string.h>
Ronald G. Minnich5079a0d2012-11-27 11:32:38 -080027#include <lib.h>
Stefan Reinauerfd611f92013-02-27 23:45:20 +010028#include <cbmem.h>
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000029#include <cpu/cpu.h>
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000030#include "northbridge.h"
31#include "cn700.h"
32
33static void memctrl_init(device_t dev)
34{
Aaron Lwefcb2a312008-05-19 12:17:43 +000035 device_t vlink_dev;
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000036 u16 reg16;
Uwe Hermannea7b5182008-10-09 17:08:32 +000037 u8 ranks, pagec, paged, pagee, pagef, shadowreg;
38
39 /* Set up the VGA framebuffer size. */
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000040 reg16 = (log2(CONFIG_VIDEO_MB) << 12) | (1 << 15);
41 pci_write_config16(dev, 0xa0, reg16);
Uwe Hermannea7b5182008-10-09 17:08:32 +000042
43 /* Set up VGA timers. */
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000044 pci_write_config8(dev, 0xa2, 0x44);
Uwe Hermannea7b5182008-10-09 17:08:32 +000045
Aaron Lwefcb2a312008-05-19 12:17:43 +000046 for (ranks = 0x4b; ranks >= 0x48; ranks--) {
47 if (pci_read_config8(dev, ranks)) {
48 ranks -= 0x48;
49 break;
50 }
51 }
52 if (ranks == 0x47)
53 ranks = 0x00;
54 reg16 = 0xaae0;
55 reg16 |= ranks;
56 /* GMINT Misc. FrameBuffer rank */
57 pci_write_config16(dev, 0xb0, reg16);
58 /* AGPCINT Misc. */
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000059 pci_write_config8(dev, 0xb8, 0x08);
Aaron Lwefcb2a312008-05-19 12:17:43 +000060
Uwe Hermannea7b5182008-10-09 17:08:32 +000061 /* Shadow RAM */
Aaron Lwefcb2a312008-05-19 12:17:43 +000062 pagec = 0xff, paged = 0xff, pagee = 0xff, pagef = 0x30;
63 /* PAGE C, D, E are all read write enable */
64 pci_write_config8(dev, 0x80, pagec);
65 pci_write_config8(dev, 0x81, paged);
66 pci_write_config8(dev, 0x82, pagee);
67 /* PAGE F are read/writable */
68 shadowreg = pci_read_config8(dev, 0x83);
69 shadowreg |= pagef;
70 pci_write_config8(dev, 0x83, shadowreg);
71 /* vlink mirror */
Uwe Hermannea7b5182008-10-09 17:08:32 +000072 vlink_dev = dev_find_device(PCI_VENDOR_ID_VIA,
73 PCI_DEVICE_ID_VIA_CN700_VLINK, 0);
Aaron Lwefcb2a312008-05-19 12:17:43 +000074 if (vlink_dev) {
75 pci_write_config8(vlink_dev, 0x61, pagec);
76 pci_write_config8(vlink_dev, 0x62, paged);
77 pci_write_config8(vlink_dev, 0x64, pagee);
Uwe Hermannea7b5182008-10-09 17:08:32 +000078
Aaron Lwefcb2a312008-05-19 12:17:43 +000079 shadowreg = pci_read_config8(vlink_dev, 0x63);
80 shadowreg |= pagef;
81 pci_write_config8(vlink_dev, 0x63, shadowreg);
82 }
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000083}
84
85static const struct device_operations memctrl_operations = {
Edward O'Callaghand2040732014-10-31 08:26:21 +110086 .read_resources = DEVICE_NOOP,
Uwe Hermannea7b5182008-10-09 17:08:32 +000087 .init = memctrl_init,
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000088};
89
90static const struct pci_driver memctrl_driver __pci_driver = {
Uwe Hermannea7b5182008-10-09 17:08:32 +000091 .ops = &memctrl_operations,
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000092 .vendor = PCI_VENDOR_ID_VIA,
93 .device = PCI_DEVICE_ID_VIA_CN700_MEMCTRL,
94};
95
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000096static void pci_domain_set_resources(device_t dev)
97{
Uwe Hermannea7b5182008-10-09 17:08:32 +000098 /* The order is important to find the correct RAM size. */
99 static const u8 ramregs[] = { 0x43, 0x42, 0x41, 0x40 };
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000100 device_t mc_dev;
Uwe Hermannea7b5182008-10-09 17:08:32 +0000101 u32 pci_tolm;
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000102
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000103 printk(BIOS_SPEW, "Entering cn700 pci_domain_set_resources.\n");
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000104
Myles Watson894a3472010-06-09 22:41:35 +0000105 pci_tolm = find_pci_tolm(dev->link_list);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000106 mc_dev = dev_find_device(PCI_VENDOR_ID_VIA,
107 PCI_DEVICE_ID_VIA_CN700_MEMCTRL, 0);
Aaron Lwefcb2a312008-05-19 12:17:43 +0000108
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000109 if (mc_dev) {
110 unsigned long tomk, tolmk;
111 unsigned char rambits;
112 int i, idx;
113
Aaron Lwefcb2a312008-05-19 12:17:43 +0000114 /*
Uwe Hermannea7b5182008-10-09 17:08:32 +0000115 * Once the register value is not zero, the RAM size is
116 * this register's value multiply 64 * 1024 * 1024.
Aaron Lwefcb2a312008-05-19 12:17:43 +0000117 */
Uwe Hermannea7b5182008-10-09 17:08:32 +0000118 for (rambits = 0, i = 0; i < ARRAY_SIZE(ramregs); i++) {
Aaron Lwefcb2a312008-05-19 12:17:43 +0000119 rambits = pci_read_config8(mc_dev, ramregs[i]);
120 if (rambits != 0)
121 break;
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000122 }
Uwe Hermannea7b5182008-10-09 17:08:32 +0000123
Aaron Lwefcb2a312008-05-19 12:17:43 +0000124 tomk = rambits * 64 * 1024;
Corey Osgoodf9765482010-08-01 17:20:20 +0000125 printk(BIOS_DEBUG, "tomk is 0x%lx\n", tomk);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000126 /* Compute the Top Of Low Memory (TOLM), in Kb. */
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000127 tolmk = pci_tolm >> 10;
128 if (tolmk >= tomk) {
129 /* The PCI hole does does not overlap the memory. */
130 tolmk = tomk;
131 }
Stefan Reinauerb5fb0c52009-04-30 13:58:42 +0000132
Kyösti Mälkki42f46512013-06-27 08:20:09 +0300133 set_top_of_ram((tolmk - CONFIG_VIDEO_MB * 1024) * 1024);
Stefan Reinauerb5fb0c52009-04-30 13:58:42 +0000134
Uwe Hermannea7b5182008-10-09 17:08:32 +0000135 /* Report the memory regions. */
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000136 idx = 10;
137 /* TODO: Hole needed? */
Uwe Hermannea7b5182008-10-09 17:08:32 +0000138 ram_resource(dev, idx++, 0, 640); /* First 640k */
139 /* Leave a hole for VGA, 0xa0000 - 0xc0000 */
140 ram_resource(dev, idx++, 768,
141 (tolmk - 768 - CONFIG_VIDEO_MB * 1024));
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000142 }
Myles Watson894a3472010-06-09 22:41:35 +0000143 assign_resources(dev->link_list);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000144}
145
Stefan Reinauer3c8ac782010-04-03 13:33:01 +0000146static struct device_operations pci_domain_ops = {
Uwe Hermannea7b5182008-10-09 17:08:32 +0000147 .read_resources = pci_domain_read_resources,
148 .set_resources = pci_domain_set_resources,
Myles Watson7eac4452010-06-17 16:16:56 +0000149 .enable_resources = NULL,
150 .init = NULL,
Uwe Hermannea7b5182008-10-09 17:08:32 +0000151 .scan_bus = pci_domain_scan_bus,
Kyösti Mälkki33e5df32013-07-03 10:51:34 +0300152 .ops_pci_bus = pci_bus_default_ops,
Uwe Hermannea7b5182008-10-09 17:08:32 +0000153};
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000154
155static void cpu_bus_init(device_t dev)
156{
Myles Watson894a3472010-06-09 22:41:35 +0000157 initialize_cpus(dev->link_list);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000158}
159
Stefan Reinauer3c8ac782010-04-03 13:33:01 +0000160static struct device_operations cpu_bus_ops = {
Edward O'Callaghand2040732014-10-31 08:26:21 +1100161 .read_resources = DEVICE_NOOP,
162 .set_resources = DEVICE_NOOP,
163 .enable_resources = DEVICE_NOOP,
Uwe Hermannea7b5182008-10-09 17:08:32 +0000164 .init = cpu_bus_init,
165 .scan_bus = 0,
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000166};
167
168static void enable_dev(struct device *dev)
169{
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000170 printk(BIOS_SPEW, "In cn700 enable_dev for device %s.\n", dev_path(dev));
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000171
Uwe Hermannea7b5182008-10-09 17:08:32 +0000172 /* Set the operations if it is a special bus type. */
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800173 if (dev->path.type == DEVICE_PATH_DOMAIN) {
Uwe Hermannea7b5182008-10-09 17:08:32 +0000174 dev->ops = &pci_domain_ops;
Stefan Reinauer0aa37c42013-02-12 15:20:54 -0800175 } else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
Uwe Hermannea7b5182008-10-09 17:08:32 +0000176 dev->ops = &cpu_bus_ops;
177 }
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000178}
179
180struct chip_operations northbridge_via_cn700_ops = {
181 CHIP_NAME("VIA CN700 Northbridge")
182 .enable_dev = enable_dev,
183};