Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ht.c
Go to the documentation of this file.
1 /*
2  * Copyright 2003 PMC-Sierra
3  * Author: Manish Lachwani ([email protected])
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; either version 2 of the License, or (at your
8  * option) any later version.
9  *
10  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
11  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
13  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
14  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
15  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
16  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
17  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
19  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program; if not, write to the Free Software Foundation, Inc.,
23  * 675 Mass Ave, Cambridge, MA 02139, USA.
24  */
25 
26 #include <linux/types.h>
27 #include <linux/pci.h>
28 #include <linux/kernel.h>
29 #include <asm/pci.h>
30 #include <asm/io.h>
31 
32 #include <linux/init.h>
33 #include <asm/titan_dep.h>
34 
35 #ifdef CONFIG_HYPERTRANSPORT
36 
37 
38 /*
39  * This function check if the Hypertransport Link Initialization completed. If
40  * it did, then proceed further with scanning bus #2
41  */
42 static __inline__ int check_titan_htlink(void)
43 {
44  u32 val;
45 
46  val = *(volatile uint32_t *)(RM9000x2_HTLINK_REG);
47  if (val & 0x00000020)
48  /* HT Link Initialization completed */
49  return 1;
50  else
51  return 0;
52 }
53 
54 static int titan_ht_config_read_dword(struct pci_dev *device,
55  int offset, u32* val)
56 {
57  int dev, bus, func;
58  uint32_t address_reg, data_reg;
60 
61  bus = device->bus->number;
62  dev = PCI_SLOT(device->devfn);
63  func = PCI_FUNC(device->devfn);
64 
65  /* XXX Need to change the Bus # */
66  if (bus > 2)
67  address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
68  0x80000000 | 0x1;
69  else
70  address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
71 
72  address_reg = RM9000x2_OCD_HTCFGA;
73  data_reg = RM9000x2_OCD_HTCFGD;
74 
75  RM9K_WRITE(address_reg, address);
76  RM9K_READ(data_reg, val);
77 
78  return PCIBIOS_SUCCESSFUL;
79 }
80 
81 
82 static int titan_ht_config_read_word(struct pci_dev *device,
83  int offset, u16* val)
84 {
85  int dev, bus, func;
86  uint32_t address_reg, data_reg;
88 
89  bus = device->bus->number;
90  dev = PCI_SLOT(device->devfn);
91  func = PCI_FUNC(device->devfn);
92 
93  /* XXX Need to change the Bus # */
94  if (bus > 2)
95  address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
96  0x80000000 | 0x1;
97  else
98  address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
99 
100  address_reg = RM9000x2_OCD_HTCFGA;
101  data_reg = RM9000x2_OCD_HTCFGD;
102 
103  if ((offset & 0x3) == 0)
104  offset = 0x2;
105  else
106  offset = 0x0;
107 
108  RM9K_WRITE(address_reg, address);
109  RM9K_READ_16(data_reg + offset, val);
110 
111  return PCIBIOS_SUCCESSFUL;
112 }
113 
114 
115 u32 longswap(unsigned long l)
116 {
117  unsigned char b1, b2, b3, b4;
118 
119  b1 = l&255;
120  b2 = (l>>8)&255;
121  b3 = (l>>16)&255;
122  b4 = (l>>24)&255;
123 
124  return ((b1<<24) + (b2<<16) + (b3<<8) + b4);
125 }
126 
127 
128 static int titan_ht_config_read_byte(struct pci_dev *device,
129  int offset, u8* val)
130 {
131  int dev, bus, func;
132  uint32_t address_reg, data_reg;
134  int offset1;
135 
136  bus = device->bus->number;
137  dev = PCI_SLOT(device->devfn);
138  func = PCI_FUNC(device->devfn);
139 
140  /* XXX Need to change the Bus # */
141  if (bus > 2)
142  address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
143  0x80000000 | 0x1;
144  else
145  address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
146 
147  address_reg = RM9000x2_OCD_HTCFGA;
148  data_reg = RM9000x2_OCD_HTCFGD;
149 
150  RM9K_WRITE(address_reg, address);
151 
152  if ((offset & 0x3) == 0) {
153  offset1 = 0x3;
154  }
155  if ((offset & 0x3) == 1) {
156  offset1 = 0x2;
157  }
158  if ((offset & 0x3) == 2) {
159  offset1 = 0x1;
160  }
161  if ((offset & 0x3) == 3) {
162  offset1 = 0x0;
163  }
164  RM9K_READ_8(data_reg + offset1, val);
165 
166  return PCIBIOS_SUCCESSFUL;
167 }
168 
169 
170 static int titan_ht_config_write_dword(struct pci_dev *device,
171  int offset, u8 val)
172 {
173  int dev, bus, func;
174  uint32_t address_reg, data_reg;
176 
177  bus = device->bus->number;
178  dev = PCI_SLOT(device->devfn);
179  func = PCI_FUNC(device->devfn);
180 
181  /* XXX Need to change the Bus # */
182  if (bus > 2)
183  address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
184  0x80000000 | 0x1;
185  else
186  address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
187 
188  address_reg = RM9000x2_OCD_HTCFGA;
189  data_reg = RM9000x2_OCD_HTCFGD;
190 
191  RM9K_WRITE(address_reg, address);
192  RM9K_WRITE(data_reg, val);
193 
194  return PCIBIOS_SUCCESSFUL;
195 }
196 
197 static int titan_ht_config_write_word(struct pci_dev *device,
198  int offset, u8 val)
199 {
200  int dev, bus, func;
201  uint32_t address_reg, data_reg;
203 
204  bus = device->bus->number;
205  dev = PCI_SLOT(device->devfn);
206  func = PCI_FUNC(device->devfn);
207 
208  /* XXX Need to change the Bus # */
209  if (bus > 2)
210  address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
211  0x80000000 | 0x1;
212  else
213  address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
214 
215  address_reg = RM9000x2_OCD_HTCFGA;
216  data_reg = RM9000x2_OCD_HTCFGD;
217 
218  if ((offset & 0x3) == 0)
219  offset = 0x2;
220  else
221  offset = 0x0;
222 
223  RM9K_WRITE(address_reg, address);
224  RM9K_WRITE_16(data_reg + offset, val);
225 
226  return PCIBIOS_SUCCESSFUL;
227 }
228 
229 static int titan_ht_config_write_byte(struct pci_dev *device,
230  int offset, u8 val)
231 {
232  int dev, bus, func;
233  uint32_t address_reg, data_reg;
235  int offset1;
236 
237  bus = device->bus->number;
238  dev = PCI_SLOT(device->devfn);
239  func = PCI_FUNC(device->devfn);
240 
241  /* XXX Need to change the Bus # */
242  if (bus > 2)
243  address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
244  0x80000000 | 0x1;
245  else
246  address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
247 
248  address_reg = RM9000x2_OCD_HTCFGA;
249  data_reg = RM9000x2_OCD_HTCFGD;
250 
251  RM9K_WRITE(address_reg, address);
252 
253  if ((offset & 0x3) == 0) {
254  offset1 = 0x3;
255  }
256  if ((offset & 0x3) == 1) {
257  offset1 = 0x2;
258  }
259  if ((offset & 0x3) == 2) {
260  offset1 = 0x1;
261  }
262  if ((offset & 0x3) == 3) {
263  offset1 = 0x0;
264  }
265 
266  RM9K_WRITE_8(data_reg + offset1, val);
267  return PCIBIOS_SUCCESSFUL;
268 }
269 
270 
271 static void titan_pcibios_set_master(struct pci_dev *dev)
272 {
273  u16 cmd;
274  int bus = dev->bus->number;
275 
276  if (check_titan_htlink())
277  titan_ht_config_read_word(dev, PCI_COMMAND, &cmd);
278 
279  cmd |= PCI_COMMAND_MASTER;
280 
281  if (check_titan_htlink())
282  titan_ht_config_write_word(dev, PCI_COMMAND, cmd);
283 }
284 
285 
286 int pcibios_enable_resources(struct pci_dev *dev)
287 {
288  u16 cmd, old_cmd;
289  u8 tmp1;
290  int idx;
291  struct resource *r;
292  int bus = dev->bus->number;
293 
294  if (check_titan_htlink())
295  titan_ht_config_read_word(dev, PCI_COMMAND, &cmd);
296 
297  old_cmd = cmd;
298  for (idx = 0; idx < 6; idx++) {
299  r = &dev->resource[idx];
300  if (!r->start && r->end) {
302  "PCI: Device %s not available because of "
303  "resource collisions\n", pci_name(dev));
304  return -EINVAL;
305  }
306  if (r->flags & IORESOURCE_IO)
307  cmd |= PCI_COMMAND_IO;
308  if (r->flags & IORESOURCE_MEM)
309  cmd |= PCI_COMMAND_MEMORY;
310  }
311  if (cmd != old_cmd) {
312  if (check_titan_htlink())
313  titan_ht_config_write_word(dev, PCI_COMMAND, cmd);
314  }
315 
316  if (check_titan_htlink())
317  titan_ht_config_read_byte(dev, PCI_CACHE_LINE_SIZE, &tmp1);
318 
319  if (tmp1 != 8) {
320  printk(KERN_WARNING "PCI setting cache line size to 8 from "
321  "%d\n", tmp1);
322  }
323 
324  if (check_titan_htlink())
325  titan_ht_config_write_byte(dev, PCI_CACHE_LINE_SIZE, 8);
326 
327  if (check_titan_htlink())
328  titan_ht_config_read_byte(dev, PCI_LATENCY_TIMER, &tmp1);
329 
330  if (tmp1 < 32 || tmp1 == 0xff) {
331  printk(KERN_WARNING "PCI setting latency timer to 32 from %d\n",
332  tmp1);
333  }
334 
335  if (check_titan_htlink())
336  titan_ht_config_write_byte(dev, PCI_LATENCY_TIMER, 32);
337 
338  return 0;
339 }
340 
341 
342 int pcibios_enable_device(struct pci_dev *dev, int mask)
343 {
344  return pcibios_enable_resources(dev);
345 }
346 
349 {
350  struct pci_dev *dev = data;
351  resource_size_t start = res->start;
352 
353  if (res->flags & IORESOURCE_IO) {
354  /* We need to avoid collisions with `mirrored' VGA ports
355  and other strange ISA hardware, so we always want the
356  addresses kilobyte aligned. */
357  if (size > 0x100) {
358  printk(KERN_ERR "PCI: I/O Region %s/%d too large"
359  " (%ld bytes)\n", pci_name(dev),
360  dev->resource - res, size);
361  }
362 
363  start = (start + 1024 - 1) & ~(1024 - 1);
364  }
365 
366  return start;
367 }
368 
369 struct pci_ops titan_pci_ops = {
370  titan_ht_config_read_byte,
371  titan_ht_config_read_word,
372  titan_ht_config_read_dword,
373  titan_ht_config_write_byte,
374  titan_ht_config_write_word,
375  titan_ht_config_write_dword
376 };
377 
378 void __init pcibios_fixup_bus(struct pci_bus *c)
379 {
381 }
382 
383 void __init pcibios_init(void)
384 {
385 
386  /* Reset PCI I/O and PCI MEM values */
387  /* XXX Need to add the proper values here */
388  ioport_resource.start = 0xe0000000;
389  ioport_resource.end = 0xe0000000 + 0x20000000 - 1;
390  iomem_resource.start = 0xc0000000;
391  iomem_resource.end = 0xc0000000 + 0x20000000 - 1;
392 
393  /* XXX Need to add bus values */
394  pci_scan_bus(2, &titan_pci_ops, NULL);
395  pci_scan_bus(3, &titan_pci_ops, NULL);
396 }
397 
398 unsigned __init int pcibios_assign_all_busses(void)
399 {
400  /* We want to use the PCI bus detection done by PMON */
401  return 0;
402 }
403 
404 #endif /* CONFIG_HYPERTRANSPORT */