Merge branch 'scif-clk-sck-brg-for-v4.5' of git://git.kernel.org/pub/scm/linux/kernel...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 8 Jan 2016 05:04:46 +0000 (21:04 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 8 Jan 2016 05:04:46 +0000 (21:04 -0800)
Geert writes:

Summary:
  - Clean up the naming of clocks in the sh-sci driver and its DT bindings,
  - Add support for the optional external clock on (H)SCI(F), where this pin
    can serve as a clock input,
  - Add support for the optional clock sources for the Baud Rate
    Generator for External Clock (BRG), as found on some SCIF variants
    and on HSCIF.

16 files changed:
Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
arch/sh/kernel/cpu/clock-cpg.c
arch/sh/kernel/cpu/sh2a/clock-sh7264.c
arch/sh/kernel/cpu/sh2a/clock-sh7269.c
arch/sh/kernel/cpu/sh4a/clock-sh7343.c
arch/sh/kernel/cpu/sh4a/clock-sh7366.c
arch/sh/kernel/cpu/sh4a/clock-sh7723.c
arch/sh/kernel/cpu/sh4a/clock-sh7734.c
arch/sh/kernel/cpu/sh4a/clock-sh7757.c
arch/sh/kernel/cpu/sh4a/clock-sh7785.c
arch/sh/kernel/cpu/sh4a/clock-sh7786.c
arch/sh/kernel/cpu/sh4a/clock-shx3.c
arch/sh/kernel/cpu/sh4a/setup-sh7734.c
drivers/tty/serial/sh-sci.c
drivers/tty/serial/sh-sci.h
include/linux/serial_sci.h

index ce23378064227775948f8420dcd793b88626a82f..401b1b33c2c406520b2dd881e506cf75dc9d3042 100644 (file)
@@ -2,7 +2,7 @@
 
 Required properties:
 
-  - compatible: Must contain one of the following:
+  - compatible: Must contain one or more of the following:
 
     - "renesas,scif-r7s72100" for R7S72100 (RZ/A1H) SCIF compatible UART.
     - "renesas,scifa-r8a73a4" for R8A73A4 (R-Mobile APE6) SCIFA compatible UART.
@@ -31,6 +31,14 @@ Required properties:
     - "renesas,hscif-r8a7795" for R8A7795 (R-Car H3) HSCIF compatible UART.
     - "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART.
     - "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB compatible UART.
+    - "renesas,rcar-gen1-scif" for R-Car Gen1 SCIF compatible UART,
+    - "renesas,rcar-gen2-scif" for R-Car Gen2 SCIF compatible UART,
+    - "renesas,rcar-gen3-scif" for R-Car Gen3 SCIF compatible UART,
+    - "renesas,rcar-gen2-scifa" for R-Car Gen2 SCIFA compatible UART,
+    - "renesas,rcar-gen2-scifb" for R-Car Gen2 SCIFB compatible UART,
+    - "renesas,rcar-gen1-hscif" for R-Car Gen1 HSCIF compatible UART,
+    - "renesas,rcar-gen2-hscif" for R-Car Gen2 HSCIF compatible UART,
+    - "renesas,rcar-gen3-hscif" for R-Car Gen3 HSCIF compatible UART,
     - "renesas,scif" for generic SCIF compatible UART.
     - "renesas,scifa" for generic SCIFA compatible UART.
     - "renesas,scifb" for generic SCIFB compatible UART.
@@ -38,15 +46,26 @@ Required properties:
     - "renesas,sci" for generic SCI compatible UART.
 
     When compatible with the generic version, nodes must list the
-    SoC-specific version corresponding to the platform first followed by the
-    generic version.
+    SoC-specific version corresponding to the platform first, followed by the
+    family-specific and/or generic versions.
 
   - reg: Base address and length of the I/O registers used by the UART.
   - interrupts: Must contain an interrupt-specifier for the SCIx interrupt.
 
   - clocks: Must contain a phandle and clock-specifier pair for each entry
     in clock-names.
-  - clock-names: Must contain "sci_ick" for the SCIx UART interface clock.
+  - clock-names: Must contain "fck" for the SCIx UART functional clock.
+    Apart from the divided functional clock, there may be other possible
+    sources for the sampling clock, depending on SCIx variant.
+    On (H)SCI(F) and some SCIFA, an additional clock may be specified:
+      - "hsck" for the optional external clock input (on HSCIF),
+      - "sck" for the optional external clock input (on other variants).
+    On UARTs equipped with a Baud Rate Generator for External Clock (BRG)
+    (some SCIF and HSCIF), additional clocks may be specified:
+      - "brg_int" for the optional internal clock source for the frequency
+       divider (typically the (AXI or SHwy) bus clock),
+      - "scif_clk" for the optional external clock source for the frequency
+       divider (SCIF_CLK).
 
 Note: Each enabled SCIx UART should have an alias correctly numbered in the
 "aliases" node.
@@ -62,12 +81,13 @@ Example:
        };
 
        scifa0: serial@e6c40000 {
-               compatible = "renesas,scifa-r8a7790", "renesas,scifa";
+               compatible = "renesas,scifa-r8a7790",
+                            "renesas,rcar-gen2-scifa", "renesas,scifa";
                reg = <0 0xe6c40000 0 64>;
                interrupt-parent = <&gic>;
                interrupts = <0 144 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&mstp2_clks R8A7790_CLK_SCIFA0>;
-               clock-names = "sci_ick";
+               clock-names = "fck";
                dmas = <&dmac0 0x21>, <&dmac0 0x22>;
                dma-names = "tx", "rx";
        };
index 8525a671266fe1491edbd383a6bedd542152ecae..786c0769b4c393b586822649830e5a00f796e1ab 100644 (file)
@@ -63,7 +63,6 @@ int __init __deprecated cpg_clk_init(void)
        clk_add_alias("fck", "sh-mtu2", "peripheral_clk", NULL);
        clk_add_alias("fck", "sh-cmt-16.0", "peripheral_clk", NULL);
        clk_add_alias("fck", "sh-cmt-32.0", "peripheral_clk", NULL);
