summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arch/arm/s3c2xx0/sscom.c163
1 files changed, 110 insertions, 53 deletions
diff --git a/sys/arch/arm/s3c2xx0/sscom.c b/sys/arch/arm/s3c2xx0/sscom.c
index 97283348844..c21d576a819 100644
--- a/sys/arch/arm/s3c2xx0/sscom.c
+++ b/sys/arch/arm/s3c2xx0/sscom.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sscom.c,v 1.6 2008/12/24 07:46:15 drahn Exp $ */
+/* $OpenBSD: sscom.c,v 1.7 2008/12/30 07:02:34 drahn Exp $ */
/* $NetBSD: sscom.c,v 1.29 2008/06/11 22:37:21 cegger Exp $ */
/*
@@ -178,16 +178,15 @@ void sscom_rxsoft (struct sscom_softc *, struct tty *);
void sscom_stsoft (struct sscom_softc *, struct tty *);
void sscom_schedrx (struct sscom_softc *);
-static void sscom_modem(struct sscom_softc *, int);
-static void sscom_break(struct sscom_softc *, int);
-static void sscom_iflush(struct sscom_softc *);
-static void sscom_hwiflow(struct sscom_softc *);
-static void sscom_loadchannelregs(struct sscom_softc *);
+void sscom_modem(struct sscom_softc *, int);
+void sscom_break(struct sscom_softc *, int);
+void sscom_iflush(struct sscom_softc *);
+void sscom_hwiflow(struct sscom_softc *);
+void sscom_loadchannelregs(struct sscom_softc *);
static void tiocm_to_sscom(struct sscom_softc *, u_long, int);
static int sscom_to_tiocm(struct sscom_softc *);
static void tiocm_to_sscom(struct sscom_softc *, u_long, int);
static int sscom_to_tiocm(struct sscom_softc *);
-static void sscom_iflush(struct sscom_softc *);
static int sscomhwiflow(struct tty *tp, int block);
int sscom_init(bus_space_tag_t, const struct sscom_uart_info *,
@@ -308,7 +307,7 @@ __sscom_output_chunk(struct sscom_softc *sc, int ufstat)
if (cnt != 0) {
cnt = q_to_b(&tp->t_outq, buffer, cnt);
for (tptr = buffer; tptr < &buffer[cnt]; tptr ++) {
- bus_space_write_1(iot, ioh, SSCOM_UTXH, *tptr);
+ bus_space_write_4(iot, ioh, SSCOM_UTXH, *tptr);
}
}
@@ -318,7 +317,7 @@ __sscom_output_chunk(struct sscom_softc *sc, int ufstat)
void
sscom_output_chunk(struct sscom_softc *sc)
{
- int ufstat = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SSCOM_UFSTAT);
+ int ufstat = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSCOM_UFSTAT);
if (!(ufstat & UFSTAT_TXFULL))
__sscom_output_chunk(sc, ufstat);
@@ -331,6 +330,9 @@ sscomspeed(long speed, long frequency)
int x, err;
+ if (speed == 115200 && frequency == 100000000)
+ return 0x1a;
+
if (speed <= 0)
return -1;
x = divrnd(frequency / 16, speed);
@@ -355,8 +357,8 @@ void
sscomstatus(struct sscom_softc *sc, const char *str)
{
struct tty *tp = sc->sc_tty;
- int umstat = bus_space_read_1(sc->sc_iot, sc->sc_iot, SSCOM_UMSTAT);
- int umcon = bus_space_read_1(sc->sc_iot, sc->sc_iot, SSCOM_UMCON);
+ int umstat = bus_space_read_4(sc->sc_iot, sc->sc_iot, SSCOM_UMSTAT);
+ int umcon = bus_space_read_4(sc->sc_iot, sc->sc_iot, SSCOM_UMCON);
printf("%s: %s %sclocal %sdcd %sts_carr_on %sdtr %stx_stopped\n",
sc->sc_dev.dv_xname, str,
@@ -388,7 +390,7 @@ sscom_enable_debugport(struct sscom_softc *sc)
s = splserial();
SSCOM_LOCK(sc);
sc->sc_ucon = UCON_DEBUGPORT;
- bus_space_write_2(sc->sc_iot, sc->sc_ioh, SSCOM_UCON, sc->sc_ucon);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSCOM_UCON, sc->sc_ucon);
sc->sc_umcon = UMCON_RTS|UMCON_DTR;
sc->set_modem_control(sc);
sscom_enable_rxint(sc);
@@ -402,7 +404,7 @@ static void
sscom_set_modem_control(struct sscom_softc *sc)
{
/* flob RTS */
- bus_space_write_1(sc->sc_iot, sc->sc_ioh,
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh,
SSCOM_UMCON, sc->sc_umcon & UMCON_HW_MASK);
/* ignore DTR */
}
@@ -412,7 +414,7 @@ sscom_read_modem_status(struct sscom_softc *sc)
{
int msts;
- msts = bus_space_read_1(sc->sc_iot, sc->sc_ioh, SSCOM_UMSTAT);
+ msts = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSCOM_UMSTAT);
/* DCD and DSR are always on */
return (msts & UMSTAT_CTS) | MSTS_DCD | MSTS_DSR;
@@ -470,11 +472,11 @@ sscom_attach_subr(struct sscom_softc *sc)
sc->sc_ucon = UCON_DEBUGPORT;
}
- bus_space_write_1(iot, ioh, SSCOM_UFCON,
+ bus_space_write_4(iot, ioh, SSCOM_UFCON,
UFCON_TXTRIGGER_8|UFCON_RXTRIGGER_8|UFCON_FIFO_ENABLE|
UFCON_TXFIFO_RESET|UFCON_RXFIFO_RESET);
- bus_space_write_1(iot, ioh, SSCOM_UCON, sc->sc_ucon);
+ bus_space_write_4(iot, ioh, SSCOM_UCON, sc->sc_ucon);
#ifdef KGDB
if (ISSET(sc->sc_hwflags, SSCOM_HW_KGDB)) {
@@ -625,7 +627,7 @@ sscom_shutdown(struct sscom_softc *sc)
sc->sc_ucon = UCON_DEBUGPORT;
else
sc->sc_ucon = 0;
- bus_space_write_2(sc->sc_iot, sc->sc_ioh, SSCOM_UCON, sc->sc_ucon);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSCOM_UCON, sc->sc_ucon);
#ifdef DIAGNOSTIC
if (!sc->enabled)
@@ -680,9 +682,6 @@ sscomopen(dev_t dev, int flag, int mode, struct proc *p)
s2 = splserial();
SSCOM_LOCK(sc);
- /* Turn on interrupts. */
- sscom_enable_txrxint(sc);
-
/* Fetch the current modem control status, needed later. */
sc->sc_msts = sc->read_modem_status(sc);
@@ -723,6 +722,8 @@ sscomopen(dev_t dev, int flag, int mode, struct proc *p)
s2 = splserial();
SSCOM_LOCK(sc);
+ sscom_loadchannelregs(sc);
+
/*
* Turn on DTR. We must always do this, even if carrier is not
* present, because otherwise we'd have to use TIOCSDTR
@@ -742,6 +743,10 @@ sscomopen(dev_t dev, int flag, int mode, struct proc *p)
if (sscom_debug)
sscomstatus(sc, "sscomopen ");
+ /* Turn on interrupts. */
+ sscom_enable_txrxint(sc);
+
+
SSCOM_UNLOCK(sc);
splx(s2);
}
@@ -988,7 +993,7 @@ sscom_schedrx(struct sscom_softc *sc)
#endif
}
-static void
+void
sscom_break(struct sscom_softc *sc, int onoff)
{
@@ -1007,7 +1012,7 @@ sscom_break(struct sscom_softc *sc, int onoff)
}
}
-static void
+void
sscom_modem(struct sscom_softc *sc, int onoff)
{
if (onoff)
@@ -1089,6 +1094,12 @@ sscom_to_tiocm(struct sscom_softc *sc)
return ttybits;
}
+void pr(char *, ...);
+void
+pr(char *arg, ...)
+{
+}
+
static int
cflag2lcr(tcflag_t cflag)
{
@@ -1118,6 +1129,7 @@ cflag2lcr(tcflag_t cflag)
}
if (ISSET(cflag, CSTOPB))
SET(lcr, ULCON_STOP);
+ pr (" lcr %x %d %d %d \n", lcr, cflag & (PARENB|PARODD), ISSET(cflag, CSIZE), CS8);
return lcr;
}
@@ -1274,7 +1286,7 @@ sscomparam(struct tty *tp, struct termios *t)
return 0;
}
-static void
+void
sscom_iflush(struct sscom_softc *sc)
{
bus_space_tag_t iot = sc->sc_iot;
@@ -1292,7 +1304,7 @@ sscom_iflush(struct sscom_softc *sc)
#endif
}
-static void
+void
sscom_loadchannelregs(struct sscom_softc *sc)
{
bus_space_tag_t iot = sc->sc_iot;
@@ -1301,12 +1313,12 @@ sscom_loadchannelregs(struct sscom_softc *sc)
/* XXXXX necessary? */
sscom_iflush(sc);
- bus_space_write_2(iot, ioh, SSCOM_UCON, 0);
+ bus_space_write_4(iot, ioh, SSCOM_UCON, 0);
- bus_space_write_2(iot, ioh, SSCOM_UBRDIV, sc->sc_ubrdiv);
- bus_space_write_1(iot, ioh, SSCOM_ULCON, sc->sc_ulcon);
+ bus_space_write_4(iot, ioh, SSCOM_UBRDIV, sc->sc_ubrdiv);
+ bus_space_write_4(iot, ioh, SSCOM_ULCON, sc->sc_ulcon);
sc->set_modem_control(sc);
- bus_space_write_2(iot, ioh, SSCOM_UCON, sc->sc_ucon);
+ bus_space_write_4(iot, ioh, SSCOM_UCON, sc->sc_ucon);
}
static int
@@ -1350,7 +1362,7 @@ sscomhwiflow(struct tty *tp, int block)
/*
* (un)block input via hw flowcontrol
*/
-static void
+void
sscom_hwiflow(struct sscom_softc *sc)
{
if (sc->sc_mcr_rts == 0)
@@ -1546,7 +1558,7 @@ sscom_rxsoft(struct sscom_softc *sc, struct tty *tp)
CLR(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
sscom_enable_rxint(sc);
sc->sc_ucon |= UCON_ERRINT;
- bus_space_write_2(sc->sc_iot, sc->sc_ioh, SSCOM_UCON,
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSCOM_UCON,
sc->sc_ucon);
}
@@ -1656,7 +1668,7 @@ sscomrxintr(void *arg)
uint16_t ufstat;
uint8_t utrstat, uerstat;
- ufstat = bus_space_read_2(iot, ioh, SSCOM_UFSTAT);
+ ufstat = bus_space_read_4(iot, ioh, SSCOM_UFSTAT);
/* XXX: break interrupt with no character? */
@@ -1701,7 +1713,7 @@ sscomrxintr(void *arg)
cc--;
}
- ufstat = bus_space_read_2(iot, ioh, SSCOM_UFSTAT);
+ ufstat = bus_space_read_4(iot, ioh, SSCOM_UFSTAT);
if ( (ufstat & (UFSTAT_RXFULL|UFSTAT_RXCOUNT)) == 0 )
break;
}
@@ -1735,13 +1747,13 @@ sscomrxintr(void *arg)
SET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
sscom_disable_rxint(sc);
sc->sc_ucon &= ~UCON_ERRINT;
- bus_space_write_2(iot, ioh, SSCOM_UCON, sc->sc_ucon);
+ bus_space_write_4(iot, ioh, SSCOM_UCON, sc->sc_ucon);
}
}
#else
- utrstat = bus_space_read_2(iot, ioh, SSCOM_UTRSTAT);
+ utrstat = bus_space_read_4(iot, ioh, SSCOM_UTRSTAT);
if (utrstat & UTRSTAT_RXREADY) {
- uerstat = bus_space_read_1((iot), (ioh), SSCOM_UERSTAT);
+ uerstat = bus_space_read_4((iot), (ioh), SSCOM_UERSTAT);
if (uerstat & UERSTAT_BREAK) {
#if defined(DDB)
if (db_console)
@@ -1751,15 +1763,15 @@ sscomrxintr(void *arg)
}
/* xxx overflow */
- put[0] = bus_space_read_1((iot), (ioh),
- SSCOM_URXH);
+ put[0] = bus_space_read_4((iot), (ioh),
+ SSCOM_URXH) & 0xff;
put[1] = uerstat;
put += 2;
if (put >= end)
put = sc->sc_rbuf;
cc--;
next:
- ufstat = bus_space_read_2(iot, ioh, SSCOM_UFSTAT);
+ ufstat = bus_space_read_4(iot, ioh, SSCOM_UFSTAT);
}
/*
* Current string of incoming characters ended because
@@ -1790,7 +1802,7 @@ next:
SET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
sscom_disable_rxint(sc);
sc->sc_ucon &= ~UCON_ERRINT;
- bus_space_write_2(iot, ioh, SSCOM_UCON, sc->sc_ucon);
+ bus_space_write_4(iot, ioh, SSCOM_UCON, sc->sc_ucon);
}
#endif
if (sc->sc_rbput != put) {
@@ -1927,7 +1939,7 @@ sscomtxintr(void *arg)
SSCOM_LOCK(sc);
- ufstat = bus_space_read_2(iot, ioh, SSCOM_UFSTAT);
+ ufstat = bus_space_read_4(iot, ioh, SSCOM_UFSTAT);
/*
* If we've delayed a parameter change, do it
@@ -1990,6 +2002,31 @@ sscomtxintr(void *arg)
return 1;
}
+int inited0;
+uint32_t init_ulcon;
+uint32_t init_ucon;
+uint32_t init_ufcon;
+uint32_t init_umcon;
+uint32_t init_utrstat;
+uint32_t init_uerstat;
+uint32_t init_ufstat;
+uint32_t init_umstat;
+uint32_t init_ubrdiv;
+
+void sscom_dump_init_state(void);
+void
+sscom_dump_init_state()
+{
+ printf("init_ulcon %x", init_ulcon);
+ printf("init_ucon %x", init_ucon);
+ printf("init_ufcon %x", init_ufcon);
+ printf("init_umcon %x", init_umcon);
+ printf("init_utrstat %x", init_utrstat);
+ printf("init_uerstat %x", init_uerstat);
+ printf("init_ufstat %x", init_ufstat);
+ printf("init_umstat %x", init_umstat);
+ printf("init_ubrdiv %x", init_ubrdiv);
+}
#if defined(KGDB) || defined(SSCOM0CONSOLE) || defined(SSCOM1CONSOLE)
/*
@@ -2001,25 +2038,45 @@ sscom_init(bus_space_tag_t iot, const struct sscom_uart_info *config,
{
bus_space_handle_t ioh;
bus_addr_t iobase = config->iobase;
+ uint32_t ufcon;
if (bus_space_map(iot, iobase, SSCOM_SIZE, 0, &ioh))
return ENOMEM; /* ??? */
- bus_space_write_2(iot, ioh, SSCOM_UCON, 0);
- bus_space_write_1(iot, ioh, SSCOM_UFCON,
+ if (inited0 == 0) {
+ init_ulcon = bus_space_read_4(iot, ioh, SSCOM_ULCON);
+ init_ucon = bus_space_read_4(iot, ioh, SSCOM_UCON);
+ init_ufcon = bus_space_read_4(iot, ioh, SSCOM_UFCON);
+ init_umcon = bus_space_read_4(iot, ioh, SSCOM_UMCON);
+ init_utrstat = bus_space_read_4(iot, ioh, SSCOM_UTRSTAT);
+ init_uerstat = bus_space_read_4(iot, ioh, SSCOM_UERSTAT);
+ init_ufstat = bus_space_read_4(iot, ioh, SSCOM_UFSTAT);
+ init_umstat = bus_space_read_4(iot, ioh, SSCOM_UMSTAT);
+ init_ubrdiv = bus_space_read_4(iot, ioh, SSCOM_UBRDIV);
+ }
+
+
+ bus_space_write_4(iot, ioh, SSCOM_UCON, 0);
+ bus_space_write_4(iot, ioh, SSCOM_UFCON,
UFCON_TXTRIGGER_8 | UFCON_RXTRIGGER_8 |
UFCON_TXFIFO_RESET | UFCON_RXFIFO_RESET |
UFCON_FIFO_ENABLE );
/* tx/rx fifo reset are auto-cleared */
+ /* wait for fifo reset to complete */
+ do {
+ ufcon = bus_space_read_4(iot, ioh, SSCOM_UFCON);
+ } while (ufcon & (UFCON_TXFIFO_RESET | UFCON_RXFIFO_RESET));
+
+
rate = sscomspeed(rate, frequency);
- bus_space_write_2(iot, ioh, SSCOM_UBRDIV, rate);
- bus_space_write_2(iot, ioh, SSCOM_ULCON, cflag2lcr(cflag));
+ bus_space_write_4(iot, ioh, SSCOM_UBRDIV, rate);
+ bus_space_write_4(iot, ioh, SSCOM_ULCON, cflag2lcr(cflag));
/* enable UART */
- bus_space_write_2(iot, ioh, SSCOM_UCON,
+ bus_space_write_4(iot, ioh, SSCOM_UCON,
UCON_TXMODE_INT|UCON_RXMODE_INT);
- bus_space_write_2(iot, ioh, SSCOM_UMCON, UMCON_RTS);
+ bus_space_write_4(iot, ioh, SSCOM_UMCON, UMCON_RTS);
*iohp = ioh;
return 0;
@@ -2036,13 +2093,13 @@ struct consdev sscomcons = {
NODEV, CN_HIGHPRI
};
-
int
sscom_cnattach(bus_space_tag_t iot, const struct sscom_uart_info *config,
int rate, int frequency, tcflag_t cflag)
{
int res;
+
res = sscom_init(iot, config, rate, frequency, cflag, &sscomconsioh);
if (res)
return res;
@@ -2143,17 +2200,17 @@ sscomcnputc(dev_t dev, int c)
/* wait for any pending transmission to finish */
timo = 150000;
- while (ISSET(bus_space_read_2(sscomconstag, sscomconsioh, SSCOM_UFSTAT),
+ while (ISSET(bus_space_read_4(sscomconstag, sscomconsioh, SSCOM_UFSTAT),
UFSTAT_TXFULL) && --timo)
continue;
- bus_space_write_1(sscomconstag, sscomconsioh, SSCOM_UTXH, c);
+ bus_space_write_4(sscomconstag, sscomconsioh, SSCOM_UTXH, c);
SSCOM_BARRIER(sscomconstag, sscomconsioh, BR | BW);
#if 0
/* wait for this transmission to complete */
timo = 1500000;
- while (!ISSET(bus_space_read_1(sscomconstag, sscomconsioh, SSCOM_UTRSTAT),
+ while (!ISSET(bus_space_read_4(sscomconstag, sscomconsioh, SSCOM_UTRSTAT),
UTRSTAT_TXEMPTY) && --timo)
continue;
#endif
@@ -2217,17 +2274,17 @@ sscom_kgdb_putc(void *arg, int c)
/* wait for any pending transmission to finish */
timo = 150000;
- while (ISSET(bus_space_read_2(sscom_kgdb_iot, sscom_kgdb_ioh,
+ while (ISSET(bus_space_read_4(sscom_kgdb_iot, sscom_kgdb_ioh,
SSCOM_UFSTAT), UFSTAT_TXFULL) && --timo)
continue;
- bus_space_write_1(sscom_kgdb_iot, sscom_kgdb_ioh, SSCOM_UTXH, c);
+ bus_space_write_4(sscom_kgdb_iot, sscom_kgdb_ioh, SSCOM_UTXH, c);
SSCOM_BARRIER(sscom_kgdb_iot, sscom_kgdb_ioh, BR | BW);
#if 0
/* wait for this transmission to complete */
timo = 1500000;
- while (!ISSET(bus_space_read_1(sscom_kgdb_iot, sscom_kgdb_ioh,
+ while (!ISSET(bus_space_read_4(sscom_kgdb_iot, sscom_kgdb_ioh,
SSCOM_UTRSTAT), UTRSTAT_TXEMPTY) && --timo)
continue;
#endif