• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
3   * Copyright (C) 2003, 2004 Paul Mundt
4   * Copyright (C) 2004 Richard Curnow
5   *
6   * May be copied or modified under the terms of the GNU General Public
7   * License.  See linux/COPYING for more information.
8   *
9   * Support functions for the SH5 PCI hardware.
10   */
11  
12  #include <linux/kernel.h>
13  #include <linux/rwsem.h>
14  #include <linux/smp.h>
15  #include <linux/interrupt.h>
16  #include <linux/init.h>
17  #include <linux/errno.h>
18  #include <linux/pci.h>
19  #include <linux/delay.h>
20  #include <linux/types.h>
21  #include <linux/irq.h>
22  #include <cpu/irq.h>
23  #include <asm/pci.h>
24  #include <asm/io.h>
25  #include "pci-sh5.h"
26  
27  unsigned long pcicr_virt;
28  unsigned long PCI_IO_AREA;
29  
30  /* Rounds a number UP to the nearest power of two. Used for
31   * sizing the PCI window.
32   */
r2p2(u32 num)33  static u32 __init r2p2(u32 num)
34  {
35  	int i = 31;
36  	u32 tmp = num;
37  
38  	if (num == 0)
39  		return 0;
40  
41  	do {
42  		if (tmp & (1 << 31))
43  			break;
44  		i--;
45  		tmp <<= 1;
46  	} while (i >= 0);
47  
48  	tmp = 1 << i;
49  	/* If the original number isn't a power of 2, round it up */
50  	if (tmp != num)
51  		tmp <<= 1;
52  
53  	return tmp;
54  }
55  
pcish5_err_irq(int irq,void * dev_id)56  static irqreturn_t pcish5_err_irq(int irq, void *dev_id)
57  {
58  	struct pt_regs *regs = get_irq_regs();
59  	unsigned pci_int, pci_air, pci_cir, pci_aint;
60  
61  	pci_int = SH5PCI_READ(INT);
62  	pci_cir = SH5PCI_READ(CIR);
63  	pci_air = SH5PCI_READ(AIR);
64  
65  	if (pci_int) {
66  		printk("PCI INTERRUPT (at %08llx)!\n", regs->pc);
67  		printk("PCI INT -> 0x%x\n", pci_int & 0xffff);
68  		printk("PCI AIR -> 0x%x\n", pci_air);
69  		printk("PCI CIR -> 0x%x\n", pci_cir);
70  		SH5PCI_WRITE(INT, ~0);
71  	}
72  
73  	pci_aint = SH5PCI_READ(AINT);
74  	if (pci_aint) {
75  		printk("PCI ARB INTERRUPT!\n");
76  		printk("PCI AINT -> 0x%x\n", pci_aint);
77  		printk("PCI AIR -> 0x%x\n", pci_air);
78  		printk("PCI CIR -> 0x%x\n", pci_cir);
79  		SH5PCI_WRITE(AINT, ~0);
80  	}
81  
82  	return IRQ_HANDLED;
83  }
84  
pcish5_serr_irq(int irq,void * dev_id)85  static irqreturn_t pcish5_serr_irq(int irq, void *dev_id)
86  {
87  	printk("SERR IRQ\n");
88  
89  	return IRQ_NONE;
90  }
91  
92  static struct resource sh5_pci_resources[2];
93  
94  static struct pci_channel sh5pci_controller = {
95  	.pci_ops		= &sh5_pci_ops,
96  	.resources		= sh5_pci_resources,
97  	.nr_resources		= ARRAY_SIZE(sh5_pci_resources),
98  	.mem_offset		= 0x00000000,
99  	.io_offset		= 0x00000000,
100  };
101  
sh5pci_init(void)102  static int __init sh5pci_init(void)
103  {
104  	unsigned long memStart = __pa(memory_start);
105  	unsigned long memSize = __pa(memory_end) - memStart;
106  	u32 lsr0;
107  	u32 uval;
108  
109          if (request_irq(IRQ_ERR, pcish5_err_irq,
110                          0, "PCI Error",NULL) < 0) {
111                  printk(KERN_ERR "PCISH5: Cannot hook PCI_PERR interrupt\n");
112                  return -EINVAL;
113          }
114  
115          if (request_irq(IRQ_SERR, pcish5_serr_irq,
116                          0, "PCI SERR interrupt", NULL) < 0) {
117                  printk(KERN_ERR "PCISH5: Cannot hook PCI_SERR interrupt\n");
118                  return -EINVAL;
119          }
120  
121  	pcicr_virt = (unsigned long)ioremap_nocache(SH5PCI_ICR_BASE, 1024);
122  	if (!pcicr_virt) {
123  		panic("Unable to remap PCICR\n");
124  	}
125  
126  	PCI_IO_AREA = (unsigned long)ioremap_nocache(SH5PCI_IO_BASE, 0x10000);
127  	if (!PCI_IO_AREA) {
128  		panic("Unable to remap PCIIO\n");
129  	}
130  
131  	/* Clear snoop registers */
132          SH5PCI_WRITE(CSCR0, 0);
133          SH5PCI_WRITE(CSCR1, 0);
134  
135          /* Switch off interrupts */
136          SH5PCI_WRITE(INTM,  0);
137          SH5PCI_WRITE(AINTM, 0);
138          SH5PCI_WRITE(PINTM, 0);
139  
140          /* Set bus active, take it out of reset */
141          uval = SH5PCI_READ(CR);
142  
143  	/* Set command Register */
144          SH5PCI_WRITE(CR, uval | CR_LOCK_MASK | CR_CFINT| CR_FTO | CR_PFE |
145  		     CR_PFCS | CR_BMAM);
146  
147  	uval=SH5PCI_READ(CR);
148  
149          /* Allow it to be a master */
150  	/* NB - WE DISABLE I/O ACCESS to stop overlap */
151          /* set WAIT bit to enable stepping, an attempt to improve stability */
152  	SH5PCI_WRITE_SHORT(CSR_CMD,
153  			    PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
154  			    PCI_COMMAND_WAIT);
155  
156          /*
157          ** Set translation mapping memory in order to convert the address
158          ** used for the main bus, to the PCI internal address.
159          */
160          SH5PCI_WRITE(MBR,0x40000000);
161  
162          /* Always set the max size 512M */
163          SH5PCI_WRITE(MBMR, PCISH5_MEM_SIZCONV(512*1024*1024));
164  
165          /*
166          ** I/O addresses are mapped at internal PCI specific address
167          ** as is described into the configuration bridge table.
168          ** These are changed to 0, to allow cards that have legacy
169          ** io such as vga to function correctly. We set the SH5 IOBAR to
170          ** 256K, which is a bit big as we can only have 64K of address space
171          */
172  
173          SH5PCI_WRITE(IOBR,0x0);
174  
175          /* Set up a 256K window. Totally pointless waste  of address space */
176          SH5PCI_WRITE(IOBMR,0);
177  
178  	/* The SH5 has a HUGE 256K I/O region, which breaks the PCI spec.
179  	 * Ideally, we would want to map the I/O region somewhere, but it
180  	 * is so big this is not that easy!
181           */
182  	SH5PCI_WRITE(CSR_IBAR0,~0);
183  	/* Set memory size value */
184          memSize = memory_end - memory_start;
185  
186  	/* Now we set up the mbars so the PCI bus can see the memory of
187  	 * the machine */
188  	if (memSize < (1024 * 1024)) {
189                  printk(KERN_ERR "PCISH5: Ridiculous memory size of 0x%lx?\n",
190  		       memSize);
191                  return -EINVAL;
192          }
193  
194          /* Set LSR 0 */
195          lsr0 = (memSize > (512 * 1024 * 1024)) ? 0x1ff00001 :
196  		((r2p2(memSize) - 0x100000) | 0x1);
197          SH5PCI_WRITE(LSR0, lsr0);
198  
199          /* Set MBAR 0 */
200          SH5PCI_WRITE(CSR_MBAR0, memory_start);
201          SH5PCI_WRITE(LAR0, memory_start);
202  
203          SH5PCI_WRITE(CSR_MBAR1,0);
204          SH5PCI_WRITE(LAR1,0);
205          SH5PCI_WRITE(LSR1,0);
206  
207          /* Enable the PCI interrupts on the device */
208          SH5PCI_WRITE(INTM,  ~0);
209          SH5PCI_WRITE(AINTM, ~0);
210          SH5PCI_WRITE(PINTM, ~0);
211  
212  	sh5_pci_resources[0].start = PCI_IO_AREA;
213  	sh5_pci_resources[0].end = PCI_IO_AREA + 0x10000;
214  
215  	sh5_pci_resources[1].start = memStart;
216  	sh5_pci_resources[1].end = memStart + memSize;
217  
218  	return register_pci_controller(&sh5pci_controller);
219  }
220  arch_initcall(sh5pci_init);
221