-       clk_add_alias("sci_ick", NULL, "peripheral_clk", NULL);
 
        return ret;
 }
index 8638fba6cd7fbf08686eedea85323ebfa7970df9..7e06e39b095864d1d76b3e743153bea5bf789829 100644 (file)
@@ -115,7 +115,14 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
 
        /* MSTP clocks */
-       CLKDEV_CON_ID("sci_ick", &mstp_clks[MSTP77]),
+       CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP77]),
+       CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP77]),
+       CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP77]),
+       CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[MSTP77]),
+       CLKDEV_ICK_ID("fck", "sh-sci.4", &mstp_clks[MSTP77]),
+       CLKDEV_ICK_ID("fck", "sh-sci.5", &mstp_clks[MSTP77]),
+       CLKDEV_ICK_ID("fck", "sh-sci.6", &mstp_clks[MSTP77]),
+       CLKDEV_ICK_ID("fck", "sh-sci.7", &mstp_clks[MSTP77]),
        CLKDEV_CON_ID("vdc3", &mstp_clks[MSTP74]),
        CLKDEV_ICK_ID("fck", "sh-cmt-16.0", &mstp_clks[MSTP72]),
        CLKDEV_CON_ID("usb0", &mstp_clks[MSTP60]),
index f8a5c2abdfb3caa18799b7e0fabe4f80204c6999..663a97bed554ec5ccb6e1d1d7f205dc2e9dbba9a 100644 (file)
@@ -150,14 +150,14 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
 
        /* MSTP clocks */
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP47]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP46]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP45]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP44]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP43]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP42]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.6", &mstp_clks[MSTP41]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.7", &mstp_clks[MSTP40]),
+       CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP47]),
+       CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP46]),
+       CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP45]),
+       CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[MSTP44]),
+       CLKDEV_ICK_ID("fck", "sh-sci.4", &mstp_clks[MSTP43]),
+       CLKDEV_ICK_ID("fck", "sh-sci.5", &mstp_clks[MSTP42]),
+       CLKDEV_ICK_ID("fck", "sh-sci.6", &mstp_clks[MSTP41]),
+       CLKDEV_ICK_ID("fck", "sh-sci.7", &mstp_clks[MSTP40]),
        CLKDEV_ICK_ID("fck", "sh-cmt-16.0", &mstp_clks[MSTP72]),
        CLKDEV_CON_ID("usb0", &mstp_clks[MSTP60]),
        CLKDEV_ICK_ID("fck", "sh-mtu2", &mstp_clks[MSTP35]),
index 9edc06c02dcf1b9cf7b4599d95ab95d0a9413a76..a907ee2388bfce508b98d5b6d2c7a714606177de 100644 (file)
@@ -232,10 +232,10 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("mfi0", &mstp_clks[MSTP011]),
        CLKDEV_CON_ID("flctl0", &mstp_clks[MSTP010]),
 
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP007]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP006]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP005]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP004]),
+       CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP007]),
+       CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP006]),
+       CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP005]),
+       CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[MSTP004]),
 
        CLKDEV_CON_ID("sio0", &mstp_clks[MSTP003]),
        CLKDEV_CON_ID("siof0", &mstp_clks[MSTP002]),
index 955b9add781063609539ccfd2b70aab5e527785b..ac9854179dee88f0642234063b911eb3d7b47e67 100644 (file)
@@ -230,9 +230,9 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("mfi0", &mstp_clks[MSTP011]),
        CLKDEV_CON_ID("flctl0", &mstp_clks[MSTP010]),
 
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP007]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP006]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP005]),
+       CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP007]),
+       CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP006]),
+       CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP005]),
 
        CLKDEV_CON_ID("msiof0", &mstp_clks[MSTP002]),
        CLKDEV_CON_ID("sbr0", &mstp_clks[MSTP001]),
index ccbcab550df24efc93896cba8136222ba130b101..fe844222f3f6ae5c809041b7e88ace6f57c4fb28 100644 (file)
@@ -267,12 +267,12 @@ static struct clk_lookup lookups[] = {
        CLKDEV_ICK_ID("fck", "sh-tmu.0", &mstp_clks[HWBLK_TMU0]),
        CLKDEV_ICK_ID("fck", "sh-tmu.1", &mstp_clks[HWBLK_TMU1]),
 
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[HWBLK_SCIF3]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[HWBLK_SCIF4]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[HWBLK_SCIF5]),
+       CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
+       CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
+       CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
+       CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[HWBLK_SCIF3]),
+       CLKDEV_ICK_ID("fck", "sh-sci.4", &mstp_clks[HWBLK_SCIF4]),
+       CLKDEV_ICK_ID("fck", "sh-sci.5", &mstp_clks[HWBLK_SCIF5]),
 
        CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[HWBLK_LCDC]),
 };
index 7f54bf2f453d7a7b31c93d4f1e356071c94bf94e..354dcac5e4cd9938a20f8b4c1ceea8d74c592b49 100644 (file)
@@ -194,12 +194,12 @@ static struct clk_lookup lookups[] = {
        /* MSTP32 clocks */
        CLKDEV_DEV_ID("i2c-sh7734.0", &mstp_clks[MSTP030]),
        CLKDEV_DEV_ID("i2c-sh7734.1", &mstp_clks[MSTP029]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP026]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP024]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP023]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP022]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP021]),
+       CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP026]),
+       CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP025]),
+       CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP024]),
+       CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[MSTP023]),
+       CLKDEV_ICK_ID("fck", "sh-sci.4", &mstp_clks[MSTP022]),
+       CLKDEV_ICK_ID("fck", "sh-sci.5", &mstp_clks[MSTP021]),
        CLKDEV_CON_ID("hscif", &mstp_clks[MSTP019]),
        CLKDEV_ICK_ID("fck", "sh-tmu.0", &mstp_clks[MSTP016]),
        CLKDEV_ICK_ID("fck", "sh-tmu.1", &mstp_clks[MSTP015]),
