NS PC87338 support

Pavel Machek (pavel@bug.ucw.cz)
Fri, 16 Oct 1998 19:09:24 +0200


--mP3DRpeJDSE+ciuQ
Content-Type: text/plain; charset=us-ascii

Hi!

This is support for National Semiconductors PC87338. It allows serial
to operate at speeds up-to 1500000bps. I wonder if something like this
has chance to make it into mainstream kernel?

Pavel

PS: On my Thinkpad, I have to run attached program before trying to insert
module for ttyS0 to be detected properly. Seems like it is disabled by
default.

PPS: Are there known bugs in serial.c's usage counts? I've seen really
strange things like module usage cound == -1.

--- clean//drivers/char/serial.c Fri Sep 11 20:54:24 1998
+++ linux/drivers/char/serial.c Fri Oct 16 17:48:27 1998
@@ -32,6 +32,8 @@
* 4/98: Added changes to support the ARM architecture proposed by
* Russell King
*
+ * 10/98: Added support for NS PC87338. Pavel Machek <pavel@ucw.cz>
+ *
* This module exports the following rs232 io functions:
*
* int rs_init(void);
@@ -182,6 +185,7 @@
static void autoconfig(struct serial_state * info);
static void change_speed(struct async_struct *info);
static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
+static void pc87338_bank(struct async_struct *info, int bank);

/*
* Here we define the default xmit fifo size used for each type of
@@ -194,10 +198,12 @@
{ "16550", 1, 0 },
{ "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO },
{ "cirrus", 1, 0 },
- { "ST16650", 1, UART_CLEAR_FIFO |UART_STARTECH },
+ { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH },
{ "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
UART_STARTECH },
{ "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
+ { "startech/reserved", 1, 0 },
+ { "PC87338", 16, UART_CLEAR_FIFO | UART_USE_FIFO},
{ 0, 0}
};

@@ -1356,8 +1377,13 @@
(cflag & CRTSCTS) ? UART_EFR_CTS : 0);
}
serial_outp(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
+ if (info->state->type == PORT_PC87338) /* Use alternate registers in bank 2 */
+ pc87338_bank(info, 2);
serial_outp(info, UART_DLL, quot & 0xff); /* LS of divisor */
serial_outp(info, UART_DLM, quot >> 8); /* MS of divisor */
+ if (info->state->type == PORT_PC87338) /* And return back to bank 0 */
+ pc87338_bank(info, 0);
+
if (info->state->type == PORT_16750)
serial_outp(info, UART_FCR, fcr); /* set fcr */
serial_outp(info, UART_LCR, cval); /* reset DLAB */
@@ -2876,6 +2902,55 @@
return (irq > 0)? irq : 0;
}

+static void pc87338_bank(struct async_struct *info, int bank)
+{
+ if (bank>=2)
+ serial_out(info, 3, 0xe0 + ((bank-2) << 2));
+ else {
+ if (bank==1)
+ printk( "must not happen\n" );
+ else {
+ int i;
+
+ pc87338_bank(info, 3);
+ i = serial_in(info, 1);
+ if (i&0x80)
+ printk( "hopefully can not happen\n" );
+ serial_out(info, 3, i);
+ }
+ }
+}
+
+int pc87338_detect(struct async_struct *info)
+{
+ int i, j;
+ /* Detect PC87338 */
+
+ serial_out(info, 0xff);
+
+ pc87338_bank(info, 3);
+ i = serial_in(info, 0);
+ if ((i & 0xf0) == 0x20) {
+ printk( "revision %d", i&0x0f);
+ } else return 0;
+ printk( "." );
+ pc87338_bank(info, 2);
+ serial_out(info, 2, 0x40); /* 41==extended mode, 40==nonextended mode */
+ if (0 != (i=serial_in(info, 2))) {
+ printk( "%x", i );
+ return 0;
+ }
+
+ printk( "-" );
+ pc87338_bank(info, 2);
+ serial_out(info, 4, j = 0x35 ); /* TXSIZE=RXSIZE=32, Prescale=1.0, noLOCK */
+ if (j != (i=serial_in(info, 4)))
+ printk( "only 16 bytes FIFO?" );
+ printk( "." );
+ pc87338_bank(info, 0);
+ return 1;
+}
+
/*
* This routine is called by rs_init() to initialize a specific serial
* port. It determines what type of UART chip this serial port is
@@ -3002,14 +3108,21 @@
if ((status1 != 0xa5) || (status2 != 0x5a))
state->type = PORT_8250;
}
- state->xmit_fifo_size = uart_config[state->type].dfl_xmit_fifo_size;
-
+ if ((state->type == PORT_16550A) || (state->type == PORT_8250)) {
+ printk( "Detecting PC87338 at %x: ", info->port );
+ if (pc87338_detect(info)) {
+ state->type = PORT_PC87338;
+ state->baud_base = 1500000;
+ }
+ printk( "\n" );
+ }
if (state->type == PORT_UNKNOWN) {
restore_flags(flags);
return;
}

request_region(info->port,8,"serial(auto)");
+ state->xmit_fifo_size = uart_config[state->type].dfl_xmit_fifo_size;

/*
* Reset the UART.
--- clean//include/linux/serial.h Sat Apr 18 21:44:46 1998
+++ linux/include/linux/serial.h Wed Oct 14 22:25:41 1998
@@ -47,7 +47,8 @@
#define PORT_16650V2 7
#define PORT_16750 8
#define PORT_STARTECH 9
-#define PORT_MAX 9
+#define PORT_PC87338 10
+#define PORT_MAX 10

struct serial_uart_config {
char *name;
@@ -91,7 +92,7 @@
#define ASYNC_USR_MASK 0x3430 /* Legal flags that non-privileged
* users can set or reset */

