Subject: High serial port (output) speeds
To: None <port-sparc@netbsd.org>
From: der Mouse <mouse@Rodents.Montreal.QC.CA>
List: port-sparc
Date: 10/21/1999 23:20:26
I think I know why the zs chips are normally run with a X16 clock
divisor.  But is there any reason why they shouldn't run X1 if userland
requests a baudrate that can be achieved that way but not with X16?

Here's a proposed patch.  I invite comments.  "It works for me."  This
also fixes a bug I suspect is present if 2bps or 1bps is requested -
the computed tconst value is too large to fit in the registers but
otherwise correct, so the registers overflow and you get some other,
more or less random, baud rate.

With this patch you can in principle go as high as 1228800 baud, though
it's not clear that all the pieces involved can cooperate to pump out
that sort of data rate.

--- OLD/sys/arch/sparc/dev/zs.c	Thu Jan  1 00:00:00 1970
+++ NEW/sys/arch/sparc/dev/zs.c	Thu Jan  1 00:00:00 1970
@@ -534,7 +534,7 @@
 	struct zs_chanstate *cs;
 	int bps;	/* bits per second */
 {
-	int tconst, real_bps;
+	int tconst, clk, bits;
 
 	if (bps == 0)
 		return (0);
@@ -544,17 +544,32 @@
 		panic("zs_set_speed");
 #endif
 
-	tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps);
-	if (tconst < 0)
-		return (EINVAL);
-
-	/* Convert back to make sure we can do it. */
-	real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst);
-
-	/* XXX - Allow some tolerance here? */
-	if (real_bps != bps)
-		return (EINVAL);
+	/* Try to find a divisor we can do it with. */
+	/* Arguably we should try X64 and X32, but with X16 we can reach
+	   as low as 2.3437+ bps; just punt below that - after all, bps
+	   is an int, not the float it would more or less have to be to
+	   make sense at speeds that slow. */
+	clk = PCLK / 16;
+	bits = ZSWR4_CLK_X16;
+	tconst = BPS_TO_TCONST(PCLK/16, bps);
+	if (tconst > 65535)
+		return (EINVAL); /* Too slow! */
+	if ((tconst < 0) || (TCONST_TO_BPS(PCLK/16, tconst) != bps)) {
+		/* Too fast for PCLK/16, or not a baudrate it can do.
+		   Try with PCLK/1. */
+		tconst = BPS_TO_TCONST(PCLK, bps);
+		if ( (tconst < 0) || /* Still too fast! */
+		     (tconst > 65535) || /* Too slow for PCLK/1 - but
+					    not a baudrate PCLK/16 can do,
+					    or we wouldn't be here */
+		     (TCONST_TO_BPS(PCLK, tconst) != bps) ) /* No can do */
+			return (EINVAL);
+		clk = PCLK;
+		bits = ZSWR4_CLK_X1;
+	}
 
+	cs->cs_brg_clk = clk;
+	cs->cs_preg[4] = (cs->cs_preg[4] & ~ZSWR4_CLK_MASK) | bits;
 	cs->cs_preg[12] = tconst;
 	cs->cs_preg[13] = tconst >> 8;
 

					der Mouse

			       mouse@rodents.montreal.qc.ca
		     7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B