PERFORCE change 36633 for review
Marcel Moolenaar
marcel at FreeBSD.org
Thu Aug 21 19:09:25 PDT 2003
http://perforce.freebsd.org/chv.cgi?CH=36633
Change 36633 by marcel at 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;
More information about the p4-projects
mailing list