index e40ec2c97ad199c9f32f2b47837fb64e948b0971..b10af2ae9f350908e78b25b522f714249578307c 100644 (file)
@@ -125,9 +125,9 @@ static struct clk_lookup lookups[] = {
 
        CLKDEV_ICK_ID("fck", "sh-tmu.0", &mstp_clks[MSTP113]),
        CLKDEV_ICK_ID("fck", "sh-tmu.1", &mstp_clks[MSTP114]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP112]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP111]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP110]),
+       CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP112]),
+       CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP111]),
+       CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP110]),
 
        CLKDEV_CON_ID("usb_fck", &mstp_clks[MSTP103]),
        CLKDEV_DEV_ID("renesas_usbhs.0", &mstp_clks[MSTP102]),
index 8eb6e62340c950bdfe1610325b1f3e12bd25c8f8..1aafd5496752f7f1132835b6a54b07a291e1a122 100644 (file)
@@ -132,12 +132,12 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
 
        /* MSTP32 clocks */
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP029]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP028]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP027]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP026]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP024]),
+       CLKDEV_ICK_ID("fck", "sh-sci.5", &mstp_clks[MSTP029]),
+       CLKDEV_ICK_ID("fck", "sh-sci.4", &mstp_clks[MSTP028]),
+       CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[MSTP027]),
+       CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP026]),
+       CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP025]),
+       CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP024]),
 
        CLKDEV_CON_ID("ssi1_fck", &mstp_clks[MSTP021]),
        CLKDEV_CON_ID("ssi0_fck", &mstp_clks[MSTP020]),
index 5e50e7ebeff089b9cd82cc9774363e03f3a58054..ac3dcfe5d303d1341c37aa81441d40a96a81ac09 100644 (file)
@@ -139,12 +139,12 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
 
        /* MSTP32 clocks */
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP029]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP028]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP027]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP026]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP024]),
+       CLKDEV_ICK_ID("fck", "sh-sci.5", &mstp_clks[MSTP029]),
+       CLKDEV_ICK_ID("fck", "sh-sci.4", &mstp_clks[MSTP028]),
+       CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[MSTP027]),
+       CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP026]),
+       CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP025]),
+       CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP024]),
 
        CLKDEV_CON_ID("ssi3_fck", &mstp_clks[MSTP023]),
        CLKDEV_CON_ID("ssi2_fck", &mstp_clks[MSTP022]),
index 605221d1448a19a7634c349d34139fc4744517dc..b1bdbc3cbc219af8df4a0d33d3e8a15616667532 100644 (file)
@@ -114,10 +114,10 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
 
        /* MSTP32 clocks */
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP027]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP026]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP024]),
+       CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[MSTP027]),
+       CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP026]),
+       CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP025]),
+       CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP024]),
 
        CLKDEV_CON_ID("h8ex_fck", &mstp_clks[MSTP003]),
        CLKDEV_CON_ID("csm_fck", &mstp_clks[MSTP002]),
index f617bcb734dfeb76a507965c58dad6c3211a3ef2..69b8a50310d9a23f5727aeebe7197aa66bad2cdc 100644 (file)
@@ -28,7 +28,7 @@ static struct plat_sci_port scif0_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .type           = PORT_SCIF,
-       .regtype        = SCIx_SH4_SCIF_REGTYPE,
+       .regtype        = SCIx_SH4_SCIF_BRG_REGTYPE,
 };
 
 static struct resource scif0_resources[] = {
@@ -50,7 +50,7 @@ static struct plat_sci_port scif1_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .type           = PORT_SCIF,
-       .regtype        = SCIx_SH4_SCIF_REGTYPE,
+       .regtype        = SCIx_SH4_SCIF_BRG_REGTYPE,
 };
 
 static struct resource scif1_resources[] = {
@@ -72,7 +72,7 @@ static struct plat_sci_port scif2_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .type           = PORT_SCIF,
-       .regtype        = SCIx_SH4_SCIF_REGTYPE,
+       .regtype        = SCIx_SH4_SCIF_BRG_REGTYPE,
 };
 
 static struct resource scif2_resources[] = {
@@ -94,7 +94,7 @@ static struct plat_sci_port scif3_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
        .type           = PORT_SCIF,
-       .regtype        = SCIx_SH4_SCIF_REGTYPE,
+       .regtype        = SCIx_SH4_SCIF_BRG_REGTYPE,
 };
 
 static struct resource scif3_resources[] = {
@@ -116,7 +116,7 @@ static struct plat_sci_port scif4_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .type           = PORT_SCIF,
-       .regtype        = SCIx_SH4_SCIF_REGTYPE,
+       .regtype        = SCIx_SH4_SCIF_BRG_REGTYPE,
 };
 
 static struct resource scif4_resources[] = {
@@ -138,7 +138,7 @@ static struct plat_sci_port scif5_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .type           = PORT_SCIF,
-       .regtype                = SCIx_SH4_SCIF_REGTYPE,
+       .regtype        = SCIx_SH4_SCIF_BRG_REGTYPE,
 };
 
 static struct resource scif5_resources[] = {
index 51c7507b0444957bcbc9c2c832bd6048a5f3b596..5f2a03acb5d9f379eaeddab436a61cd0c9160fd4 100644 (file)
@@ -2,6 +2,7 @@
  * SuperH on-chip serial module support.  (SCI with no FIFO / with FIFO)
  *
  *  Copyright (C) 2002 - 2011  Paul Mundt
+ *  Copyright (C) 2015 Glider bvba
  *  Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007).
  *
  * based off of the old drivers/char/sh-sci.c by:
