607 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			607 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * (C) Copyright 2003
 | |
|  * Martin Winistoerfer, martinwinistoerfer@gmx.ch.
 | |
|  * Atapted for PATI
 | |
|  * Denis Peter, d.peter@mpl.ch
 | |
|  * SPDX-License-Identifier:	GPL-2.0+
 | |
|  */
 | |
| 
 | |
| /***********************************************************************************
 | |
|  * Bits for the SDRAM controller
 | |
|  * -----------------------------
 | |
|  *
 | |
|  * CAL:	CAS Latency. If cleared to 0 (default) the SDRAM controller asserts TA# on
 | |
|  *	the 2nd Clock after ACTIVE command (CAS Latency = 2). If set to 1 the SDRAM
 | |
|  *	controller asserts TA# on the 3rd Clock after ACTIVE command (CAS Latency = 3).
 | |
|  * RCD:	RCD ACTIVE to READ or WRITE Delay (Ras to Cas Delay). If cleared 0 (default)
 | |
|  *	tRCD of the SDRAM must equal or less 25ns. If set to 1 tRCD must be equal or less 50ns.
 | |
|  * WREC:Write Recovery. If cleared 0 (default) tWR of the SDRAM must equal or less 25ns.
 | |
|  *	If set to 1 tWR must be equal or less 50ns.
 | |
|  * RP:	Precharge Command Time. If cleared 0 (default) tRP of the SDRAM must equal or less
 | |
|  *	25ns. If set to 1 tRP must be equal or less 50ns.
 | |
|  * RC:	Auto Refresh to Active Time. If cleared 0 (default) tRC of the SDRAM must equal
 | |
|  *	or less 75ns. If set to 1 tRC must be equal or less 100ns.
 | |
|  * LMR:	Bit to set the Mode Register of the SDRAM. If set, the next access to the SDRAM
 | |
|  *	is the Load Mode Register Command.
 | |
|  * IIP:	Init in progress. Set to 1 for starting the init sequence
 | |
|  *	(Precharge All). As long this bit is set, the Precharge All is still in progress.
 | |
|  *	After command has completed, wait at least for 8 refresh (200usec) before proceed.
 | |
|  **********************************************************************************/
 | |
| 
 | |
| #include <common.h>
 | |
| #include <console.h>
 | |
| #include <mpc5xx.h>
 | |
| #include <stdio_dev.h>
 | |
| #include <pci_ids.h>
 | |
| #define PLX9056_LOC
 | |
| #include "plx9056.h"
 | |
| #include "pati.h"
 | |
| 
 | |
| #if defined(__APPLE__)
 | |
| /* Leading underscore on symbols */
 | |
| #  define SYM_CHAR "_"
 | |
| #else /* No leading character on symbols */
 | |
| #  define SYM_CHAR
 | |
| #endif
 | |
| 
 | |
| #undef SDRAM_DEBUG
 | |
| /*
 | |
|  * Macros to generate global absolutes.
 | |
|  */
 | |
| #define GEN_SYMNAME(str) SYM_CHAR #str
 | |
| #define GEN_VALUE(str) #str
 | |
| #define GEN_ABS(name, value) \
 | |
| 		asm (".globl " GEN_SYMNAME(name)); \
 | |
| 		asm (GEN_SYMNAME(name) " = " GEN_VALUE(value))
 | |
| 
 | |
| 
 | |
| /************************************************************************
 | |
|  * Early debug routines
 | |
|  */
 | |
| void write_hex (unsigned char i)
 | |
| {
 | |
| 	char cc;
 | |
| 
 | |
| 	cc = i >> 4;
 | |
| 	cc &= 0xf;
 | |
| 	if (cc > 9)
 | |
| 		serial_putc (cc + 55);
 | |
| 	else
 | |
| 		serial_putc (cc + 48);
 | |
| 	cc = i & 0xf;
 | |
| 	if (cc > 9)
 | |
| 		serial_putc (cc + 55);
 | |
| 	else
 | |
| 		serial_putc (cc + 48);
 | |
| }
 | |
| 
 | |
| #if defined(SDRAM_DEBUG)
 | |
| 
 | |
