xref: /openbmc/linux/arch/powerpc/sysdev/tsi108_pci.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1  // SPDX-License-Identifier: GPL-2.0-or-later
2  /*
3   * Common routines for Tundra Semiconductor TSI108 host bridge.
4   *
5   * 2004-2005 (c) Tundra Semiconductor Corp.
6   * Author: Alex Bounine (alexandreb@tundra.com)
7   * Author: Roy Zang (tie-fei.zang@freescale.com)
8   * 	   Add pci interrupt router host
9   */
10  
11  #include <linux/kernel.h>
12  #include <linux/init.h>
13  #include <linux/pci.h>
14  #include <linux/irq.h>
15  #include <linux/irqdomain.h>
16  #include <linux/interrupt.h>
17  #include <linux/of_address.h>
18  
19  #include <asm/byteorder.h>
20  #include <asm/io.h>
21  #include <asm/irq.h>
22  #include <linux/uaccess.h>
23  #include <asm/machdep.h>
24  #include <asm/pci-bridge.h>
25  #include <asm/tsi108.h>
26  #include <asm/tsi108_pci.h>
27  #include <asm/tsi108_irq.h>
28  
29  #undef DEBUG
30  #ifdef DEBUG
31  #define DBG(x...) printk(x)
32  #else
33  #define DBG(x...)
34  #endif
35  
36  #define tsi_mk_config_addr(bus, devfunc, offset) \
37  	((((bus)<<16) | ((devfunc)<<8) | (offset & 0xfc)) + tsi108_pci_cfg_base)
38  
39  u32 tsi108_pci_cfg_base;
40  static u32 tsi108_pci_cfg_phys;
41  u32 tsi108_csr_vir_base;
42  static struct irq_domain *pci_irq_host;
43  
44  extern u32 get_vir_csrbase(void);
45  extern u32 tsi108_read_reg(u32 reg_offset);
46  extern void tsi108_write_reg(u32 reg_offset, u32 val);
47  
48  int
tsi108_direct_write_config(struct pci_bus * bus,unsigned int devfunc,int offset,int len,u32 val)49  tsi108_direct_write_config(struct pci_bus *bus, unsigned int devfunc,
50  			   int offset, int len, u32 val)
51  {
52  	volatile unsigned char *cfg_addr;
53  	struct pci_controller *hose = pci_bus_to_host(bus);
54  
55  	if (ppc_md.pci_exclude_device)
56  		if (ppc_md.pci_exclude_device(hose, bus->number, devfunc))
57  			return PCIBIOS_DEVICE_NOT_FOUND;
58  
59  	cfg_addr = (unsigned char *)(tsi_mk_config_addr(bus->number,
60  							devfunc, offset) |
61  							(offset & 0x03));
62  
63  #ifdef DEBUG
64  	printk("PCI CFG write : ");
65  	printk("%d:0x%x:0x%x ", bus->number, devfunc, offset);
66  	printk("%d ADDR=0x%08x ", len, (uint) cfg_addr);
67  	printk("data = 0x%08x\n", val);
68  #endif
69  
70  	switch (len) {
71  	case 1:
72  		out_8((u8 *) cfg_addr, val);
73  		break;
74  	case 2:
75  		out_le16((u16 *) cfg_addr, val);
76  		break;
77  	default:
78  		out_le32((u32 *) cfg_addr, val);
79  		break;
80  	}
81  
82  	return PCIBIOS_SUCCESSFUL;
83  }
84  
tsi108_clear_pci_error(u32 pci_cfg_base)85  void tsi108_clear_pci_error(u32 pci_cfg_base)
86  {
87  	u32 err_stat, err_addr, pci_stat;
88  
89  	/*
90  	 * Quietly clear PB and PCI error flags set as result
91  	 * of PCI/X configuration read requests.
92  	 */
93  
94  	/* Read PB Error Log Registers */
95  
96  	err_stat = tsi108_read_reg(TSI108_PB_OFFSET + TSI108_PB_ERRCS);
97  	err_addr = tsi108_read_reg(TSI108_PB_OFFSET + TSI108_PB_AERR);
98  
99  	if (err_stat & TSI108_PB_ERRCS_ES) {
100  		/* Clear error flag */
101  		tsi108_write_reg(TSI108_PB_OFFSET + TSI108_PB_ERRCS,
102  				 TSI108_PB_ERRCS_ES);
103  
104  		/* Clear read error reported in PB_ISR */
105  		tsi108_write_reg(TSI108_PB_OFFSET + TSI108_PB_ISR,
106  				 TSI108_PB_ISR_PBS_RD_ERR);
107  
108  		/* Clear PCI/X bus cfg errors if applicable */
109  		if ((err_addr & 0xFF000000) == pci_cfg_base) {
110  			pci_stat =
111  			    tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_CSR);
112  			tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_CSR,
113  					 pci_stat);
114  		}
115  	}
116  
117  	return;
118  }
119  
120  #define __tsi108_read_pci_config(x, addr, op)		\
121  	__asm__ __volatile__(				\
122  		"	"op" %0,0,%1\n"		\
123  		"1:	eieio\n"			\
124  		"2:\n"					\
125  		".section .fixup,\"ax\"\n"		\
126  		"3:	li %0,-1\n"			\
127  		"	b 2b\n"				\
128  		".previous\n"				\
129  		EX_TABLE(1b, 3b)			\
130  		: "=r"(x) : "r"(addr))
131  
132  int
tsi108_direct_read_config(struct pci_bus * bus,unsigned int devfn,int offset,int len,u32 * val)133  tsi108_direct_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
134  			  int len, u32 * val)
135  {
136  	volatile unsigned char *cfg_addr;
137  	struct pci_controller *hose = pci_bus_to_host(bus);
138  	u32 temp;
139  
140  	if (ppc_md.pci_exclude_device)
141  		if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
142  			return PCIBIOS_DEVICE_NOT_FOUND;
143  
144  	cfg_addr = (unsigned char *)(tsi_mk_config_addr(bus->number,
145  							devfn,
146  							offset) | (offset &
147  								   0x03));
148  
149  	switch (len) {
150  	case 1:
151  		__tsi108_read_pci_config(temp, cfg_addr, "lbzx");
152  		break;
153  	case 2:
154  		__tsi108_read_pci_config(temp, cfg_addr, "lhbrx");
155  		break;
156  	default:
157  		__tsi108_read_pci_config(temp, cfg_addr, "lwbrx");
158  		break;
159  	}
160  
161  	*val = temp;
162  
163  #ifdef DEBUG
164  	if ((0xFFFFFFFF != temp) && (0xFFFF != temp) && (0xFF != temp)) {
165  		printk("PCI CFG read : ");
166  		printk("%d:0x%x:0x%x ", bus->number, devfn, offset);
167  		printk("%d ADDR=0x%08x ", len, (uint) cfg_addr);
168  		printk("data = 0x%x\n", *val);
169  	}
170  #endif
171  	return PCIBIOS_SUCCESSFUL;
172  }
173  
tsi108_clear_pci_cfg_error(void)174  void tsi108_clear_pci_cfg_error(void)
175  {
176  	tsi108_clear_pci_error(tsi108_pci_cfg_phys);
177  }
178  
179  static struct pci_ops tsi108_direct_pci_ops = {
180  	.read = tsi108_direct_read_config,
181  	.write = tsi108_direct_write_config,
182  };
183  
tsi108_setup_pci(struct device_node * dev,u32 cfg_phys,int primary)184  int __init tsi108_setup_pci(struct device_node *dev, u32 cfg_phys, int primary)
185  {
186  	int len;
187  	struct pci_controller *hose;
188  	struct resource rsrc;
189  	const int *bus_range;
190  	int has_address = 0;
191  
192  	/* PCI Config mapping */
193  	tsi108_pci_cfg_base = (u32)ioremap(cfg_phys, TSI108_PCI_CFG_SIZE);
194  	tsi108_pci_cfg_phys = cfg_phys;
195  	DBG("TSI_PCI: %s tsi108_pci_cfg_base=0x%x\n", __func__,
196  	    tsi108_pci_cfg_base);
197  
198  	/* Fetch host bridge registers address */
199  	has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
200  
201  	/* Get bus range if any */
202  	bus_range = of_get_property(dev, "bus-range", &len);
203  	if (bus_range == NULL || len < 2 * sizeof(int)) {
204  		printk(KERN_WARNING "Can't get bus-range for %pOF, assume"
205  		       " bus 0\n", dev);
206  	}
207  
208  	hose = pcibios_alloc_controller(dev);
209  
210  	if (!hose) {
211  		printk("PCI Host bridge init failed\n");
212  		return -ENOMEM;
213  	}
214  
215  	hose->first_busno = bus_range ? bus_range[0] : 0;
216  	hose->last_busno = bus_range ? bus_range[1] : 0xff;
217  
218  	(hose)->ops = &tsi108_direct_pci_ops;
219  
220  	pr_info("Found tsi108 PCI host bridge at 0x%pa. Firmware bus number: %d->%d\n",
221  		&rsrc.start, hose->first_busno, hose->last_busno);
222  
223  	/* Interpret the "ranges" property */
224  	/* This also maps the I/O region and sets isa_io/mem_base */
225  	pci_process_bridge_OF_ranges(hose, dev, primary);
226  	return 0;
227  }
228  
229  /*
230   * Low level utility functions
231   */
232  
tsi108_pci_int_mask(u_int irq)233  static void tsi108_pci_int_mask(u_int irq)
234  {
235  	u_int irp_cfg;
236  	int int_line = (irq - IRQ_PCI_INTAD_BASE);
237  
238  	irp_cfg = tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL);
239  	mb();
240  	irp_cfg |= (1 << int_line);	/* INTx_DIR = output */
241  	irp_cfg &= ~(3 << (8 + (int_line * 2)));	/* INTx_TYPE = unused */
242  	tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL, irp_cfg);
243  	mb();
244  	irp_cfg = tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL);
245  }
246  
tsi108_pci_int_unmask(u_int irq)247  static void tsi108_pci_int_unmask(u_int irq)
248  {
249  	u_int irp_cfg;
250  	int int_line = (irq - IRQ_PCI_INTAD_BASE);
251  
252  	irp_cfg = tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL);
253  	mb();
254  	irp_cfg &= ~(1 << int_line);
255  	irp_cfg |= (3 << (8 + (int_line * 2)));
256  	tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL, irp_cfg);
257  	mb();
258  }
259  
init_pci_source(void)260  static void __init init_pci_source(void)
261  {
262  	tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL,
263  			0x0000ff00);
264  	tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE,
265  			TSI108_PCI_IRP_ENABLE_P_INT);
266  	mb();
267  }
268  
get_pci_source(void)269  static inline unsigned int get_pci_source(void)
270  {
271  	u_int temp = 0;
272  	int irq = -1;
273  	int i;
274  	u_int pci_irp_stat;
275  	static int mask = 0;
276  
277  	/* Read PCI/X block interrupt status register */
278  	pci_irp_stat = tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_STAT);
279  	mb();
280  
281  	if (pci_irp_stat & TSI108_PCI_IRP_STAT_P_INT) {
282  		/* Process Interrupt from PCI bus INTA# - INTD# lines */
283  		temp =
284  		    tsi108_read_reg(TSI108_PCI_OFFSET +
285  				    TSI108_PCI_IRP_INTAD) & 0xf;
286  		mb();
287  		for (i = 0; i < 4; i++, mask++) {
288  			if (temp & (1 << mask % 4)) {
289  				irq = IRQ_PCI_INTA + mask % 4;
290  				mask++;
291  				break;
292  			}
293  		}
294  
295  		/* Disable interrupts from PCI block */
296  		temp = tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE);
297  		tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE,
298  				temp & ~TSI108_PCI_IRP_ENABLE_P_INT);
299  		mb();
300  		(void)tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE);
301  		mb();
302  	}
303  #ifdef DEBUG
304  	else {
305  		printk("TSI108_PIC: error in TSI108_PCI_IRP_STAT\n");
306  		pci_irp_stat =
307  		    tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_STAT);
308  		temp =
309  		    tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_INTAD);
310  		mb();
311  		printk(">> stat=0x%08x intad=0x%08x ", pci_irp_stat, temp);
312  		temp =
313  		    tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL);
314  		mb();
315  		printk("cfg_ctl=0x%08x ", temp);
316  		temp =
317  		    tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE);
318  		mb();
319  		printk("irp_enable=0x%08x\n", temp);
320  	}
321  #endif	/* end of DEBUG */
322  
323  	return irq;
324  }
325  
326  
327  /*
328   * Linux descriptor level callbacks
329   */
330  
tsi108_pci_irq_unmask(struct irq_data * d)331  static void tsi108_pci_irq_unmask(struct irq_data *d)
332  {
333  	tsi108_pci_int_unmask(d->irq);
334  
335  	/* Enable interrupts from PCI block */
336  	tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE,
337  			 tsi108_read_reg(TSI108_PCI_OFFSET +
338  					 TSI108_PCI_IRP_ENABLE) |
339  			 TSI108_PCI_IRP_ENABLE_P_INT);
340  	mb();
341  }
342  
tsi108_pci_irq_mask(struct irq_data * d)343  static void tsi108_pci_irq_mask(struct irq_data *d)
344  {
345  	tsi108_pci_int_mask(d->irq);
346  }
347  
tsi108_pci_irq_ack(struct irq_data * d)348  static void tsi108_pci_irq_ack(struct irq_data *d)
349  {
350  	tsi108_pci_int_mask(d->irq);
351  }
352  
353  /*
354   * Interrupt controller descriptor for cascaded PCI interrupt controller.
355   */
356  
357  static struct irq_chip tsi108_pci_irq = {
358  	.name = "tsi108_PCI_int",
359  	.irq_mask = tsi108_pci_irq_mask,
360  	.irq_ack = tsi108_pci_irq_ack,
361  	.irq_unmask = tsi108_pci_irq_unmask,
362  };
363  
pci_irq_host_xlate(struct irq_domain * h,struct device_node * ct,const u32 * intspec,unsigned int intsize,irq_hw_number_t * out_hwirq,unsigned int * out_flags)364  static int pci_irq_host_xlate(struct irq_domain *h, struct device_node *ct,
365  			    const u32 *intspec, unsigned int intsize,
366  			    irq_hw_number_t *out_hwirq, unsigned int *out_flags)
367  {
368  	*out_hwirq = intspec[0];
369  	*out_flags = IRQ_TYPE_LEVEL_HIGH;
370  	return 0;
371  }
372  
pci_irq_host_map(struct irq_domain * h,unsigned int virq,irq_hw_number_t hw)373  static int pci_irq_host_map(struct irq_domain *h, unsigned int virq,
374  			  irq_hw_number_t hw)
375  {	unsigned int irq;
376  	DBG("%s(%d, 0x%lx)\n", __func__, virq, hw);
377  	if ((virq >= 1) && (virq <= 4)){
378  		irq = virq + IRQ_PCI_INTAD_BASE - 1;
379  		irq_set_status_flags(irq, IRQ_LEVEL);
380  		irq_set_chip(irq, &tsi108_pci_irq);
381  	}
382  	return 0;
383  }
384  
385  static const struct irq_domain_ops pci_irq_domain_ops = {
386  	.map = pci_irq_host_map,
387  	.xlate = pci_irq_host_xlate,
388  };
389  
390  /*
391   * Exported functions
392   */
393  
394  /*
395   * The Tsi108 PCI interrupts initialization routine.
396   *
397   * The INTA# - INTD# interrupts on the PCI bus are reported by the PCI block
398   * to the MPIC using single interrupt source (IRQ_TSI108_PCI). Therefore the
399   * PCI block has to be treated as a cascaded interrupt controller connected
400   * to the MPIC.
401   */
402  
tsi108_pci_int_init(struct device_node * node)403  void __init tsi108_pci_int_init(struct device_node *node)
404  {
405  	DBG("Tsi108_pci_int_init: initializing PCI interrupts\n");
406  
407  	pci_irq_host = irq_domain_add_legacy(node, NR_IRQS_LEGACY, 0, 0,
408  					     &pci_irq_domain_ops, NULL);
409  	if (pci_irq_host == NULL) {
410  		printk(KERN_ERR "pci_irq_host: failed to allocate irq domain!\n");
411  		return;
412  	}
413  
414  	init_pci_source();
415  }
416  
tsi108_irq_cascade(struct irq_desc * desc)417  void tsi108_irq_cascade(struct irq_desc *desc)
418  {
419  	struct irq_chip *chip = irq_desc_get_chip(desc);
420  	unsigned int cascade_irq = get_pci_source();
421  
422  	if (cascade_irq)
423  		generic_handle_irq(cascade_irq);
424  
425  	chip->irq_eoi(&desc->irq_data);
426  }
427