@@ -76,6 +77,14 @@ enum {
        ((port)->irqs[SCIx_ERI_IRQ] &&  \
         ((port)->irqs[SCIx_RXI_IRQ] < 0))
 
+enum SCI_CLKS {
+       SCI_FCK,                /* Functional Clock */
+       SCI_SCK,                /* Optional External Clock */
+       SCI_BRG_INT,            /* Optional BRG Internal Clock Source */
+       SCI_SCIF_CLK,           /* Optional BRG External Clock Source */
+       SCI_NUM_CLKS
+};
+
 struct sci_port {
        struct uart_port        port;
 
@@ -92,10 +101,9 @@ struct sci_port {
        struct timer_list       break_timer;
        int                     break_flag;
 
-       /* Interface clock */
-       struct clk              *iclk;
-       /* Function clock */
-       struct clk              *fclk;
+       /* Clocks */
+       struct clk              *clks[SCI_NUM_CLKS];
+       unsigned long           clk_rates[SCI_NUM_CLKS];
 
        int                     irqs[SCIx_NR_IRQS];
        char                    *irqstr[SCIx_NR_IRQS];
@@ -163,6 +171,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
                [HSSRR]         = sci_reg_invalid,
                [SCPCR]         = sci_reg_invalid,
                [SCPDR]         = sci_reg_invalid,
+               [SCDL]          = sci_reg_invalid,
+               [SCCKS]         = sci_reg_invalid,
        },
 
        /*
@@ -185,6 +195,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
                [HSSRR]         = sci_reg_invalid,
                [SCPCR]         = sci_reg_invalid,
                [SCPDR]         = sci_reg_invalid,
+               [SCDL]          = sci_reg_invalid,
+               [SCCKS]         = sci_reg_invalid,
        },
 
        /*
@@ -206,6 +218,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
                [HSSRR]         = sci_reg_invalid,
                [SCPCR]         = { 0x30, 16 },
                [SCPDR]         = { 0x34, 16 },
+               [SCDL]          = sci_reg_invalid,
+               [SCCKS]         = sci_reg_invalid,
        },
 
        /*
@@ -227,6 +241,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
                [HSSRR]         = sci_reg_invalid,
                [SCPCR]         = { 0x30, 16 },
                [SCPDR]         = { 0x34, 16 },
+               [SCDL]          = sci_reg_invalid,
+               [SCCKS]         = sci_reg_invalid,
        },
 
        /*
@@ -249,6 +265,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
                [HSSRR]         = sci_reg_invalid,
                [SCPCR]         = sci_reg_invalid,
                [SCPDR]         = sci_reg_invalid,
+               [SCDL]          = sci_reg_invalid,
+               [SCCKS]         = sci_reg_invalid,
        },
 
        /*
@@ -270,6 +288,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
                [HSSRR]         = sci_reg_invalid,
                [SCPCR]         = sci_reg_invalid,
                [SCPDR]         = sci_reg_invalid,
+               [SCDL]          = sci_reg_invalid,
+               [SCCKS]         = sci_reg_invalid,
        },
 
        /*
@@ -291,6 +311,32 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
                [HSSRR]         = sci_reg_invalid,
                [SCPCR]         = sci_reg_invalid,
                [SCPDR]         = sci_reg_invalid,
+               [SCDL]          = sci_reg_invalid,
+               [SCCKS]         = sci_reg_invalid,
+       },
+
+       /*
+        * Common SCIF definitions for ports with a Baud Rate Generator for
+        * External Clock (BRG).
+        */
+       [SCIx_SH4_SCIF_BRG_REGTYPE] = {
+               [SCSMR]         = { 0x00, 16 },
+               [SCBRR]         = { 0x04,  8 },
+               [SCSCR]         = { 0x08, 16 },
+               [SCxTDR]        = { 0x0c,  8 },
+               [SCxSR]         = { 0x10, 16 },
+               [SCxRDR]        = { 0x14,  8 },
+               [SCFCR]         = { 0x18, 16 },
+               [SCFDR]         = { 0x1c, 16 },
+               [SCTFDR]        = sci_reg_invalid,
+               [SCRFDR]        = sci_reg_invalid,
+               [SCSPTR]        = { 0x20, 16 },
+               [SCLSR]         = { 0x24, 16 },
+               [HSSRR]         = sci_reg_invalid,
+               [SCPCR]         = sci_reg_invalid,
+               [SCPDR]         = sci_reg_invalid,
+               [SCDL]          = { 0x30, 16 },
+               [SCCKS]         = { 0x34, 16 },
        },
 
        /*
@@ -312,6 +358,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
                [HSSRR]         = { 0x40, 16 },
                [SCPCR]         = sci_reg_invalid,
                [SCPDR]         = sci_reg_invalid,
+               [SCDL]          = { 0x30, 16 },
+               [SCCKS]         = { 0x34, 16 },
        },
 
        /*
@@ -334,6 +382,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
                [HSSRR]         = sci_reg_invalid,
                [SCPCR]         = sci_reg_invalid,
                [SCPDR]         = sci_reg_invalid,
+               [SCDL]          = sci_reg_invalid,
+               [SCCKS]         = sci_reg_invalid,
        },
 
        /*
@@ -356,6 +406,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
                [HSSRR]         = sci_reg_invalid,
                [SCPCR]         = sci_reg_invalid,
                [SCPDR]         = sci_reg_invalid,
+               [SCDL]          = sci_reg_invalid,
+               [SCCKS]         = sci_reg_invalid,
        },
 
        /*
@@ -378,6 +430,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
                [HSSRR]         = sci_reg_invalid,
                [SCPCR]         = sci_reg_invalid,
                [SCPDR]         = sci_reg_invalid,
+               [SCDL]          = sci_reg_invalid,
+               [SCCKS]         = sci_reg_invalid,
        },
 };
 
@@ -452,18 +506,24 @@ static int sci_probe_regmap(struct plat_sci_port *cfg)
 
 static void sci_port_enable(struct sci_port *sci_port)
 {
+       unsigned int i;
+
        if (!sci_port->port.dev)
                return;
 
        pm_runtime_get_sync(sci_port->port.dev);
 
-       clk_prepare_enable(sci_port->iclk);
-       sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
-       clk_prepare_enable(sci_port->fclk);
+       for (i = 0; i < SCI_NUM_CLKS; i++) {
+               clk_prepare_enable(sci_port->clks[i]);
+               sci_port->clk_rates[i] = clk_get_rate(sci_port->clks[i]);
+       }
+       sci_port->port.uartclk = sci_port->clk_rates[SCI_FCK];
 }
 
 static void sci_port_disable(struct sci_port *sci_port)
 {
+       unsigned int i;
+
        if (!sci_port->port.dev)
                return;
 
@@ -475,8 +535,8 @@ static void sci_port_disable(struct sci_port *sci_port)
        del_timer_sync(&sci_port->break_timer);
        sci_port->break_flag = 0;
 
-       clk_disable_unprepare(sci_port->fclk);
-       clk_disable_unprepare(sci_port->iclk);
+       for (i = SCI_NUM_CLKS; i-- > 0; )
+               clk_disable_unprepare(sci_port->clks[i]);
 
        pm_runtime_put_sync(sci_port->port.dev);
 }
@@ -1615,6 +1675,7 @@ static int sci_notifier(struct notifier_block *self,
 {
        struct sci_port *sci_port;
        unsigned long flags;
+       unsigned int i;
 
        sci_port = container_of(self, struct sci_port, freq_transition);
 
@@ -1622,7 +1683,9 @@ static int sci_notifier(struct notifier_block *self,
                struct uart_port *port = &sci_port->port;
 
                spin_lock_irqsave(&port->lock, flags);
-               port->uartclk = clk_get_rate(sci_port->iclk);
+               for (i = 0; i < SCI_NUM_CLKS; i++)
+                       sci_port->clk_rates[i] =
+                               clk_get_rate(sci_port->clks[i]);
                spin_unlock_irqrestore(&port->lock, flags);
        }
 
@@ -1864,90 +1927,149 @@ static void sci_shutdown(struct uart_port *port)
        sci_free_irq(s);
 }
 
-static unsigned int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
-                                  unsigned long freq)
+static int sci_sck_calc(struct sci_port *s, unsigned int bps,
+                       unsigned int *srr)
 {
-       if (s->sampling_rate)
-               return DIV_ROUND_CLOSEST(freq, s->sampling_rate * bps) - 1;
+       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;
 
-       /* Warn, but use a safe default */
-       WARN_ON(1);
+               if (!err)
+                       break;
+       }
 
-       return ((freq + 16 * bps) / (32 * bps) - 1);
+       dev_dbg(s->port.dev, "SCK: %u%+d bps using SR %u\n", bps, min_err,
+               *srr + 1);
+       return min_err;
 }
 
