Rudolf Marek | 1d4fc0c | 2007-10-22 19:59:57 +0000 | [diff] [blame] | 1 | /* |
Stefan Reinauer | 7e61e45 | 2008-01-18 10:35:56 +0000 | [diff] [blame] | 2 | * This file is part of the coreboot project. |
Rudolf Marek | 1d4fc0c | 2007-10-22 19:59:57 +0000 | [diff] [blame] | 3 | * |
| 4 | * Copyright (C) 2007 Rudolf Marek <r.marek@assembler.cz> |
Alexandru Gagniuc | 025ead7 | 2011-02-16 13:43:00 +0000 | [diff] [blame] | 5 | * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me@gmail.com> |
Rudolf Marek | 1d4fc0c | 2007-10-22 19:59:57 +0000 | [diff] [blame] | 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify |
Uwe Hermann | c70e9fc | 2010-02-15 23:10:19 +0000 | [diff] [blame] | 8 | * it under the terms of the GNU General Public License as published by |
| 9 | * the Free Software Foundation; version 2 of the License. |
Rudolf Marek | 1d4fc0c | 2007-10-22 19:59:57 +0000 | [diff] [blame] | 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. |
Rudolf Marek | 1d4fc0c | 2007-10-22 19:59:57 +0000 | [diff] [blame] | 15 | */ |
| 16 | |
| 17 | #include <device/device.h> |
| 18 | #include <device/pci.h> |
Rudolf Marek | 1d4fc0c | 2007-10-22 19:59:57 +0000 | [diff] [blame] | 19 | #include <device/pci_ids.h> |
| 20 | #include <console/console.h> |
| 21 | #include <cpu/x86/msr.h> |
| 22 | #include <cpu/amd/mtrr.h> |
Luc Verhaegen | aeb6c98 | 2009-07-23 16:04:58 +0000 | [diff] [blame] | 23 | #include <pc80/mc146818rtc.h> |
Ronald G. Minnich | 5079a0d | 2012-11-27 11:32:38 -0800 | [diff] [blame] | 24 | #include <lib.h> |
Alexandru Gagniuc | 025ead7 | 2011-02-16 13:43:00 +0000 | [diff] [blame] | 25 | #include "k8x8xx.h" |
Rudolf Marek | 1d4fc0c | 2007-10-22 19:59:57 +0000 | [diff] [blame] | 26 | |
| 27 | static void dram_enable(struct device *dev) |
| 28 | { |
Rudolf Marek | 1d4fc0c | 2007-10-22 19:59:57 +0000 | [diff] [blame] | 29 | u16 reg; |
Florian Zumbiehl | 1e1e859 | 2011-11-01 20:18:30 +0100 | [diff] [blame] | 30 | struct k8x8xx_vt8237_mirrored_regs mregs; |
Rudolf Marek | 1d4fc0c | 2007-10-22 19:59:57 +0000 | [diff] [blame] | 31 | |
Florian Zumbiehl | 1e1e859 | 2011-11-01 20:18:30 +0100 | [diff] [blame] | 32 | k8x8xx_vt8237_mirrored_regs_fill(&mregs); |
Rudolf Marek | 1d4fc0c | 2007-10-22 19:59:57 +0000 | [diff] [blame] | 33 | /* |
| 34 | * Enable Lowest Interrupt arbitration for APIC, enable NB APIC |
Alexandru Gagniuc | 025ead7 | 2011-02-16 13:43:00 +0000 | [diff] [blame] | 35 | * decoding, MSI support, no SMRAM, compatible SMM. |
Rudolf Marek | 1d4fc0c | 2007-10-22 19:59:57 +0000 | [diff] [blame] | 36 | */ |
Florian Zumbiehl | 1e1e859 | 2011-11-01 20:18:30 +0100 | [diff] [blame] | 37 | pci_write_config8(dev, 0x86, mregs.smm_apic_decoding); |
Rudolf Marek | 1d4fc0c | 2007-10-22 19:59:57 +0000 | [diff] [blame] | 38 | |
| 39 | /* |
| 40 | * We want to use the 0xC0000-0xEFFFF as RAM mark area as RW, even if |
| 41 | * memory is doing K8 the DMA from SB will fail if we have it wrong, |
| 42 | * AND even we have it here, we must later copy it to SB to make it work :/ |
| 43 | */ |
| 44 | |
| 45 | /* For CC000-CFFFF, bits 7:6 (10 = REn, 01 = WEn) bits 1:0 for |
| 46 | * C0000-C3FFF etc. |
| 47 | */ |
Florian Zumbiehl | 1e1e859 | 2011-11-01 20:18:30 +0100 | [diff] [blame] | 48 | pci_write_config8(dev, 0x80, mregs.rom_shadow_ctrl_pg_c); |
Rudolf Marek | 1d4fc0c | 2007-10-22 19:59:57 +0000 | [diff] [blame] | 49 | /* For page D0000-DFFFF */ |
Florian Zumbiehl | 1e1e859 | 2011-11-01 20:18:30 +0100 | [diff] [blame] | 50 | pci_write_config8(dev, 0x81, mregs.rom_shadow_ctrl_pg_d); |
Rudolf Marek | 1d4fc0c | 2007-10-22 19:59:57 +0000 | [diff] [blame] | 51 | /* For page E0000-EFFFF */ |
Florian Zumbiehl | 1e1e859 | 2011-11-01 20:18:30 +0100 | [diff] [blame] | 52 | pci_write_config8(dev, 0x82, mregs.rom_shadow_ctrl_pg_e_memhole_smi_decoding); |
| 53 | pci_write_config8(dev, 0x83, mregs.rom_shadow_ctrl_pg_f_memhole); |
Rudolf Marek | 1d4fc0c | 2007-10-22 19:59:57 +0000 | [diff] [blame] | 54 | |
Rudolf Marek | 1d4fc0c | 2007-10-22 19:59:57 +0000 | [diff] [blame] | 55 | reg = pci_read_config16(dev, 0x84); |
| 56 | reg &= 0xf; |
Florian Zumbiehl | 1e1e859 | 2011-11-01 20:18:30 +0100 | [diff] [blame] | 57 | pci_write_config16(dev, 0x84, mregs.low_top_address | reg); |
Rudolf Marek | 1d4fc0c | 2007-10-22 19:59:57 +0000 | [diff] [blame] | 58 | |
| 59 | reg = pci_read_config16(dev, 0x88); |
| 60 | reg &= 0xf800; |
| 61 | |
Rudolf Marek | 316e07f | 2008-03-20 21:19:50 +0000 | [diff] [blame] | 62 | /* The Address Next to the Last Valid DRAM Address */ |
Florian Zumbiehl | 1e1e859 | 2011-11-01 20:18:30 +0100 | [diff] [blame] | 63 | pci_write_config16(dev, 0x88, reg | mregs.shadow_mem_ctrl); |
Stefan Reinauer | 5ff7c13 | 2011-10-31 12:56:45 -0700 | [diff] [blame] | 64 | |
Stefan Reinauer | 5ab52dd | 2015-01-05 13:01:01 -0800 | [diff] [blame] | 65 | printk(BIOS_DEBUG, " VIA_X_3 device dump:\n"); |
Alexandru Gagniuc | 025ead7 | 2011-02-16 13:43:00 +0000 | [diff] [blame] | 66 | dump_south(dev); |
Rudolf Marek | 0b0771d | 2008-09-19 22:58:59 +0000 | [diff] [blame] | 67 | |
| 68 | } |
| 69 | |
| 70 | static void dram_enable_k8m890(struct device *dev) |
| 71 | { |
Rudolf Marek | a3c10ac | 2010-04-25 15:21:18 +0000 | [diff] [blame] | 72 | #if CONFIG_GFXUMA |
| 73 | msr_t msr; |
| 74 | int ret; |
| 75 | unsigned int fbbits; |
Rudolf Marek | 0b0771d | 2008-09-19 22:58:59 +0000 | [diff] [blame] | 76 | |
Rudolf Marek | a3c10ac | 2010-04-25 15:21:18 +0000 | [diff] [blame] | 77 | /* use CMOS */ |
| 78 | if (CONFIG_VIDEO_MB == -1) { |
| 79 | ret = get_option(&fbbits, "videoram_size"); |
| 80 | if (ret) { |
| 81 | printk(BIOS_WARNING, "Failed to get videoram size (error %d), using default.\n", ret); |
| 82 | fbbits = 5; |
| 83 | } |
| 84 | |
| 85 | if ((fbbits < 1) || (fbbits > 7)) { |
| 86 | printk(BIOS_WARNING, "Invalid videoram size (%d), using default.\n", |
| 87 | 4 << fbbits); |
| 88 | fbbits = 5; |
| 89 | } |
| 90 | uma_memory_size = 4 << (fbbits + 20); |
| 91 | } else { |
| 92 | uma_memory_size = (CONFIG_VIDEO_MB << 20); |
| 93 | } |
| 94 | |
| 95 | msr = rdmsr(TOP_MEM); |
| 96 | uma_memory_base = msr.lo - uma_memory_size; |
Rudolf Marek | 53b0b50 | 2010-04-25 20:24:09 +0000 | [diff] [blame] | 97 | printk(BIOS_INFO, "K8M890: UMA base is %llx size is %u (MB)\n", uma_memory_base, |
| 98 | (u32) (uma_memory_size / 1024 / 1024)); |
Rudolf Marek | 0b0771d | 2008-09-19 22:58:59 +0000 | [diff] [blame] | 99 | /* enable VGA, so the bridges gets VGA_EN and resources are set */ |
| 100 | pci_write_config8(dev, 0xa1, 0x80); |
Rudolf Marek | 9e9fa82 | 2009-03-21 11:50:20 +0000 | [diff] [blame] | 101 | #endif |
Rudolf Marek | a3c10ac | 2010-04-25 15:21:18 +0000 | [diff] [blame] | 102 | dram_enable(dev); |
Rudolf Marek | 316e07f | 2008-03-20 21:19:50 +0000 | [diff] [blame] | 103 | } |
| 104 | |
Luc Verhaegen | aeb6c98 | 2009-07-23 16:04:58 +0000 | [diff] [blame] | 105 | int |
| 106 | k8m890_host_fb_size_get(void) |
| 107 | { |
| 108 | struct device *dev = dev_find_device(PCI_VENDOR_ID_VIA, |
Alexandru Gagniuc | 025ead7 | 2011-02-16 13:43:00 +0000 | [diff] [blame] | 109 | PCI_DEVICE_ID_VIA_K8M800_DRAM, 0); |
| 110 | if(!dev) dev = dev_find_device(PCI_VENDOR_ID_VIA, |
Luc Verhaegen | aeb6c98 | 2009-07-23 16:04:58 +0000 | [diff] [blame] | 111 | PCI_DEVICE_ID_VIA_K8M890CE_3, 0); |
| 112 | unsigned char tmp; |
| 113 | |
| 114 | tmp = pci_read_config8(dev, 0xA1); |
| 115 | tmp >>= 4; |
| 116 | if (tmp & 0x08) |
| 117 | return 4 << (tmp & 7); |
| 118 | else |
| 119 | return 0; |
| 120 | } |
Rudolf Marek | 316e07f | 2008-03-20 21:19:50 +0000 | [diff] [blame] | 121 | |
| 122 | static void dram_init_fb(struct device *dev) |
| 123 | { |
Rudolf Marek | a3c10ac | 2010-04-25 15:21:18 +0000 | [diff] [blame] | 124 | #if CONFIG_GFXUMA |
Rudolf Marek | 316e07f | 2008-03-20 21:19:50 +0000 | [diff] [blame] | 125 | /* Important bits: |
| 126 | * Enable the internal GFX bit 7 of reg 0xa1 plus in same reg: |
Luc Verhaegen | aeb6c98 | 2009-07-23 16:04:58 +0000 | [diff] [blame] | 127 | * bits 6:4 X fbuffer size will be 2^(X+2) or 100 = 64MB, 101 = 128MB |
Rudolf Marek | 316e07f | 2008-03-20 21:19:50 +0000 | [diff] [blame] | 128 | * bits 3:0 BASE [31:28] |
| 129 | * reg 0xa0 bits 7:1 BASE [27:21] bit0 enable CPU access |
| 130 | */ |
Luc Verhaegen | aeb6c98 | 2009-07-23 16:04:58 +0000 | [diff] [blame] | 131 | unsigned int fbbits = 0; |
Rudolf Marek | a3c10ac | 2010-04-25 15:21:18 +0000 | [diff] [blame] | 132 | u8 tmp; |
Luc Verhaegen | aeb6c98 | 2009-07-23 16:04:58 +0000 | [diff] [blame] | 133 | |
Rudolf Marek | a3c10ac | 2010-04-25 15:21:18 +0000 | [diff] [blame] | 134 | fbbits = ((log2(uma_memory_size >> 20) - 2) << 4); |
| 135 | printk(BIOS_INFO, "K8M890: Using a %dMB framebuffer.\n", (unsigned int) (uma_memory_size >> 20)); |
Rudolf Marek | 316e07f | 2008-03-20 21:19:50 +0000 | [diff] [blame] | 136 | |
Rudolf Marek | 0b0771d | 2008-09-19 22:58:59 +0000 | [diff] [blame] | 137 | /* Step 1: enable UMA but no FB */ |
Rudolf Marek | 316e07f | 2008-03-20 21:19:50 +0000 | [diff] [blame] | 138 | pci_write_config8(dev, 0xa1, 0x80); |
| 139 | |
Rudolf Marek | 0b0771d | 2008-09-19 22:58:59 +0000 | [diff] [blame] | 140 | /* Step 2: enough is just the FB size, the CPU accessible address is not needed */ |
Rudolf Marek | a3c10ac | 2010-04-25 15:21:18 +0000 | [diff] [blame] | 141 | tmp = fbbits | 0x80; |
Rudolf Marek | 316e07f | 2008-03-20 21:19:50 +0000 | [diff] [blame] | 142 | pci_write_config8(dev, 0xa1, tmp); |
| 143 | |
| 144 | /* TODO K8 needs some UMA fine tuning too maybe call some generic routine here? */ |
Rudolf Marek | a3c10ac | 2010-04-25 15:21:18 +0000 | [diff] [blame] | 145 | #endif |
Rudolf Marek | 316e07f | 2008-03-20 21:19:50 +0000 | [diff] [blame] | 146 | } |
| 147 | |
Rudolf Marek | 0f1dc4e | 2011-04-22 20:48:21 +0200 | [diff] [blame] | 148 | static struct pci_operations lops_pci = { |
| 149 | .set_subsystem = pci_dev_set_subsystem, |
| 150 | }; |
| 151 | |
Rudolf Marek | 316e07f | 2008-03-20 21:19:50 +0000 | [diff] [blame] | 152 | static const struct device_operations dram_ops_t = { |
Uwe Hermann | 70ab323 | 2007-11-15 15:52:42 +0000 | [diff] [blame] | 153 | .read_resources = pci_dev_read_resources, |
| 154 | .set_resources = pci_dev_set_resources, |
| 155 | .enable_resources = pci_dev_enable_resources, |
| 156 | .enable = dram_enable, |
Rudolf Marek | 0f1dc4e | 2011-04-22 20:48:21 +0200 | [diff] [blame] | 157 | .ops_pci = &lops_pci, |
Rudolf Marek | 1d4fc0c | 2007-10-22 19:59:57 +0000 | [diff] [blame] | 158 | }; |
| 159 | |
Rudolf Marek | 316e07f | 2008-03-20 21:19:50 +0000 | [diff] [blame] | 160 | static const struct device_operations dram_ops_m = { |
| 161 | .read_resources = pci_dev_read_resources, |
| 162 | .set_resources = pci_dev_set_resources, |
| 163 | .enable_resources = pci_dev_enable_resources, |
Rudolf Marek | 0b0771d | 2008-09-19 22:58:59 +0000 | [diff] [blame] | 164 | .enable = dram_enable_k8m890, |
Rudolf Marek | 316e07f | 2008-03-20 21:19:50 +0000 | [diff] [blame] | 165 | .init = dram_init_fb, |
Rudolf Marek | 0f1dc4e | 2011-04-22 20:48:21 +0200 | [diff] [blame] | 166 | .ops_pci = &lops_pci, |
Rudolf Marek | 316e07f | 2008-03-20 21:19:50 +0000 | [diff] [blame] | 167 | }; |
| 168 | |
Alexandru Gagniuc | 025ead7 | 2011-02-16 13:43:00 +0000 | [diff] [blame] | 169 | static const struct pci_driver northbridge_driver_t800 __pci_driver = { |
| 170 | .ops = &dram_ops_t, |
| 171 | .vendor = PCI_VENDOR_ID_VIA, |
| 172 | .device = PCI_DEVICE_ID_VIA_K8T800_DRAM, |
| 173 | }; |
| 174 | |
| 175 | static const struct pci_driver northbridge_driver_m800 __pci_driver = { |
| 176 | .ops = &dram_ops_m, |
| 177 | .vendor = PCI_VENDOR_ID_VIA, |
| 178 | .device = PCI_DEVICE_ID_VIA_K8M800_DRAM, |
| 179 | }; |
| 180 | |
| 181 | static const struct pci_driver northbridge_driver_t890 __pci_driver = { |
Rudolf Marek | 316e07f | 2008-03-20 21:19:50 +0000 | [diff] [blame] | 182 | .ops = &dram_ops_t, |
Uwe Hermann | 70ab323 | 2007-11-15 15:52:42 +0000 | [diff] [blame] | 183 | .vendor = PCI_VENDOR_ID_VIA, |
| 184 | .device = PCI_DEVICE_ID_VIA_K8T890CE_3, |
Rudolf Marek | 1d4fc0c | 2007-10-22 19:59:57 +0000 | [diff] [blame] | 185 | }; |
Rudolf Marek | 316e07f | 2008-03-20 21:19:50 +0000 | [diff] [blame] | 186 | |
Alexandru Gagniuc | 025ead7 | 2011-02-16 13:43:00 +0000 | [diff] [blame] | 187 | static const struct pci_driver northbridge_driver_t890cf __pci_driver = { |
Tobias Diedrich | d50b43a | 2010-11-02 20:54:37 +0000 | [diff] [blame] | 188 | .ops = &dram_ops_t, |
| 189 | .vendor = PCI_VENDOR_ID_VIA, |
| 190 | .device = PCI_DEVICE_ID_VIA_K8T890CF_3, |
| 191 | }; |
| 192 | |
Alexandru Gagniuc | 025ead7 | 2011-02-16 13:43:00 +0000 | [diff] [blame] | 193 | static const struct pci_driver northbridge_driver_m890 __pci_driver = { |
Rudolf Marek | 316e07f | 2008-03-20 21:19:50 +0000 | [diff] [blame] | 194 | .ops = &dram_ops_m, |
| 195 | .vendor = PCI_VENDOR_ID_VIA, |
| 196 | .device = PCI_DEVICE_ID_VIA_K8M890CE_3, |
| 197 | }; |