Marc Jones | a67d4fd | 2007-05-04 19:05:36 +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. |
Uwe Hermann | 344e457 | 2007-05-22 10:12:49 +0000 | [diff] [blame] | 3 | * |
| 4 | * Copyright (C) 2007 Advanced Micro Devices, Inc. |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License version 2 as |
| 8 | * published by the Free Software Foundation. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
Paul Menzel | a8ae1c6 | 2013-02-20 13:21:20 +0100 | [diff] [blame] | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
Uwe Hermann | 344e457 | 2007-05-22 10:12:49 +0000 | [diff] [blame] | 13 | * GNU General Public License for more details. |
Uwe Hermann | 344e457 | 2007-05-22 10:12:49 +0000 | [diff] [blame] | 14 | */ |
Li-Ta Lo | 5d69896 | 2006-04-20 21:31:47 +0000 | [diff] [blame] | 15 | |
| 16 | #include <arch/io.h> |
Uwe Hermann | 74d1a6e | 2010-10-12 17:34:08 +0000 | [diff] [blame] | 17 | #include <arch/ioapic.h> |
Li-Ta Lo | 5d69896 | 2006-04-20 21:31:47 +0000 | [diff] [blame] | 18 | #include <device/device.h> |
| 19 | #include <device/pci.h> |
| 20 | #include <device/pci_ops.h> |
| 21 | #include <device/pci_ids.h> |
Christian Gmeiner | b5dfcae | 2012-07-20 10:21:29 +0200 | [diff] [blame] | 22 | #include <device/smbus.h> |
Li-Ta Lo | 5d69896 | 2006-04-20 21:31:47 +0000 | [diff] [blame] | 23 | #include <console/console.h> |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 24 | #include <stdint.h> |
| 25 | #include <pc80/isa-dma.h> |
| 26 | #include <pc80/mc146818rtc.h> |
Stefan Reinauer | ae762b5 | 2009-03-06 18:39:54 +0000 | [diff] [blame] | 27 | #include <pc80/i8259.h> |
Ronald G. Minnich | cf120d1 | 2006-04-25 19:57:39 +0000 | [diff] [blame] | 28 | #include <cpu/x86/msr.h> |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 29 | #include <cpu/amd/vr.h> |
Carl-Daniel Hailfinger | 2ee6779 | 2008-10-01 12:52:52 +0000 | [diff] [blame] | 30 | #include <stdlib.h> |
Ronald G. Minnich | cf120d1 | 2006-04-25 19:57:39 +0000 | [diff] [blame] | 31 | #include "chip.h" |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 32 | #include "cs5536.h" |
Christian Gmeiner | b5dfcae | 2012-07-20 10:21:29 +0200 | [diff] [blame] | 33 | #include "smbus.h" |
Li-Ta Lo | 5d69896 | 2006-04-20 21:31:47 +0000 | [diff] [blame] | 34 | |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 35 | struct msrinit { |
Stefan Reinauer | 78b4033 | 2010-03-17 22:09:26 +0000 | [diff] [blame] | 36 | u32 msrnum; |
Ronald G. Minnich | 5d573c2 | 2006-05-16 02:51:16 +0000 | [diff] [blame] | 37 | msr_t msr; |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 38 | }; |
Ronald G. Minnich | 5d573c2 | 2006-05-16 02:51:16 +0000 | [diff] [blame] | 39 | |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 40 | /* Master Configuration Register for Bus Masters.*/ |
Stefan Reinauer | ba09695 | 2010-04-22 09:22:15 +0000 | [diff] [blame] | 41 | static struct msrinit SB_MASTER_CONF_TABLE[] = { |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 42 | {USB2_SB_GLD_MSR_CONF, {.hi = 0,.lo = 0x00008f000}}, |
| 43 | {ATA_SB_GLD_MSR_CONF, {.hi = 0,.lo = 0x00048f000}}, |
| 44 | {AC97_SB_GLD_MSR_CONF, {.hi = 0,.lo = 0x00008f000}}, |
| 45 | {MDD_SB_GLD_MSR_CONF, {.hi = 0,.lo = 0x00000f000}}, |
| 46 | {0, {0, 0}} |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 47 | }; |
Ronald G. Minnich | 5d573c2 | 2006-05-16 02:51:16 +0000 | [diff] [blame] | 48 | |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 49 | /* 5536 Clock Gating*/ |
Stefan Reinauer | ba09695 | 2010-04-22 09:22:15 +0000 | [diff] [blame] | 50 | static struct msrinit CS5536_CLOCK_GATING_TABLE[] = { |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 51 | /* MSR Setting*/ |
| 52 | {GLIU_SB_GLD_MSR_PM, {.hi = 0,.lo = 0x000000004}}, |
| 53 | {GLPCI_SB_GLD_MSR_PM, {.hi = 0,.lo = 0x000000005}}, |
| 54 | {GLCP_SB_GLD_MSR_PM, {.hi = 0,.lo = 0x000000004}}, |
| 55 | {MDD_SB_GLD_MSR_PM, {.hi = 0,.lo = 0x050554111}}, /* SMBus clock gating errata (PBZ 2226 & SiBZ 3977) */ |
| 56 | {ATA_SB_GLD_MSR_PM, {.hi = 0,.lo = 0x000000005}}, |
| 57 | {AC97_SB_GLD_MSR_PM, {.hi = 0,.lo = 0x000000005}}, |
| 58 | {0, {0, 0}} |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 59 | }; |
Ronald G. Minnich | 5d573c2 | 2006-05-16 02:51:16 +0000 | [diff] [blame] | 60 | |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 61 | struct acpiinit { |
Stefan Reinauer | 78b4033 | 2010-03-17 22:09:26 +0000 | [diff] [blame] | 62 | u16 ioreg; |
| 63 | u32 regdata; |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 64 | }; |
| 65 | |
Stefan Reinauer | ba09695 | 2010-04-22 09:22:15 +0000 | [diff] [blame] | 66 | static struct acpiinit acpi_init_table[] = { |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 67 | {ACPI_IO_BASE + 0x00, 0x01000000}, |
| 68 | {ACPI_IO_BASE + 0x08, 0}, |
| 69 | {ACPI_IO_BASE + 0x0C, 0}, |
| 70 | {ACPI_IO_BASE + 0x1C, 0}, |
| 71 | {ACPI_IO_BASE + 0x18, 0x0FFFFFFFF}, |
| 72 | {ACPI_IO_BASE + 0x00, 0x0000FFFF}, |
| 73 | {PMS_IO_BASE + PM_SCLK, 0x000000E00}, |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 74 | {PMS_IO_BASE + PM_SED, 0x000004601}, |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 75 | {PMS_IO_BASE + PM_SIDD, 0x000008C02}, |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 76 | {PMS_IO_BASE + PM_WKD, 0x0000000A0}, |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 77 | {PMS_IO_BASE + PM_WKXD, 0x0000000A0}, |
Stefan Reinauer | 720297c | 2010-04-02 22:11:20 +0000 | [diff] [blame] | 78 | {0, 0} |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 79 | }; |
| 80 | |
| 81 | struct FLASH_DEVICE { |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 82 | unsigned char fType; /* Flash type: NOR or NAND */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 83 | unsigned char fInterface; /* Flash interface: I/O or Memory */ |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 84 | unsigned long fMask; /* Flash size/mask */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 85 | }; |
| 86 | |
Stefan Reinauer | ba09695 | 2010-04-22 09:22:15 +0000 | [diff] [blame] | 87 | static struct FLASH_DEVICE FlashInitTable[] = { |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 88 | {FLASH_TYPE_NAND, FLASH_IF_MEM, FLASH_MEM_4K}, /* CS0, or Flash Device 0 */ |
| 89 | {FLASH_TYPE_NONE, 0, 0}, /* CS1, or Flash Device 1 */ |
| 90 | {FLASH_TYPE_NONE, 0, 0}, /* CS2, or Flash Device 2 */ |
| 91 | {FLASH_TYPE_NONE, 0, 0}, /* CS3, or Flash Device 3 */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 92 | }; |
| 93 | |
Carl-Daniel Hailfinger | 2ee6779 | 2008-10-01 12:52:52 +0000 | [diff] [blame] | 94 | #define FlashInitTableLen (ARRAY_SIZE(FlashInitTable)) |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 95 | |
Stefan Reinauer | ba09695 | 2010-04-22 09:22:15 +0000 | [diff] [blame] | 96 | static u32 FlashPort[] = { |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 97 | MDD_LBAR_FLSH0, |
| 98 | MDD_LBAR_FLSH1, |
| 99 | MDD_LBAR_FLSH2, |
| 100 | MDD_LBAR_FLSH3 |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 101 | }; |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 102 | |
| 103 | /* ***************************************************************************/ |
| 104 | /* **/ |
| 105 | /* * pmChipsetInit*/ |
| 106 | /* **/ |
| 107 | /* * Program ACPI LBAR and initialize ACPI registers.*/ |
| 108 | /* **/ |
| 109 | /* ***************************************************************************/ |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 110 | static void pmChipsetInit(void) |
| 111 | { |
Stefan Reinauer | 78b4033 | 2010-03-17 22:09:26 +0000 | [diff] [blame] | 112 | u32 val = 0; |
| 113 | u16 port; |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 114 | |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 115 | port = (PMS_IO_BASE + 0x010); |
| 116 | val = 0x0E00; /* 1ms */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 117 | outl(val, port); |
| 118 | |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 119 | /* PM_WKXD */ |
| 120 | /* Make sure bits[3:0]=0000b to clear the */ |
| 121 | /* saved Sx state */ |
| 122 | port = (PMS_IO_BASE + 0x034); |
| 123 | val = 0x0A0; /* 5ms */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 124 | outl(val, port); |
| 125 | |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 126 | /* PM_WKD */ |
| 127 | port = (PMS_IO_BASE + 0x030); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 128 | outl(val, port); |
| 129 | |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 130 | /* PM_SED */ |
| 131 | port = (PMS_IO_BASE + 0x014); |
Marc Jones | ddf845f | 2007-05-10 23:22:27 +0000 | [diff] [blame] | 132 | val = 0x04601; /* 5ms, # of 3.57954MHz clock edges */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 133 | outl(val, port); |
| 134 | |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 135 | /* PM_SIDD */ |
| 136 | port = (PMS_IO_BASE + 0x020); |
Marc Jones | ddf845f | 2007-05-10 23:22:27 +0000 | [diff] [blame] | 137 | val = 0x08C02; /* 10ms, # of 3.57954MHz clock edges */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 138 | outl(val, port); |
Ronald G. Minnich | 5d573c2 | 2006-05-16 02:51:16 +0000 | [diff] [blame] | 139 | } |
| 140 | |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 141 | /*************************************************************************** |
| 142 | * |
| 143 | * ChipsetFlashSetup |
| 144 | * |
| 145 | * Flash LBARs need to be setup before VSA init so the PCI BARs have |
| 146 | * correct size info. Call this routine only if flash needs to be |
| 147 | * configured (don't call it if you want IDE). |
| 148 | * |
| 149 | **************************************************************************/ |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 150 | static void ChipsetFlashSetup(void) |
| 151 | { |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 152 | msr_t msr; |
| 153 | int i; |
| 154 | int numEnabled = 0; |
| 155 | |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 156 | printk(BIOS_DEBUG, "ChipsetFlashSetup: Start\n"); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 157 | for (i = 0; i < FlashInitTableLen; i++) { |
| 158 | if (FlashInitTable[i].fType != FLASH_TYPE_NONE) { |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 159 | printk(BIOS_DEBUG, "Enable CS%d\n", i); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 160 | /* we need to configure the memory/IO mask */ |
| 161 | msr = rdmsr(FlashPort[i]); |
| 162 | msr.hi = 0; /* start with the "enabled" bit clear */ |
| 163 | if (FlashInitTable[i].fType == FLASH_TYPE_NAND) |
| 164 | msr.hi |= 0x00000002; |
| 165 | else |
| 166 | msr.hi &= ~0x00000002; |
| 167 | if (FlashInitTable[i].fInterface == FLASH_IF_MEM) |
| 168 | msr.hi |= 0x00000004; |
| 169 | else |
| 170 | msr.hi &= ~0x00000004; |
| 171 | msr.hi |= FlashInitTable[i].fMask; |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 172 | printk(BIOS_DEBUG, "MSR(0x%08X, %08X_%08X)\n", FlashPort[i], |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 173 | msr.hi, msr.lo); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 174 | wrmsr(FlashPort[i], msr); |
| 175 | |
| 176 | /* now write-enable the device */ |
| 177 | msr = rdmsr(MDD_NORF_CNTRL); |
| 178 | msr.lo |= (1 << i); |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 179 | printk(BIOS_DEBUG, "MSR(0x%08X, %08X_%08X)\n", MDD_NORF_CNTRL, |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 180 | msr.hi, msr.lo); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 181 | wrmsr(MDD_NORF_CNTRL, msr); |
| 182 | |
| 183 | /* update the number enabled */ |
| 184 | numEnabled++; |
Ronald G. Minnich | 88fb1a6 | 2006-06-22 04:37:27 +0000 | [diff] [blame] | 185 | } |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 186 | } |
| 187 | |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 188 | printk(BIOS_DEBUG, "ChipsetFlashSetup: Finish\n"); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 189 | |
| 190 | } |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 191 | |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 192 | /* ***************************************************************************/ |
| 193 | /* **/ |
| 194 | /* * enable_ide_nand_flash_header */ |
| 195 | /* Run after VSA init to enable the flash PCI device header */ |
| 196 | /* **/ |
| 197 | /* ***************************************************************************/ |
Stefan Reinauer | 720297c | 2010-04-02 22:11:20 +0000 | [diff] [blame] | 198 | static void enable_ide_nand_flash_header(void) |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 199 | { |
| 200 | /* Tell VSA to use FLASH PCI header. Not IDE header. */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 201 | outl(0x80007A40, 0xCF8); |
| 202 | outl(0xDEADBEEF, 0xCFC); |
| 203 | } |
| 204 | |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 205 | #define RTC_CENTURY 0x32 |
| 206 | #define RTC_DOMA 0x3D |
| 207 | #define RTC_MONA 0x3E |
| 208 | |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 209 | static void lpc_init(struct southbridge_amd_cs5536_config *sb) |
| 210 | { |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 211 | msr_t msr; |
| 212 | |
| 213 | if (sb->lpc_serirq_enable) { |
| 214 | msr.lo = sb->lpc_serirq_enable; |
| 215 | msr.hi = 0; |
| 216 | wrmsr(MDD_IRQM_LPC, msr); |
| 217 | if (sb->lpc_serirq_polarity) { |
| 218 | msr.lo = sb->lpc_serirq_polarity << 16; |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 219 | msr.lo |= (sb->lpc_serirq_mode << 6) | (1 << 7); /* enable */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 220 | msr.hi = 0; |
| 221 | wrmsr(MDD_LPC_SIRQ, msr); |
| 222 | } |
| 223 | } |
| 224 | |
| 225 | /* Allow DMA from LPC */ |
| 226 | msr = rdmsr(MDD_DMA_MAP); |
| 227 | msr.lo = 0x7777; |
| 228 | wrmsr(MDD_DMA_MAP, msr); |
| 229 | |
| 230 | /* enable the RTC/CMOS century byte at address 32h */ |
| 231 | msr = rdmsr(MDD_RTC_CENTURY_OFFSET); |
| 232 | msr.lo = RTC_CENTURY; |
| 233 | wrmsr(MDD_RTC_CENTURY_OFFSET, msr); |
| 234 | |
| 235 | /* enable the RTC/CMOS day of month and month alarms */ |
| 236 | msr = rdmsr(MDD_RTC_DOMA_IND); |
| 237 | msr.lo = RTC_DOMA; |
| 238 | wrmsr(MDD_RTC_DOMA_IND, msr); |
| 239 | |
| 240 | msr = rdmsr(MDD_RTC_MONA_IND); |
| 241 | msr.lo = RTC_MONA; |
| 242 | wrmsr(MDD_RTC_MONA_IND, msr); |
| 243 | |
Gabe Black | b3f08c6 | 2014-04-30 17:12:25 -0700 | [diff] [blame] | 244 | cmos_init(0); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 245 | |
| 246 | isa_dma_init(); |
| 247 | } |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 248 | |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 249 | |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 250 | /** |
| 251 | * Depending on settings in the config struct, enable COM1 or COM2 or both. |
| 252 | * |
| 253 | * If the enable is NOT set, the UARTs are explicitly disabled, which is |
| 254 | * required if (e.g.) there is a Super I/O attached that does COM1 or COM2. |
| 255 | * |
| 256 | * @param sb Southbridge config structure. |
| 257 | */ |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 258 | static void uarts_init(struct southbridge_amd_cs5536_config *sb) |
| 259 | { |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 260 | msr_t msr; |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 261 | u16 addr = 0; |
| 262 | u32 gpio_addr; |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 263 | device_t dev; |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 264 | |
| 265 | dev = dev_find_device(PCI_VENDOR_ID_AMD, |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 266 | PCI_DEVICE_ID_AMD_CS5536_ISA, 0); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 267 | gpio_addr = pci_read_config32(dev, PCI_BASE_ADDRESS_1); |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 268 | gpio_addr &= ~1; /* Clear I/O bit */ |
| 269 | printk(BIOS_DEBUG, "GPIO_ADDR: %08X\n", gpio_addr); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 270 | |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 271 | /* This could be extended to support IR modes. */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 272 | |
| 273 | /* COM1 */ |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 274 | if (sb->com1_enable) { |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 275 | printk(BIOS_SPEW, "uarts_init: enable COM1\n"); |
| 276 | /* Set the address. */ |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 277 | switch (sb->com1_address) { |
| 278 | case 0x3F8: |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 279 | addr = 7; |
| 280 | break; |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 281 | case 0x3E8: |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 282 | addr = 6; |
| 283 | break; |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 284 | case 0x2F8: |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 285 | addr = 5; |
| 286 | break; |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 287 | case 0x2E8: |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 288 | addr = 4; |
| 289 | break; |
| 290 | } |
| 291 | msr = rdmsr(MDD_LEG_IO); |
| 292 | msr.lo |= addr << 16; |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 293 | wrmsr(MDD_LEG_IO, msr); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 294 | |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 295 | /* Set the IRQ. */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 296 | msr = rdmsr(MDD_IRQM_YHIGH); |
| 297 | msr.lo |= sb->com1_irq << 24; |
| 298 | wrmsr(MDD_IRQM_YHIGH, msr); |
| 299 | |
| 300 | /* GPIO8 - UART1_TX */ |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 301 | /* Set: Output Enable (0x4) */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 302 | outl(GPIOL_8_SET, gpio_addr + GPIOL_OUTPUT_ENABLE); |
| 303 | /* Set: OUTAUX1 Select (0x10) */ |
| 304 | outl(GPIOL_8_SET, gpio_addr + GPIOL_OUT_AUX1_SELECT); |
| 305 | |
Stefan Reinauer | 5a559d4 | 2010-02-03 13:49:24 +0000 | [diff] [blame] | 306 | /* GPIO9 - UART1_RX */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 307 | /* Set: Input Enable (0x20) */ |
| 308 | outl(GPIOL_9_SET, gpio_addr + GPIOL_INPUT_ENABLE); |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 309 | /* Set: INAUX1 Select (0x34) */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 310 | outl(GPIOL_9_SET, gpio_addr + GPIOL_IN_AUX1_SELECT); |
| 311 | |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 312 | /* Set: GPIO 8 + 9 Pull Up (0x18) */ |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 313 | outl(GPIOL_8_SET | GPIOL_9_SET, |
| 314 | gpio_addr + GPIOL_PULLUP_ENABLE); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 315 | |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 316 | /* Enable COM1. |
| 317 | * |
| 318 | * Bit 1 = device enable |
| 319 | * Bit 4 = allow access to the upper banks |
| 320 | */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 321 | msr.lo = (1 << 4) | (1 << 1); |
| 322 | msr.hi = 0; |
| 323 | wrmsr(MDD_UART1_CONF, msr); |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 324 | } else { |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 325 | /* Reset and disable COM1. */ |
| 326 | printk(BIOS_SPEW, "uarts_init: disable COM1\n"); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 327 | msr = rdmsr(MDD_UART1_CONF); |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 328 | msr.lo = 1; /* Reset */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 329 | wrmsr(MDD_UART1_CONF, msr); |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 330 | msr.lo = 0; /* Disabled */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 331 | wrmsr(MDD_UART1_CONF, msr); |
| 332 | |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 333 | /* Disable the IRQ. */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 334 | msr = rdmsr(MDD_LEG_IO); |
Marc Jones | f027280 | 2007-06-02 23:55:17 +0000 | [diff] [blame] | 335 | msr.lo &= ~(0xF << 16); |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 336 | wrmsr(MDD_LEG_IO, msr); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 337 | } |
| 338 | |
| 339 | /* COM2 */ |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 340 | if (sb->com2_enable) { |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 341 | printk(BIOS_SPEW, "uarts_init: enable COM2\n"); |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 342 | switch (sb->com2_address) { |
| 343 | case 0x3F8: |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 344 | addr = 7; |
| 345 | break; |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 346 | case 0x3E8: |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 347 | addr = 6; |
| 348 | break; |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 349 | case 0x2F8: |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 350 | addr = 5; |
| 351 | break; |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 352 | case 0x2E8: |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 353 | addr = 4; |
| 354 | break; |
| 355 | } |
| 356 | msr = rdmsr(MDD_LEG_IO); |
| 357 | msr.lo |= addr << 20; |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 358 | wrmsr(MDD_LEG_IO, msr); |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 359 | printk(BIOS_SPEW, "uarts_init: wrote COM2 address 0x%x\n", sb->com2_address); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 360 | |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 361 | /* Set the IRQ. */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 362 | msr = rdmsr(MDD_IRQM_YHIGH); |
| 363 | msr.lo |= sb->com2_irq << 28; |
| 364 | wrmsr(MDD_IRQM_YHIGH, msr); |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 365 | printk(BIOS_SPEW, "uarts_init: set COM2 irq\n"); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 366 | |
Stefan Reinauer | 5a559d4 | 2010-02-03 13:49:24 +0000 | [diff] [blame] | 367 | /* GPIO3 - UART2_RX */ |
Marc Jones | c72ff11 | 2007-06-19 22:07:16 +0000 | [diff] [blame] | 368 | /* Set: Input Enable (0x20) */ |
| 369 | outl(GPIOL_3_SET, gpio_addr + GPIOL_INPUT_ENABLE); |
| 370 | /* Set: INAUX1 Select (0x34) */ |
| 371 | outl(GPIOL_3_SET, gpio_addr + GPIOL_IN_AUX1_SELECT); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 372 | |
Stefan Reinauer | 5a559d4 | 2010-02-03 13:49:24 +0000 | [diff] [blame] | 373 | /* GPIO4 - UART2_TX */ |
| 374 | /* Set: Output Enable (0x4) */ |
| 375 | outl(GPIOL_4_SET, gpio_addr + GPIOL_OUTPUT_ENABLE); |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 376 | printk(BIOS_SPEW, "uarts_init: set output enable\n"); |
Stefan Reinauer | 5a559d4 | 2010-02-03 13:49:24 +0000 | [diff] [blame] | 377 | /* Set: OUTAUX1 Select (0x10) */ |
| 378 | outl(GPIOL_4_SET, gpio_addr + GPIOL_OUT_AUX1_SELECT); |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 379 | printk(BIOS_SPEW, "uarts_init: set OUTAUX1\n"); |
Stefan Reinauer | 5a559d4 | 2010-02-03 13:49:24 +0000 | [diff] [blame] | 380 | |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 381 | /* Set: GPIO 3 + 4 Pull Up (0x18) */ |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 382 | outl(GPIOL_3_SET | GPIOL_4_SET, |
| 383 | gpio_addr + GPIOL_PULLUP_ENABLE); |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 384 | printk(BIOS_SPEW, "uarts_init: set pullup COM2\n"); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 385 | |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 386 | /* Enable COM2. |
| 387 | * |
| 388 | * Bit 1 = device enable |
| 389 | * Bit 4 = allow access to the upper banks |
| 390 | */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 391 | msr.lo = (1 << 4) | (1 << 1); |
| 392 | msr.hi = 0; |
| 393 | wrmsr(MDD_UART2_CONF, msr); |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 394 | printk(BIOS_SPEW, "uarts_init: COM2 enabled\n"); |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 395 | } else { |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 396 | printk(BIOS_SPEW, "uarts_init: disable COM2\n"); |
| 397 | /* Reset and disable COM2. */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 398 | msr = rdmsr(MDD_UART2_CONF); |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 399 | msr.lo = 1; /* Reset */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 400 | wrmsr(MDD_UART2_CONF, msr); |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 401 | msr.lo = 0; /* Disabled */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 402 | wrmsr(MDD_UART2_CONF, msr); |
| 403 | |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 404 | /* Disable the IRQ. */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 405 | msr = rdmsr(MDD_LEG_IO); |
Marc Jones | f027280 | 2007-06-02 23:55:17 +0000 | [diff] [blame] | 406 | msr.lo &= ~(0xF << 20); |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 407 | wrmsr(MDD_LEG_IO, msr); |
Ronald G. Minnich | 88fb1a6 | 2006-06-22 04:37:27 +0000 | [diff] [blame] | 408 | } |
| 409 | } |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 410 | |
Edwin Beasant | e30db0e | 2010-02-09 10:22:33 +0000 | [diff] [blame] | 411 | |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 412 | #define HCCPARAMS 0x08 |
| 413 | #define IPREG04 0xA0 |
| 414 | #define USB_HCCPW_SET (1 << 1) |
| 415 | #define UOCCAP 0x00 |
| 416 | #define APU_SET (1 << 15) |
| 417 | #define UOCMUX 0x04 |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 418 | #define PMUX_HOST 0x02 |
| 419 | #define PMUX_DEVICE 0x03 |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 420 | #define PUEN_SET (1 << 2) |
| 421 | #define UDCDEVCTL 0x404 |
| 422 | #define UDC_SD_SET (1 << 10) |
| 423 | #define UOCCTL 0x0C |
| 424 | #define PADEN_SET (1 << 7) |
| 425 | |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 426 | static void enable_USB_port4(struct southbridge_amd_cs5536_config *sb) |
| 427 | { |
Kevin Paul Herbert | bde6d30 | 2014-12-24 18:43:20 -0800 | [diff] [blame] | 428 | void *bar; |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 429 | msr_t msr; |
| 430 | device_t dev; |
| 431 | |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 432 | dev = dev_find_device(PCI_VENDOR_ID_AMD, |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 433 | PCI_DEVICE_ID_AMD_CS5536_EHCI, 0); |
| 434 | if (dev) { |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 435 | |
| 436 | /* Serial Short Detect Enable */ |
| 437 | msr = rdmsr(USB2_SB_GLD_MSR_CONF); |
| 438 | msr.hi |= USB2_UPPER_SSDEN_SET; |
| 439 | wrmsr(USB2_SB_GLD_MSR_CONF, msr); |
| 440 | |
| 441 | /* write to clear diag register */ |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 442 | wrmsr(USB2_SB_GLD_MSR_DIAG, rdmsr(USB2_SB_GLD_MSR_DIAG)); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 443 | |
Kevin Paul Herbert | bde6d30 | 2014-12-24 18:43:20 -0800 | [diff] [blame] | 444 | bar = (void *)pci_read_config32(dev, PCI_BASE_ADDRESS_0); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 445 | |
Martin Roth | 55e31a9 | 2014-12-16 20:53:49 -0700 | [diff] [blame] | 446 | /* Make HCCPARAMS writable */ |
Stefan Reinauer | 9fe4d79 | 2010-01-16 17:53:38 +0000 | [diff] [blame] | 447 | write32(bar + IPREG04, read32(bar + IPREG04) | USB_HCCPW_SET); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 448 | |
| 449 | /* ; EECP=50h, IST=01h, ASPC=1 */ |
Stefan Reinauer | 9fe4d79 | 2010-01-16 17:53:38 +0000 | [diff] [blame] | 450 | write32(bar + HCCPARAMS, 0x00005012); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 451 | } |
| 452 | |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 453 | dev = dev_find_device(PCI_VENDOR_ID_AMD, |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 454 | PCI_DEVICE_ID_AMD_CS5536_OTG, 0); |
| 455 | if (dev) { |
Kevin Paul Herbert | bde6d30 | 2014-12-24 18:43:20 -0800 | [diff] [blame] | 456 | bar = (void *)pci_read_config32(dev, PCI_BASE_ADDRESS_0); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 457 | |
Stefan Reinauer | 9fe4d79 | 2010-01-16 17:53:38 +0000 | [diff] [blame] | 458 | write32(bar + UOCMUX, read32(bar + UOCMUX) & PUEN_SET); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 459 | |
| 460 | /* Host or Device? */ |
| 461 | if (sb->enable_USBP4_device) { |
Stefan Reinauer | 9fe4d79 | 2010-01-16 17:53:38 +0000 | [diff] [blame] | 462 | write32(bar + UOCMUX, read32(bar + UOCMUX) | PMUX_DEVICE); |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 463 | } else { |
Stefan Reinauer | 9fe4d79 | 2010-01-16 17:53:38 +0000 | [diff] [blame] | 464 | write32(bar + UOCMUX, read32(bar + UOCMUX) | PMUX_HOST); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 465 | } |
| 466 | |
| 467 | /* Overcurrent configuration */ |
| 468 | if (sb->enable_USBP4_overcurrent) { |
Stefan Reinauer | 9fe4d79 | 2010-01-16 17:53:38 +0000 | [diff] [blame] | 469 | write32(bar + UOCCAP, read32(bar + UOCCAP) |
| 470 | | sb->enable_USBP4_overcurrent); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 471 | } |
| 472 | } |
| 473 | |
| 474 | /* PBz#6466: If the UOC(OTG) device, port 4, is configured as a device, |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 475 | * then perform the following sequence: |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 476 | * |
| 477 | * - set SD bit in DEVCTRL udc register |
| 478 | * - set PADEN (former OTGPADEN) bit in uoc register |
| 479 | * - set APU bit in uoc register */ |
| 480 | if (sb->enable_USBP4_device) { |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 481 | dev = dev_find_device(PCI_VENDOR_ID_AMD, |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 482 | PCI_DEVICE_ID_AMD_CS5536_UDC, 0); |
| 483 | if (dev) { |
Kevin Paul Herbert | bde6d30 | 2014-12-24 18:43:20 -0800 | [diff] [blame] | 484 | bar = (void *)pci_read_config32(dev, |
| 485 | PCI_BASE_ADDRESS_0); |
Stefan Reinauer | 9fe4d79 | 2010-01-16 17:53:38 +0000 | [diff] [blame] | 486 | write32(bar + UDCDEVCTL, |
| 487 | read32(bar + UDCDEVCTL) | UDC_SD_SET); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 488 | |
| 489 | } |
| 490 | |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 491 | dev = dev_find_device(PCI_VENDOR_ID_AMD, |
| 492 | PCI_DEVICE_ID_AMD_CS5536_OTG, 0); |
| 493 | if (dev) { |
Kevin Paul Herbert | bde6d30 | 2014-12-24 18:43:20 -0800 | [diff] [blame] | 494 | bar = (void *)pci_read_config32(dev, |
| 495 | PCI_BASE_ADDRESS_0); |
Stefan Reinauer | 9fe4d79 | 2010-01-16 17:53:38 +0000 | [diff] [blame] | 496 | write32(bar + UOCCTL, read32(bar + UOCCTL) | PADEN_SET); |
| 497 | write32(bar + UOCCAP, read32(bar + UOCCAP) | APU_SET); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 498 | } |
| 499 | } |
| 500 | |
| 501 | /* Disable virtual PCI UDC and OTG headers */ |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 502 | dev = dev_find_device(PCI_VENDOR_ID_AMD, |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 503 | PCI_DEVICE_ID_AMD_CS5536_UDC, 0); |
| 504 | if (dev) { |
Marc Jones | d03b7d4 | 2007-05-10 23:53:11 +0000 | [diff] [blame] | 505 | pci_write_config32(dev, 0x7C, 0xDEADBEEF); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 506 | } |
| 507 | |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 508 | dev = dev_find_device(PCI_VENDOR_ID_AMD, |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 509 | PCI_DEVICE_ID_AMD_CS5536_OTG, 0); |
| 510 | if (dev) { |
Marc Jones | d03b7d4 | 2007-05-10 23:53:11 +0000 | [diff] [blame] | 511 | pci_write_config32(dev, 0x7C, 0xDEADBEEF); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 512 | } |
| 513 | } |
| 514 | |
Stefan Reinauer | ba09695 | 2010-04-22 09:22:15 +0000 | [diff] [blame] | 515 | /**************************************************************************** |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 516 | * |
| 517 | * ChipsetInit |
Stefan Reinauer | ba09695 | 2010-04-22 09:22:15 +0000 | [diff] [blame] | 518 | * |
| 519 | * Called from northbridge init (Pre-VSA). |
| 520 | * |
Stefan Reinauer | ba09695 | 2010-04-22 09:22:15 +0000 | [diff] [blame] | 521 | ****************************************************************************/ |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 522 | void chipsetinit(void) |
| 523 | { |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 524 | device_t dev; |
| 525 | msr_t msr; |
Stefan Reinauer | 78b4033 | 2010-03-17 22:09:26 +0000 | [diff] [blame] | 526 | u32 msrnum; |
Stefan Reinauer | 4292685 | 2010-04-22 10:44:08 +0000 | [diff] [blame] | 527 | struct southbridge_amd_cs5536_config *sb; |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 528 | struct msrinit *csi; |
| 529 | |
Peter Stuge | ae3f4b5 | 2010-05-23 04:50:41 +0000 | [diff] [blame] | 530 | dev = dev_find_slot(0, PCI_DEVFN(0xf, 0)); |
Stefan Reinauer | 4292685 | 2010-04-22 10:44:08 +0000 | [diff] [blame] | 531 | |
| 532 | if (!dev) { |
| 533 | printk(BIOS_ERR, "CS5536 not found.\n"); |
| 534 | return; |
| 535 | } |
| 536 | |
| 537 | sb = (struct southbridge_amd_cs5536_config *)dev->chip_info; |
| 538 | |
| 539 | if (!sb) { |
| 540 | printk(BIOS_ERR, "CS5536 configuration not found.\n"); |
| 541 | return; |
| 542 | } |
| 543 | |
Marc Jones | d03b7d4 | 2007-05-10 23:53:11 +0000 | [diff] [blame] | 544 | post_code(P80_CHIPSET_INIT); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 545 | |
Stefan Reinauer | f8ee180 | 2008-01-18 15:08:58 +0000 | [diff] [blame] | 546 | /* we hope NEVER to be in coreboot when S3 resumes |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 547 | if (! IsS3Resume()) */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 548 | { |
| 549 | struct acpiinit *aci = acpi_init_table; |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 550 | for (; aci->ioreg; aci++) { |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 551 | outl(aci->regdata, aci->ioreg); |
| 552 | inl(aci->ioreg); |
| 553 | } |
| 554 | |
| 555 | pmChipsetInit(); |
| 556 | } |
| 557 | |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 558 | /* set hd IRQ */ |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 559 | outl(GPIOL_2_SET, GPIO_IO_BASE + GPIOL_INPUT_ENABLE); |
| 560 | outl(GPIOL_2_SET, GPIO_IO_BASE + GPIOL_IN_AUX1_SELECT); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 561 | |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 562 | /* Allow IO read and writes during a ATA DMA operation. */ |
| 563 | /* This could be done in the HD rom but do it here for easier debugging. */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 564 | msrnum = ATA_SB_GLD_MSR_ERR; |
| 565 | msr = rdmsr(msrnum); |
| 566 | msr.lo &= ~0x100; |
| 567 | wrmsr(msrnum, msr); |
| 568 | |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 569 | /* Enable Post Primary IDE. */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 570 | msrnum = GLPCI_SB_CTRL; |
| 571 | msr = rdmsr(msrnum); |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 572 | msr.lo |= GLPCI_CRTL_PPIDE_SET; |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 573 | wrmsr(msrnum, msr); |
| 574 | |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 575 | csi = SB_MASTER_CONF_TABLE; |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 576 | for (; csi->msrnum; csi++) { |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 577 | msr.lo = csi->msr.lo; |
| 578 | msr.hi = csi->msr.hi; |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 579 | wrmsr(csi->msrnum, msr); // MSR - see table above |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 580 | } |
| 581 | |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 582 | /* Flash BAR size Setup */ |
Christian Gmeiner | 01c095f | 2013-05-29 20:30:18 +0000 | [diff] [blame] | 583 | printk(BIOS_INFO, "%sDoing ChipsetFlashSetup()\n", |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 584 | sb->enable_ide_nand_flash == 1 ? "" : "Not "); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 585 | if (sb->enable_ide_nand_flash == 1) |
| 586 | ChipsetFlashSetup(); |
| 587 | |
| 588 | /* */ |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 589 | /* Set up Hardware Clock Gating */ |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 590 | /* */ |
| 591 | { |
| 592 | csi = CS5536_CLOCK_GATING_TABLE; |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 593 | for (; csi->msrnum; csi++) { |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 594 | msr.lo = csi->msr.lo; |
| 595 | msr.hi = csi->msr.hi; |
| 596 | wrmsr(csi->msrnum, msr); // MSR - see table above |
| 597 | } |
| 598 | } |
| 599 | } |
Ronald G. Minnich | 5d573c2 | 2006-05-16 02:51:16 +0000 | [diff] [blame] | 600 | |
Ronald G. Minnich | da7ee9f | 2006-07-21 19:21:38 +0000 | [diff] [blame] | 601 | static void southbridge_init(struct device *dev) |
Li-Ta Lo | 5d69896 | 2006-04-20 21:31:47 +0000 | [diff] [blame] | 602 | { |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 603 | struct southbridge_amd_cs5536_config *sb = |
| 604 | (struct southbridge_amd_cs5536_config *)dev->chip_info; |
Ronald G. Minnich | da7ee9f | 2006-07-21 19:21:38 +0000 | [diff] [blame] | 605 | int i; |
Ronald G. Minnich | cf120d1 | 2006-04-25 19:57:39 +0000 | [diff] [blame] | 606 | /* |
| 607 | * struct device *gpiodev; |
| 608 | * unsigned short gpiobase = MDD_GPIO; |
| 609 | */ |
Ronald G. Minnich | 1c2f49e | 2006-04-25 19:40:20 +0000 | [diff] [blame] | 610 | |
Christian Gmeiner | 01c095f | 2013-05-29 20:30:18 +0000 | [diff] [blame] | 611 | printk(BIOS_INFO, "cs5536: %s\n", __func__); |
Stefan Reinauer | 4292685 | 2010-04-22 10:44:08 +0000 | [diff] [blame] | 612 | |
| 613 | if (!sb) { |
| 614 | printk(BIOS_ERR, "CS5536 configuration not found.\n"); |
| 615 | return; |
| 616 | } |
| 617 | |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 618 | setup_i8259(); |
| 619 | lpc_init(sb); |
| 620 | uarts_init(sb); |
Ronald G. Minnich | da7ee9f | 2006-07-21 19:21:38 +0000 | [diff] [blame] | 621 | |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 622 | if (sb->enable_gpio_int_route) { |
| 623 | vrWrite((VRC_MISCELLANEOUS << 8) + PCI_INT_AB, |
| 624 | (sb->enable_gpio_int_route & 0xFFFF)); |
| 625 | vrWrite((VRC_MISCELLANEOUS << 8) + PCI_INT_CD, |
| 626 | (sb->enable_gpio_int_route >> 16)); |
Ronald G. Minnich | 2d7bb59 | 2006-06-18 02:28:07 +0000 | [diff] [blame] | 627 | } |
| 628 | |
Christian Gmeiner | 01c095f | 2013-05-29 20:30:18 +0000 | [diff] [blame] | 629 | printk(BIOS_DEBUG, "cs5536: %s: enable_ide_nand_flash is %d\n", __func__, |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 630 | sb->enable_ide_nand_flash); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 631 | if (sb->enable_ide_nand_flash == 1) { |
| 632 | enable_ide_nand_flash_header(); |
Ronald G. Minnich | 88fb1a6 | 2006-06-22 04:37:27 +0000 | [diff] [blame] | 633 | } |
| 634 | |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 635 | enable_USB_port4(sb); |
Richard Smith | bcd1f23 | 2006-08-28 16:18:32 +0000 | [diff] [blame] | 636 | |
Ronald G. Minnich | da7ee9f | 2006-07-21 19:21:38 +0000 | [diff] [blame] | 637 | /* disable unwanted virtual PCI devices */ |
| 638 | for (i = 0; (i < MAX_UNWANTED_VPCI) && (0 != sb->unwanted_vpci[i]); i++) { |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 639 | printk(BIOS_DEBUG, "Disabling VPCI device: 0x%08X\n", |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 640 | sb->unwanted_vpci[i]); |
Ronald G. Minnich | da7ee9f | 2006-07-21 19:21:38 +0000 | [diff] [blame] | 641 | outl(sb->unwanted_vpci[i] + 0x7C, 0xCF8); |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 642 | outl(0xDEADBEEF, 0xCFC); |
Ronald G. Minnich | da7ee9f | 2006-07-21 19:21:38 +0000 | [diff] [blame] | 643 | } |
Li-Ta Lo | 5d69896 | 2006-04-20 21:31:47 +0000 | [diff] [blame] | 644 | } |
| 645 | |
Myles Watson | 29cc9ed | 2009-07-02 18:56:24 +0000 | [diff] [blame] | 646 | static void cs5536_read_resources(device_t dev) |
| 647 | { |
| 648 | struct resource *res; |
| 649 | |
| 650 | pci_dev_read_resources(dev); |
| 651 | |
| 652 | res = new_resource(dev, 1); |
| 653 | res->base = 0x0UL; |
Myles Watson | 81af48e | 2010-06-07 15:39:04 +0000 | [diff] [blame] | 654 | res->size = 0x1000UL; |
Myles Watson | 29cc9ed | 2009-07-02 18:56:24 +0000 | [diff] [blame] | 655 | res->limit = 0xffffUL; |
Myles Watson | 81af48e | 2010-06-07 15:39:04 +0000 | [diff] [blame] | 656 | res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; |
Myles Watson | 29cc9ed | 2009-07-02 18:56:24 +0000 | [diff] [blame] | 657 | |
| 658 | res = new_resource(dev, 3); /* IOAPIC */ |
Uwe Hermann | 74d1a6e | 2010-10-12 17:34:08 +0000 | [diff] [blame] | 659 | res->base = IO_APIC_ADDR; |
Myles Watson | 29cc9ed | 2009-07-02 18:56:24 +0000 | [diff] [blame] | 660 | res->size = 0x00001000; |
| 661 | res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; |
| 662 | } |
| 663 | |
Ronald G. Minnich | da7ee9f | 2006-07-21 19:21:38 +0000 | [diff] [blame] | 664 | static void southbridge_enable(struct device *dev) |
| 665 | { |
Christian Gmeiner | 01c095f | 2013-05-29 20:30:18 +0000 | [diff] [blame] | 666 | printk(BIOS_DEBUG, "cs5536: %s: dev is %p\n", __func__, dev); |
Marc Jones | a67d4fd | 2007-05-04 19:05:36 +0000 | [diff] [blame] | 667 | |
| 668 | } |
Ronald G. Minnich | da7ee9f | 2006-07-21 19:21:38 +0000 | [diff] [blame] | 669 | |
Christian Gmeiner | b5dfcae | 2012-07-20 10:21:29 +0200 | [diff] [blame] | 670 | static int lsmbus_read_byte(device_t dev, u8 address) |
| 671 | { |
| 672 | u16 device; |
| 673 | struct resource *res; |
| 674 | struct bus *pbus; |
| 675 | |
| 676 | device = dev->path.i2c.device; |
| 677 | pbus = get_pbus_smbus(dev); |
| 678 | res = find_resource(pbus->dev, 0x10); |
| 679 | |
| 680 | return do_smbus_read_byte(res->base, device, address); |
| 681 | } |
| 682 | |
| 683 | static struct smbus_bus_operations lops_smbus_bus = { |
| 684 | .read_byte = lsmbus_read_byte, |
| 685 | }; |
| 686 | |
Kyösti Mälkki | 580e722 | 2015-03-19 21:04:23 +0200 | [diff] [blame] | 687 | static void scan_lpc_smbus(device_t dev) |
Kyösti Mälkki | d0e212c | 2015-02-26 20:47:47 +0200 | [diff] [blame] | 688 | { |
| 689 | /* FIXME. Do we have mixed LPC/SMBus device node here. */ |
Kyösti Mälkki | 580e722 | 2015-03-19 21:04:23 +0200 | [diff] [blame] | 690 | scan_smbus(dev); |
Kyösti Mälkki | d0e212c | 2015-02-26 20:47:47 +0200 | [diff] [blame] | 691 | } |
| 692 | |
Li-Ta Lo | 5d69896 | 2006-04-20 21:31:47 +0000 | [diff] [blame] | 693 | static struct device_operations southbridge_ops = { |
Myles Watson | 29cc9ed | 2009-07-02 18:56:24 +0000 | [diff] [blame] | 694 | .read_resources = cs5536_read_resources, |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 695 | .set_resources = pci_dev_set_resources, |
Myles Watson | 7eac445 | 2010-06-17 16:16:56 +0000 | [diff] [blame] | 696 | .enable_resources = pci_dev_enable_resources, |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 697 | .init = southbridge_init, |
Kyösti Mälkki | d0e212c | 2015-02-26 20:47:47 +0200 | [diff] [blame] | 698 | .scan_bus = scan_lpc_smbus, |
Christian Gmeiner | b5dfcae | 2012-07-20 10:21:29 +0200 | [diff] [blame] | 699 | .ops_smbus_bus = &lops_smbus_bus, |
Li-Ta Lo | 5d69896 | 2006-04-20 21:31:47 +0000 | [diff] [blame] | 700 | }; |
| 701 | |
Stefan Reinauer | f1cf1f7 | 2007-10-24 09:08:58 +0000 | [diff] [blame] | 702 | static const struct pci_driver cs5536_pci_driver __pci_driver = { |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 703 | .ops = &southbridge_ops, |
Li-Ta Lo | 5d69896 | 2006-04-20 21:31:47 +0000 | [diff] [blame] | 704 | .vendor = PCI_VENDOR_ID_AMD, |
| 705 | .device = PCI_DEVICE_ID_AMD_CS5536_ISA |
| 706 | }; |
Ronald G. Minnich | cf120d1 | 2006-04-25 19:57:39 +0000 | [diff] [blame] | 707 | |
| 708 | struct chip_operations southbridge_amd_cs5536_ops = { |
Uwe Hermann | a7aa29b | 2006-11-05 18:50:49 +0000 | [diff] [blame] | 709 | CHIP_NAME("AMD Geode CS5536 Southbridge") |
Jordan Crouse | 2a133f7 | 2007-05-10 18:43:57 +0000 | [diff] [blame] | 710 | /* This is only called when this device is listed in the |
| 711 | * static device tree. |
| 712 | */ |
| 713 | .enable_dev = southbridge_enable, |
Ronald G. Minnich | cf120d1 | 2006-04-25 19:57:39 +0000 | [diff] [blame] | 714 | }; |