| void write_4hex (unsigned long val)
 | |
| {
 | |
| 	write_hex ((unsigned char) (val >> 24));
 | |
| 	write_hex ((unsigned char) (val >> 16));
 | |
| 	write_hex ((unsigned char) (val >> 8));
 | |
| 	write_hex ((unsigned char) val);
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| unsigned long in32(unsigned long addr)
 | |
| {
 | |
| 	unsigned long *p=(unsigned long *)addr;
 | |
| 	return *p;
 | |
| }
 | |
| 
 | |
| void out32(unsigned long addr,unsigned long data)
 | |
| {
 | |
| 	unsigned long *p=(unsigned long *)addr;
 | |
| 	*p=data;
 | |
| }
 | |
| 
 | |
| typedef struct {
 | |
| 	unsigned short boardtype; /* Board revision and Population Options */
 | |
| 	unsigned char cal;		/* cas Latency  0:CAL=2 1:CAL=3 */
 | |
| 	unsigned char rcd;		/* ras to cas delay  0:<25ns 1:<50ns*/
 | |
| 	unsigned char wrec;		/* write recovery 0:<25ns 1:<50ns */
 | |
| 	unsigned char pr;		/* Precharge Command Time 0:<25ns 1:<50ns */
 | |
| 	unsigned char rc;		/* Auto Refresh to Active Time 0:<75ns 1:<100ns */
 | |
| 	unsigned char sz;		/* log binary => Size = (4MByte<<sz) 5 = 128, 4 = 64, 3 = 32, 2 = 16, 1=8 */
 | |
| } sdram_t;
 | |
| 
 | |
| const sdram_t sdram_table[] = {
 | |
| 	{ 0x0000,	/* PATI Rev A, 16MByte -1 Board */
 | |
| 		1,	/* Case Latenty = 3 */
 | |
| 		0,	/* ras to cas delay  0 (20ns) */
 | |
| 		0,	/* write recovery 0:<25ns 1:<50ns*/
 | |
| 		0,	/* Precharge Command Time 0 (20ns) */
 | |
| 		0,	/* Auto Refresh to Active Time 0 (68) */
 | |
| 		2	/* log binary => Size 2 = 16MByte, 1=8 */
 | |
| 	},
 | |
| 	{ 0xffff, /* terminator */
 | |
| 	  0xff,
 | |
| 	  0xff,
 | |
| 	  0xff,
 | |
| 	  0xff,
 | |
| 	  0xff,
 | |
| 	  0xff }
 | |
| };
 | |
| 
 | |
| 
 | |
| extern int mem_test (unsigned long start, unsigned long ramsize, int quiet);
 | |
| 
 | |
| /*
 | |
|  * Get RAM size.
 | |
|  */
 | |
| phys_size_t initdram(int board_type)
 | |
| {
 | |
| 	unsigned char board_rev;
 | |
| 	unsigned long reg;
 | |
| 	unsigned long lmr;
 | |
| 	int i,timeout;
 | |
| 
 | |
| #if defined(SDRAM_DEBUG)
 | |
| 	reg=in32(PLD_CONFIG_BASE+PLD_PART_ID);
 | |
| 	puts("\n\nSYSTEM part 0x"); write_4hex(SYSCNTR_PART(reg));
 | |
| 	puts(" Vers 0x"); write_4hex(SYSCNTR_ID(reg));
 | |
| 	puts("\nSDRAM  part  0x"); write_4hex(SDRAM_PART(reg));
 | |
| 	puts(" Vers 0x"); write_4hex(SDRAM_ID(reg));
 | |
| 	reg=in32(PLD_CONFIG_BASE+PLD_BOARD_TIMING);
 | |
| 	puts("\nBoard rev.   0x"); write_4hex(SYSCNTR_BREV(reg));
 | |
|    putc('\n');
 | |
| #endif
 | |
| 	reg=in32(PLD_CONFIG_BASE+PLD_BOARD_TIMING);
 | |
| 	board_rev=(unsigned char)(SYSCNTR_BREV(reg));
 | |
| 	i=0;
 | |
| 	while(1) {
 | |
| 		if(sdram_table[i].boardtype==0xffff) {
 | |
| 			puts("ERROR, found no table for Board 0x");
 | |
| 			write_hex(board_rev);
 | |
| 			while(1);
 | |
| 		}
 | |
| 		if(sdram_table[i].boardtype==(unsigned char)board_rev)
 | |
| 			break;
 | |
| 		i++;
 | |
| 	}
 | |
| 	/* Set CAL, RCD, WREQ, PR and RC Bits */
 | |
| #if defined(SDRAM_DEBUG)
 | |
| 	puts("Set CAL, RCD, WREQ, PR and RC Bits\n");
 | |
| #endif
 | |
| 	/* mask bits */
 | |
| 	reg &= ~(SET_REG_BIT(1,SDRAM_CAL) | SET_REG_BIT(1,SDRAM_RCD) | SET_REG_BIT(1,SDRAM_WREQ) |
 | |
| 				SET_REG_BIT(1,SDRAM_PR)  |  SET_REG_BIT(1,SDRAM_RC) | SET_REG_BIT(1,SDRAM_LMR)  |
 | |
| 				SET_REG_BIT(1,SDRAM_IIP) | SET_REG_BIT(1,SDRAM_RES0));
 | |
| 	/* set bits */
 | |
| 	reg |= (SET_REG_BIT(sdram_table[i].cal,SDRAM_CAL) |
 | |
| 			  SET_REG_BIT(sdram_table[i].rcd,SDRAM_RCD) |
 | |
| 			  SET_REG_BIT(sdram_table[i].wrec,SDRAM_WREQ) |
 | |
| 			  SET_REG_BIT(sdram_table[i].pr,SDRAM_PR) |
 | |
| 			  SET_REG_BIT(sdram_table[i].rc,SDRAM_RC));
 | |
| 
 | |
| 	out32(PLD_CONFIG_BASE+PLD_BOARD_TIMING,reg);
 | |
| 	/* step 2 set IIP */
 | |
| #if defined(SDRAM_DEBUG)
 | |
| 	puts("step 2 set IIP\n");
 | |
| #endif
 | |
| 	/* step 2 set IIP */
 | |
| 	reg |= SET_REG_BIT(1,SDRAM_IIP);
 | |
| 	timeout=0;
 | |
| 	while (timeout!=0xffff) {
 | |
| 		__asm__ volatile("eieio");
 | |
| 		reg=in32(PLD_CONFIG_BASE+PLD_BOARD_TIMING);
 | |
| 		if((reg & SET_REG_BIT(1,SDRAM_IIP))==0)
 | |
| 			break;
 | |
| 		timeout++;
 | |
| 		udelay(1);
 | |
| 	}
 | |
| 	/* wait for at least 8 refresh */
 | |
| 	udelay(1000);
 | |
| 	/* set LMR */
 | |
| 	reg |= SET_REG_BIT(1,SDRAM_LMR);
 | |
| 	out32(PLD_CONFIG_BASE+PLD_BOARD_TIMING,reg);
 | |
| 	__asm__ volatile("eieio");
 | |
| 	lmr=0x00000002; /* sequential burst 4 data */
 | |
| 	if(sdram_table[i].cal==1)
 | |
| 		lmr|=0x00000030; /* cal = 3 */
 | |
| 	else
 | |
| 		lmr|=0000000020; /* cal = 2 */
 | |
| 	/* rest standard operation programmed write burst length */
 | |
| 	/* we have a x32 bit bus to the SDRAM, so shift the addr with 2 */
 | |
| 	lmr<<=2;
 | |
| 	in32(CONFIG_SYS_SDRAM_BASE + lmr);
 | |
| 	/* ok, we're done, return SDRAM size */
 | |
| 	return ((0x400000 << sdram_table[i].sz));		/* log2 value of 4MByte  */
 | |
| }
 | |
| 
 | |
| 
 | |
| void set_flash_vpp(int ext_vpp, int ext_wp, int int_vpp)
 | |
| {
 | |
| 	unsigned long reg;
 | |
| 	reg=in32(PLD_CONF_REG2+PLD_CONFIG_BASE);
 | |
| 	reg &= ~(SET_REG_BIT(1,SYSCNTR_CPU_VPP) |
 | |
| 			   SET_REG_BIT(1,SYSCNTR_FL_VPP) |
 | |
| 				SET_REG_BIT(1,SYSCNTR_FL_WP));
 | |
| 
 | |
| 	reg |= (SET_REG_BIT(int_vpp,SYSCNTR_CPU_VPP) |
 | |
| 			   SET_REG_BIT(ext_vpp,SYSCNTR_FL_VPP) |
 | |
| 				SET_REG_BIT(ext_wp,SYSCNTR_FL_WP));
 | |
| 	out32(PLD_CONF_REG2+PLD_CONFIG_BASE,reg);
 | |
| 	udelay(100);
 | |
| }
 | |
| 
 | |
| 
 | |
| void show_pld_regs(void)
 | |
| {
 | |
| 	unsigned long reg,reg1;
 | |
| 	reg=in32(PLD_CONFIG_BASE+PLD_PART_ID);
 | |
| 	printf("\nSYSTEM part %ld, Vers %ld\n",SYSCNTR_PART(reg),SYSCNTR_ID(reg));
 | |
| 	printf("SDRAM  part %ld, Vers %ld\n",SDRAM_PART(reg),SDRAM_ID(reg));
 | |
| 	reg=in32(PLD_CONFIG_BASE+PLD_BOARD_TIMING);
 | |
| 	printf("Board rev.  %c\n",(char) (SYSCNTR_BREV(reg)+'A'));
 | |
| 	printf("Waitstates  %ld\n",GET_SYSCNTR_FLWAIT(reg));
 | |
| 	printf("SDRAM:      CAL=%ld RCD=%ld WREQ=%ld PR=%ld\n            RC=%ld  LMR=%ld IIP=%ld\n",
 | |
| 		GET_REG_BIT(reg,SDRAM_CAL),GET_REG_BIT(reg,SDRAM_RCD),
 | |
| 		GET_REG_BIT(reg,SDRAM_WREQ),GET_REG_BIT(reg,SDRAM_PR),
 | |
| 		GET_REG_BIT(reg,SDRAM_RC),GET_REG_BIT(reg,SDRAM_LMR),
 | |
| 		GET_REG_BIT(reg,SDRAM_IIP));
 | |
| 	reg=in32(PLD_CONFIG_BASE+PLD_CONF_REG1);
 | |
| 	reg1=in32(PLD_CONFIG_BASE+PLD_CONF_REG2);
 | |
| 	printf("HW Config:  FLAG=%ld IP=%ld  index=%ld PRPM=%ld\n            ICW=%ld  ISB=%ld BDIS=%ld  PCIM=%ld\n",
 | |
| 		GET_REG_BIT(reg,SYSCNTR_FLAG),GET_REG_BIT(reg,SYSCNTR_IP),
 | |
| 		GET_SYSCNTR_BOOTIND(reg),GET_REG_BIT(reg,SYSCNTR_PRM),
 | |
| 		GET_REG_BIT(reg,SYSCNTR_ICW),GET_SYSCNTR_ISB(reg),
 | |
| 		GET_REG_BIT(reg1,SYSCNTR_BDIS),GET_REG_BIT(reg1,SYSCNTR_PCIM));
 | |
| 	printf("Switches:   MUX=%ld PCI_DIS=%ld Boot_EN=%ld  Config=%ld\n",GET_SDRAM_MUX(reg),
 | |
| 		GET_REG_BIT(reg,SDRAM_PDIS),GET_REG_BIT(reg1,SYSCNTR_BOOTEN),
 | |
| 		GET_SYSCNTR_CFG(reg1));
 | |
| 	printf("Misc:       RIP=%ld CPU_VPP=%ld FLSH_VPP=%ld FLSH_WP=%ld\n\n",
 | |
| 		GET_REG_BIT(reg,SDRAM_RIP),GET_REG_BIT(reg1,SYSCNTR_CPU_VPP),
 | |
| 		GET_REG_BIT(reg1,SYSCNTR_FL_VPP),GET_REG_BIT(reg1,SYSCNTR_FL_WP));
 | |
| }
 | |
| 
 | |
| 
 | |
| /****************************************************************
 | |
|  * Setting IOs
 | |
|  * -----------
 | |
|  * GPIO6 is User LED1
 | |
|  * GPIO7 is Interrupt PLX (Output)
 | |
|  * GPIO5 is User LED0
 | |
|  * GPIO2 is PLX USERi (Output)
 | |
|  * GPIO1 is PLX Interrupt (Input)
 | |
|  ****************************************************************/
 | |
|  void init_ios(void)
 | |
|  {
 | |
| 	volatile immap_t * immr = (immap_t *) CONFIG_SYS_IMMR;
 | |
| 	volatile sysconf5xx_t *sysconf = &immr->im_siu_conf;
 | |
| 	unsigned long reg;
 | |
| 	reg=sysconf->sc_sgpiocr; /* Data direction register */
 | |
| 	reg &= ~0x67000000;
 | |
| 	reg |= 0x27000000; /* set outpupts */
 | |
| 	sysconf->sc_sgpiocr=reg; /* Data direction register */
 | |
| 	reg=sysconf->sc_sgpiodt2; /* Data register */
 | |
| 	/* set output to 0 */
 | |
| 	reg &= ~0x27000000;
 | |
| 	/* set IRQ and USERi to 1 */
 | |
| 	reg |= 0x28000000;
 | |
| 	sysconf->sc_sgpiodt2=reg; /* Data register */
 | |
| }
 | |
| 
 | |
| void user_led0(int led_on)
 | |
| {
 | |
| 	volatile immap_t * immr = (immap_t *) CONFIG_SYS_IMMR;
 | |
| 	volatile sysconf5xx_t *sysconf = &immr->im_siu_conf;
 | |
| 	unsigned long reg;
 | |
| 	reg=sysconf->sc_sgpiodt2; /* Data register */
 | |
| 	if(led_on)	/* set output to 1 */
 | |
| 		reg |= 0x04000000;
 | |
| 	else
 | |
| 		reg &= ~0x04000000;
 | |
| 	sysconf->sc_sgpiodt2=reg; /* Data register */
 | |
| }
 | |
| 
 | |
| void user_led1(int led_on)
 | |
| {
 | |
| 	volatile immap_t * immr = (immap_t *) CONFIG_SYS_IMMR;
 | |
| 	volatile sysconf5xx_t *sysconf = &immr->im_siu_conf;
 | |
| 	unsigned long reg;
 | |
| 	reg=sysconf->sc_sgpiodt2; /* Data register */
 | |
| 	if(led_on)	/* set output to 1 */
 | |
| 		reg |= 0x02000000;
 | |
| 	else
 | |
| 		reg &= ~0x02000000;
 | |
| 	sysconf->sc_sgpiodt2=reg; /* Data register */
 | |
| }
 | |
| 
 | |
| int board_early_init_f(void)
 | |
| {
 | |
| 	spi_init_f();
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /****************************************************************
 | |
|  * Last Stage Init
 | |
|  ****************************************************************/
 | |
| int last_stage_init (void)
 | |
| {
 | |
| 	init_ios();
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /****************************************************************
 | |
|  * Check the board
 | |
|  ****************************************************************/
 | |
| 
 | |
| #define BOARD_NAME	"PATI"
 | |
| 
 | |
| int checkboard (void)
 | |
| {
 | |
| 	char s[50];
 | |
| 	ulong reg;
 | |
| 	char rev;
 | |
| 	int i;
 | |
| 
 | |
| 	puts ("\nBoard: ");
 | |
| 	reg=in32(PLD_CONFIG_BASE+PLD_BOARD_TIMING);
 | |
| 	rev=(char)(SYSCNTR_BREV(reg)+'A');
 | |
| 	i = getenv_f("serial#", s, 32);
 | |
| 	if ((i == -1)) {
 | |
| 		puts ("### No HW ID - assuming " BOARD_NAME);
 | |
| 		printf(" Rev. %c\n",rev);
 | |
| 	}
 | |
| 	else {
 | |
| 		s[sizeof(BOARD_NAME)-1] = 0;
 | |
| 		printf ("%s-1 Rev %c SN: %s\n", s,rev,
 | |
| 				&s[sizeof(BOARD_NAME)]);
 | |
| 	}
 | |
| 	set_flash_vpp(1,0,0); /* set Flash VPP */
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| #ifdef CONFIG_SYS_PCI_CON_DEVICE
 | |
| /************************************************************************
 | |
|  * PCI Communication
 | |
|  *
 | |
|  * Alive (Pinging):
 | |
|  * ----------------
 | |
|  * PCI Host sends message ALIVE, Local acknowledges with ALIVE
 | |
|  *
 | |
|  * PCI_CON console over PCI:
 | |
|  * -------------------------
 | |
|  * Local side:
 | |
|  *     - uses PCI9056_LOC_TO_PCI_DBELL register to signal that
 | |
|  *       data is avaible (PCIMSG_CONN)
 | |
|  *     - uses PCI9056_MAILBOX1 to send data
 | |
|  *     - uses PCI9056_MAILBOX0 to receive data
 | |
|  * PCI side:
 | |
|  *     - uses PCI9056_PCI_TO_LOC_DBELL register to signal that
 | |
|  *       data is avaible (PCIMSG_CONN)
 | |
|  *     - uses PCI9056_MAILBOX0 to send data
 | |
|  *     - uses PCI9056_MAILBOX1 to receive data
 | |
|  *
 | |
|  * How it works:
 | |
|  *     Send:
 | |
|  *     - check if PCICON_TRANSMIT_REG is empty
 | |
|  *     - write data or'ed with 0x80000000 into the PCICON_TRANSMIT_REG
 | |
|  *     - write PCIMSG_CONN into the PCICON_DBELL_REG to signal a data
 | |
|  *       is waiting
 | |
|  *     Receive:
 | |
|  *     - get an interrupt via the PCICON_ACK_REG register message
 | |
|  *       PCIMSG_CONN
 | |
|  *     - write the data from the PCICON_RECEIVE_REG into the receive
 | |
|  *       buffer and if the receive buffer is not full, clear the
 | |
|  *       PCICON_RECEIVE_REG (this allows the counterpart to write more data)
 | |
|  *     - Clear the interrupt by writing 0xFFFFFFFF to the PCICON_ACK_REG
 | |
|  *
 | |
|  *     The PCICON_RECEIVE_REG must be cleared by the routine which reads
 | |
|  *     the receive buffer if the buffer is not full any more
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #undef PCI_CON_DEBUG
 | |
| 
 | |
| #ifdef	PCI_CON_DEBUG
 | |
| #define	PCI_CON_PRINTF(fmt,args...)	serial_printf (fmt ,##args)
 | |
| #else
 | |
| #define PCI_CON_PRINTF(fmt,args...)
 | |
| #endif
 | |
| 
 | |
| 
 | |
| /*********************************************************
 | |
|  * we work only with a receive buffer on eiter side.
 | |
|  * Transmit buffer is free, if mailbox is cleared.
 | |
|  * Transmit character is or'ed with 0x80000000
 | |
|  * PATI receive register MAILBOX0
 | |
|  * PATI transmit register MAILBOX1
 | |
|  *********************************************************/
 | |
| #define PCICON_RECEIVE_REG	PCI9056_MAILBOX0
 | |
| #define PCICON_TRANSMIT_REG	PCI9056_MAILBOX1
 | |
| #define PCICON_DBELL_REG	PCI9056_LOC_TO_PCI_DBELL
 | |
| #define PCICON_ACK_REG		PCI9056_PCI_TO_LOC_DBELL
 | |
| 
 | |
| 
 | |
| #define PCIMSG_ALIVE		0x1
 | |
| #define PCIMSG_CONN		0x2
 | |
| #define PCIMSG_DISC		0x3
 | |
| #define PCIMSG_CON_DATA	0x5
 | |
| 
 | |
| 
 | |
| #define PCICON_GET_REG(x)	(in32(x + PCI_CONFIG_BASE))
 | |
| #define PCICON_SET_REG(x,y)	(out32(x + PCI_CONFIG_BASE,y))
 | |
| #define PCICON_TX_FLAG		0x80000000
 | |
| 
 | |
| 
 | |
| #define REC_BUFFER_SIZE	0x100
 | |
| int recbuf[REC_BUFFER_SIZE];
 | |
| static int r_ptr = 0;
 | |
| int w_ptr;
 | |
| struct stdio_dev pci_con_dev;
 | |
| int conn=0;
 | |
| int buff_full=0;
 | |
| 
 | |
| void pci_con_put_it(const char c)
 | |
| {
 | |
| 	/* Test for completition */
 | |
| 	unsigned long reg;
 | |
| 	do {
 | |
| 		reg=PCICON_GET_REG(PCICON_TRANSMIT_REG);
 | |
| 	}while(reg);
 | |
| 	reg=PCICON_TX_FLAG + c;
 | |
| 	PCICON_SET_REG(PCICON_TRANSMIT_REG,reg);
 | |
| 	PCICON_SET_REG(PCICON_DBELL_REG,PCIMSG_CON_DATA);
 | |
| }
 | |
| 
 | |
| void pci_con_putc(struct stdio_dev *dev, const char c)
 | |
| {
 | |
| 	pci_con_put_it(c);
 | |
| 	if(c == '\n')
 | |
| 		pci_con_put_it('\r');
 | |
| }
 | |
| 
 | |
| 
 | |
| int pci_con_getc(struct stdio_dev *dev)
 | |
| {
 | |
| 	int res;
 | |
| 	int diff;
 | |
| 	while(r_ptr==(volatile int)w_ptr);
 | |
| 	res=recbuf[r_ptr++];
 | |
| 	if(r_ptr==REC_BUFFER_SIZE)
 | |
| 		r_ptr=0;
 | |
| 	if(w_ptr<r_ptr)
 | |
| 		diff=r_ptr+REC_BUFFER_SIZE-w_ptr;
 | |
| 	else
 | |
| 		diff=r_ptr-w_ptr;
 | |
| 	if((diff<(REC_BUFFER_SIZE-4)) && buff_full) {
 | |
| 		/* clear Mail box */
 | |
| 			buff_full=0;
 | |
| 			PCICON_SET_REG(PCICON_RECEIVE_REG,0L);
 | |
| 	}
 | |
| 	return res;
 | |
| }
 | |
| 
 | |
| int pci_con_tstc(struct stdio_dev *dev)
 | |
| {
 | |
| 	if(r_ptr==(volatile int)w_ptr)
 | |
| 		return 0;
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| void pci_con_puts(struct stdio_dev *dev, const char *s)
 | |
| {
 | |
| 	while (*s) {
 | |
| 		pci_con_putc(*s);
 | |
| 		++s;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void pci_con_init (void)
 | |
| {
 | |
| 	w_ptr = 0;
 | |
| 	r_ptr = 0;
 | |
| 	PCICON_SET_REG(PCICON_RECEIVE_REG,0L);
 | |
| 	conn=1;
 | |
| }
 | |
| 
 | |
| /*******************************************
 | |
|  * IRQ routine
 | |
|  ******************************************/
 | |
| int pci_dorbell_irq(void)
 | |
| {
 | |
| 	unsigned long reg,data;
 | |
| 	int diff;
 | |
| 	reg=PCICON_GET_REG(PCI9056_INT_CTRL_STAT);
 | |
| 	PCI_CON_PRINTF(" PCI9056_INT_CTRL_STAT = %08lX\n",reg);
 | |
| 	if(reg & (1<<20) ) {
 | |
| 		/* read doorbell */
 | |
| 		reg=PCICON_GET_REG(PCICON_ACK_REG);
 | |
| 		switch(reg) {
 | |
| 			case PCIMSG_ALIVE:
 | |
| 				PCI_CON_PRINTF(" Alive\n");
 | |
| 				PCICON_SET_REG(PCICON_DBELL_REG,PCIMSG_ALIVE);
 | |
| 				break;
 | |
| 			case PCIMSG_CONN:
 | |
| 				PCI_CON_PRINTF(" Conn %d",conn);
 | |
| 				w_ptr = 0;
 | |
| 				r_ptr = 0;
 | |
| 				buff_full=0;
 | |
| 				PCICON_SET_REG(PCICON_RECEIVE_REG,0L);
 | |
| 				conn=1;
 | |
| 				PCI_CON_PRINTF(" ... %d\n",conn);
 | |
| 				break;
 | |
| 			case PCIMSG_CON_DATA:
 | |
| 				data=PCICON_GET_REG(PCICON_RECEIVE_REG);
 | |
| 				recbuf[w_ptr++]=(int)(data&0xff);
 | |
| 				PCI_CON_PRINTF(" Data Console %lX, %X %d %d %X\n",data,((int)(data&0xFF)),
 | |
| 					r_ptr,w_ptr,recbuf[w_ptr-1]);
 | |
| 				if(w_ptr==REC_BUFFER_SIZE)
 | |
| 					w_ptr=0;
 | |
| 				if(w_ptr<r_ptr)
 | |
| 					diff=r_ptr+REC_BUFFER_SIZE-w_ptr;
 | |
| 				else
 | |
| 					diff=r_ptr-w_ptr;
 | |
| 				if(diff>(REC_BUFFER_SIZE-4))
 | |
| 					buff_full=1;
 | |
| 				else
 | |
| 					/* clear Mail box */
 | |
| 					PCICON_SET_REG(PCICON_RECEIVE_REG,0L);
 | |
| 				break;
 | |
| 			default:
 | |
| 				serial_printf(" PCI9056_PCI_TO_LOC_DBELL = %08lX\n",reg);
 | |
| 		}
 | |
| 		/* clear IRQ */
 | |
| 		PCICON_SET_REG(PCICON_ACK_REG,~0L);
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void pci_con_connect(void)
 | |
| {
 | |
| 	unsigned long reg;
 | |
| 	conn=0;
 | |
| 	reg=PCICON_GET_REG(PCI9056_INT_CTRL_STAT);
 | |
| 	/* default 0x0f010180 */
 | |
| 	reg &= 0xff000000;
 | |
| 	reg |= 0x00030000; /* enable local dorbell */
 | |
| 	reg |= 0x00000300; /* enable PCI dorbell */
 | |
| 	PCICON_SET_REG(PCI9056_INT_CTRL_STAT , reg);
 | |
| 	irq_install_handler (0x2, (interrupt_handler_t *) pci_dorbell_irq,NULL);
 | |
| 	memset (&pci_con_dev, 0, sizeof (pci_con_dev));
 | |
| 	strcpy (pci_con_dev.name, "pci_con");
 | |
| 	pci_con_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;
 | |
| 	pci_con_dev.putc = pci_con_putc;
 | |
| 	pci_con_dev.puts = pci_con_puts;
 | |
| 	pci_con_dev.getc = pci_con_getc;
 | |
| 	pci_con_dev.tstc = pci_con_tstc;
 | |
| 	stdio_register (&pci_con_dev);
 | |
| 	printf("PATI ready for PCI connection, type ctrl-c for exit\n");
 | |
| 	do {
 | |
| 		udelay(10);
 | |
| 		if((volatile int)conn)
 | |
| 			break;
 | |
| 		if(ctrlc()) {
 | |
| 			irq_free_handler(0x2);
 | |
| 			return;
 | |
| 		}
 | |
| 	}while(1);
 | |
| 	console_assign(stdin,"pci_con");
 | |
| 	console_assign(stderr,"pci_con");
 | |
| 	console_assign(stdout,"pci_con");
 | |
| }
 | |
| 
 | |
| void pci_con_disc(void)
 | |
| {
 | |
| 	console_assign(stdin,"serial");
 | |
| 	console_assign(stderr,"serial");
 | |
| 	console_assign(stdout,"serial");
 | |
| 	PCICON_SET_REG(PCICON_DBELL_REG,PCIMSG_DISC);
 | |
| 	/* reconnection */
 | |
| 	irq_free_handler(0x02);
 | |
| 	pci_con_connect();
 | |
| }
 | |
| #endif /* #ifdef CONFIG_SYS_PCI_CON_DEVICE */
 | |
| 
 | |
| /*
 | |
|  * Absolute environment address for linker file.
 | |
|  */
 | |
| GEN_ABS(env_start, CONFIG_ENV_OFFSET + CONFIG_SYS_FLASH_BASE);
 |