Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cs5536_isa.c
Go to the documentation of this file.
1 /*
2  * the ISA Virtual Support Module of AMD CS5536
3  *
4  * Copyright (C) 2007 Lemote, Inc.
5  * Author : jlliu, [email protected]
6  *
7  * Copyright (C) 2009 Lemote, Inc.
8  * Author: Wu Zhangjin, [email protected]
9  *
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.
14  */
15 
16 #include <cs5536/cs5536.h>
17 #include <cs5536/cs5536_pci.h>
18 
19 /* common variables for PCI_ISA_READ/WRITE_BAR */
20 static const u32 divil_msr_reg[6] = {
24 };
25 
26 static const u32 soft_bar_flag[6] = {
29 };
30 
31 static const u32 sb_msr_reg[6] = {
34 };
35 
36 static const u32 bar_space_range[6] = {
39 };
40 
41 static const int bar_space_len[6] = {
44 };
45 
46 /*
47  * enable the divil module bar space.
48  *
49  * For all the DIVIL module LBAR, you should control the DIVIL LBAR reg
50  * and the RCONFx(0~5) reg to use the modules.
51  */
52 static void divil_lbar_enable(void)
53 {
54  u32 hi, lo;
55  int offset;
56 
57  /*
58  * The DIVIL IRQ is not used yet. and make the RCONF0 reserved.
59  */
60 
61  for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {
62  _rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
63  hi |= 0x01;
64  _wrmsr(DIVIL_MSR_REG(offset), hi, lo);
65  }
66 }
67 
68 /*
69  * disable the divil module bar space.
70  */
71 static void divil_lbar_disable(void)
72 {
73  u32 hi, lo;
74  int offset;
75 
76  for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {
77  _rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
78  hi &= ~0x01;
79  _wrmsr(DIVIL_MSR_REG(offset), hi, lo);
80  }
81 }
82 
83 /*
84  * BAR write: write value to the n BAR
85  */
86 
88 {
89  u32 hi = 0, lo = value;
90 
91  if (value == PCI_BAR_RANGE_MASK) {
92  _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
93  lo |= soft_bar_flag[n];
95  } else if (value & 0x01) {
96  /* NATIVE reg */
97  hi = 0x0000f001;
98  lo &= bar_space_range[n];
99  _wrmsr(divil_msr_reg[n], hi, lo);
100 
101  /* RCONFx is 4bytes in units for I/O space */
102  hi = ((value & 0x000ffffc) << 12) |
103  ((bar_space_len[n] - 4) << 12) | 0x01;
104  lo = ((value & 0x000ffffc) << 12) | 0x01;
105  _wrmsr(sb_msr_reg[n], hi, lo);
106  }
107 }
108 
109 /*
110  * BAR read: read the n BAR
111  */
112 
114 {
115  u32 conf_data = 0;
116  u32 hi, lo;
117 
118  _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
119  if (lo & soft_bar_flag[n]) {
120  conf_data = bar_space_range[n] | PCI_BASE_ADDRESS_SPACE_IO;
121  lo &= ~soft_bar_flag[n];
123  } else {
124  _rdmsr(divil_msr_reg[n], &hi, &lo);
125  conf_data = lo & bar_space_range[n];
126  conf_data |= 0x01;
127  conf_data &= ~0x02;
128  }
129  return conf_data;
130 }
131 
132 /*
133  * isa_write: ISA write transfer
134  *
135  * We assume that this is not a bus master transfer.
136  */
138 {
139  u32 hi = 0, lo = value;
140  u32 temp;
141 
142  switch (reg) {
143  case PCI_COMMAND:
144  if (value & PCI_COMMAND_IO)
145  divil_lbar_enable();
146  else
147  divil_lbar_disable();
148  break;
149  case PCI_STATUS:
150  _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
151  temp = lo & 0x0000ffff;
152  if ((value & PCI_STATUS_SIG_TARGET_ABORT) &&
153  (lo & SB_TAS_ERR_EN))
154  temp |= SB_TAS_ERR_FLAG;
155 
156  if ((value & PCI_STATUS_REC_TARGET_ABORT) &&
157  (lo & SB_TAR_ERR_EN))
158  temp |= SB_TAR_ERR_FLAG;
159 
160  if ((value & PCI_STATUS_REC_MASTER_ABORT)
161  && (lo & SB_MAR_ERR_EN))
162  temp |= SB_MAR_ERR_FLAG;
163 
164  if ((value & PCI_STATUS_DETECTED_PARITY)
165  && (lo & SB_PARE_ERR_EN))
166  temp |= SB_PARE_ERR_FLAG;
167 
168  lo = temp;
169  _wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
170  break;
171  case PCI_CACHE_LINE_SIZE:
172  value &= 0x0000ff00;
173  _rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
174  hi &= 0xffffff00;
175  hi |= (value >> 8);
176  _wrmsr(SB_MSR_REG(SB_CTRL), hi, lo);
177  break;
178  case PCI_BAR0_REG:
179  pci_isa_write_bar(0, value);
180  break;
181  case PCI_BAR1_REG:
182  pci_isa_write_bar(1, value);
183  break;
184  case PCI_BAR2_REG:
185  pci_isa_write_bar(2, value);
186  break;
187  case PCI_BAR3_REG:
188  pci_isa_write_bar(3, value);
189  break;
190  case PCI_BAR4_REG:
191  pci_isa_write_bar(4, value);
192  break;
193  case PCI_BAR5_REG:
194  pci_isa_write_bar(5, value);
195  break;
196  case PCI_UART1_INT_REG:
197  _rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), &hi, &lo);
198  /* disable uart1 interrupt in PIC */
199  lo &= ~(0xf << 24);
200  if (value) /* enable uart1 interrupt in PIC */
201  lo |= (CS5536_UART1_INTR << 24);
203  break;
204  case PCI_UART2_INT_REG:
205  _rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), &hi, &lo);
206  /* disable uart2 interrupt in PIC */
207  lo &= ~(0xf << 28);
208  if (value) /* enable uart2 interrupt in PIC */
209  lo |= (CS5536_UART2_INTR << 28);
211  break;
212  case PCI_ISA_FIXUP_REG:
213  if (value) {
214  /* enable the TARGET ABORT/MASTER ABORT etc. */
215  _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
216  lo |= 0x00000063;
217  _wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
218  }
219 
220  default:
221  /* ALL OTHER PCI CONFIG SPACE HEADER IS NOT IMPLEMENTED. */
222  break;
223  }
224 }
225 
226 /*
227  * isa_read: ISA read transfers
228  *
229  * We assume that this is not a bus master transfer.
230  */
232 {
233  u32 conf_data = 0;
234  u32 hi, lo;
235 
236  switch (reg) {
237  case PCI_VENDOR_ID:
238  conf_data =
240  break;
241  case PCI_COMMAND:
242  /* we just check the first LBAR for the IO enable bit, */
243  /* maybe we should changed later. */
244  _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_SMB), &hi, &lo);
245  if (hi & 0x01)
246  conf_data |= PCI_COMMAND_IO;
247  break;
248  case PCI_STATUS:
249  conf_data |= PCI_STATUS_66MHZ;
250  conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
251  conf_data |= PCI_STATUS_FAST_BACK;
252 
253  _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
254  if (lo & SB_TAS_ERR_FLAG)
255  conf_data |= PCI_STATUS_SIG_TARGET_ABORT;
256  if (lo & SB_TAR_ERR_FLAG)
257  conf_data |= PCI_STATUS_REC_TARGET_ABORT;
258  if (lo & SB_MAR_ERR_FLAG)
259  conf_data |= PCI_STATUS_REC_MASTER_ABORT;
260  if (lo & SB_PARE_ERR_FLAG)
261  conf_data |= PCI_STATUS_DETECTED_PARITY;
262  break;
263  case PCI_CLASS_REVISION:
265  conf_data = lo & 0x000000ff;
266  conf_data |= (CS5536_ISA_CLASS_CODE << 8);
267  break;
268  case PCI_CACHE_LINE_SIZE:
269  _rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
270  hi &= 0x000000f8;
272  break;
273  /*
274  * we only use the LBAR of DIVIL, no RCONF used.
275  * all of them are IO space.
276  */
277  case PCI_BAR0_REG:
278  return pci_isa_read_bar(0);
279  break;
280  case PCI_BAR1_REG:
281  return pci_isa_read_bar(1);
282  break;
283  case PCI_BAR2_REG:
284  return pci_isa_read_bar(2);
285  break;
286  case PCI_BAR3_REG:
287  break;
288  case PCI_BAR4_REG:
289  return pci_isa_read_bar(4);
290  break;
291  case PCI_BAR5_REG:
292  return pci_isa_read_bar(5);
293  break;
294  case PCI_CARDBUS_CIS:
295  conf_data = PCI_CARDBUS_CIS_POINTER;
296  break;
298  conf_data =
300  break;
301  case PCI_ROM_ADDRESS:
302  conf_data = PCI_EXPANSION_ROM_BAR;
303  break;
304  case PCI_CAPABILITY_LIST:
305  conf_data = PCI_CAPLIST_POINTER;
306  break;
307  case PCI_INTERRUPT_LINE:
308  /* no interrupt used here */
309  conf_data = CFG_PCI_INTERRUPT_LINE(0x00, 0x00);
310  break;
311  default:
312  break;
313  }
314 
315  return conf_data;
316 }