enum SCI_CLKS {
        SCI_FCK,                /* Functional Clock */
+       SCI_SCK,                /* Optional External Clock */
        SCI_NUM_CLKS
 };
 
        sci_free_irq(s);
 }
 
+static int sci_sck_calc(struct sci_port *s, unsigned int bps,
+                       unsigned int *srr)
+{
+       unsigned long freq = s->clk_rates[SCI_SCK];
+       unsigned int min_sr, max_sr, sr;
+       int err, min_err = INT_MAX;
+
+       if (s->sampling_rate) {
+               /* SCI(F) has a fixed sampling rate */
+               min_sr = max_sr = s->sampling_rate / 2;
+       } else {
+               /* HSCIF has a variable 1/(8..32) sampling rate */
+               min_sr = 8;
+               max_sr = 32;
+       }
+
+       for (sr = max_sr; sr >= min_sr; sr--) {
+               err = DIV_ROUND_CLOSEST(freq, sr) - bps;
+               if (abs(err) >= abs(min_err))
+                       continue;
+
+               min_err = err;
+               *srr = sr - 1;
+
+               if (!err)
+                       break;
+       }
+
+       dev_dbg(s->port.dev, "SCK: %u%+d bps using SR %u\n", bps, min_err,
+               *srr + 1);
+       return min_err;
+}
+
 /* calculate sample rate, BRR, and clock select */
 static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
                          unsigned int *brr, unsigned int *srr,
                            struct ktermios *old)
 {
        unsigned int baud, smr_val = 0, scr_val = 0, i;
-       unsigned int brr = 255, cks = 0, srr = 15;
+       unsigned int brr = 255, cks = 0, srr = 15, sccks = 0;
        unsigned int brr1 = 255, cks1 = 0, srr1 = 15;
        struct sci_port *s = to_sci_port(port);
        const struct plat_sci_reg *reg;
         * that gives us the smallest deviation from the desired baud rate.
         */
 
+       /* Optional Undivided External Clock */
+       if (s->clk_rates[SCI_SCK] && port->type != PORT_SCIFA &&
+           port->type != PORT_SCIFB) {
+               err = sci_sck_calc(s, baud, &srr1);
+               if (abs(err) < abs(min_err)) {
+                       best_clk = SCI_SCK;
+                       scr_val = SCSCR_CKE1;
+                       sccks = SCCKS_CKS;
+                       min_err = err;
+                       srr = srr1;
+                       if (!err)
+                               goto done;
+               }
+       }
+
        /* Divided Functional Clock using standard Bit Rate Register */
        err = sci_scbrr_calc(s, baud, &brr1, &srr1, &cks1);
        if (abs(err) < abs(min_err)) {
                best_clk = SCI_FCK;
+               scr_val = 0;
                min_err = err;
                brr = brr1;
                srr = srr1;
 
        sci_port_enable(s);
 
+       /*
+        * Program the optional External Baud Rate Generator (BRG) first.
+        * It controls the mux to select (H)SCK or frequency divided clock.
+        */
+       if (best_clk >= 0 && sci_getreg(port, SCCKS)->size)
+               serial_port_out(port, SCCKS, sccks);
+
        sci_reset(port);
 
        uart_update_timeout(port, termios->c_cflag, baud);
 
        if (best_clk >= 0) {
                smr_val |= cks;
-               dev_dbg(port->dev, "SMR 0x%x BRR %u SRR %u\n", smr_val, brr,
-                       srr);
+               dev_dbg(port->dev,
+                        "SCR 0x%x SMR 0x%x BRR %u CKS 0x%x SRR %u\n",
+                        scr_val, smr_val, brr, sccks, srr);
+               serial_port_out(port, SCSCR, scr_val);
                serial_port_out(port, SCSMR, smr_val);
                serial_port_out(port, SCBRR, brr);
                if (sci_getreg(port, HSSRR)->size)
 {
        const char *clk_names[] = {
                [SCI_FCK] = "fck",
+               [SCI_SCK] = "sck",
        };
        struct clk *clk;
        unsigned int i;
 
+       if (sci_port->cfg->type == PORT_HSCIF)
+               clk_names[SCI_SCK] = "hsck";
+
        for (i = 0; i < SCI_NUM_CLKS; i++) {
                clk = devm_clk_get(dev, clk_names[i]);
                if (PTR_ERR(clk) == -EPROBE_DEFER)