-/* calculate frame length from SMR */
-static int sci_baud_calc_frame_len(unsigned int smr_val)
+static int sci_brg_calc(struct sci_port *s, unsigned int bps,
+                       unsigned long freq, unsigned int *dlr,
+                       unsigned int *srr)
 {
-       int len = 10;
+       unsigned int min_sr, max_sr, sr, dl;
+       int err, min_err = INT_MAX;
 
-       if (smr_val & SCSMR_CHR)
-               len--;
-       if (smr_val & SCSMR_PE)
-               len++;
-       if (smr_val & SCSMR_STOP)
-               len++;
+       if (s->sampling_rate) {
+               /* SCIF 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;
+       }
 
-       return len;
-}
+       for (sr = max_sr; sr >= min_sr; sr--) {
+               dl = DIV_ROUND_CLOSEST(freq, sr * bps);
+               dl = clamp(dl, 1U, 65535U);
+
+               err = DIV_ROUND_CLOSEST(freq, sr * dl) - bps;
+               if (abs(err) >= abs(min_err))
+                       continue;
+
+               min_err = err;
+               *dlr = dl;
+               *srr = sr - 1;
+
+               if (!err)
+                       break;
+       }
 
+       dev_dbg(s->port.dev, "BRG: %u%+d bps using DL %u SR %u\n", bps,
+               min_err, *dlr, *srr + 1);
+       return min_err;
+}
 
-/* calculate sample rate, BRR, and clock select for HSCIF */
-static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq,
-                               int *brr, unsigned int *srr,
-                               unsigned int *cks, int frame_len)
+/* 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,
+                         unsigned int *cks)
 {
-       int sr, c, br, err, recv_margin;
-       int min_err = 1000; /* 100% */
-       int recv_max_margin = 0;
+       unsigned int min_sr, max_sr, shift, sr, br, prediv, scrate, c;
+       unsigned long freq = s->clk_rates[SCI_FCK];
+       int err, min_err = INT_MAX;
 
-       /* Find the combination of sample rate and clock select with the
-          smallest deviation from the desired baud rate. */
-       for (sr = 8; sr <= 32; sr++) {
+       if (s->sampling_rate) {
+               min_sr = max_sr = s->sampling_rate;
+               shift = 0;
+       } else {
+               /* HSCIF has a variable sample rate */
+               min_sr = 8;
+               max_sr = 32;
+               shift = 1;
+       }
+
+       /*
+        * Find the combination of sample rate and clock select with the
+        * smallest deviation from the desired baud rate.
+        * Prefer high sample rates to maximise the receive margin.
+        *
+        * M: Receive margin (%)
+        * N: Ratio of bit rate to clock (N = sampling rate)
+        * D: Clock duty (D = 0 to 1.0)
+        * L: Frame length (L = 9 to 12)
+        * F: Absolute value of clock frequency deviation
+        *
+        *  M = |(0.5 - 1 / 2 * N) - ((L - 0.5) * F) -
+        *      (|D - 0.5| / N * (1 + F))|
+        *  NOTE: Usually, treat D for 0.5, F is 0 by this calculation.
+        */
+       for (sr = max_sr; sr >= min_sr; sr--) {
                for (c = 0; c <= 3; c++) {
                        /* integerized formulas from HSCIF documentation */
-                       br = DIV_ROUND_CLOSEST(freq, (sr *
-                                             (1 << (2 * c + 1)) * bps)) - 1;
-                       br = clamp(br, 0, 255);
-                       err = DIV_ROUND_CLOSEST(freq, ((br + 1) * bps * sr *
-                                              (1 << (2 * c + 1)) / 1000)) -
-                                              1000;
-                       /* Calc recv margin
-                        * M: Receive margin (%)
-                        * N: Ratio of bit rate to clock (N = sampling rate)
-                        * D: Clock duty (D = 0 to 1.0)
-                        * L: Frame length (L = 9 to 12)
-                        * F: Absolute value of clock frequency deviation
+                       prediv = sr * (1 << (2 * c + shift));
+
+                       /*
+                        * We need to calculate:
+                        *
+                        *     br = freq / (prediv * bps) clamped to [1..256]
+                        *     err = freq / (br * prediv) - bps
                         *
-                        *  M = |(0.5 - 1 / 2 * N) - ((L - 0.5) * F) -
-                        *      (|D - 0.5| / N * (1 + F))|
-                        *  NOTE: Usually, treat D for 0.5, F is 0 by this
-                        *        calculation.
+                        * Watch out for overflow when calculating the desired
+                        * sampling clock rate!
                         */
-                       recv_margin = abs((500 -
-                                       DIV_ROUND_CLOSEST(1000, sr << 1)) / 10);
-                       if (abs(min_err) > abs(err)) {
-                               min_err = err;
-                               recv_max_margin = recv_margin;
-                       } else if ((min_err == err) &&
-                                  (recv_margin > recv_max_margin))
-                               recv_max_margin = recv_margin;
-                       else
+                       if (bps > UINT_MAX / prediv)
+                               break;
+
+                       scrate = prediv * bps;
+                       br = DIV_ROUND_CLOSEST(freq, scrate);
+                       br = clamp(br, 1U, 256U);
+
+                       err = DIV_ROUND_CLOSEST(freq, br * prediv) - bps;
+                       if (abs(err) >= abs(min_err))
                                continue;
 
-                       *brr = br;
+                       min_err = err;
+                       *brr = br - 1;
                        *srr = sr - 1;
                        *cks = c;
+
+                       if (!err)
+                               goto found;
                }
        }
 
-       if (min_err == 1000) {
-               WARN_ON(1);
-               /* use defaults */
-               *brr = 255;
-               *srr = 15;
-               *cks = 0;
-       }
+found:
+       dev_dbg(s->port.dev, "BRR: %u%+d bps using N %u SR %u cks %u\n", bps,
+               min_err, *brr, *srr + 1, *cks);
+       return min_err;
 }
 
 static void sci_reset(struct uart_port *port)
@@ -1969,11 +2091,14 @@ static void sci_reset(struct uart_port *port)
 static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
                            struct ktermios *old)
 {
+       unsigned int baud, smr_val = 0, scr_val = 0, i;
+       unsigned int brr = 255, cks = 0, srr = 15, dl = 0, sccks = 0;
+       unsigned int brr1 = 255, cks1 = 0, srr1 = 15, dl1 = 0;
        struct sci_port *s = to_sci_port(port);
        const struct plat_sci_reg *reg;
-       unsigned int baud, smr_val = 0, max_baud, cks = 0;
-       int t = -1;
-       unsigned int srr = 15;
+       int min_err = INT_MAX, err;
+       unsigned long max_freq = 0;
+       int best_clk = -1;
 
        if ((termios->c_cflag & CSIZE) == CS7)
                smr_val |= SCSMR_CHR;
@@ -1992,41 +2117,123 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
         * that the previous boot loader has enabled required clocks and
         * setup the baud rate generator hardware for us already.
         */
-       max_baud = port->uartclk ? port->uartclk / 16 : 115200;
-
-       baud = uart_get_baud_rate(port, termios, old, 0, max_baud);
-       if (likely(baud && port->uartclk)) {
-               if (s->cfg->type == PORT_HSCIF) {
-                       int frame_len = sci_baud_calc_frame_len(smr_val);
-                       sci_baud_calc_hscif(baud, port->uartclk, &t, &srr,
-                                           &cks, frame_len);
-               } else {
-                       t = sci_scbrr_calc(s, baud, port->uartclk);
-                       for (cks = 0; t >= 256 && cks <= 3; cks++)
-                               t >>= 2;
+       if (!port->uartclk) {
+               baud = uart_get_baud_rate(port, termios, old, 0, 115200);
+               goto done;
+       }
+
+       for (i = 0; i < SCI_NUM_CLKS; i++)
+               max_freq = max(max_freq, s->clk_rates[i]);
+
+       baud = uart_get_baud_rate(port, termios, old, 0,
+                                 max_freq / max(s->sampling_rate, 8U));
+       if (!baud)
+               goto done;
+
+       /*
+        * There can be multiple sources for the sampling clock.  Find the one
+        * 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;
+               }
+       }
+
+       /* Optional BRG Frequency Divided External Clock */
+       if (s->clk_rates[SCI_SCIF_CLK] && sci_getreg(port, SCDL)->size) {
+               err = sci_brg_calc(s, baud, s->clk_rates[SCI_SCIF_CLK], &dl1,
+                                  &srr1);
+               if (abs(err) < abs(min_err)) {
+                       best_clk = SCI_SCIF_CLK;
+                       scr_val = SCSCR_CKE1;
+                       sccks = 0;
+                       min_err = err;
+                       dl = dl1;
+                       srr = srr1;
+                       if (!err)
+                               goto done;
+               }
+       }
+
+       /* Optional BRG Frequency Divided Internal Clock */
+       if (s->clk_rates[SCI_BRG_INT] && sci_getreg(port, SCDL)->size) {
+               err = sci_brg_calc(s, baud, s->clk_rates[SCI_BRG_INT], &dl1,
+                                  &srr1);
+               if (abs(err) < abs(min_err)) {
+                       best_clk = SCI_BRG_INT;
+                       scr_val = SCSCR_CKE1;
+                       sccks = SCCKS_XIN;
+                       min_err = err;
+                       dl = dl1;
+                       srr = srr1;
+                       if (!min_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;
+               cks = cks1;
+       }
+
+done:
+       if (best_clk >= 0)
+               dev_dbg(port->dev, "Using clk %pC for %u%+d bps\n",
+                       s->clks[best_clk], baud, min_err);
+
        sci_port_enable(s);
 
-       sci_reset(port);
+       /*
+        * 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, SCDL, dl);
+               serial_port_out(port, SCCKS, sccks);
+       }
 
-       smr_val |= serial_port_in(port, SCSMR) & SCSMR_CKS;
+       sci_reset(port);
 
        uart_update_timeout(port, termios->c_cflag, baud);
 
-       dev_dbg(port->dev, "%s: SMR %x, cks %x, t %x, SCSCR %x\n",
-               __func__, smr_val, cks, t, s->cfg->scscr);
-
-       if (t >= 0) {
-               serial_port_out(port, SCSMR, (smr_val & ~SCSMR_CKS) | cks);
-               serial_port_out(port, SCBRR, t);
-               reg = sci_getreg(port, HSSRR);
-               if (reg->size)
+       if (best_clk >= 0) {
+               smr_val |= cks;
+               dev_dbg(port->dev,
+                        "SCR 0x%x SMR 0x%x BRR %u CKS 0x%x DL %u SRR %u\n",
+                        scr_val, smr_val, brr, sccks, dl, 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)
                        serial_port_out(port, HSSRR, srr | HSCIF_SRE);
-               udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */
-       } else
+
+               /* Wait one bit interval */
+               udelay((1000000 + (baud - 1)) / baud);
+       } else {
+               /* Don't touch the bit rate configuration */
+               scr_val = s->cfg->scscr & (SCSCR_CKE1 | SCSCR_CKE0);
+               smr_val |= serial_port_in(port, SCSMR) & SCSMR_CKS;
+               dev_dbg(port->dev, "SCR 0x%x SMR 0x%x\n", scr_val, smr_val);
+               serial_port_out(port, SCSCR, scr_val);
                serial_port_out(port, SCSMR, smr_val);
+       }
 
        sci_init_pins(port, termios->c_cflag);
 
@@ -2051,7 +2258,9 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
                serial_port_out(port, SCFCR, ctrl);
        }
 
-       serial_port_out(port, SCSCR, s->cfg->scscr);
+       scr_val |= s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0);
+       dev_dbg(port->dev, "SCSCR 0x%x\n", scr_val);
+       serial_port_out(port, SCSCR, scr_val);
 
 #ifdef CONFIG_SERIAL_SH_SCI_DMA
        /*
@@ -2241,6 +2450,63 @@ static struct uart_ops sci_uart_ops = {
 #endif
 };
 
+static int sci_init_clocks(struct sci_port *sci_port, struct device *dev)
+{
+       const char *clk_names[] = {
+               [SCI_FCK] = "fck",
+               [SCI_SCK] = "sck",
+               [SCI_BRG_INT] = "brg_int",
+               [SCI_SCIF_CLK] = "scif_clk",
+       };
+       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)
+                       return -EPROBE_DEFER;
+
+               if (IS_ERR(clk) && i == SCI_FCK) {
+                       /*
+                        * "fck" used to be called "sci_ick", and we need to
+                        * maintain DT backward compatibility.
+                        */
+                       clk = devm_clk_get(dev, "sci_ick");
+                       if (PTR_ERR(clk) == -EPROBE_DEFER)
+                               return -EPROBE_DEFER;
+
+                       if (!IS_ERR(clk))
+                               goto found;
+
+                       /*
+                        * Not all SH platforms declare a clock lookup entry
+                        * for SCI devices, in which case we need to get the
+                        * global "peripheral_clk" clock.
+                        */
+                       clk = devm_clk_get(dev, "peripheral_clk");
+                       if (!IS_ERR(clk))
+                               goto found;
+
+                       dev_err(dev, "failed to get %s (%ld)\n", clk_names[i],
+                               PTR_ERR(clk));
+                       return PTR_ERR(clk);
+               }
+
+found:
+               if (IS_ERR(clk))
+                       dev_dbg(dev, "failed to get %s (%ld)\n", clk_names[i],
+                               PTR_ERR(clk));
+               else
+                       dev_dbg(dev, "clk %s is %pC rate %pCr\n", clk_names[i],
+                               clk, clk);
+               sci_port->clks[i] = IS_ERR(clk) ? NULL : clk;
+       }
+       return 0;
+}
+
 static int sci_init_single(struct platform_device *dev,
                           struct sci_port *sci_port, unsigned int index,
                           struct plat_sci_port *p, bool early)
