* MPC5200,PSC in uart mode, receiving problem
@ 2005-10-10 11:37 Tomasz Prochownik
2005-10-10 13:13 ` AW: " Achim Machura
2005-10-10 18:38 ` Wolfgang Denk
0 siblings, 2 replies; 5+ messages in thread
From: Tomasz Prochownik @ 2005-10-10 11:37 UTC (permalink / raw)
To: linuxppc-embedded
Hello.
I'm beginner in ppc linux, so I believe, you can help me. I hope you'll =
be able to understand my english :o).
I have MPC5200Lite board with Linux from Denx (kernel 2.4.25).
I try to use PSC in UART mode to read chars from other system.
My init ttyS function:
i_Fd =3D open("/dev/ttyS2", O_RDWR | O_NOCTTY |O_NDELAY);
if (i_Fd =3D=3D -1 )
{DEBUG_OUT("[ERROR]\r\n");}
else
{
tcgetattr(i_Fd,&strBufOptions);=09
bzero(&strOptions, sizeof(strOptions));
strOptions.c_cflag =3D Baud | CS8 |CREAD |CLOCAL;
strOptions.c_iflag =3D 0;
strOptions.c_oflag =3D 0;
strOptions.c_lflag =3D 0;
strOptions.c_cc[VTIME] =3D 0;
strOptions.c_cc[VMIN] =3D 0;
tcflush(i_Fd, TCIFLUSH);
tcsetattr(i_Fd,TCSANOW,&strOptions);
}
Everything works fine until first framing error (FE) in receiver. Since =
then function read(i_Fd,DataBuffer,CO_MAX_BUF_LEN-1) returns number of =
received chars, but value of every char in DataBuffer is zero.
I have done some experiments and noticed one more strange things:
1. I use hyperterminal in 115200 baud as root console
2. If I change speed to 9600, send one char to MPC5200 (framing error?) =
and change speed back to 115200 -> uart blocks (there is no response in =
the console).
..so maybe bug isn't in my code...?
I have read in errata about blocking uart receiver(bug ID: 364) , but I =
don't know it can be in my application.
Best regards
-=3D=3D=3D-
Tomasz Prochownik
MCD Electronics
33 861 60 35 w. 13
916@mcd.com.pl
^ permalink raw reply [flat|nested] 5+ messages in thread
* AW: MPC5200,PSC in uart mode, receiving problem
2005-10-10 11:37 MPC5200,PSC in uart mode, receiving problem Tomasz Prochownik
@ 2005-10-10 13:13 ` Achim Machura
2005-10-10 18:38 ` Wolfgang Denk
1 sibling, 0 replies; 5+ messages in thread
From: Achim Machura @ 2005-10-10 13:13 UTC (permalink / raw)
To: 'Tomasz Prochownik'; +Cc: Linuxppc-Embedded (E-Mail)
Hello Tomasz
> blocks (there is no response in the console).
perhaps we have the same problem a few times ago.
When we connect devices on ttySx which have wrong level on the lines the
uart stay in break mode.
I have made some fixes on the psc-driver. With these fixes the uart works,
but i don't know how efficient.
(clear breakmode and clear buffer)
If you want, i can send the code
best regards
achim
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: MPC5200,PSC in uart mode, receiving problem
2005-10-10 11:37 MPC5200,PSC in uart mode, receiving problem Tomasz Prochownik
2005-10-10 13:13 ` AW: " Achim Machura
@ 2005-10-10 18:38 ` Wolfgang Denk
1 sibling, 0 replies; 5+ messages in thread
From: Wolfgang Denk @ 2005-10-10 18:38 UTC (permalink / raw)
To: Tomasz Prochownik; +Cc: linuxppc-embedded
Dear Tomasz,
in message <99477CB23E7ACB4EA366A2B6970DA618060F7E@mcdserver.mcd.com.pl> you wrote:
>
> I have MPC5200Lite board with Linux from Denx (kernel 2.4.25).
Is this the latest code from the git resp. CVS server? If not, please
make sure to update.
Best regards,
Wolfgang Denk
--
Software Engineering: Embedded and Realtime Systems, Embedded Linux
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
grep me no patterns and I'll tell you no lines.
^ permalink raw reply [flat|nested] 5+ messages in thread
* AW: MPC5200,PSC in uart mode, receiving problem
2005-10-11 7:18 Wolfgang Denk
@ 2005-10-11 8:10 ` Achim Machura
2006-02-02 18:22 ` Frank Bodammer
0 siblings, 1 reply; 5+ messages in thread
From: Achim Machura @ 2005-10-11 8:10 UTC (permalink / raw)
To: 'Wolfgang Denk'; +Cc: Linuxppc-Embedded (E-Mail)
[-- Attachment #1: Type: text/plain, Size: 108 bytes --]
Here the patch
> Even better, post a patch here on the list so we all can benefit.
Best regards,
Achim
[-- Attachment #2: patch_linuxppc_2_4_develLABEL_2004_04_30_1320_psc --]
[-- Type: application/octet-stream, Size: 7506 bytes --]
Index: psc.c
===================================================================
--- psc.c (.../kernel/linux/arch/ppc/5xxx_io/psc.c) (Revision 777)
+++ psc.c (.../firmware/kernel/linux/arch/ppc/5xxx_io/psc.c) (Arbeitskopie)
@@ -29,6 +29,7 @@
#include <linux/serial.h>
#include <linux/serialP.h>
#include <linux/generic_serial.h>
+#include <linux/proc_fs.h>
#ifdef CONFIG_UBOOT
#include <asm/ppcboot.h>
#endif
@@ -37,7 +38,7 @@
* This driver can spew a whole lot of debugging output at you. If you
* need maximum performance, you should disable the DEBUG define.
*/
-#undef MPC5xxx_PSC_DEBUG
+#undef MPC5xxx_PSC_DEBUG
#ifdef MPC5xxx_PSC_DEBUG
#define MPC5xxx_PSC_DEBUG_OPEN 0x00000001
@@ -55,6 +56,7 @@
#define MPC5xxx_PSC_DEBUG_FIRMWARE 0x00001000
#define MPC5xxx_PSC_DEBUG_MEMTEST 0x00002000
#define MPC5xxx_PSC_DEBUG_THROTTLE 0x00004000
+#define MPC5xxx_PSC_DEBUG_CLEARERR 0x00008000
#define MPC5xxx_PSC_DEBUG_ALL 0xffffffff
int rs_debug = MPC5xxx_PSC_DEBUG_ALL & ~MPC5xxx_PSC_DEBUG_TRANSMIT;
@@ -150,13 +152,23 @@
int rs_refcount;
int rs_initialized = 0;
+
/*
+ * proc stuff
+ */
+static int sio_read_info(char * buf, char ** start, off_t offset, int count, int *eof, void * data );
+static int sio_clear_err(struct file *file, const char *buffer, unsigned long count, void *data);
+static struct proc_dir_entry *pProcEntry = NULL;
+
+
+void clear_err(struct mpc5xxx_psc * psc);
+/*
* ----------------------------------------------------------------------
*
* Here starts the interrupt handling routines. All of the following
* subroutines are declared as inline and are folded into
* rs_interrupt(). They were separated out for readability's sake.
- *
+ *MPC5xxx_PSC_DEBUG_RECEIVE
* Note: rs_interrupt() is a "fast" interrupt, which means that it
* runs with interrupts turned off. People who may want to modify
* rs_interrupt() should try to keep the interrupt handler as fast as
@@ -294,19 +306,36 @@
static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
- struct rs_port * port;
+ struct rs_port * port = (struct rs_port *)dev_id;
+ struct mpc5xxx_psc *psc = port->psc;
unsigned long flags;
+ u16 status;
spin_lock_irqsave(&mpc5xxx_serial_lock, flags);
- port = (struct rs_port *)dev_id;
+
rs_dprintk(MPC5xxx_PSC_DEBUG_INTERRUPTS,
"rs_interrupt (port %p)...", port);
+ if (!port || !port->gs.tty) {
+ printk( KERN_DEBUG"%s(%d): port=%p tty=%p\n", __FUNCTION__, __LINE__,
+ port, port?port->gs.tty:NULL );
+ goto out;
+ }
+
+ status = in_be16(&psc->mpc5xxx_psc_status);
+ /* RB-Bit is set ? */
+ if(status & MPC5xxx_PSC_SR_RB)
+ {
+ clear_err(psc);
+ rs_dprintk(MPC5xxx_PSC_DEBUG_INTERRUPTS, "clear err in isr nach status %d.\n", status);
+ goto out;
+ }
+
receive_char(port);
transmit_char(port);
-
+out:
spin_unlock_irqrestore(&mpc5xxx_serial_lock, flags);
rs_dprintk(MPC5xxx_PSC_DEBUG_INTERRUPTS, "end.\n");
@@ -318,7 +347,7 @@
* interface with the generic_serial driver *
************************************************************************
*/
-static void rs_disable_tx_interrupts(void * ptr)
+static void rs_disable_tx_interrupts(void * ptr)
{
struct rs_port *port = ptr;
struct mpc5xxx_psc *psc = port->psc;
@@ -360,7 +389,7 @@
port->imr &= ~MPC5xxx_PSC_IMR_RXRDY;
out_be16(&psc->mpc5xxx_psc_imr, port->imr);
-
+ rs_dprintk(MPC5xxx_PSC_DEBUG_RECEIVE,"disable RxInt\n");
spin_unlock_irqrestore(&mpc5xxx_serial_lock, flags);
}
@@ -382,7 +411,7 @@
* while (in_be16(&psc->mpc5xxx_psc_status) & MPC5xxx_PSC_SR_RXRDY)
* in_8(&psc->mpc5xxx_psc_buffer_8);
*/
-
+ rs_dprintk(MPC5xxx_PSC_DEBUG_RECEIVE,"enable RxInt\n");
spin_unlock_irqrestore(&mpc5xxx_serial_lock, flags);
}
@@ -442,9 +471,15 @@
val32 |= (MPC5xxx_GPIO_PSC_CONFIG_UART_WITHOUT_CD << (4*line));
out_be32(&gpio->port_config, val32);
/* reset and enable PSC */
- out_8(&psc->command, MPC5xxx_PSC_RST_TX
- | MPC5xxx_PSC_RX_DISABLE | MPC5xxx_PSC_TX_ENABLE);
- out_8(&psc->command, MPC5xxx_PSC_RST_RX);
+// out_8(&psc->command, MPC5xxx_PSC_RST_TX
+// | MPC5xxx_PSC_RX_DISABLE | MPC5xxx_PSC_TX_ENABLE);
+// out_8(&psc->command, MPC5xxx_PSC_RST_RX);
+
+ /* neu */
+ /* reset and enable PSC */
+ out_8(&psc->command, MPC5xxx_PSC_RST_TX | MPC5xxx_PSC_TX_ENABLE);
+ //out_8(&psc->command, MPC5xxx_PSC_RST_RX);
+ /* ende neu*/
/* Set PSC operation mode as 'UART, DCD ignored' */
out_be32(&psc->sicr, 0x0);
/* Set clocking */
@@ -539,7 +574,7 @@
line = minor(tty->device) - tty->driver.minor_start;
rs_dprintk(MPC5xxx_PSC_DEBUG_OPEN,
- "%d: opening line %d. tty=%p ctty=%p)\n",
+ "%d: opening line %d. tty=%p ctty=%p)\n",
(int) current->pid, line, tty, current->tty);
if ((line < 0) || (line >= RS_TABLE_SIZE))
@@ -813,6 +848,7 @@
#endif
rs_dprintk(MPC5xxx_PSC_DEBUG_INIT, "psc base 0x%08lx\n",
(unsigned long)port->psc);
+ clear_err(port->psc);
port++;
}
@@ -878,6 +914,11 @@
return 1;
}
+ //pProcEntry = create_proc_read_entry("driver/sio0",0444,NULL,sio_read_info,NULL);
+ pProcEntry = create_proc_entry("driver/sio0",0444,NULL);
+ pProcEntry->read_proc = sio_read_info;
+ pProcEntry->write_proc = sio_clear_err;
+ pProcEntry->owner = THIS_MODULE;
func_exit();
return 0;
}
@@ -1094,3 +1135,61 @@
}
#endif
+static int sio_read_info(char * buf, char ** start, off_t offset, int count, int *eof, void * data )
+{
+
+ int len = 0;
+ struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *) MPC5xxx_PSC1;
+ u16 nStat;
+
+ *eof = 1;
+ *buf = 0;
+ nStat = in_be16(&psc->mpc5xxx_psc_status);
+ if(count > len + 120)
+ {
+ len += sprintf(buf+len, "\n Status PSC 1: %d",nStat);
+ len += sprintf(buf+len, "\n RB: %d",(nStat & MPC5xxx_PSC_SR_RB) ? 1 : 0);
+ len += sprintf(buf+len, "\n FE: %d",(nStat & MPC5xxx_PSC_SR_FE) ? 1 : 0);
+ len += sprintf(buf+len, "\n PE: %d",(nStat & MPC5xxx_PSC_SR_PE) ? 1 : 0);
+ len += sprintf(buf+len, "\n OR: %d",(nStat & MPC5xxx_PSC_SR_OE) ? 1 : 0);
+ len += sprintf(buf+len, "\n TxEMP: %d",(nStat & MPC5xxx_PSC_SR_TXEMP) ? 1 : 0);
+ len += sprintf(buf+len, "\n TxRDY: %d",(nStat & MPC5xxx_PSC_SR_TXRDY) ? 1 : 0);
+ len += sprintf(buf+len, "\n RXFULL: %d",(nStat & MPC5xxx_PSC_SR_RXFULL) ? 1 : 0);
+ len += sprintf(buf+len, "\n RxRDY: %d",(nStat & MPC5xxx_PSC_SR_RXRDY) ? 1 : 0);
+ len += sprintf(buf+len, "\n CDE: %d\n",(nStat & MPC5xxx_PSC_SR_CDE) ? 1 : 0);
+
+ }
+ return len;
+
+}
+static int sio_clear_err(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+
+ struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *) MPC5xxx_PSC1;
+
+ clear_err(psc);
+ return (int)count;
+}
+
+void clear_err(struct mpc5xxx_psc * psc)
+{
+ u8 byCmd;
+ u16 i;
+ unsigned int status, nBytes;
+
+ nBytes = in_be16(&psc->rfnum) & MPC5xxx_PSC_RFNUM_MASK;
+ for(i=0; i< nBytes;i++)
+ {
+ byCmd = in_8(&psc->mpc5xxx_psc_buffer_8);
+ rs_dprintk(MPC5xxx_PSC_DEBUG_CLEARERR,"loesche Byte %d von %d Bytes\n",i+1,nBytes);
+ }
+ status = in_be16(&psc->mpc5xxx_psc_status);
+ rs_dprintk(MPC5xxx_PSC_DEBUG_CLEARERR,"status Start %d\n",status);
+ byCmd = (u8) MPC5xxx_PSC_RST_ERR_STAT;
+ out_8(&psc->command, byCmd);
+ wmb();
+ status = in_be16(&psc->mpc5xxx_psc_status);
+ rmb();
+ rs_dprintk(MPC5xxx_PSC_DEBUG_CLEARERR,"status clear %d\n",status);
+}
+
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: AW: MPC5200,PSC in uart mode, receiving problem
2005-10-11 8:10 ` AW: " Achim Machura
@ 2006-02-02 18:22 ` Frank Bodammer
0 siblings, 0 replies; 5+ messages in thread
From: Frank Bodammer @ 2006-02-02 18:22 UTC (permalink / raw)
To: Linuxppc-Embedded
[-- Attachment #1: Type: text/plain, Size: 1145 bytes --]
Achim Machura wrote:
> Here the patch
>
>
>>Even better, post a patch here on the list so we all can benefit.
I experienced similar problems with the serial ports on mpc5200 PSCs
and so i was happy to find your patch, which solved some problem, but
not all. The overrun flag still wasn´t reset after an input overrun
error, so this error was reported persistent for each received character.
I fixed this by adding an command to reset the psc error flags in
receive_char() where the overrun flag is checked. Maybe this isn't
the best solution, but it seems to work.
To reset the overrun error flag, i tried the following statement:
out_8(&psc->command, MPC5xxx_PSC_RST_ERR_STAT);
but i got unpredictable behaviour in some cases ending in a reset.
Doing the same this way:
psc->command = MPC5xxx_PSC_RST_ERR_STAT;
always worked as expected. Does someone know what may be wrong with
'out_8' on mpc5200 with kernel 2.4.25 or is that a configuration problem.
By the way, i improved some other parts of the code, especially the
/proc output and the portconfig stuff, so i also attach a patch here,
even not all of it may be useful.
Frank
[-- Attachment #2: patch_linuxppc_2_4_psc-060202.diff --]
[-- Type: text/plain, Size: 18129 bytes --]
--- psc-orig.c 2006-02-02 10:41:45.000000000 +0100
+++ psc.c 2006-02-02 17:30:59.000000000 +0100
@@ -29,6 +29,7 @@
#include <linux/serial.h>
#include <linux/serialP.h>
#include <linux/generic_serial.h>
+#include <linux/proc_fs.h>
#ifdef CONFIG_UBOOT
#include <asm/ppcboot.h>
#endif
@@ -37,7 +38,8 @@
* This driver can spew a whole lot of debugging output at you. If you
* need maximum performance, you should disable the DEBUG define.
*/
-#undef MPC5xxx_PSC_DEBUG
+#undef MPC5xxx_PSC_DEBUG
+//#define MPC5xxx_PSC_DEBUG 1
#ifdef MPC5xxx_PSC_DEBUG
#define MPC5xxx_PSC_DEBUG_OPEN 0x00000001
@@ -55,6 +57,7 @@
#define MPC5xxx_PSC_DEBUG_FIRMWARE 0x00001000
#define MPC5xxx_PSC_DEBUG_MEMTEST 0x00002000
#define MPC5xxx_PSC_DEBUG_THROTTLE 0x00004000
+#define MPC5xxx_PSC_DEBUG_CLEARERR 0x00008000
#define MPC5xxx_PSC_DEBUG_ALL 0xffffffff
int rs_debug = MPC5xxx_PSC_DEBUG_ALL & ~MPC5xxx_PSC_DEBUG_TRANSMIT;
@@ -73,7 +76,7 @@
/*
* Number of serial ports
*/
-#define MPC5xxx_PSC_NPORTS 3
+#define MPC5xxx_PSC_NPORTS 4
#ifdef CONFIG_PPC_5xxx_PSC_CONSOLE
#ifndef CONFIG_PPC_5xxx_PSC_CONSOLE_PORT
@@ -89,7 +92,7 @@
/*
* Hardware specific serial port structure
*/
-struct rs_port {
+struct rs_port {
struct gs_port gs; /* Must be first field! */
struct mpc5xxx_psc *psc;
@@ -121,7 +124,7 @@
/*
* Used by generic serial driver to access hardware
*/
-static struct real_driver rs_real_driver = {
+static struct real_driver rs_real_driver = {
.disable_tx_interrupts = rs_disable_tx_interrupts,
.enable_tx_interrupts = rs_enable_tx_interrupts,
.disable_rx_interrupts = rs_disable_rx_interrupts,
@@ -134,9 +137,15 @@
.hungup = rs_hungup,
};
+#ifdef CONFIG_PS2MULT
+struct serial_state rs_table[RS_TABLE_SIZE] = {
+ SERIAL_PORT_DFNS /* Defined in serial.h */
+};
+#else
static struct serial_state rs_table[RS_TABLE_SIZE] = {
SERIAL_PORT_DFNS /* Defined in serial.h */
};
+#endif
/*
* Structures and such for TTY sessions and usage counts
@@ -151,6 +160,14 @@
int rs_initialized = 0;
/*
+ * proc stuff
+ */
+static int sio_read_info(char * buf, char ** start, off_t offset, int count, int *eof, void * data);
+
+static struct proc_dir_entry *proc_psc_dir,
+ *proc_psc[MPC5xxx_PSC_NPORTS];
+
+/*
* ----------------------------------------------------------------------
*
* Here starts the interrupt handling routines. All of the following
@@ -180,11 +197,11 @@
/* While there are characters, get them ... */
while (--count >= 0) {
- status = in_be16(&psc->mpc5xxx_psc_status);
+ status = psc->mpc5xxx_psc_status;
if (!(status & MPC5xxx_PSC_SR_RXRDY))
break;
- ch = in_8(&psc->mpc5xxx_psc_buffer_8);
+ ch = psc->mpc5xxx_psc_buffer_8;
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
continue;
@@ -215,6 +232,9 @@
tty->flip.count++;
}
*tty->flip.flag_buf_ptr = TTY_OVERRUN;
+ rs_dprintk(MPC5xxx_PSC_DEBUG_RECEIVE, "reset psc overrun error status: 0x%04x\n", status);
+ /* Reset PSC error status */
+ psc->command = MPC5xxx_PSC_RST_ERR_STAT;
}
}
@@ -234,7 +254,7 @@
/* While I'm able to transmit ... */
while (--count >= 0) {
- status = in_be16(&psc->mpc5xxx_psc_status);
+ status = psc->mpc5xxx_psc_status;
/*
* XXX -df
* check_modem_status(status);
@@ -243,7 +263,7 @@
break;
if (port->x_char) {
- out_8(&psc->mpc5xxx_psc_buffer_8, port->x_char);
+ psc->mpc5xxx_psc_buffer_8 = port->x_char;
port->icount.tx++;
port->x_char = 0;
}
@@ -252,8 +272,7 @@
break;
}
else {
- out_8(&psc->mpc5xxx_psc_buffer_8,
- port->gs.xmit_buf[port->gs.xmit_tail++]);
+ psc->mpc5xxx_psc_buffer_8 = port->gs.xmit_buf[port->gs.xmit_tail++];
port->icount.tx++;
port->gs.xmit_tail &= SERIAL_XMIT_SIZE-1;
if (--port->gs.xmit_cnt <= 0) {
@@ -266,7 +285,7 @@
port->gs.tty->hw_stopped) {
rs_disable_tx_interrupts(port);
}
-
+
if (port->gs.xmit_cnt <= port->gs.wakeup_chars) {
if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
port->gs.tty->ldisc.write_wakeup)
@@ -275,7 +294,7 @@
"Waking up.... ldisc (%d)....\n",
port->gs.wakeup_chars);
wake_up_interruptible(&port->gs.tty->write_wait);
- }
+ }
}
@@ -294,19 +313,35 @@
static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
- struct rs_port * port;
+ struct rs_port * port = (struct rs_port *)dev_id;
+ struct mpc5xxx_psc *psc = port->psc;
unsigned long flags;
+ u16 status;
spin_lock_irqsave(&mpc5xxx_serial_lock, flags);
- port = (struct rs_port *)dev_id;
rs_dprintk(MPC5xxx_PSC_DEBUG_INTERRUPTS,
"rs_interrupt (port %p)...", port);
+ if (!port || !port->gs.tty) {
+ printk( KERN_DEBUG"%s(%d): port=%p tty=%p\n", __FUNCTION__, __LINE__,
+ port, port?port->gs.tty:NULL );
+ goto out;
+ }
+
+ status = psc->mpc5xxx_psc_status;
+ /* RB-Bit is set ? */
+ if (status & MPC5xxx_PSC_SR_RB)
+ {
+ rs_dprintk(MPC5xxx_PSC_DEBUG_INTERRUPTS, "reset psc error status: 0x%04x\n", status);
+ psc->command = MPC5xxx_PSC_RST_ERR_STAT;
+ goto out;
+ }
+
receive_char(port);
transmit_char(port);
-
+out:
spin_unlock_irqrestore(&mpc5xxx_serial_lock, flags);
rs_dprintk(MPC5xxx_PSC_DEBUG_INTERRUPTS, "end.\n");
@@ -318,7 +353,7 @@
* interface with the generic_serial driver *
************************************************************************
*/
-static void rs_disable_tx_interrupts(void * ptr)
+static void rs_disable_tx_interrupts(void *ptr)
{
struct rs_port *port = ptr;
struct mpc5xxx_psc *psc = port->psc;
@@ -328,7 +363,7 @@
port->gs.flags &= ~GS_TX_INTEN;
port->imr &= ~MPC5xxx_PSC_IMR_TXRDY;
- out_be16(&psc->mpc5xxx_psc_imr, port->imr);
+ psc->mpc5xxx_psc_imr = port->imr;
spin_unlock_irqrestore(&mpc5xxx_serial_lock, flags);
}
@@ -342,7 +377,7 @@
spin_lock_irqsave(&mpc5xxx_serial_lock, flags);
port->imr |= MPC5xxx_PSC_IMR_TXRDY;
- out_be16(&psc->mpc5xxx_psc_imr, port->imr);
+ psc->mpc5xxx_psc_imr = port->imr;
/* Send a char to start TX interrupts happening */
transmit_char(port);
@@ -359,7 +394,8 @@
spin_lock_irqsave(&mpc5xxx_serial_lock, flags);
port->imr &= ~MPC5xxx_PSC_IMR_RXRDY;
- out_be16(&psc->mpc5xxx_psc_imr, port->imr);
+ psc->mpc5xxx_psc_imr = port->imr;
+ rs_dprintk(MPC5xxx_PSC_DEBUG_RECEIVE,"disable RxInt\n");
spin_unlock_irqrestore(&mpc5xxx_serial_lock, flags);
}
@@ -373,18 +409,10 @@
spin_lock_irqsave(&mpc5xxx_serial_lock, flags);
port->imr |= MPC5xxx_PSC_IMR_RXRDY;
- out_be16(&psc->mpc5xxx_psc_imr, port->imr);
-
- /* Empty the input buffer - apparently this is *vital* */
- /*
- * XXXX add this back in if needed, -df
- *
- * while (in_be16(&psc->mpc5xxx_psc_status) & MPC5xxx_PSC_SR_RXRDY)
- * in_8(&psc->mpc5xxx_psc_buffer_8);
- */
+ psc->mpc5xxx_psc_imr = port->imr;
+ rs_dprintk(MPC5xxx_PSC_DEBUG_RECEIVE,"enable RxInt\n");
spin_unlock_irqrestore(&mpc5xxx_serial_lock, flags);
-
}
static int rs_get_CD(void * ptr)
@@ -394,7 +422,7 @@
func_enter();
func_exit();
- return (in_8(&port->psc->mpc5xxx_psc_ipcr) & MPC5xxx_PSC_DCD) != 0;
+ return (port->psc->mpc5xxx_psc_ipcr & MPC5xxx_PSC_DCD) != 0;
}
static void rs_shutdown_port(void * ptr)
@@ -432,34 +460,67 @@
divisor = ((port->gs.baud_base / (port->gs.baud * 16)) + 1) >> 1;
if (port->gs.baud < 50 || divisor == 0) {
- printk(KERN_NOTICE "MPC5xxx PSC: Bad speed requested, %d\n",
- port->gs.baud);
+ printk(KERN_NOTICE "MPC5xxx PSC: Bad speed requested, %d, %d\n",
+ port->gs.baud, divisor);
return 0;
}
/* Configure the PSC for UART mode */
line = minor(port->gs.tty->device) - port->gs.tty->driver.minor_start;
+
+#if 0
+ /* This works only for PSC1..PSC3 and assumes that the ports are assigned */
+ /* in this order. In other configurations it affects functions like usb */
+ /* or ethernet. It isn't needed, when portconfig is done by the bootloader */
val32 = in_be32(&gpio->port_config);
val32 |= (MPC5xxx_GPIO_PSC_CONFIG_UART_WITHOUT_CD << (4*line));
out_be32(&gpio->port_config, val32);
+#else
+ switch ((int) port->psc) {
+ case MPC5xxx_PSC1: {
+ rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS, "Setup portconfig for PSC1\n");
+ gpio->port_config |= MPC5xxx_GPIO_PSC_CONFIG_UART_WITHOUT_CD;
+ break;
+ }
+ case MPC5xxx_PSC2: {
+ rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS, "Setup portconfig for PSC2\n");
+ gpio->port_config |= (MPC5xxx_GPIO_PSC_CONFIG_UART_WITHOUT_CD << 4);
+ break;
+ }
+ case MPC5xxx_PSC3: {
+ rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS, "Setup portconfig for PSC3\n");
+ gpio->port_config |= (MPC5xxx_GPIO_PSC_CONFIG_UART_WITHOUT_CD << 8);
+ break;
+ }
+ case MPC5xxx_PSC4: {
+ rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS, "Setup portconfig for PSC4\n");
+ break;
+ }
+ case MPC5xxx_PSC5: {
+ rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS, "Setup portconfig for PSC5\n");
+ break;
+ }
+ case MPC5xxx_PSC6: {
+ rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS, "Setup portconfig for PSC6\n");
+ break;
+ }
+ }
+#endif
+
/* reset and enable PSC */
- out_8(&psc->command, MPC5xxx_PSC_RST_TX
- | MPC5xxx_PSC_RX_DISABLE | MPC5xxx_PSC_TX_ENABLE);
- out_8(&psc->command, MPC5xxx_PSC_RST_RX);
+ psc->command = MPC5xxx_PSC_RST_TX | MPC5xxx_PSC_TX_ENABLE;
+
/* Set PSC operation mode as 'UART, DCD ignored' */
- out_be32(&psc->sicr, 0x0);
+ psc->sicr = 0x0;
/* Set clocking */
- out_be16(&psc->mpc5xxx_psc_clock_select, 0xdd00);
+ psc->mpc5xxx_psc_clock_select = 0xdd00;
/* Set tx FIFO alarm level */
- out_be16(&psc->tfalarm, 0xf8);
+ psc->tfalarm = 0xf8;
/* Put PSC into the operation */
- out_8(&psc->command, MPC5xxx_PSC_SEL_MODE_REG_1
- | MPC5xxx_PSC_RX_ENABLE
- | MPC5xxx_PSC_TX_ENABLE);
-
- rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS, "calculated divisor: %d\n",
- divisor);
- out_8(&psc->ctur, divisor>>8);
- out_8(&psc->ctlr, divisor);
+ psc->command = MPC5xxx_PSC_SEL_MODE_REG_1 | MPC5xxx_PSC_RX_ENABLE | MPC5xxx_PSC_TX_ENABLE;
+
+ rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS, "calculated divisor: %d\n", divisor);
+ psc->ctur = divisor >> 8;
+ psc->ctlr = divisor;
/* Program hardware for parity, data bits, stop bits */
if ((CFLAG & CSIZE)==CS5)
@@ -496,19 +557,20 @@
rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS,
"baud_base: %d\n", port->gs.baud_base);
#ifdef MPC5xxx_PSC_DEBUG
- if (rs_debug & MPC5xxx_PSC_DEBUG_TERMIOS)
- out_8(&psc->command, MPC5xxx_PSC_SEL_MODE_REG_1);
+ if (rs_debug & MPC5xxx_PSC_DEBUG_TERMIOS) {
+ psc->command = MPC5xxx_PSC_SEL_MODE_REG_1;
+ }
#endif
rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS,
"mode 1 register was: %08x, now: %08x\n",
- in_8(&psc->mode), mode1);
+ psc->mode, mode1);
rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS,
"mode 2 register was: %08x, now: %08x\n",
- in_8(&psc->mode), mode2);
+ psc->mode, mode2);
- out_8(&psc->command, MPC5xxx_PSC_SEL_MODE_REG_1);
- out_8(&psc->mode, mode1);
- out_8(&psc->mode, mode2);
+ psc->command = MPC5xxx_PSC_SEL_MODE_REG_1;
+ psc->mode = mode1;
+ psc->mode = mode2;
func_exit();
return 0;
@@ -539,7 +601,7 @@
line = minor(tty->device) - tty->driver.minor_start;
rs_dprintk(MPC5xxx_PSC_DEBUG_OPEN,
- "%d: opening line %d. tty=%p ctty=%p)\n",
+ "%d: opening line %d. tty=%p ctty=%p)\n",
(int) current->pid, line, tty, current->tty);
if ((line < 0) || (line >= RS_TABLE_SIZE))
@@ -728,7 +790,7 @@
#endif
func_enter();
-
+
if (I_IXOFF(tty)) {
if (port->x_char)
port->x_char = 0;
@@ -763,6 +825,7 @@
static int rs_init_portstructs(void)
{
struct rs_port *port;
+ struct mpc5xxx_psc *psc;
int i;
#ifdef CONFIG_UBOOT
extern unsigned char __res[];
@@ -789,7 +852,7 @@
rs_driver.termios_locked = rs_termios_locked;
port = rs_ports;
- for (i=0; i < MPC5xxx_PSC_NPORTS;i++) {
+ for (i = 0; i < MPC5xxx_PSC_NPORTS; i++) {
rs_dprintk(MPC5xxx_PSC_DEBUG_INIT, "initing port %d\n", i);
port->gs.callout_termios = tty_std_termios;
port->gs.normal_termios = tty_std_termios;
@@ -813,6 +876,8 @@
#endif
rs_dprintk(MPC5xxx_PSC_DEBUG_INIT, "psc base 0x%08lx\n",
(unsigned long)port->psc);
+ psc = port->psc;
+ psc->command = MPC5xxx_PSC_RST_ERR_STAT;
port++;
}
@@ -822,7 +887,9 @@
static int rs_init_drivers(void)
{
- int error;
+ struct rs_port *port;
+ char proc_psc_name[8];
+ int i, error;
func_enter();
@@ -878,6 +945,19 @@
return 1;
}
+ /* Create /proc entries */
+ proc_psc_dir = proc_mkdir("driver/psc_mpc52xx", NULL);
+ if (proc_psc_dir != NULL) {
+ for (i=0; i < MPC5xxx_PSC_NPORTS; i++) {
+ sprintf(proc_psc_name, "ttyS%1d", i);
+ proc_psc[i] = create_proc_entry(proc_psc_name, 0444, proc_psc_dir);
+ proc_psc[i]->read_proc = sio_read_info;
+ proc_psc[i]->write_proc = NULL;
+ proc_psc[i]->data = &rs_ports[i];
+ proc_psc[i]->owner = THIS_MODULE;
+ }
+ }
+
func_exit();
return 0;
}
@@ -888,6 +968,7 @@
int rc;
int i;
struct rs_port *port;
+ char name[6];
func_enter();
rs_dprintk(MPC5xxx_PSC_DEBUG_INIT,
@@ -896,20 +977,29 @@
rc = rs_init_portstructs();
rs_init_drivers();
port = rs_ports;
- for (i=0; i < MPC5xxx_PSC_NPORTS;i++) {
- rs_disable_rx_interrupts(port);
- rs_disable_tx_interrupts(port);
+ for (i=0; i < MPC5xxx_PSC_NPORTS; i++) {
+ rs_disable_rx_interrupts(port);
+ rs_disable_tx_interrupts(port);
+ switch ((int) port->psc) {
+ case MPC5xxx_PSC1: { sprintf(name, "PSC1"); break; }
+ case MPC5xxx_PSC2: { sprintf(name, "PSC2"); break; }
+ case MPC5xxx_PSC3: { sprintf(name, "PSC3"); break; }
+ case MPC5xxx_PSC4: { sprintf(name, "PSC4"); break; }
+ case MPC5xxx_PSC5: { sprintf(name, "PSC5"); break; }
+ case MPC5xxx_PSC6: { sprintf(name, "PSC6"); break; }
+ default: { sprintf(name, "PSC?"); break; }
+ }
+
if (request_irq(port->irq, rs_interrupt,
SA_SHIRQ | SA_INTERRUPT, "serial", port)) {
- printk(KERN_ERR
- "rs: Cannot allocate irq for PSC%d.\n", i+1);
+ printk(KERN_ERR "rs: Cannot allocate irq for %s (ttyS%d).\n", name, i);
rc = 0;
continue;
}
rs_dprintk(MPC5xxx_PSC_DEBUG_INIT,
"requested irq for port[%d] = %08x\n",
i, (u32)port);
- printk(KERN_INFO "ttyS%d on PSC%d\n", i, i+1);
+ printk(KERN_INFO "ttyS%d on %s\n", i, name);
port++;
}
@@ -940,25 +1030,27 @@
/*
* Turn PSC interrupts off
*/
- out_be16(&psc->mpc5xxx_psc_imr, 0);
+ psc->mpc5xxx_psc_imr = 0;
/*
* Wait for the Tx register to become empty
*/
i = BUSY_WAIT;
- while (!(in_be16(&psc->mpc5xxx_psc_status) & MPC5xxx_PSC_SR_TXEMP) &&
- i--)
+ while (!(psc->mpc5xxx_psc_status & MPC5xxx_PSC_SR_TXEMP) && i--) {
udelay(1);
- out_8(&psc->mpc5xxx_psc_buffer_8, c);
+ }
+
+ psc->mpc5xxx_psc_buffer_8 = c;
+
i = BUSY_WAIT;
- while (!(in_be16(&psc->mpc5xxx_psc_status) & MPC5xxx_PSC_SR_TXEMP) &&
- i--)
+ while (!(psc->mpc5xxx_psc_status & MPC5xxx_PSC_SR_TXEMP) && i--) {
udelay(1);
+ }
/*
* Turn PSC interrupts back on
*/
- out_be16(&psc->mpc5xxx_psc_imr, port->imr);
+ psc->mpc5xxx_psc_imr = port->imr;
}
static void serial_console_write(struct console *co, const char *s,
@@ -1050,17 +1142,14 @@
break;
}
- out_8(&psc->command, MPC5xxx_PSC_RST_TX
- | MPC5xxx_PSC_RX_DISABLE | MPC5xxx_PSC_TX_ENABLE);
- out_8(&psc->command, MPC5xxx_PSC_RST_RX);
-
- out_be32(&psc->sicr, 0x0);
- out_be16(&psc->mpc5xxx_psc_clock_select, 0xdd00);
- out_be16(&psc->tfalarm, 0xf8);
-
- out_8(&psc->command, MPC5xxx_PSC_SEL_MODE_REG_1
- | MPC5xxx_PSC_RX_ENABLE
- | MPC5xxx_PSC_TX_ENABLE);
+ psc->command = MPC5xxx_PSC_RST_TX | MPC5xxx_PSC_RX_DISABLE | MPC5xxx_PSC_TX_ENABLE;
+ psc->command = MPC5xxx_PSC_RST_RX;
+
+ psc->sicr = 0x0;
+ psc->mpc5xxx_psc_clock_select = 0xdd00;
+ psc->tfalarm = 0xf8;
+
+ psc->command = MPC5xxx_PSC_SEL_MODE_REG_1 | MPC5xxx_PSC_RX_ENABLE | MPC5xxx_PSC_TX_ENABLE;
#ifdef CONFIG_UBOOT
divisor = ((bd->bi_ipbfreq / (baud * 16)) + 1) >> 1; /* round up */
@@ -1071,11 +1160,11 @@
mode1 = bits | parity | MPC5xxx_PSC_MODE_ERR;
mode2 = MPC5xxx_PSC_MODE_ONE_STOP;
- out_8(&psc->ctur, divisor>>8);
- out_8(&psc->ctlr, divisor);
- out_8(&psc->command, MPC5xxx_PSC_SEL_MODE_REG_1);
- out_8(&psc->mode, mode1);
- out_8(&psc->mode, mode2);
+ psc->ctur = divisor >> 8;
+ psc->ctlr = divisor;
+ psc->command = MPC5xxx_PSC_SEL_MODE_REG_1;
+ psc->mode = mode1;
+ psc->mode = mode2;
return 0;
}
@@ -1095,3 +1184,51 @@
}
#endif
+
+static int sio_read_info(char *buf, char **start, off_t offset, int count, int *eof, void *data)
+{
+ struct rs_port *port;
+ struct mpc5xxx_psc *psc;
+ u16 nStat;
+ int len = 0;
+
+ port = (struct rs_port *) data;
+ psc = port->psc;
+ nStat = psc->mpc5xxx_psc_status;
+
+ switch ((int) psc) {
+ case MPC5xxx_PSC1: { len += sprintf(buf+len, "PSC1: "); break; }
+ case MPC5xxx_PSC2: { len += sprintf(buf+len, "PSC2: "); break; }
+ case MPC5xxx_PSC3: { len += sprintf(buf+len, "PSC3: "); break; }
+ case MPC5xxx_PSC4: { len += sprintf(buf+len, "PSC4: "); break; }
+ case MPC5xxx_PSC5: { len += sprintf(buf+len, "PSC5: "); break; }
+ case MPC5xxx_PSC6: { len += sprintf(buf+len, "PSC6: "); break; }
+ default: { len += sprintf(buf+len, "PSC?: "); break; }
+ }
+ len += sprintf(buf+len, "Baudrate=%d, ", port->baud);
+ len += sprintf(buf+len, "Flags=0x%04x, ", port->cflag);
+ len += sprintf(buf+len, "Status=0x%04x ", nStat);
+ len += sprintf(buf+len, "Irq=%d, ", port->irq);
+ len += sprintf(buf+len, "Base=0x%08x\n ", port->psc);
+ len += sprintf(buf+len, "RB:%d, ",(nStat & MPC5xxx_PSC_SR_RB) ? 1 : 0);
+ len += sprintf(buf+len, "FE:%d, ",(nStat & MPC5xxx_PSC_SR_FE) ? 1 : 0);
+ len += sprintf(buf+len, "PE:%d, ",(nStat & MPC5xxx_PSC_SR_PE) ? 1 : 0);
+ len += sprintf(buf+len, "OR:%d, ",(nStat & MPC5xxx_PSC_SR_OE) ? 1 : 0);
+ len += sprintf(buf+len, "TxEMP:%d, ",(nStat & MPC5xxx_PSC_SR_TXEMP) ? 1 : 0);
+ len += sprintf(buf+len, "TxRDY:%d, ",(nStat & MPC5xxx_PSC_SR_TXRDY) ? 1 : 0);
+ len += sprintf(buf+len, "RXFULL:%d, ",(nStat & MPC5xxx_PSC_SR_RXFULL) ? 1 : 0);
+ len += sprintf(buf+len, "RxRDY:%d, ",(nStat & MPC5xxx_PSC_SR_RXRDY) ? 1 : 0);
+ len += sprintf(buf+len, "CDE:%d\n",(nStat & MPC5xxx_PSC_SR_CDE) ? 1 : 0);
+
+ if (len <= offset + count)
+ *eof = 1;
+ *start = buf + offset;
+ len -= offset;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
+
+ return len;
+}
+
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2006-02-02 18:43 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-10-10 11:37 MPC5200,PSC in uart mode, receiving problem Tomasz Prochownik
2005-10-10 13:13 ` AW: " Achim Machura
2005-10-10 18:38 ` Wolfgang Denk
-- strict thread matches above, loose matches on Subject: below --
2005-10-11 7:18 Wolfgang Denk
2005-10-11 8:10 ` AW: " Achim Machura
2006-02-02 18:22 ` Frank Bodammer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).