Date: Thu, 21 Aug 2003 19:09:22 -0700 (PDT) From: Marcel Moolenaar <marcel@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 36633 for review Message-ID: <200308220209.h7M29MLe049949@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=36633 Change 36633 by marcel@marcel_nfs on 2003/08/21 19:08:30 Flesh out the SAB driver some more: o Implement sab82532_delay() which returns the delay value of roughly 1/10th the time to send a character. For this we duplicate the BGR register in the TCR register, which is otherwise unused. The BGR register is write-only, so doesn't allow us to read the divisor from the chip. o Initialize the SCC in sab82532_init(). We do that when we initialize both channels even for the global registers. This is harmless, though redundant. o Implement sab82532_term(). We drop DTR. o Improve sab82532_putc(). o Implement sab82532_poll() in terms of sab82532_getc(). o Implement sab82532_getc(). This completes the console code. Affected files ... .. //depot/projects/uart/dev/uart/uart_dev_sab82532.c#9 edit Differences ... ==== //depot/projects/uart/dev/uart/uart_dev_sab82532.c#9 (text+ko) ==== @@ -42,7 +42,32 @@ #define DEFAULT_RCLK 29491200 +#define IS_CHANNEL_A(bas) (((bas)->bsh & 0x40) == 0x00) +#define IS_CHANNEL_B(bas) (((bas)->bsh & 0x40) == 0x40) + +/* + * NOTE: To allow us to read the baudrate divisor from the chip, we + * copy the value written to the write-only BGR register to an unused + * read-write register. We use TCR for that. + */ + static int +sab82532_delay(struct uart_bas *bas) +{ + int divisor, m, n; + uint8_t bgr, ccr2; + + bgr = uart_getreg(bas, SAB_TCR); + ccr2 = uart_getreg(bas, SAB_CCR2); + n = (bgr & 0x3f) + 1; + m = (bgr >> 6) | ((ccr2 >> 4) & 0xC); + divisor = n * (1<<m); + + /* 1/10th the time to transmit 1 character (estimate). */ + return (16000000 * divisor / bas->rclk); +} + +static int sab82532_divisor(int rclk, int baudrate) { int act_baud, act_div, divisor; @@ -110,6 +135,9 @@ return (EINVAL); uart_setreg(bas, SAB_BGR, divisor & 0xff); uart_barrier(bas); + /* Allow reading the (n-1,m) tuple from the chip. */ + uart_setreg(bas, SAB_TCR, divisor & 0xff); + uart_barrier(bas); ccr2 = uart_getreg(bas, SAB_CCR2); ccr2 &= ~(SAB_CCR2_BR9 | SAB_CCR2_BR8); ccr2 |= (divisor >> 2) & (SAB_CCR2_BR9 | SAB_CCR2_BR8); @@ -152,45 +180,95 @@ sab82532_init(struct uart_bas *bas, int baudrate, int databits, int stopbits, int parity) { + uint8_t pvr; if (bas->rclk == 0) bas->rclk = DEFAULT_RCLK; + + /* Set all pins, except DTR pins to be inputs. */ + uart_setreg(bas, SAB_PCR, ~(SAB_PVR_DTR_A | SAB_PVR_DTR_B)); + uart_barrier(bas); + /* Disable port interrupts */ + uart_setreg(bas, SAB_PIM, 0xff); + uart_barrier(bas); + /* Interrupts are active low. */ + uart_setreg(bas, SAB_IPC, SAB_IPC_ICPL); + uart_barrier(bas); + sab82532_param(bas, baudrate, databits, stopbits, parity); + + pvr = uart_getreg(bas, SAB_PVR); + pvr |= IS_CHANNEL_A(bas) ? SAB_PVR_DTR_A : SAB_PVR_DTR_B; + uart_setreg(bas, SAB_PVR, pvr); + uart_barrier(bas); } static void sab82532_term(struct uart_bas *bas) { + uint8_t pvr; + + pvr = uart_getreg(bas, SAB_PVR); + pvr &= IS_CHANNEL_A(bas) ? ~SAB_PVR_DTR_A : ~SAB_PVR_DTR_B; + uart_setreg(bas, SAB_PVR, pvr); + uart_barrier(bas); } static void sab82532_putc(struct uart_bas *bas, int c) { - int limit; + int delay, limit; + + /* 1/10th the time to transmit 1 character (estimate). */ + delay = sab82532_delay(bas); - limit = 500; - for (;;) { - if ((uart_getreg(bas, SAB_STAR) & SAB_STAR_TEC) == 0) - break; - if (--limit == 0) - break; - DELAY(100); - } + limit = 20; + while ((uart_getreg(bas, SAB_STAR) & SAB_STAR_TEC) && --limit) + DELAY(delay); uart_setreg(bas, SAB_TIC, c); + limit = 20; + while ((uart_getreg(bas, SAB_STAR) & SAB_STAR_TEC) && --limit) + DELAY(delay); } static int sab82532_poll(struct uart_bas *bas) { + if (uart_getreg(bas, SAB_STAR) & SAB_STAR_RFNE) + return (sab82532_getc(bas)); return (-1); } static int sab82532_getc(struct uart_bas *bas) { + int c, delay; + + /* 1/10th the time to transmit 1 character (estimate). */ + delay = sab82532_delay(bas); + + while (!(uart_getreg(bas, SAB_STAR) & SAB_STAR_RFNE)) + DELAY(delay); + while ((uart_getreg(bas, SAB_STAR) & SAB_STAR_CEC)) + DELAY(delay); + + uart_setreg(bas, SAB_CMDR, SAB_CMDR_RFRD); + uart_barrier(bas); + + while (!(uart_getreg(bas, SAB_ISR0) & SAB_ISR0_TCD)) + DELAY(delay); + + c = uart_getreg(bas, SAB_RFIFO); + uart_barrier(bas); + + /* Blow away everything left in the FIFO... */ + while ((uart_getreg(bas, SAB_STAR) & SAB_STAR_CEC)) + DELAY(delay); - return (-1); + uart_setreg(bas, SAB_CMDR, SAB_CMDR_RMC); + uart_barrier(bas); + return (c); } /* @@ -241,11 +319,6 @@ bas = &sc->sc_bas; - /* Set all pins, except DTR pins to be inputs */ - uart_setreg(bas, SAB_PCR, ~(SAB_PVR_DTR_A | SAB_PVR_DTR_B)); - /* Disable port interrupts */ - uart_setreg(bas, SAB_PIM, 0xff); - if (!sc->sc_console && !sc->sc_dbgport) sab82532_init(bas, 9600, 8, 1, UART_PARITY_NONE); @@ -307,7 +380,7 @@ return (error); /* Assume the address range is naturally aligned. */ - ch = ((sc->sc_bas.bsh & 0x40) == 0) ? "A" : "B"; + ch = IS_CHANNEL_A(&sc->sc_bas) ? "A" : "B"; switch (uart_getreg(&sc->sc_bas, SAB_VSTR) & SAB_VSTR_VMASK) { case SAB_VSTR_V_1: vstr = "v1"; break;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200308220209.h7M29MLe049949>