@@ -2333,22 +2599,9 @@ static int sci_init_single(struct platform_device *dev,
                sci_port->sampling_rate = p->sampling_rate;
 
        if (!early) {
-               sci_port->iclk = clk_get(&dev->dev, "sci_ick");
-               if (IS_ERR(sci_port->iclk)) {
-                       sci_port->iclk = clk_get(&dev->dev, "peripheral_clk");
-                       if (IS_ERR(sci_port->iclk)) {
-                               dev_err(&dev->dev, "can't get iclk\n");
-                               return PTR_ERR(sci_port->iclk);
-                       }
-               }
-
-               /*
-                * The function clock is optional, ignore it if we can't
-                * find it.
-                */
-               sci_port->fclk = clk_get(&dev->dev, "sci_fck");
-               if (IS_ERR(sci_port->fclk))
-                       sci_port->fclk = NULL;
+               ret = sci_init_clocks(sci_port, &dev->dev);
+               if (ret < 0)
+                       return ret;
 
                port->dev = &dev->dev;
 
@@ -2405,9 +2658,6 @@ static int sci_init_single(struct platform_device *dev,
 
 static void sci_cleanup_single(struct sci_port *port)
 {
-       clk_put(port->iclk);
-       clk_put(port->fclk);
-
        pm_runtime_disable(port->port.dev);
 }
 
@@ -2426,7 +2676,7 @@ static void serial_console_write(struct console *co, const char *s,
 {
        struct sci_port *sci_port = &sci_ports[co->index];
        struct uart_port *port = &sci_port->port;
-       unsigned short bits, ctrl;
+       unsigned short bits, ctrl, ctrl_temp;
        unsigned long flags;
        int locked = 1;
 
@@ -2438,9 +2688,11 @@ static void serial_console_write(struct console *co, const char *s,
        else
                spin_lock(&port->lock);
 
-       /* first save the SCSCR then disable the interrupts */
+       /* first save SCSCR then disable interrupts, keep clock source */
        ctrl = serial_port_in(port, SCSCR);
-       serial_port_out(port, SCSCR, sci_port->cfg->scscr);
+       ctrl_temp = (sci_port->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) |
+                   (ctrl & (SCSCR_CKE1 | SCSCR_CKE0));
+       serial_port_out(port, SCSCR, ctrl_temp);
 
        uart_console_write(port, s, count, serial_console_putchar);
 
@@ -2569,42 +2821,44 @@ static int sci_remove(struct platform_device *dev)
        return 0;
 }
 
-struct sci_port_info {
-       unsigned int type;
-       unsigned int regtype;
-};
+
+#define SCI_OF_DATA(type, regtype)     (void *)((type) << 16 | (regtype))
+#define SCI_OF_TYPE(data)              ((unsigned long)(data) >> 16)
+#define SCI_OF_REGTYPE(data)           ((unsigned long)(data) & 0xffff)
 
 static const struct of_device_id of_sci_match[] = {
+       /* SoC-specific types */
+       {
+               .compatible = "renesas,scif-r7s72100",
+               .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH2_SCIF_FIFODATA_REGTYPE),
+       },
+       /* Family-specific types */
+       {
+               .compatible = "renesas,rcar-gen1-scif",
+               .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+       }, {
+               .compatible = "renesas,rcar-gen2-scif",
+               .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+       }, {
+               .compatible = "renesas,rcar-gen3-scif",
+               .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+       },
+       /* Generic types */
        {
                .compatible = "renesas,scif",
-               .data = &(const struct sci_port_info) {
-                       .type = PORT_SCIF,
-                       .regtype = SCIx_SH4_SCIF_REGTYPE,
-               },
+               .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_REGTYPE),
        }, {
                .compatible = "renesas,scifa",
-               .data = &(const struct sci_port_info) {
-                       .type = PORT_SCIFA,
-                       .regtype = SCIx_SCIFA_REGTYPE,
-               },
+               .data = SCI_OF_DATA(PORT_SCIFA, SCIx_SCIFA_REGTYPE),
        }, {
                .compatible = "renesas,scifb",
-               .data = &(const struct sci_port_info) {
-                       .type = PORT_SCIFB,
-                       .regtype = SCIx_SCIFB_REGTYPE,
-               },
+               .data = SCI_OF_DATA(PORT_SCIFB, SCIx_SCIFB_REGTYPE),
        }, {
                .compatible = "renesas,hscif",
-               .data = &(const struct sci_port_info) {
-                       .type = PORT_HSCIF,
-                       .regtype = SCIx_HSCIF_REGTYPE,
-               },
+               .data = SCI_OF_DATA(PORT_HSCIF, SCIx_HSCIF_REGTYPE),
        }, {
                .compatible = "renesas,sci",
-               .data = &(const struct sci_port_info) {
-                       .type = PORT_SCI,
-                       .regtype = SCIx_SCI_REGTYPE,
-               },
+               .data = SCI_OF_DATA(PORT_SCI, SCIx_SCI_REGTYPE),
        }, {
                /* Terminator */
        },
@@ -2616,24 +2870,21 @@ sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id)
 {
        struct device_node *np = pdev->dev.of_node;
        const struct of_device_id *match;
-       const struct sci_port_info *info;
        struct plat_sci_port *p;
        int id;
 
        if (!IS_ENABLED(CONFIG_OF) || !np)
                return NULL;
 
-       match = of_match_node(of_sci_match, pdev->dev.of_node);
+       match = of_match_node(of_sci_match, np);
        if (!match)
                return NULL;
 
-       info = match->data;
-
        p = devm_kzalloc(&pdev->dev, sizeof(struct plat_sci_port), GFP_KERNEL);
        if (!p)
                return NULL;
 
-       /* Get the line number for the aliases node. */
+       /* Get the line number from the aliases node. */
        id = of_alias_get_id(np, "serial");
        if (id < 0) {
                dev_err(&pdev->dev, "failed to get alias id (%d)\n", id);
@@ -2643,8 +2894,8 @@ sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id)
        *dev_id = id;
 
        p->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
-       p->type = info->type;
-       p->regtype = info->regtype;
+       p->type = SCI_OF_TYPE(match->data);
+       p->regtype = SCI_OF_REGTYPE(match->data);
        p->scscr = SCSCR_RE | SCSCR_TE;
 
        return p;
index bf69bbdcc1f9aa3975a7847ec323d23fa50a73ce..fb176025042185c44c7ae0ec2eeaa3134393219e 100644 (file)
@@ -27,6 +27,8 @@ enum {
        HSSRR,                          /* Sampling Rate Register */
        SCPCR,                          /* Serial Port Control Register */
        SCPDR,                          /* Serial Port Data Register */
+       SCDL,                           /* BRG Frequency Division Register */
+       SCCKS,                          /* BRG Clock Select Register */
 
        SCIx_NR_REGS,
 };
@@ -109,6 +111,14 @@ enum {
 #define SCPDR_RTSD     BIT(4)  /* Serial Port RTS Output Pin Data */
 #define SCPDR_CTSD     BIT(3)  /* Serial Port CTS Input Pin Data */
 
+/*
+ * BRG Clock Select Register (Some SCIF and HSCIF)
+ * The Baud Rate Generator for external clock can provide a clock source for
+ * the sampling clock. It outputs either its frequency divided clock, or the
+ * (undivided) (H)SCK external clock.
+ */
+#define SCCKS_CKS      BIT(15) /* Select (H)SCK (1) or divided SC_CLK (0) */
+#define SCCKS_XIN      BIT(14) /* SC_CLK uses bus clock (1) or SCIF_CLK (0) */
 
 #define SCxSR_TEND(port)       (((port)->type == PORT_SCI) ? SCI_TEND   : SCIF_TEND)
 #define SCxSR_RDxF(port)       (((port)->type == PORT_SCI) ? SCI_RDRF   : SCIF_RDF)
index 7c536ac5be05d3aa01c27d69f17f721c31341d7a..9f2bfd0557429ac37d6098ccd8f6bb86e52255c5 100644 (file)
@@ -32,6 +32,7 @@ enum {
        SCIx_SH2_SCIF_FIFODATA_REGTYPE,
        SCIx_SH3_SCIF_REGTYPE,
        SCIx_SH4_SCIF_REGTYPE,
+       SCIx_SH4_SCIF_BRG_REGTYPE,
        SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
        SCIx_SH4_SCIF_FIFODATA_REGTYPE,
        SCIx_SH7705_SCIF_REGTYPE,