DDR3 support for AMD Fam10.
[coreboot.git] / src / northbridge / amd / amdmct / mct_ddr3 / mctchi_d.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2010 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 as published by
8  * the Free Software Foundation; version 2 of the License.
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
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  */
19
20 void InterleaveChannels_D(struct MCTStatStruc *pMCTstat,
21                         struct DCTStatStruc *pDCTstatA)
22 {
23
24         u8 Node;
25         u32 DramBase, DctSelBase;
26         u8 DctSelIntLvAddr, DctSelHi;
27         u8 HoleValid = 0;
28         u32 HoleSize, HoleBase = 0;
29         u32 val, tmp;
30         u32 dct0_size, dct1_size;
31         struct DCTStatStruc *pDCTstat;
32
33         /* HoleValid - indicates whether the current Node contains hole.
34          * HoleSize - indicates whether there is IO hole in the whole system
35          * memory.
36          */
37
38         /* call back to wrapper not needed ManualChannelInterleave_D(); */
39         /* call back - DctSelIntLvAddr = mctGet_NVbits(NV_ChannelIntlv);*/      /* override interleave */
40         /* Manually set: typ=5, otherwise typ=7. */
41         DctSelIntLvAddr = mctGet_NVbits(NV_ChannelIntlv); /* typ=5: Hash*: exclusive OR of address bits[20:16, 6]. */
42
43         if (DctSelIntLvAddr & 1) {
44                 DctSelIntLvAddr >>= 1;
45                 HoleSize = 0;
46                 if ((pMCTstat->GStatus & (1 << GSB_SoftHole)) ||
47                      (pMCTstat->GStatus & (1 << GSB_HWHole))) {
48                         if (pMCTstat->HoleBase) {
49                                 HoleBase = pMCTstat->HoleBase >> 8;
50                                 HoleSize = HoleBase & 0xFFFF0000;
51                                 HoleSize |= ((~HoleBase) + 1) & 0xFFFF;
52                         }
53                 }
54                 Node = 0;
55                 while (Node < MAX_NODES_SUPPORTED) {
56                         pDCTstat = pDCTstatA + Node;
57                         val = Get_NB32(pDCTstat->dev_map, 0xF0);
58                         if (val & (1 << DramHoleValid))
59                                 HoleValid = 1;
60                         if (!pDCTstat->GangedMode && pDCTstat->DIMMValidDCT[0] && pDCTstat->DIMMValidDCT[1]) {
61                                 DramBase = pDCTstat->NodeSysBase >> 8;
62                                 dct1_size = ((pDCTstat->NodeSysLimit) + 2) >> 8;
63                                 dct0_size = Get_NB32(pDCTstat->dev_dct, 0x114);
64                                         if (dct0_size >= 0x10000) {
65                                                 dct0_size -= HoleSize;
66                                         }
67
68                                 dct0_size -= DramBase;
69                                 dct1_size -= dct0_size;
70                                 DctSelHi = 0x05;                /* DctSelHiRngEn = 1, DctSelHi = 0 */
71                                 if (dct1_size == dct0_size) {
72                                         dct1_size = 0;
73                                         DctSelHi = 0x04;        /* DctSelHiRngEn = 0 */
74                                 } else if (dct1_size > dct0_size ) {
75                                         dct1_size = dct0_size;
76                                         DctSelHi = 0x07;        /* DctSelHiRngEn = 1, DctSelHi = 1 */
77                                 }
78                                 dct0_size = dct1_size;
79                                 dct0_size += DramBase;
80                                 dct0_size += dct1_size;
81                                 if (dct0_size >= HoleBase)      /* if DctSelBaseAddr > HoleBase */
82                                         dct0_size += HoleSize;
83                                 DctSelBase = dct0_size;
84
85                                 if (dct1_size == 0)
86                                         dct0_size = 0;
87                                 dct0_size -= dct1_size;         /* DctSelBaseOffset = DctSelBaseAddr - Interleaved region */
88                                 Set_NB32(pDCTstat->dev_dct, 0x114, dct0_size);
89
90                                 if (dct1_size == 0)
91                                         dct1_size = DctSelBase;
92                                 val = Get_NB32(pDCTstat->dev_dct, 0x110);
93                                 val &= 0x7F8;
94                                 val |= dct1_size;
95                                 val |= DctSelHi;
96                                 val |= (DctSelIntLvAddr << 6) & 0xFF;
97                                 Set_NB32(pDCTstat->dev_dct, 0x110, val);
98
99                                 if (HoleValid) {
100                                         tmp = DramBase;
101                                         val = DctSelBase;
102                                         if (val < HoleBase) {   /* DctSelBaseAddr < DramHoleBase */
103                                                 val -= DramBase;
104                                                 val >>= 1;
105                                                 tmp += val;
106                                         }
107                                         tmp += HoleSize;
108                                         val = Get_NB32(pDCTstat->dev_map, 0xF0);        /* DramHoleOffset */
109                                         val &= 0xFFFF007F;
110                                         val |= (tmp & ~0xFFFF007F);
111                                         Set_NB32(pDCTstat->dev_map, 0xF0, val);
112                                 }
113                         }
114                         printk(BIOS_DEBUG, "InterleaveChannels_D: Node %x\n", Node);
115                         printk(BIOS_DEBUG, "InterleaveChannels_D: Status %x\n", pDCTstat->Status);
116                         printk(BIOS_DEBUG, "InterleaveChannels_D: ErrStatus %x\n", pDCTstat->ErrStatus);
117                         printk(BIOS_DEBUG, "InterleaveChannels_D: ErrCode %x\n", pDCTstat->ErrCode);
118                         Node++;
119                 }
120         }
121         printk(BIOS_DEBUG, "InterleaveChannels_D: Done\n\n");
122 }