-/* Internal flags used only by kernel/chr_drv/serial.c */
+/* Internal flags used only by drivers/char/serial.c */
#define ASYNC_INITIALIZED 0x80000000 /* Serial port was initialized */
#define ASYNC_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
#define ASYNC_NORMAL_ACTIVE 0x20000000 /* Normal device is active */

-- 
I'm really pavel@atrey.karlin.mff.cuni.cz. 	   Pavel
Look at http://atrey.karlin.mff.cuni.cz/~pavel/ ;-).
--mP3DRpeJDSE+ciuQ
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="port_ibm.c"

#include <asm/io.h>

void main(void) { int i,j; iopl(3); outb(0x08,0x2e); printf( "08: %x - ", i = inb(0x2f)); if ((i & 0xf8) == 0xb0) printf( "we have PCxxxxx\n" ); else printf( "PCxxxxx not detected\n" );

#if 0 outb(0x00,0x2e); outb(0x00,0x2f);

outb(0x01,0x2e); outb(0x10,0x2f);

outb(0x01,0x2e); printf( "01: %x ", i = inb(0x2f)); printf( "parport at %x, ttyS0 at %x, ttyS1 at %x\n", i & 3, (i >> 2) & 3, (i >> 4) & 3 );

outb(0x00,0x2e); printf( "00: %x ", i = inb(0x2f)); if (i & 1) printf( "parport enabled, " ); if (i & 2) printf( "ttyS0 enabled, " ); if (i & 4) printf( "ttyS1 enabled, " ); if (i & 8) printf( "FDC enabled, " ); if (i & 16) printf( "FDC fourport, " ); if (i & 32) printf( "FDC secondary, " ); printf( "\n" );

outb(0x00,0x2e); outb(0xcf,0x2f);

outb(0x00,0x2e); printf( "00: %x ", i = inb(0x2f)); if (i & 1) printf( "parport enabled, " ); if (i & 2) printf( "ttyS0 enabled, " ); if (i & 4) printf( "ttyS1 enabled, " ); if (i & 8) printf( "FDC enabled, " ); if (i & 16) printf( "FDC fourport, " ); if (i & 32) printf( "FDC secondary, " ); printf( "\n" ); #endif #if 0 outb(0x44,0x2e); i = inb(0x2f); outb(0x45,0x2e); j = inb(0x2f); printf( "44,45: %x <- location of ttyS0\n", (j << 8) | i );

outb(0x46,0x2e); i = inb(0x2f); outb(0x47,0x2e); j = inb(0x2f); printf( "46,47: %x <- location of ttyS1\n", (j << 8) | i ); #endif

#if 1 outb(0x40,0x2e); /* THIS IS MAGIC COMBINATION! */ outb(0xbc,0x2f); #endif outb(0x40,0x2e); printf( "40: %x - ", i = inb(0x2f)); if (i & 0x10) printf( "ttyS0 bank select enable, " ); if (i & 0x20) printf( "ttyS1 normal power, " ); if (i & 0x40) printf( "ttyS1 busy, " ); if (i & 0x80) printf( "ttyS1 bank select enable, " ); printf("\n");

outb(0x08,0x2e); printf( "08: %x - ", i = inb(0x2f)); if ((i & 0xf8) == 0xb0) printf( "we have PCxxxxx\n" ); else printf( "PCxxxxx not detected\n" ); }

--mP3DRpeJDSE+ciuQ--

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/