> Date: Fri, 06 Feb 2026 13:11:00 +0100
> From: Mark Kettenis <[email protected]>
> 
> > Date: Fri, 6 Feb 2026 12:57:36 +0100
> > From: Alexandr Nedvedicky <[email protected]>
> > 
> > Hello,
> > 
> > On Fri, Feb 06, 2026 at 12:20:20PM +0100, Mark Kettenis wrote:
> > </snip>
> > > 
> > > What device are you using to connect to the serial port?  OpenBSD does
> > 
> >     taking better look at drawing here [1] my device is actually 
> > NanoPC-T6LTS
> >     on the right hand side there is USB-C(Debug-UART) label. So this what
> >     I'm using for console. I connect using USB A-to-C. According to dmesg
> >     the device reports itself as:
> > 
> > uchcom0 at uhub4 port 1 configuration 1 interface 0 "QinHeng Electronics 
> > USB Serial" rev 1.10/2.64 addr 4
> > uchcom0: CH341
> > ucom0 at uchcom0: usb0.2.00001.0
> > 
> >     Trying to increasing the speed I'm seeing this error:
> > 
> >     lifty# cu -l  usb0.2.00001.0 -s 1500000 
> >     cu: tcsetattr: Invalid argument
> > 
> >     I'm using USB A-to-C cable (~20cm long) plugged to USB-A port
> >     directly in my T-14. Not sure if it is cable or driver. I will
> >     try to dig more details later today. May be will try my luck
> >     with USB C-to-C
> 
> Definitely the driver.  I'll have a look.

Can you try this diff?

Index: dev/usb/uchcom.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uchcom.c,v
diff -u -p -r1.40 uchcom.c
--- dev/usb/uchcom.c    18 Nov 2025 00:33:16 -0000      1.40
+++ dev/usb/uchcom.c    6 Feb 2026 13:30:29 -0000
@@ -83,10 +83,6 @@ int  uchcomdebug = 0;
 
 #define UCHCOM_VER_20          0x20
 
-#define UCHCOM_BASE_UNKNOWN    0
-#define UCHCOM_BPS_MOD_BASE    20000000
-#define UCHCOM_BPS_MOD_BASE_OFS        1100
-
 #define UCHCOM_BPS_PRE_IMM     0x80    /* CH341: immediate RX forwarding */
 
 #define UCHCOM_DTR_MASK                0x20
@@ -152,6 +148,21 @@ struct uchcom_endpoints {
        int             ep_intr_size;
 };
 
+struct uchcom_divider
+{
+       uint8_t         dv_prescaler;
+       uint8_t         dv_div;
+};
+
+/* 0,1,2,3,7 are prescale factors for given 4x 12000000 clock formula */
+static const uint32_t rates4x[8] = {
+       [0] = 4 * 12000000 / 1024,
+       [1] = 4 * 12000000 / 128,
+       [2] = 4 * 12000000 / 16,
+       [3] = 4 * 12000000 / 2,
+       [7] = 4 * 12000000,
+};
+
 void           uchcom_get_status(void *, int, u_char *, u_char *);
 void           uchcom_set(void *, int, int, int);
 int            uchcom_param(void *, int, struct termios *);
@@ -634,52 +645,86 @@ uchcom_set_break_ch343(struct uchcom_sof
        return 0;
 }
 
-void
-uchcom_calc_baudrate(struct uchcom_softc *sc, uint32_t rate, uint8_t *divisor,
-    uint8_t *factor)
+int
+uchcom_calc_divider_settings(struct uchcom_divider *dp, uint32_t rate)
 {
-       uint32_t clk = 12000000;
+/*
+ * combined with rates4x[] defined above, this routine generates,
+ *   1200: prescale = 1/0x1, divisor = 178/0xb2
+ *   2400: prescale = 1/0x1, divisor = 217/0xd9
+ *   4800: prescale = 2/0x2, divisor = 100/0x64
+ *   9600: prescale = 2/0x2, divisor = 178/0xb2
+ *  19200: prescale = 2/0x2, divisor = 217/0xd9
+ *  38400: prescale = 3/0x3, divisor = 100/0x64
+ *  57600: prescale = 2/0x2, divisor = 243/0xf3
+ * 115200: prescale = 3/0x3, divisor = 204/0xcc
+ * 921600: prescale = 7/0x7, divisor = 243/0xf3
+ * 500000: prescale = 3/0x3, divisor = 244/0xf4
+ * 1000000: prescale = 3/0x3, divisor = 250/0xfa
+ * 1500000: prescale = 3/0x3, divisor = 252/0xfc
+ * 2000000: prescale = 3/0x3, divisor = 253/0xfd
+ * 2500000: unsupported
+ * 3000000: prescale = 3/0x3, divisor = 254/0xfe
+ */
+       size_t i;
+       uint32_t best, div, pre;
+       const uint32_t rate4x = rate * 4U;
 
-       if (rate == 921600 || rate == 4000000)
-               *divisor = 7;
-       else if (rate > 23529) {
-               clk /= 2;
-               *divisor = 3;
-       } else if (rate > 2941) {
-               clk /=  16;
-               *divisor = 2;
-       } else if (rate > 367) {
-               clk /= 128;
-               *divisor = 1;
-       } else {
-               clk = 11719;
-               *divisor = 0;
+       if (rate == 0 || rate > 3000000)
+               return -1;
+
+       pre = nitems(rates4x);
+       best = UINT32_MAX;
+
+       for (i = 0; i < nitems(rates4x); i++) {
+               uint32_t score, try;
+               try = rates4x[i] * 2 / rate4x;
+               try = (try / 2) + (try & 1);
+               if (try < 2)
+                       continue;
+               if (try > 255)
+                       try = 255;
+               score = abs((int)rate4x - rates4x[i] / try);
+               if (score < best) {
+                       best = score;
+                       pre = i;
+                       div = try;
+               }
        }
 
-       if (rate == 921600 && sc->sc_type != UCHCOM_TYPE_CH343)
-               *factor = 243;
-       else
-               *factor = 256 - clk / rate;
+       if (pre >= nitems(rates4x))
+               return -1;
+       if ((rates4x[pre] / div / 4) < (rate * 99 / 100))
+               return -1;
+       if ((rates4x[pre] / div / 4) > (rate * 101 / 100))
+               return -1;
+
+       dp->dv_prescaler = pre;
+       dp->dv_div = 256 - div;
+
+       return 0;
 }
 
 int
 uchcom_set_dte_rate(struct uchcom_softc *sc, uint32_t rate, uint16_t val)
 {
        usbd_status err;
+       struct uchcom_divider dv;
        uint16_t idx;
-       uint8_t factor, div;
 
-       uchcom_calc_baudrate(sc, rate, &div, &factor);
+       if (uchcom_calc_divider_settings(&dv, rate))
+               return EINVAL;
 
        if (sc->sc_type != UCHCOM_TYPE_CH343) {
-               if ((err = uchcom_write_reg(sc,
-                   UCHCOM_REG_BPS_PRE, div | 0x80,
-                   UCHCOM_REG_BPS_DIV, factor)) ||
-                   (err = uchcom_write_reg(sc, UCHCOM_REG_LCR, val >> 8,
+               if ((err = uchcom_write_reg(sc, UCHCOM_REG_BPS_PRE,
+                   dv.dv_prescaler | UCHCOM_BPS_PRE_IMM,
+                   UCHCOM_REG_BPS_DIV, dv.dv_div)))
+                       goto failed;
+               if ((err = uchcom_write_reg(sc, UCHCOM_REG_LCR, val >> 8,
                    UCHCOM_REG_LCR2, 0)))
                        goto failed;
        } else {
-               idx = (factor << 8) | div;
+               idx = (dv.dv_div << 8) | dv.dv_prescaler;
                if ((err = uchcom_generic_control_out(sc,
                    UCHCOM_REQ_SET_BAUDRATE, val, idx)))
                        goto failed;

Reply via email to