Commit b7e711ba authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] sh: Add H8/300 support to sh-sci

From: Paul Mundt <lethal@linux-sh.org>

This adds support for the H8/300 series to the sh-sci driver.  Patch from
Yoshinori Sato.
parent f4dd156e
/* $Id: sh-sci.c,v 1.15 2003/10/13 07:21:19 lethal Exp $
/* $Id: sh-sci.c,v 1.16 2004/02/10 17:04:17 lethal Exp $
*
* linux/drivers/char/sh-sci.c
*
......@@ -7,6 +7,7 @@
* Copyright (C) 2000 Sugioka Toshinobu
* Modified to support multiple serial ports. Stuart Menefy (May 2000).
* Modified to support SH7760 SCIF. Paul Mundt (Oct 2003).
* Modified to support H8/300 Series. Yoshinori Sato (Feb 2004).
*
* TTY code is based on sx.c (Specialix SX driver) by:
*
......@@ -337,6 +338,7 @@ static struct real_driver sci_real_driver = {
NULL
};
#if !defined(__H8300H__) && !defined(__H8300S__)
#if defined(SCI_ONLY) || defined(SCI_AND_SCIF)
static void sci_init_pins_sci(struct sci_port* port, unsigned int cflag)
{
......@@ -403,6 +405,32 @@ static void sci_init_pins_scif(struct sci_port* port, unsigned int cflag)
#endif
#endif /* SCIF_ONLY || SCI_AND_SCIF */
#else /* !defined(__H8300H__) && !defined(__H8300S__) */
static void sci_init_pins_sci(struct sci_port* port, unsigned int cflag)
{
int ch = (port->base - SMR0) >> 3;
/* set DDR regs */
H8300_GPIO_DDR(h8300_sci_pins[ch].port,h8300_sci_pins[ch].rx,H8300_GPIO_INPUT);
H8300_GPIO_DDR(h8300_sci_pins[ch].port,h8300_sci_pins[ch].tx,H8300_GPIO_OUTPUT);
/* tx mark output*/
H8300_SCI_DR(ch) |= h8300_sci_pins[ch].tx;
}
#if defined(__H8300S__)
enum {sci_disable,sci_enable};
static void h8300_sci_enable(struct sci_port* port, unsigned int ctrl)
{
volatile unsigned char *mstpcrl=(volatile unsigned char *)MSTPCRL;
int ch = (port->base - SMR0) >> 3;
unsigned char mask = 1 << (ch+1);
if (ctrl == sci_disable)
*mstpcrl |= mask;
else
*mstpcrl &= ~mask;
}
#endif
#endif
static void sci_setsignals(struct sci_port *port, int dtr, int rts)
{
......@@ -487,9 +515,11 @@ static void sci_set_termios_cflag(struct sci_port *port, int cflag, int baud)
sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */
#if !defined(SCI_ONLY)
if (port->type == PORT_SCIF) {
sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
}
#endif
smr_val = sci_in(port, SCSMR) & 3;
if ((cflag & CSIZE) == CS7)
......@@ -559,11 +589,15 @@ static void sci_transmit_chars(struct sci_port *port)
while (1) {
count = port->gs.xmit_cnt;
#if !defined(SCI_ONLY)
if (port->type == PORT_SCIF) {
txroom = 16 - (sci_in(port, SCFDR)>>8);
} else {
txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0;
}
#else
txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0;
#endif
if (count > txroom)
count = txroom;
......@@ -600,10 +634,12 @@ static void sci_transmit_chars(struct sci_port *port)
ctrl &= ~SCI_CTRL_FLAGS_TIE;
port->gs.flags &= ~GS_TX_INTEN;
} else {
#if !defined(SCI_ONLY)
if (port->type == PORT_SCIF) {
sci_in(port, SCxSR); /* Dummy read */
sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
}
#endif
ctrl |= SCI_CTRL_FLAGS_TIE;
}
sci_out(port, SCSCR, ctrl);
......@@ -627,11 +663,15 @@ static inline void sci_receive_chars(struct sci_port *port,
tty = port->gs.tty;
while (1) {
#if !defined(SCI_ONLY)
if (port->type == PORT_SCIF) {
count = sci_in(port, SCFDR)&0x001f;
} else {
count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0;
}
#else
count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0;
#endif
/* Don't copy more bytes than there is room for in the buffer */
if (tty->flip.count + count > TTY_FLIPBUF_SIZE)
......@@ -861,6 +901,7 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs)
return IRQ_HANDLED;
}
#if !defined(SCI_ONLY)
static irqreturn_t sci_br_interrupt(int irq, void *ptr, struct pt_regs *regs)
{
struct sci_port *port = ptr;
......@@ -871,6 +912,7 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr, struct pt_regs *regs)
return IRQ_HANDLED;
}
#endif
static void do_softint(void *private_)
{
......@@ -955,11 +997,15 @@ static int sci_chars_in_buffer(void * ptr)
{
struct sci_port *port = ptr;
#if !defined(SCI_ONLY)
if (port->type == PORT_SCIF) {
return (sci_in(port, SCFDR) >> 8) + ((sci_in(port, SCxSR) & SCxSR_TEND(port))? 0: 1);
} else {
return (sci_in(port, SCxSR) & SCxSR_TEND(port))? 0: 1;
}
#else
return (sci_in(port, SCxSR) & SCxSR_TEND(port))? 0: 1;
#endif
}
static void sci_shutdown_port(void * ptr)
......@@ -970,6 +1016,9 @@ static void sci_shutdown_port(void * ptr)
if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL)
sci_setsignals(port, 0, 0);
sci_free_irq(port);
#if defined(__H8300S__)
h8300_sci_enable(port,sci_disable);
#endif
}
/* ********************************************************************** *
......@@ -996,6 +1045,10 @@ static int sci_open(struct tty_struct * tty, struct file * filp)
port->event = 0;
INIT_WORK(&port->tqueue, do_softint, port);
#if defined(__H8300S__)
h8300_sci_enable(port,sci_enable);
#endif
/*
* Start up serial port
*/
......@@ -1282,12 +1335,17 @@ static int sci_init_drivers(void)
static int sci_request_irq(struct sci_port *port)
{
int i;
#if !defined(SCI_ONLY)
irqreturn_t (*handlers[4])(int irq, void *p, struct pt_regs *regs) = {
sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt,
sci_br_interrupt,
};
for (i=0; i<4; i++) {
#else
void (*handlers[3])(int irq, void *ptr, struct pt_regs *regs) = {
sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt,
};
#endif
for (i=0; i<(sizeof(handlers)/sizeof(handlers[0])); i++) {
if (!port->irqs[i]) continue;
if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT,
"sci", port)) {
......@@ -1432,6 +1490,9 @@ static int __init serial_console_setup(struct console *co, char *options)
co->cflag = cflag;
sercons_baud = baud;
#if defined(__H8300S__)
h8300_sci_enable(sercons_port,sci_enable);
#endif
sci_set_termios_cflag(sercons_port, cflag, baud);
sercons_port->old_cflag = cflag;
......
/* $Id: sh-sci.h,v 1.6 2003/10/13 01:11:11 lethal Exp $
/* $Id: sh-sci.h,v 1.7 2004/02/10 17:04:17 lethal Exp $
*
* linux/drivers/char/sh-sci.h
*
......@@ -7,10 +7,21 @@
* Copyright (C) 2000 Greg Banks
* Modified to support multiple serial ports. Stuart Menefy (May 2000).
* Modified to support SH7760 SCIF. Paul Mundt (Oct 2003).
* Modified to support H8/300 Serise Yoshinori Sato (Feb 2004).
*
*/
#include <linux/config.h>
#if defined(__H8300H__) || defined(__H8300S__)
#include <asm/gpio.h>
#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
#include <asm/regs306x.h>
#endif
#if defined(CONFIG_H8S2678)
#include <asm/regs267x.h>
#endif
#endif
/* Values for sci_port->type */
#define PORT_SCI 0
#define PORT_SCIF 1
......@@ -30,6 +41,12 @@
#define SH7760_SCIF0_IRQS { 52, 53, 55, 54 }
#define SH7760_SCIF1_IRQS { 72, 73, 75, 74 }
#define SH7760_SCIF2_IRQS { 76, 77, 79, 78 }
#define H8300H_SCI_IRQS0 {52, 53, 54, 0 }
#define H8300H_SCI_IRQS1 {56, 57, 58, 0 }
#define H8300H_SCI_IRQS2 {60, 61, 62, 0 }
#define H8S_SCI_IRQS0 {88, 89, 90, 0 }
#define H8S_SCI_IRQS1 {92, 93, 94, 0 }
#define H8S_SCI_IRQS2 {96, 97, 98, 0 }
#if defined(CONFIG_CPU_SUBTYPE_SH7708)
# define SCI_NPORTS 1
......@@ -87,6 +104,26 @@
# define SCIF_ORER 0x0001 /* overrun error bit */
# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
# define SCIF_ONLY
#elif defined(CONFIG_H83007) || defined(CONFIG_H83068)
# define SCI_NPORTS 3
# define SCI_INIT { \
{ {}, PORT_SCI, 0x00ffffb0, H8300H_SCI_IRQS0, sci_init_pins_sci }, \
{ {}, PORT_SCI, 0x00ffffb8, H8300H_SCI_IRQS1, sci_init_pins_sci }, \
{ {}, PORT_SCI, 0x00ffffc0, H8300H_SCI_IRQS2, sci_init_pins_sci } \
}
# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
# define SCI_ONLY
# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
#elif defined(CONFIG_H8S2678)
# define SCI_NPORTS 3
# define SCI_INIT { \
{ {}, PORT_SCI, 0x00ffff78, H8S_SCI_IRQS0, sci_init_pins_sci }, \
{ {}, PORT_SCI, 0x00ffff80, H8S_SCI_IRQS1, sci_init_pins_sci }, \
{ {}, PORT_SCI, 0x00ffff88, H8S_SCI_IRQS2, sci_init_pins_sci } \
}
# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
# define SCI_ONLY
# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
#else
# error CPU subtype not defined
#endif
......@@ -242,28 +279,46 @@ struct sci_port {
SCI_OUT(scif_size, scif_offset, value); \
}
#define CPU_SCI_FNS(name, sci_offset, sci_size) \
static inline unsigned int sci_##name##_in(struct sci_port* port) \
{ \
SCI_IN(sci_size, sci_offset); \
} \
static inline void sci_##name##_out(struct sci_port* port, unsigned int value) \
{ \
SCI_OUT(sci_size, sci_offset, value); \
}
#ifdef CONFIG_CPU_SH3
#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
h8_sci_offset, h8_sci_size) \
CPU_SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh3_scif_offset, sh3_scif_size)
#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size)
#elif defined(__H8300H__) || defined(__H8300S__)
#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
h8_sci_offset, h8_sci_size) \
CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size)
#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size)
#else
#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
h8_sci_offset, h8_sci_size) \
CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
#endif
/* reg SCI/SH3 SCI/SH4 SCIF/SH3 SCIF/SH4 */
/* name off sz off sz off sz off sz */
SCIx_FNS(SCSMR, 0x00, 8, 0x00, 8, 0x00, 8, 0x00, 16)
SCIx_FNS(SCBRR, 0x02, 8, 0x04, 8, 0x02, 8, 0x04, 8)
SCIx_FNS(SCSCR, 0x04, 8, 0x08, 8, 0x04, 8, 0x08, 16)
SCIx_FNS(SCxTDR, 0x06, 8, 0x0c, 8, 0x06, 8, 0x0C, 8)
SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16)
SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8)
/* reg SCI/SH3 SCI/SH4 SCIF/SH3 SCIF/SH4 SCI/H8*/
/* name off sz off sz off sz off sz off sz*/
SCIx_FNS(SCSMR, 0x00, 8, 0x00, 8, 0x00, 8, 0x00, 16, 0x00, 8)
SCIx_FNS(SCBRR, 0x02, 8, 0x04, 8, 0x02, 8, 0x04, 8, 0x01, 8)
SCIx_FNS(SCSCR, 0x04, 8, 0x08, 8, 0x04, 8, 0x08, 16, 0x02, 8)
SCIx_FNS(SCxTDR, 0x06, 8, 0x0c, 8, 0x06, 8, 0x0C, 8, 0x03, 8)
SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16, 0x04, 8)
SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8, 0x05, 8)
SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16)
SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16)
SCIF_FNS(SCLSR, 0, 0, 0x24, 16)
......@@ -271,6 +326,50 @@ SCIF_FNS(SCLSR, 0, 0, 0x24, 16)
#define sci_in(port, reg) sci_##reg##_in(port)
#define sci_out(port, reg, value) sci_##reg##_out(port, value)
/* H8/300 series SCI pins assignment */
#if defined(__H8300H__) || defined(__H8300S__)
static const struct __attribute__((packed))
{
int port; /* GPIO port no */
unsigned short rx,tx; /* GPIO bit no */
} h8300_sci_pins[] =
{
#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
{ /* SCI0 */
.port = H8300_GPIO_P9,
.rx = H8300_GPIO_B2,
.tx = H8300_GPIO_B0,
},
{ /* SCI1 */
.port = H8300_GPIO_P9,
.rx = H8300_GPIO_B3,
.tx = H8300_GPIO_B1,
},
{ /* SCI2 */
.port = H8300_GPIO_PB,
.rx = H8300_GPIO_B7,
.tx = H8300_GPIO_B6,
}
#elif defined(CONFIG_H8S2678)
{ /* SCI0 */
.port = H8300_GPIO_P3,
.rx = H8300_GPIO_B2,
.tx = H8300_GPIO_B0,
},
{ /* SCI1 */
.port = H8300_GPIO_P3,
.rx = H8300_GPIO_B3,
.tx = H8300_GPIO_B1,
},
{ /* SCI2 */
.port = H8300_GPIO_P5,
.rx = H8300_GPIO_B1,
.tx = H8300_GPIO_B0,
}
#endif
};
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7708)
static inline int sci_rxd_in(struct sci_port *port)
{
......@@ -321,6 +420,12 @@ static inline int sci_rxd_in(struct sci_port *port)
return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */
}
#elif defined(__H8300H__) || defined(__H8300S__)
static inline int sci_rxd_in(struct sci_port *port)
{
int ch = (port->base - SMR0) >> 3;
return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0;
}
#endif
/*
......@@ -357,7 +462,11 @@ static inline int sci_rxd_in(struct sci_port *port)
#define PCLK (current_cpu_data.module_clock)
#if !defined(__H8300H__) && !defined(__H8300S__)
#define SCBRR_VALUE(bps) ((PCLK+16*bps)/(32*bps)-1)
#else
#define SCBRR_VALUE(bps) (((CONFIG_CPU_CLOCK*1000/32)/bps)-1)
#endif
#define BPS_2400 SCBRR_VALUE(2400)
#define BPS_4800 SCBRR_VALUE(4800)
#define BPS_9600 SCBRR_VALUE(9600)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment