summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sparc/leon2/cchip/cchip.c
blob: 51c45f81bdc0e38e77dd85fa5e0108b97b169816 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
/** 
 * @file
 * @ingroup cchip
 * @brief Companion Chip PCI board driver
 */

/*
 *  GR-701 (Companion Chip) PCI board driver
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.com/license/LICENSE.
 */

#include <bsp.h>
#include <rtems/bspIo.h>
#include <rtems.h>
#include <string.h>

#include <rtems.h>
#include <leon.h>
#include <ambapp.h>
#include <pci.h>

#include <b1553brm_pci.h>
#include <occan_pci.h>
#include <grspw_pci.h>
#include <apbuart_pci.h>

#include <cchip.h>

/*
#define DEBUG
#define DEBUG_IRQS
*/
#define BOARD_INFO
/*#define PRINT_SPURIOUS*/

/* AT697 Register MAP */
static LEON_Register_Map *regs = (LEON_Register_Map *)0x80000000;

/* initializes interrupt management for companionship board */
void cchip1_irq_init(void);

/* register interrupt handler (called from drivers) */
void cchip1_set_isr(void *handler, int irqno, void *arg);

#define READ_REG(address) _READ_REG((unsigned int)address)
static __inline__ unsigned int _READ_REG(unsigned int addr) {
	unsigned int tmp;
	__asm__ ("lda [%1]1, %0 "
	  : "=r"(tmp)
	  : "r"(addr)
	);
	return tmp;
}

/* PCI bride reg layout on AMBA side */
typedef struct {
	unsigned int bar0;
	unsigned int bar1;
	unsigned int bar2;
	unsigned int bar3;
	unsigned int bar4;/* 0x10 */

	unsigned int unused[4*3-1];

	unsigned int ambabars[1]; /* 0x40 */
} amba_bridge_regs;

/* PCI bride reg layout on PCI side */
typedef struct {
	unsigned int bar0;
	unsigned int bar1;
	unsigned int bar2;
	unsigned int bar3;
	unsigned int bar4; /* 0x10 */

	unsigned int ilevel;
	unsigned int ipend;
	unsigned int iforce;
	unsigned int istatus;
	unsigned int iclear;
	unsigned int imask;
} pci_bridge_regs;

typedef struct {
	pci_bridge_regs  *pcib;
	amba_bridge_regs *ambab;

	/* AT697 PCI */
	unsigned int bars[5];
	int bus, dev, fun;

	/* AMBA bus */
	struct ambapp_bus amba_bus;
	struct ambapp_mmap amba_maps[2];

	/* FT AHB SRAM */
	int ftsram_size; /* kb */
	unsigned int ftsram_start;
	unsigned int ftsram_end;

} cchip1;

cchip1 cc1;

