source: rtems/c/src/lib/libbsp/powerpc/ep1a/console/rsPMCQ1.c @ 41a4657

4.104.114.84.9
Last change on this file since 41a4657 was 41a4657, checked in by Jennifer Averett <Jennifer.Averett@…>, on May 17, 2005 at 2:58:28 PM

2005-05-17 Jennifer Averett <jennifer.averett@…>

  • console/rsPMCQ1.c, irq/irq.c: Modified to use rtems/irq.h.
  • Property mode set to 100644
File size: 15.8 KB
Line 
1/* rsPMCQ1.c - Radstone PMCQ1 Common Initialisation Code
2 *
3 * Copyright 2000 Radstone Technology
4 *
5 * THIS FILE IS PROVIDED TO YOU, THE USER, "AS IS", WITHOUT WARRANTY OF ANY
6 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
7 * IMPLIED WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
8 * AS TO THE QUALITY AND PERFORMANCE OF ALL CODE IN THIS FILE IS WITH YOU.
9 *
10 * You are hereby granted permission to use, copy, modify, and distribute
11 * this file, provided that this notice, plus the above copyright notice
12 * and disclaimer, appears in all copies. Radstone Technology will provide
13 * no support for this code.
14 *
15 *  COPYRIGHT (c) 2005.
16 *  On-Line Applications Research Corporation (OAR).
17 *
18 *  The license and distribution terms for this file may be
19 *  found in the file LICENSE in this distribution or at
20 *  http://www.rtems.com/license/LICENSE.
21 *
22 */
23
24/*
25DESCRIPTION
26These functions are responsible for scanning for PMCQ1's and setting up
27the Motorola MC68360's if present.
28
29USAGE
30call rsPMCQ1Init() to perform ba  sic initialisation of the PMCQ1's.
31*/
32
33/* includes */
34#include <libcpu/io.h>
35#include <bsp/irq.h>
36#include <stdlib.h>
37#include <rtems/bspIo.h>        
38#include <bsp/pci.h>
39#include <bsp.h>
40#include "rsPMCQ1.h"
41#include "m68360.h"
42
43/* defines */
44#if 0
45#define DEBUG_360
46#endif
47
48/* Local data */
49PPMCQ1BoardData         pmcq1BoardData = NULL;
50
51static unsigned char rsPMCQ1Initialized = FALSE;
52
53/* forward declarations */
54
55/* local Qspan II serial eeprom table */
56static unsigned char rsPMCQ1eeprom[] =
57    {
58    0x00,       /* Byte 0 - PCI_SID */
59    0x00,       /* Byte 1 - PCI_SID */
60    0x00,       /* Byte 2 - PCI_SID */
61    0x00,       /* Byte 3 - PCI_SID */
62    0x00,       /* Byte 4 - PBROM_CTL */
63    0x00,       /* Byte 5 - PBROM_CTL */
64    0x00,       /* Byte 6 - PBROM_CTL */
65    0x2C,       /* Byte 7 - PBTI0_CTL */
66    0xB0,       /* Byte 8 - PBTI1_CTL */
67    0x00,       /* Byte 9 - QBSI0_AT */
68    0x00,       /* Byte 10 - QBSI0_AT */
69    0x02,       /* Byte 11 - QBSI0_AT */
70    0x00,       /* Byte 12 - PCI_ID */
71    0x07,       /* Byte 13 - PCI_ID */
72    0x11,       /* Byte 14 - PCI_ID */
73    0xB5,       /* Byte 15 - PCI_ID */
74    0x06,       /* Byte 16 - PCI_CLASS */
75    0x80,       /* Byte 17 - PCI_CLASS */
76    0x00,       /* Byte 18 - PCI_CLASS */
77    0x00,       /* Byte 19 - PCI_MISC1 */
78    0x00,       /* Byte 20 - PCI_MISC1 */
79    0xC0,       /* Byte 21 - PCI_PMC */
80    0x00        /* Byte 22 - PCI_BST */
81};
82
83void MsDelay()
84{
85  printk(".");
86}
87
88void write8( int addr, int data ){
89  out_8((void *)addr, (unsigned char)data);
90}
91
92void write16( int addr, int data ) {
93  out_be16((void *)addr, (short)data );
94}
95
96void write32( int addr, int data ) {
97  out_be32((unsigned int *)addr, data );
98}
99
100int read32( int addr){
101  return in_be32((unsigned int *)addr);
102}
103
104
105void rsPMCQ1_scc_nullFunc() {}
106 
107/*******************************************************************************
108* rsPMCQ1Int - handle a PMCQ1 interrupt
109*
110* This routine gets called when the QUICC or MA causes
111* an interrupt.
112*
113* RETURNS: NONE.
114*/
115
116void rsPMCQ1Int( void *ptr )
117{
118  unsigned long status;
119  unsigned long status1;
120  unsigned long mask;
121  PPMCQ1BoardData boardData = ptr;
122
123  status = PMCQ1_Read_EPLD(boardData->baseaddr, PMCQ1_INT_STATUS );
124  mask   = PMCQ1_Read_EPLD(boardData->baseaddr, PMCQ1_INT_MASK );
125
126  if (((mask & PMCQ1_INT_MASK_QUICC) == 0) && (status & PMCQ1_INT_STATUS_QUICC))
127  {
128    /* If there is a handler call it otherwise mask the interrupt */
129    if (boardData->quiccInt) {
130      boardData->quiccInt(boardData->quiccArg);
131    } else {
132      *(unsigned long *)(boardData->baseaddr + PMCQ1_INT_MASK) |= PMCQ1_INT_MASK_QUICC;
133    }
134  }
135
136  if (((mask & PMCQ1_INT_MASK_MA) == 0) && (status & PMCQ1_INT_STATUS_MA))
137  {
138    /* If there is a handler call it otherwise mask the interrupt */
139    if (boardData->maInt) {
140      boardData->maInt(boardData->maArg);
141    } else {
142     *(unsigned long *)(boardData->baseaddr + PMCQ1_INT_MASK) |= PMCQ1_INT_MASK_MA;
143    }
144  }
145
146  /* Clear Interrupt on QSPAN */
147  *(unsigned long *)(boardData->bridgeaddr + 0x600) = 0x00001000;
148
149  /* read back the status register to ensure that the pci write has completed */
150  status1 = *(volatile unsigned long *)(boardData->bridgeaddr + 0x600);
151}
152
153
154/*******************************************************************************
155*
156* rsPMCQ1MaIntConnect - connect a MiniAce interrupt routine
157*
158* This routine is called to connect a MiniAce interrupt handler
159* upto a PMCQ1.
160*
161* RETURNS: OK if PMCQ1 found, ERROR if not.
162*/
163
164unsigned int rsPMCQ1MaIntConnect (
165    unsigned long       busNo,  /* Pci Bus number of PMCQ1 */
166    unsigned long       slotNo, /* Pci Slot number of PMCQ1 */
167    unsigned long       funcNo, /* Pci Function number of PMCQ1 */
168    rtems_irq_hdl       routine,/* interrupt routine */
169    rtems_irq_hdl_param arg     /* argument to pass to interrupt routine */
170)
171{
172  PPMCQ1BoardData boardData;
173  unsigned int status = RTEMS_IO_ERROR;
174
175  for (boardData = pmcq1BoardData; boardData; boardData = boardData->pNext)
176  {
177    if ((boardData->busNo == busNo) && (boardData->slotNo == slotNo) && 
178        (boardData->funcNo == funcNo))
179    {
180      boardData->maInt = routine;
181      boardData->maArg = arg;
182      status = RTEMS_SUCCESSFUL;
183      break;
184    }
185  }
186
187  return (status);
188}
189   
190/*******************************************************************************
191*
192* rsPMCQ1MaIntDisconnect - disconnect a MiniAce interrupt routine
193*
194* This routine is called to disconnect a MiniAce interrupt handler
195* from a PMCQ1. It also masks the interrupt source on the PMCQ1.
196*
197* RETURNS: OK if PMCQ1 found, ERROR if not.
198*/
199
200unsigned int rsPMCQ1MaIntDisconnect(
201    unsigned long       busNo,  /* Pci Bus number of PMCQ1 */
202    unsigned long       slotNo, /* Pci Slot number of PMCQ1 */
203    unsigned long       funcNo  /* Pci Function number of PMCQ1 */
204)
205{
206  PPMCQ1BoardData boardData;
207  unsigned int status = RTEMS_IO_ERROR;
208
209  for (boardData = pmcq1BoardData; boardData; boardData = boardData->pNext) {
210    if ((boardData->busNo == busNo) && (boardData->slotNo == slotNo) && 
211        (boardData->funcNo == funcNo))
212    {
213      boardData->maInt = NULL;
214      *(unsigned long *)(boardData->baseaddr + PMCQ1_INT_MASK) |= PMCQ1_INT_MASK_MA;
215      status = RTEMS_SUCCESSFUL;
216      break;
217    }
218  }
219
220  return (status);
221}
222   
223/*******************************************************************************
224*
225* rsPMCQ1QuiccIntConnect - connect a Quicc interrupt routine
226*
227* This routine is called to connect a Quicc interrupt handler
228* upto a PMCQ1.
229*
230* RETURNS: OK if PMCQ1 found, ERROR if not.
231*/
232
233unsigned int rsPMCQ1QuiccIntConnect(
234    unsigned long       busNo,  /* Pci Bus number of PMCQ1 */
235    unsigned long       slotNo, /* Pci Slot number of PMCQ1 */
236    unsigned long       funcNo, /* Pci Function number of PMCQ1 */
237    rtems_irq_hdl       routine,/* interrupt routine */
238    rtems_irq_hdl_param arg     /* argument to pass to interrupt routine */
239)
240{
241  PPMCQ1BoardData boardData;
242  unsigned int status = RTEMS_IO_ERROR;
243
244  for (boardData = pmcq1BoardData; boardData; boardData = boardData->pNext)
245  {
246    if ((boardData->busNo == busNo) && (boardData->slotNo == slotNo) && 
247        (boardData->funcNo == funcNo)) 
248    {
249      boardData->quiccInt = routine;
250      boardData->quiccArg = arg;
251      status = RTEMS_SUCCESSFUL;
252      break;
253    }
254  }
255  return (status);
256}
257   
258/*******************************************************************************
259*
260* rsPMCQ1QuiccIntDisconnect - disconnect a Quicc interrupt routine
261*
262* This routine is called to disconnect a Quicc interrupt handler
263* from a PMCQ1. It also masks the interrupt source on the PMCQ1.
264*
265* RETURNS: OK if PMCQ1 found, ERROR if not.
266*/
267
268unsigned int rsPMCQ1QuiccIntDisconnect(
269    unsigned long       busNo,  /* Pci Bus number of PMCQ1 */
270    unsigned long       slotNo, /* Pci Slot number of PMCQ1 */
271    unsigned long       funcNo  /* Pci Function number of PMCQ1 */
272)
273{
274  PPMCQ1BoardData boardData;
275  unsigned int status = RTEMS_IO_ERROR;
276
277  for (boardData = pmcq1BoardData; boardData; boardData = boardData->pNext) 
278  {
279    if ((boardData->busNo == busNo) && (boardData->slotNo == slotNo) && 
280        (boardData->funcNo == funcNo))
281    {
282      boardData->quiccInt = NULL;
283      *(unsigned long *)(boardData->baseaddr + PMCQ1_INT_MASK) |= PMCQ1_INT_MASK_QUICC;
284      status = RTEMS_SUCCESSFUL;
285      break;
286    }
287  }
288
289  return (status);
290}
291 
292   
293/*******************************************************************************
294*
295* rsPMCQ1Init - initialize the PMCQ1's
296*
297* This routine is called to initialize the PCI card to a quiescent state.
298*
299* RETURNS: OK if PMCQ1 found, ERROR if not.
300*/
301
302unsigned int rsPMCQ1Init()
303{
304  int busNo;
305  int slotNo;
306  unsigned int baseaddr = 0;
307  unsigned int bridgeaddr = 0;
308  unsigned long pbti0_ctl;
309  int i;
310  unsigned char int_vector;
311  int fun;
312  unsigned int temp;
313  PPMCQ1BoardData       boardData;
314  rtems_irq_connect_data IrqData = {0,
315                                    rsPMCQ1Int,
316                                    NULL,
317                                    (rtems_irq_enable)rsPMCQ1_scc_nullFunc,
318                                    (rtems_irq_disable)rsPMCQ1_scc_nullFunc,
319                                    (rtems_irq_is_enabled)rsPMCQ1_scc_nullFunc,
320                                    NULL};
321
322  if (rsPMCQ1Initialized)
323  {
324    return RTEMS_SUCCESSFUL;
325  }
326  for (i=0;;i++){
327    if ( pci_find_device(PCI_VEN_ID_RADSTONE, PCI_DEV_ID_PMCQ1, i, &busNo, &slotNo, &fun) != 0 )
328      break;
329
330    pci_read_config_dword(busNo, slotNo, 0, PCI_BASE_ADDRESS_2, &baseaddr);
331    pci_read_config_dword(busNo, slotNo, 0, PCI_BASE_ADDRESS_0, &bridgeaddr);
332#ifdef DEBUG_360
333  printk("PMCQ1 baseaddr 0x%08x bridgeaddr 0x%08x\n", baseaddr, bridgeaddr );
334#endif
335
336    /* Set function code to normal mode and enable window */
337    pbti0_ctl = *(unsigned long *)(bridgeaddr + 0x100) & 0xff0fffff;
338    eieio();
339    *(unsigned long *)(bridgeaddr + 0x100) = pbti0_ctl | 0x00500080;
340    eieio();
341
342    /* Assert QBUS reset */
343    *(unsigned long *)(bridgeaddr + 0x800) |= 0x00000080;
344    eieio();
345
346    /*
347     * Hold QBus in reset for 1ms
348     */
349    MsDelay();
350
351    /* Take QBUS out of reset */
352    *(unsigned long *)(bridgeaddr + 0x800) &= ~0x00000080;
353    eieio();
354
355    MsDelay();
356
357    /* If a QUICC is fitted initialise it */
358    if (PMCQ1_Read_EPLD(baseaddr, PMCQ1_BUILD_OPTION) & PMCQ1_QUICC_FITTED)
359    {
360#ifdef DEBUG_360
361  printk(" Found QUICC busNo %d slotNo %d\n", busNo, slotNo);
362#endif
363
364      /* Initialise MBAR (must use function code of 7) */
365      *(unsigned long *)(bridgeaddr + 0x100) = pbti0_ctl | 0x00700080;
366      eieio();
367
368      /* place internal 8K SRAM and registers at address 0x0 */
369      *(unsigned long *)(baseaddr + Q1_360_MBAR) = 0x1;
370      eieio();
371
372      /* Set function code to normal mode */
373      *(unsigned long *)(bridgeaddr + 0x100) = pbti0_ctl | 0x00500080;
374      eieio();
375
376      /* Disable the SWT and perform basic initialisation */
377      write8(baseaddr+Q1_360_SIM_SYPCR,0);             
378      eieio();
379
380      write32(baseaddr+Q1_360_SIM_MCR,0xa0001029);
381      write16(baseaddr+Q1_360_SIM_PICR,0);
382      write16(baseaddr+Q1_360_SIM_PITR,0);
383
384      write16(baseaddr+Q1_360_CPM_ICCR,0x770);
385      write16(baseaddr+Q1_360_CPM_SDCR,0x770);
386      write32(baseaddr+Q1_360_CPM_CICR,0x00e49f00);
387      write16(baseaddr+Q1_360_SIM_PEPAR,0x2080);
388      eieio();
389
390      /* Enable SRAM */
391      write32(baseaddr+Q1_360_SIM_GMR,0x00001000);  /* external master wait state */
392      eieio();
393      write32(baseaddr+Q1_360_SIM_OR0,0x1ff00000);  /*| MEMC_OR_FC*/
394      eieio();
395      write32(baseaddr+Q1_360_SIM_BR0,0); 
396      eieio();
397      write32(baseaddr+Q1_360_SIM_OR1,(0x5ff00000 | 0x00000780));  /*| MEMC_OR_FC*/
398      eieio();
399      write32(baseaddr+Q1_360_SIM_BR1,(0x00000040 | 0x00000001 | 0x00200280) ); 
400      eieio();
401    }
402
403    /*
404     * If a second PCI window is present then make it opposite
405     * endian to simplify 1553 integration.
406     */
407    pci_read_config_dword(busNo, slotNo, 0, PCI_BASE_ADDRESS_3, &temp);
408    if (temp) {
409      *(unsigned long *)(bridgeaddr + 0x110) |= 0x00500880;
410    }
411
412    /*
413     * Create descriptor structure for this card
414     */
415    if ((boardData = malloc(sizeof(struct _PMCQ1BoardData))) == NULL)
416    {
417      printk("Error Unable to allocate memory for _PMCQ1BoardData\n");
418      return(RTEMS_IO_ERROR);
419    }
420
421    boardData->pNext = pmcq1BoardData;
422    boardData->busNo = busNo;
423    boardData->slotNo = slotNo;
424    boardData->funcNo = 0;
425    boardData->baseaddr = baseaddr;
426    boardData->bridgeaddr = bridgeaddr;
427    boardData->quiccInt = NULL;
428    boardData->maInt = NULL;
429    pmcq1BoardData = boardData;
430    mc68360_scc_create_chip( boardData, int_vector );
431
432    /*
433     * Connect PMCQ1 interrupt handler.
434     */
435    pci_read_config_byte(busNo, slotNo, 0, 0x3c, &int_vector);
436#ifdef DEBUG_360
437    printk("PMCQ1 int_vector %d\n", int_vector);
438#endif
439    IrqData.name  = (rtems_irq_number)((unsigned int)BSP_PCI_IRQ0 + int_vector);
440    IrqData.handle = boardData;
441    if (!BSP_install_rtems_shared_irq_handler (&IrqData)) {
442        printk("Error installing interrupt handler!\n");
443        rtems_fatal_error_occurred(1);
444    }
445
446    /*
447     * Enable PMCQ1 Interrupts from QSPAN-II
448     */
449       
450    *(unsigned long *)(bridgeaddr + 0x600) = 0x00001000;
451    eieio();
452    *(unsigned long *)(bridgeaddr + 0x604) |= 0x00001000;
453
454    eieio();
455  }
456
457  if (i > 0)
458  {
459    rsPMCQ1Initialized = TRUE;
460  }
461  return((i > 0) ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR);
462}
463
464/*******************************************************************************
465*
466* rsPMCQ1Commission - initialize the serial EEPROM on the QSPAN
467*
468* This routine is called to initialize the EEPROM attached to the QSPAN
469* on the PMCQ1 module. It will load standard settings into any QSPAN's
470* found with apparently uninitialised EEPROM's or PMCQ1's (to allow
471* EEPROM modifications to be performed).
472*/
473
474unsigned int rsPMCQ1Commission( unsigned long busNo, unsigned long slotNo )
475{
476  unsigned int status = RTEMS_IO_ERROR;
477  unsigned int bridgeaddr = 0;
478  unsigned long val;
479  int i;
480  unsigned int venId1;
481  unsigned int venId2;
482
483  pci_read_config_dword(busNo, slotNo, 0, PCI_VENDOR_ID, &venId1);
484  pci_read_config_dword(busNo, slotNo, 0, PCI_VENDOR_ID, &venId2);
485  if ((venId1 == 0x086210e3) ||
486      (venId2 == PCI_ID(PCI_VEN_ID_RADSTONE, PCI_DEV_ID_PMCQ1)))
487  {
488    pci_read_config_dword(busNo, slotNo, 0, PCI_BASE_ADDRESS_0, &bridgeaddr);
489    status = RTEMS_SUCCESSFUL;
490
491    /*
492     * The On board PMCQ1 on an EP1A has a subVendor ID of 0.
493     * A real PMCQ1 also has the sub vendor ID set up.
494     */
495    if ((busNo == 0) && (slotNo == 1)) {
496      *(unsigned long *)rsPMCQ1eeprom = 0;
497    } else {
498      *(unsigned long *)rsPMCQ1eeprom = PCI_ID(PCI_VEN_ID_RADSTONE, PCI_DEV_ID_PMCQ1);
499    }
500
501    for (i = 0; i < 23; i++) {
502      /* Wait until interface not active */
503      while(read32(bridgeaddr + 0x804) & 0x80000000) {
504        rtems_bsp_delay(1);
505      }
506
507      /* Write value */
508      write32(bridgeaddr + 0x804, (rsPMCQ1eeprom[i] << 8) | i);
509
510      /* delay for > 31 usec to allow active bit to become set */
511      rtems_bsp_delay(100);
512
513      /* Wait until interface not active */
514      while(read32(bridgeaddr + 0x804) & 0x80000000) {
515        rtems_bsp_delay(1);
516      }
517
518      /* Re-read value */
519      write32(bridgeaddr + 0x804, 0x40000000 | i);
520
521      /* delay for > 31 usec to allow active bit to become set */
522      rtems_bsp_delay(100);
523
524      /* Wait until interface not active */
525      while((val = read32(bridgeaddr + 0x804)) & 0x80000000) {
526        rtems_bsp_delay(1);
527      }
528
529      if (((val >> 8) & 0xff) != rsPMCQ1eeprom[i]) {
530        printk("Error writing byte %d expected 0x%02x got 0x%02x\n",
531               i, rsPMCQ1eeprom[i], (unsigned char)(val >> 8));
532        status = RTEMS_IO_ERROR;
533        break; 
534      }
535    }
536  }
537  return(status);
538}
539
540uint32_t PMCQ1_Read_EPLD( uint32_t base, uint32_t reg )
541{
542  uint32_t data;
543
544  data = ( *((unsigned long *) (base + reg)) );
545#ifdef DEBUG_360
546  printk("EPLD Read 0x%x: 0x%08x\n", reg + base, data );
547#endif
548  return data;
549}
550
551void PMCQ1_Write_EPLD( uint32_t base, uint32_t reg, uint32_t data )
552{
553  *((unsigned long *) (base + reg)) = data;
554#ifdef DEBUG_360
555  printk("EPLD Write 0x%x: 0x%08x\n", reg+base, data );
556#endif
557}
558
Note: See TracBrowser for help on using the repository browser.