2 * the ISA Virtual Support Module of AMD CS5536
4 * Copyright (C) 2007 Lemote, Inc.
5 * Author : jlliu, liujl@lemote.com
7 * Copyright (C) 2009 Lemote, Inc.
8 * Author: Wu Zhangjin, wuzhangjin@gmail.com
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
16 #include <linux/pci.h>
17 #include <cs5536/cs5536.h>
18 #include <cs5536/cs5536_pci.h>
20 /* common variables for PCI_ISA_READ/WRITE_BAR */
21 static const u32 divil_msr_reg
[6] = {
22 DIVIL_MSR_REG(DIVIL_LBAR_SMB
), DIVIL_MSR_REG(DIVIL_LBAR_GPIO
),
23 DIVIL_MSR_REG(DIVIL_LBAR_MFGPT
), DIVIL_MSR_REG(DIVIL_LBAR_IRQ
),
24 DIVIL_MSR_REG(DIVIL_LBAR_PMS
), DIVIL_MSR_REG(DIVIL_LBAR_ACPI
),
27 static const u32 soft_bar_flag
[6] = {
28 SOFT_BAR_SMB_FLAG
, SOFT_BAR_GPIO_FLAG
, SOFT_BAR_MFGPT_FLAG
,
29 SOFT_BAR_IRQ_FLAG
, SOFT_BAR_PMS_FLAG
, SOFT_BAR_ACPI_FLAG
,
32 static const u32 sb_msr_reg
[6] = {
33 SB_MSR_REG(SB_R0
), SB_MSR_REG(SB_R1
), SB_MSR_REG(SB_R2
),
34 SB_MSR_REG(SB_R3
), SB_MSR_REG(SB_R4
), SB_MSR_REG(SB_R5
),
37 static const u32 bar_space_range
[6] = {
38 CS5536_SMB_RANGE
, CS5536_GPIO_RANGE
, CS5536_MFGPT_RANGE
,
39 CS5536_IRQ_RANGE
, CS5536_PMS_RANGE
, CS5536_ACPI_RANGE
,
42 static const int bar_space_len
[6] = {
43 CS5536_SMB_LENGTH
, CS5536_GPIO_LENGTH
, CS5536_MFGPT_LENGTH
,
44 CS5536_IRQ_LENGTH
, CS5536_PMS_LENGTH
, CS5536_ACPI_LENGTH
,
48 * enable the divil module bar space.
50 * For all the DIVIL module LBAR, you should control the DIVIL LBAR reg
51 * and the RCONFx(0~5) reg to use the modules.
53 static void divil_lbar_enable(void)
59 * The DIVIL IRQ is not used yet. and make the RCONF0 reserved.
62 for (offset
= DIVIL_LBAR_SMB
; offset
<= DIVIL_LBAR_PMS
; offset
++) {
63 _rdmsr(DIVIL_MSR_REG(offset
), &hi
, &lo
);
65 _wrmsr(DIVIL_MSR_REG(offset
), hi
, lo
);
70 * disable the divil module bar space.
72 static void divil_lbar_disable(void)
77 for (offset
= DIVIL_LBAR_SMB
; offset
<= DIVIL_LBAR_PMS
; offset
++) {
78 _rdmsr(DIVIL_MSR_REG(offset
), &hi
, &lo
);
80 _wrmsr(DIVIL_MSR_REG(offset
), hi
, lo
);
85 * BAR write: write value to the n BAR
88 void pci_isa_write_bar(int n
, u32 value
)
90 u32 hi
= 0, lo
= value
;
92 if (value
== PCI_BAR_RANGE_MASK
) {
93 _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM
), &hi
, &lo
);
94 lo
|= soft_bar_flag
[n
];
95 _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM
), hi
, lo
);
96 } else if (value
& 0x01) {
99 lo
&= bar_space_range
[n
];
100 _wrmsr(divil_msr_reg
[n
], hi
, lo
);
102 /* RCONFx is 4bytes in units for I/O space */
103 hi
= ((value
& 0x000ffffc) << 12) |
104 ((bar_space_len
[n
] - 4) << 12) | 0x01;
105 lo
= ((value
& 0x000ffffc) << 12) | 0x01;
106 _wrmsr(sb_msr_reg
[n
], hi
, lo
);
111 * BAR read: read the n BAR
114 u32
pci_isa_read_bar(int n
)
119 _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM
), &hi
, &lo
);
120 if (lo
& soft_bar_flag
[n
]) {
121 conf_data
= bar_space_range
[n
] | PCI_BASE_ADDRESS_SPACE_IO
;
122 lo
&= ~soft_bar_flag
[n
];
123 _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM
), hi
, lo
);
125 _rdmsr(divil_msr_reg
[n
], &hi
, &lo
);
126 conf_data
= lo
& bar_space_range
[n
];
134 * isa_write: ISA write transfer
136 * We assume that this is not a bus master transfer.
138 void pci_isa_write_reg(int reg
, u32 value
)
140 u32 hi
= 0, lo
= value
;
145 if (value
& PCI_COMMAND_IO
)
148 divil_lbar_disable();
151 _rdmsr(SB_MSR_REG(SB_ERROR
), &hi
, &lo
);
152 temp
= lo
& 0x0000ffff;
153 if ((value
& PCI_STATUS_SIG_TARGET_ABORT
) &&
154 (lo
& SB_TAS_ERR_EN
))
155 temp
|= SB_TAS_ERR_FLAG
;
157 if ((value
& PCI_STATUS_REC_TARGET_ABORT
) &&
158 (lo
& SB_TAR_ERR_EN
))
159 temp
|= SB_TAR_ERR_FLAG
;
161 if ((value
& PCI_STATUS_REC_MASTER_ABORT
)
162 && (lo
& SB_MAR_ERR_EN
))
163 temp
|= SB_MAR_ERR_FLAG
;
165 if ((value
& PCI_STATUS_DETECTED_PARITY
)
166 && (lo
& SB_PARE_ERR_EN
))
167 temp
|= SB_PARE_ERR_FLAG
;
170 _wrmsr(SB_MSR_REG(SB_ERROR
), hi
, lo
);
172 case PCI_CACHE_LINE_SIZE
:
174 _rdmsr(SB_MSR_REG(SB_CTRL
), &hi
, &lo
);
177 _wrmsr(SB_MSR_REG(SB_CTRL
), hi
, lo
);
180 pci_isa_write_bar(0, value
);
183 pci_isa_write_bar(1, value
);
186 pci_isa_write_bar(2, value
);
189 pci_isa_write_bar(3, value
);
192 pci_isa_write_bar(4, value
);
195 pci_isa_write_bar(5, value
);
197 case PCI_UART1_INT_REG
:
198 _rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH
), &hi
, &lo
);
199 /* disable uart1 interrupt in PIC */
201 if (value
) /* enable uart1 interrupt in PIC */
202 lo
|= (CS5536_UART1_INTR
<< 24);
203 _wrmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH
), hi
, lo
);
205 case PCI_UART2_INT_REG
:
206 _rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH
), &hi
, &lo
);
207 /* disable uart2 interrupt in PIC */
209 if (value
) /* enable uart2 interrupt in PIC */
210 lo
|= (CS5536_UART2_INTR
<< 28);
211 _wrmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH
), hi
, lo
);
213 case PCI_ISA_FIXUP_REG
:
215 /* enable the TARGET ABORT/MASTER ABORT etc. */
216 _rdmsr(SB_MSR_REG(SB_ERROR
), &hi
, &lo
);
218 _wrmsr(SB_MSR_REG(SB_ERROR
), hi
, lo
);
222 /* ALL OTHER PCI CONFIG SPACE HEADER IS NOT IMPLEMENTED. */
228 * isa_read: ISA read transfers
230 * We assume that this is not a bus master transfer.
232 u32
pci_isa_read_reg(int reg
)
240 CFG_PCI_VENDOR_ID(CS5536_ISA_DEVICE_ID
, CS5536_VENDOR_ID
);
243 /* we just check the first LBAR for the IO enable bit, */
244 /* maybe we should changed later. */
245 _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_SMB
), &hi
, &lo
);
247 conf_data
|= PCI_COMMAND_IO
;
250 conf_data
|= PCI_STATUS_66MHZ
;
251 conf_data
|= PCI_STATUS_DEVSEL_MEDIUM
;
252 conf_data
|= PCI_STATUS_FAST_BACK
;
254 _rdmsr(SB_MSR_REG(SB_ERROR
), &hi
, &lo
);
255 if (lo
& SB_TAS_ERR_FLAG
)
256 conf_data
|= PCI_STATUS_SIG_TARGET_ABORT
;
257 if (lo
& SB_TAR_ERR_FLAG
)
258 conf_data
|= PCI_STATUS_REC_TARGET_ABORT
;
259 if (lo
& SB_MAR_ERR_FLAG
)
260 conf_data
|= PCI_STATUS_REC_MASTER_ABORT
;
261 if (lo
& SB_PARE_ERR_FLAG
)
262 conf_data
|= PCI_STATUS_DETECTED_PARITY
;
264 case PCI_CLASS_REVISION
:
265 _rdmsr(GLCP_MSR_REG(GLCP_CHIP_REV_ID
), &hi
, &lo
);
266 conf_data
= lo
& 0x000000ff;
267 conf_data
|= (CS5536_ISA_CLASS_CODE
<< 8);
269 case PCI_CACHE_LINE_SIZE
:
270 _rdmsr(SB_MSR_REG(SB_CTRL
), &hi
, &lo
);
272 conf_data
= CFG_PCI_CACHE_LINE_SIZE(PCI_BRIDGE_HEADER_TYPE
, hi
);
275 * we only use the LBAR of DIVIL, no RCONF used.
276 * all of them are IO space.
279 return pci_isa_read_bar(0);
282 return pci_isa_read_bar(1);
285 return pci_isa_read_bar(2);
290 return pci_isa_read_bar(4);
293 return pci_isa_read_bar(5);
295 case PCI_CARDBUS_CIS
:
296 conf_data
= PCI_CARDBUS_CIS_POINTER
;
298 case PCI_SUBSYSTEM_VENDOR_ID
:
300 CFG_PCI_VENDOR_ID(CS5536_ISA_SUB_ID
, CS5536_SUB_VENDOR_ID
);
302 case PCI_ROM_ADDRESS
:
303 conf_data
= PCI_EXPANSION_ROM_BAR
;
305 case PCI_CAPABILITY_LIST
:
306 conf_data
= PCI_CAPLIST_POINTER
;
308 case PCI_INTERRUPT_LINE
:
309 /* no interrupt used here */
310 conf_data
= CFG_PCI_INTERRUPT_LINE(0x00, 0x00);
320 * The mfgpt timer interrupt is running early, so we must keep the south bridge
321 * mmio always enabled. Otherwise we may race with the PCI configuration which
322 * may temporarily disable it. When that happens and the timer interrupt fires,
323 * we are not able to clear it and the system will hang.
325 static void cs5536_isa_mmio_always_on(struct pci_dev
*dev
)
327 dev
->mmio_always_on
= 1;
329 DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_AMD
, PCI_DEVICE_ID_AMD_CS5536_ISA
,
330 PCI_CLASS_BRIDGE_ISA
, 8, cs5536_isa_mmio_always_on
);