int init_pcif(void){
	unsigned int com1;
	int i,bus,dev,fun;
	pci_bridge_regs *pcib;
	amba_bridge_regs *ambab;
	struct ambapp_bus *abus;

  if ( BSP_pciFindDevice(0x1AC8, 0x0701, 0, &bus, &dev, &fun) == 0 ) {
    ;
  }else if (BSP_pciFindDevice(0x16E3, 0x0210, 0, &bus, &dev, &fun) == 0) {
    ;
  } else {
    /* didn't find any Companionship board on the PCI bus. */
    return -1;
  }

  /* found Companionship PCI board, Set it up: */

	pci_read_config_dword(bus, dev, fun, 0x10, &cc1.bars[0]);
	pci_read_config_dword(bus, dev, fun, 0x14, &cc1.bars[1]);
	pci_read_config_dword(bus, dev, fun, 0x18, &cc1.bars[2]);
	pci_read_config_dword(bus, dev, fun, 0x1c, &cc1.bars[3]);
	pci_read_config_dword(bus, dev, fun, 0x20, &cc1.bars[4]);

#ifdef DEBUG
	for(i=0; i<5; i++){
		printk("PCI: BAR%d: 0x%x\n\r",i,cc1.bars[i]);
	}
#endif

	/* Set up PCI ==> AMBA */
	pcib = (void *)cc1.bars[0];
	pcib->bar0 = 0xfc000000;
/*	pcib->bar1 = 0xff000000;*/
#ifdef BOARD_INFO
	printk("Found CCHIP1 Board at 0x%lx\n\r",(unsigned int)pcib);
#endif

	/* AMBA MAP cc1.bars[1] (in CPU) ==> 0xf0000000(remote amba address) */
	cc1.amba_maps[0].size = 0x04000000;
	cc1.amba_maps[0].local_adr = cc1.bars[1];
	cc1.amba_maps[0].remote_adr = 0xfc000000;

	/* Mark end of table */
	cc1.amba_maps[1].size=0;
	cc1.amba_maps[1].local_adr = 0;
	cc1.amba_maps[1].remote_adr = 0;

	/* Enable I/O and Mem accesses */
	pci_read_config_dword(bus, dev, fun, 0x4, &com1);
	com1 |= 0x3;
	pci_write_config_dword(bus, dev, fun, 0x4, com1);
	pci_read_config_dword(bus, dev, fun, 0x4, &com1);

	/* Set up AMBA Masters ==> PCI */
	ambab = (void *)(cc1.bars[1]+0x400);
#ifdef DEBUG
	printk("AMBA: PCIBAR[%d]: 0x%x, 0x%x\n\r",0,ambab->bar0,pcib->bar0);
	printk("AMBA: PCIBAR[%d]: 0x%x, 0x%x\n\r",1,ambab->bar1,pcib->bar1);
	printk("AMBA: PCIBAR[%d]: 0x%x, 0x%x\n\r",2,ambab->bar2,pcib->bar2);
#endif
	ambab->ambabars[0] = 0x40000000; /* 0xe0000000(AMBA) ==> 0x40000000(PCI) ==> 0x40000000(AT697 AMBA) */

	/* Scan bus for AMBA devices */
	abus = &cc1.amba_bus;
	memset(abus,0,sizeof(*abus));
	ambapp_scan(abus, cc1.bars[1]+0x3f00000, NULL, &cc1.amba_maps[0]);

	/* Init all msters, max 16 */
	for(i=1; i<16; i++) {
		ambab->ambabars[i] = 0x40000000;
		if (READ_REG(&ambab->ambabars[i]) != 0x40000000)
			break;
	}

	/* Enable PCI Master */
   pci_read_config_dword(bus, dev, fun, 0x4, &com1);
   com1 |= 0x4;
   pci_write_config_dword(bus, dev, fun, 0x4, com1);
   pci_read_config_dword(bus, dev, fun, 0x4, &com1);

	cc1.pcib  = pcib;
	cc1.ambab = ambab;
	cc1.bus = bus;
	cc1.dev = dev;
	cc1.fun = fun;

	return 0;
}

#ifndef GAISLER_FTAHBRAM
 #define GAISLER_FTAHBRAM 0x50
#endif
int init_onboard_sram(void){
	struct ambapp_ahb_info ahb;
	struct ambapp_apb_info apb;
	unsigned int conf, size;

	/* Find SRAM controller
	 * 1. AHB slave interface
	 * 2. APB slave interface
	 */
	if ( ambapp_find_apbslv(&cc1.amba_bus, VENDOR_GAISLER, GAISLER_FTAHBRAM,
                                &apb) != 1 ){
		printk("On Board FT SRAM not found (APB)\n");
		return -1;
	}

	if ( ambapp_find_ahbslv(&cc1.amba_bus, VENDOR_GAISLER, GAISLER_FTAHBRAM,
                                &ahb) != 1 ){
		printk("On Board FT SRAM not found (AHB)\n");
		return -1;
	}

	/* We have found the controller.
	 * Get it going.
	 *
	 * Get size of SRAM
	 */
	conf = *(unsigned int *)apb.start;
	size = (conf >>10) & 0x7;

	/* 2^x kb */
	cc1.ftsram_size = 1<<size;
	cc1.ftsram_start = ahb.start[0];
	cc1.ftsram_end = size*1024 + cc1.ftsram_start;
#ifdef BOARD_INFO
	printk("Found FT AHB SRAM %dkb at 0x%lx\n",cc1.ftsram_size,cc1.ftsram_start);
#endif
	return 0;
}

