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