int cchip1_register(void){

	/* Init AT697 PCI Controller */
	init_pci();

	/* Find & init CChip board .
	 * Also scan AMBA Plug&Play info for us.
	 */
	if ( init_pcif() ){
		printk("Failed to initialize CCHIP board\n\r");
		return -1;
	}

	/* Set interrupt common board stuff */
	cchip1_irq_init();

	/* Find on board SRAM */
	if ( init_onboard_sram() ){
		printk("Failed to register On Board SRAM. It is needed by b1553BRM\n");
		return -1;
	}

	/* Register interrupt install functions */
	b1553brm_pci_int_reg = cchip1_set_isr;
	occan_pci_int_reg = cchip1_set_isr;
	grspw_pci_int_reg = cchip1_set_isr;
	apbuart_pci_int_reg = cchip1_set_isr;

	/* register the BRM PCI driver, use 16k FTSRAM... */
	if ( b1553brm_pci_register(&cc1.amba_bus,0,0,3,cc1.ftsram_start,0xffa00000) ){
		printk("Failed to register BRM PCI driver\n");
		return -1;
	}

	/* register the BRM PCI driver, no DMA memory... */
	if ( occan_pci_register(&cc1.amba_bus) ){
		printk("Failed to register OC_CAN PCI driver\n");
		return -1;
	}

	/* register the GRSPW PCI driver, use malloc... */
	if ( grspw_pci_register(&cc1.amba_bus,0,0xe0000000) ){
		printk("Failed to register GRSPW PCI driver\n");
		return -1;
	}

	/* register the APBUART PCI driver, no DMA memory */
	if ( apbuart_pci_register(&cc1.amba_bus) ){
		printk("Failed to register APBUART PCI driver\n");
		return -1;
	}

	return 0;
}

static rtems_isr cchip1_interrupt_dispatcher(rtems_vector_number v);
static unsigned int cchip1_spurious_cnt;

typedef struct {
	unsigned int (*handler)(int irqno, void *arg);
	void *arg;
} int_handler;

static int_handler int_handlers[16];

void cchip1_irq_init(void){

	/* Configure AT697 ioport bit 7 to input pci irq */
  regs->PIO_Direction &= ~(1<<7);
  regs->PIO_Interrupt  = 0x87;          /* level sensitive */

  /* Set up irq controller (mask all IRQs) */
	cc1.pcib->imask = 0x0000;
	cc1.pcib->ipend = 0;
	cc1.pcib->iclear = 0xffff;
	cc1.pcib->iforce = 0;
	cc1.pcib->ilevel = 0x0;

	memset(int_handlers,0,sizeof(int_handlers));

	/* Reset spurious counter */
	cchip1_spurious_cnt = 0;

	/* Register interrupt handler */
	set_vector(cchip1_interrupt_dispatcher,LEON_TRAP_TYPE(CCHIP_IRQ),1);
}

void cchip1_set_isr(void *handler, int irqno, void *arg){
	int_handlers[irqno].handler = handler;
	int_handlers[irqno].arg = arg;
#ifdef DEBUG
	printk("Registering IRQ %d to 0x%lx(%d,0x%lx)\n\r",irqno,(unsigned int)handler,irqno,(unsigned int)arg);
#endif
	cc1.pcib->imask |= 1<<irqno; /* Enable the registered IRQ */
}

static rtems_isr cchip1_interrupt_dispatcher(rtems_vector_number v){
	unsigned int pending = READ_REG(&cc1.pcib->ipend);
	unsigned int (*handler)(int irqno, void *arg);
	unsigned int clr = pending;
	int irq=1;

	if ( !pending ){
#ifdef PRINT_SPURIOUS
		printk("Spurious IRQ %d: %d\n",v,cchip1_spurious_cnt);
#endif
		cchip1_spurious_cnt++;
		return;
	}
#ifdef DEBUG_IRQS
  printk("CCIRQ: 0x%x\n",(unsigned int)pending);
#endif
	/* IRQ 0 doesn't exist */
	irq=1;
	pending = pending>>1;

	while ( pending ){
		if ( (pending & 1) && (handler=int_handlers[irq].handler) ){
			handler(irq,int_handlers[irq].arg);
		}
		irq++;
		pending = pending>>1;
	}

	cc1.pcib->iclear = clr;

	/*LEON_Clear_interrupt( brd->irq );*/
}