Commit f658f21c authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge branch 'scif-clk-sck-brg-for-v4.5' of...

Merge branch 'scif-clk-sck-brg-for-v4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers into tty-next

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.
parents c93a5993 192d367f
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
Required properties: 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,scif-r7s72100" for R7S72100 (RZ/A1H) SCIF compatible UART.
- "renesas,scifa-r8a73a4" for R8A73A4 (R-Mobile APE6) SCIFA compatible UART. - "renesas,scifa-r8a73a4" for R8A73A4 (R-Mobile APE6) SCIFA compatible UART.
...@@ -31,6 +31,14 @@ Required properties: ...@@ -31,6 +31,14 @@ Required properties:
- "renesas,hscif-r8a7795" for R8A7795 (R-Car H3) HSCIF compatible UART. - "renesas,hscif-r8a7795" for R8A7795 (R-Car H3) HSCIF compatible UART.
- "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA 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,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,scif" for generic SCIF compatible UART.
- "renesas,scifa" for generic SCIFA compatible UART. - "renesas,scifa" for generic SCIFA compatible UART.
- "renesas,scifb" for generic SCIFB compatible UART. - "renesas,scifb" for generic SCIFB compatible UART.
...@@ -38,15 +46,26 @@ Required properties: ...@@ -38,15 +46,26 @@ Required properties:
- "renesas,sci" for generic SCI compatible UART. - "renesas,sci" for generic SCI compatible UART.
When compatible with the generic version, nodes must list the When compatible with the generic version, nodes must list the
SoC-specific version corresponding to the platform first followed by the SoC-specific version corresponding to the platform first, followed by the
generic version. family-specific and/or generic versions.
- reg: Base address and length of the I/O registers used by the UART. - reg: Base address and length of the I/O registers used by the UART.
- interrupts: Must contain an interrupt-specifier for the SCIx interrupt. - interrupts: Must contain an interrupt-specifier for the SCIx interrupt.
- clocks: Must contain a phandle and clock-specifier pair for each entry - clocks: Must contain a phandle and clock-specifier pair for each entry
in clock-names. 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 Note: Each enabled SCIx UART should have an alias correctly numbered in the
"aliases" node. "aliases" node.
...@@ -62,12 +81,13 @@ Example: ...@@ -62,12 +81,13 @@ Example:
}; };
scifa0: serial@e6c40000 { scifa0: serial@e6c40000 {
compatible = "renesas,scifa-r8a7790", "renesas,scifa"; compatible = "renesas,scifa-r8a7790",
"renesas,rcar-gen2-scifa", "renesas,scifa";
reg = <0 0xe6c40000 0 64>; reg = <0 0xe6c40000 0 64>;
interrupt-parent = <&gic>; interrupt-parent = <&gic>;
interrupts = <0 144 IRQ_TYPE_LEVEL_HIGH>; interrupts = <0 144 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7790_CLK_SCIFA0>; clocks = <&mstp2_clks R8A7790_CLK_SCIFA0>;
clock-names = "sci_ick"; clock-names = "fck";
dmas = <&dmac0 0x21>, <&dmac0 0x22>; dmas = <&dmac0 0x21>, <&dmac0 0x22>;
dma-names = "tx", "rx"; dma-names = "tx", "rx";
}; };
...@@ -63,7 +63,6 @@ int __init __deprecated cpg_clk_init(void) ...@@ -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-mtu2", "peripheral_clk", NULL);
clk_add_alias("fck", "sh-cmt-16.0", "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("fck", "sh-cmt-32.0", "peripheral_clk", NULL);
clk_add_alias("sci_ick", NULL, "peripheral_clk", NULL);
return ret; return ret;
} }
......
...@@ -115,7 +115,14 @@ static struct clk_lookup lookups[] = { ...@@ -115,7 +115,14 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]), CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
/* MSTP clocks */ /* 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_CON_ID("vdc3", &mstp_clks[MSTP74]),
CLKDEV_ICK_ID("fck", "sh-cmt-16.0", &mstp_clks[MSTP72]), CLKDEV_ICK_ID("fck", "sh-cmt-16.0", &mstp_clks[MSTP72]),
CLKDEV_CON_ID("usb0", &mstp_clks[MSTP60]), CLKDEV_CON_ID("usb0", &mstp_clks[MSTP60]),
......
...@@ -150,14 +150,14 @@ static struct clk_lookup lookups[] = { ...@@ -150,14 +150,14 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]), CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
/* MSTP clocks */ /* MSTP clocks */
CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP47]), CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP47]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP46]), CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP46]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP45]), CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP45]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP44]), CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[MSTP44]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP43]), CLKDEV_ICK_ID("fck", "sh-sci.4", &mstp_clks[MSTP43]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP42]), CLKDEV_ICK_ID("fck", "sh-sci.5", &mstp_clks[MSTP42]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.6", &mstp_clks[MSTP41]), CLKDEV_ICK_ID("fck", "sh-sci.6", &mstp_clks[MSTP41]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.7", &mstp_clks[MSTP40]), CLKDEV_ICK_ID("fck", "sh-sci.7", &mstp_clks[MSTP40]),
CLKDEV_ICK_ID("fck", "sh-cmt-16.0", &mstp_clks[MSTP72]), CLKDEV_ICK_ID("fck", "sh-cmt-16.0", &mstp_clks[MSTP72]),
CLKDEV_CON_ID("usb0", &mstp_clks[MSTP60]), CLKDEV_CON_ID("usb0", &mstp_clks[MSTP60]),
CLKDEV_ICK_ID("fck", "sh-mtu2", &mstp_clks[MSTP35]), CLKDEV_ICK_ID("fck", "sh-mtu2", &mstp_clks[MSTP35]),
......
...@@ -232,10 +232,10 @@ static struct clk_lookup lookups[] = { ...@@ -232,10 +232,10 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("mfi0", &mstp_clks[MSTP011]), CLKDEV_CON_ID("mfi0", &mstp_clks[MSTP011]),
CLKDEV_CON_ID("flctl0", &mstp_clks[MSTP010]), CLKDEV_CON_ID("flctl0", &mstp_clks[MSTP010]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP007]), CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP007]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP006]), CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP006]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP005]), CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP005]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP004]), CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[MSTP004]),
CLKDEV_CON_ID("sio0", &mstp_clks[MSTP003]), CLKDEV_CON_ID("sio0", &mstp_clks[MSTP003]),
CLKDEV_CON_ID("siof0", &mstp_clks[MSTP002]), CLKDEV_CON_ID("siof0", &mstp_clks[MSTP002]),
......
...@@ -230,9 +230,9 @@ static struct clk_lookup lookups[] = { ...@@ -230,9 +230,9 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("mfi0", &mstp_clks[MSTP011]), CLKDEV_CON_ID("mfi0", &mstp_clks[MSTP011]),
CLKDEV_CON_ID("flctl0", &mstp_clks[MSTP010]), CLKDEV_CON_ID("flctl0", &mstp_clks[MSTP010]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP007]), CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP007]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP006]), CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP006]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP005]), CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP005]),
CLKDEV_CON_ID("msiof0", &mstp_clks[MSTP002]), CLKDEV_CON_ID("msiof0", &mstp_clks[MSTP002]),
CLKDEV_CON_ID("sbr0", &mstp_clks[MSTP001]), CLKDEV_CON_ID("sbr0", &mstp_clks[MSTP001]),
......
...@@ -267,12 +267,12 @@ static struct clk_lookup lookups[] = { ...@@ -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.0", &mstp_clks[HWBLK_TMU0]),
CLKDEV_ICK_ID("fck", "sh-tmu.1", &mstp_clks[HWBLK_TMU1]), 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("fck", "sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[HWBLK_SCIF1]), CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[HWBLK_SCIF2]), CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[HWBLK_SCIF3]), CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[HWBLK_SCIF3]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[HWBLK_SCIF4]), CLKDEV_ICK_ID("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.5", &mstp_clks[HWBLK_SCIF5]),
CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[HWBLK_LCDC]), CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[HWBLK_LCDC]),
}; };
......
...@@ -194,12 +194,12 @@ static struct clk_lookup lookups[] = { ...@@ -194,12 +194,12 @@ static struct clk_lookup lookups[] = {
/* MSTP32 clocks */ /* MSTP32 clocks */
CLKDEV_DEV_ID("i2c-sh7734.0", &mstp_clks[MSTP030]), CLKDEV_DEV_ID("i2c-sh7734.0", &mstp_clks[MSTP030]),
CLKDEV_DEV_ID("i2c-sh7734.1", &mstp_clks[MSTP029]), CLKDEV_DEV_ID("i2c-sh7734.1", &mstp_clks[MSTP029]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP026]), CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP026]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]), CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP025]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP024]), CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP024]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP023]), CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[MSTP023]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP022]), CLKDEV_ICK_ID("fck", "sh-sci.4", &mstp_clks[MSTP022]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP021]), CLKDEV_ICK_ID("fck", "sh-sci.5", &mstp_clks[MSTP021]),
CLKDEV_CON_ID("hscif", &mstp_clks[MSTP019]), CLKDEV_CON_ID("hscif", &mstp_clks[MSTP019]),
CLKDEV_ICK_ID("fck", "sh-tmu.0", &mstp_clks[MSTP016]), CLKDEV_ICK_ID("fck", "sh-tmu.0", &mstp_clks[MSTP016]),
CLKDEV_ICK_ID("fck", "sh-tmu.1", &mstp_clks[MSTP015]), CLKDEV_ICK_ID("fck", "sh-tmu.1", &mstp_clks[MSTP015]),
......
...@@ -125,9 +125,9 @@ static struct clk_lookup lookups[] = { ...@@ -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.0", &mstp_clks[MSTP113]),
CLKDEV_ICK_ID("fck", "sh-tmu.1", &mstp_clks[MSTP114]), CLKDEV_ICK_ID("fck", "sh-tmu.1", &mstp_clks[MSTP114]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP112]), CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP112]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP111]), CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP111]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP110]), CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP110]),
CLKDEV_CON_ID("usb_fck", &mstp_clks[MSTP103]), CLKDEV_CON_ID("usb_fck", &mstp_clks[MSTP103]),
CLKDEV_DEV_ID("renesas_usbhs.0", &mstp_clks[MSTP102]), CLKDEV_DEV_ID("renesas_usbhs.0", &mstp_clks[MSTP102]),
......
...@@ -132,12 +132,12 @@ static struct clk_lookup lookups[] = { ...@@ -132,12 +132,12 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]), CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
/* MSTP32 clocks */ /* MSTP32 clocks */
CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP029]), CLKDEV_ICK_ID("fck", "sh-sci.5", &mstp_clks[MSTP029]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP028]), CLKDEV_ICK_ID("fck", "sh-sci.4", &mstp_clks[MSTP028]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP027]), CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[MSTP027]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP026]), CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP026]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]), CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP025]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP024]), CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP024]),
CLKDEV_CON_ID("ssi1_fck", &mstp_clks[MSTP021]), CLKDEV_CON_ID("ssi1_fck", &mstp_clks[MSTP021]),
CLKDEV_CON_ID("ssi0_fck", &mstp_clks[MSTP020]), CLKDEV_CON_ID("ssi0_fck", &mstp_clks[MSTP020]),
......
...@@ -139,12 +139,12 @@ static struct clk_lookup lookups[] = { ...@@ -139,12 +139,12 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]), CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
/* MSTP32 clocks */ /* MSTP32 clocks */
CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP029]), CLKDEV_ICK_ID("fck", "sh-sci.5", &mstp_clks[MSTP029]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP028]), CLKDEV_ICK_ID("fck", "sh-sci.4", &mstp_clks[MSTP028]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP027]), CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[MSTP027]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP026]), CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP026]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]), CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP025]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP024]), CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP024]),
CLKDEV_CON_ID("ssi3_fck", &mstp_clks[MSTP023]), CLKDEV_CON_ID("ssi3_fck", &mstp_clks[MSTP023]),
CLKDEV_CON_ID("ssi2_fck", &mstp_clks[MSTP022]), CLKDEV_CON_ID("ssi2_fck", &mstp_clks[MSTP022]),
......
...@@ -114,10 +114,10 @@ static struct clk_lookup lookups[] = { ...@@ -114,10 +114,10 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]), CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
/* MSTP32 clocks */ /* MSTP32 clocks */
CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP027]), CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[MSTP027]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP026]), CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP026]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]), CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP025]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP024]), CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP024]),
CLKDEV_CON_ID("h8ex_fck", &mstp_clks[MSTP003]), CLKDEV_CON_ID("h8ex_fck", &mstp_clks[MSTP003]),
CLKDEV_CON_ID("csm_fck", &mstp_clks[MSTP002]), CLKDEV_CON_ID("csm_fck", &mstp_clks[MSTP002]),
......
...@@ -28,7 +28,7 @@ static struct plat_sci_port scif0_platform_data = { ...@@ -28,7 +28,7 @@ static struct plat_sci_port scif0_platform_data = {
.flags = UPF_BOOT_AUTOCONF, .flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCIF, .type = PORT_SCIF,
.regtype = SCIx_SH4_SCIF_REGTYPE, .regtype = SCIx_SH4_SCIF_BRG_REGTYPE,
}; };
static struct resource scif0_resources[] = { static struct resource scif0_resources[] = {
...@@ -50,7 +50,7 @@ static struct plat_sci_port scif1_platform_data = { ...@@ -50,7 +50,7 @@ static struct plat_sci_port scif1_platform_data = {
.flags = UPF_BOOT_AUTOCONF, .flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCIF, .type = PORT_SCIF,
.regtype = SCIx_SH4_SCIF_REGTYPE, .regtype = SCIx_SH4_SCIF_BRG_REGTYPE,
}; };
static struct resource scif1_resources[] = { static struct resource scif1_resources[] = {
...@@ -72,7 +72,7 @@ static struct plat_sci_port scif2_platform_data = { ...@@ -72,7 +72,7 @@ static struct plat_sci_port scif2_platform_data = {
.flags = UPF_BOOT_AUTOCONF, .flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCIF, .type = PORT_SCIF,
.regtype = SCIx_SH4_SCIF_REGTYPE, .regtype = SCIx_SH4_SCIF_BRG_REGTYPE,
}; };
static struct resource scif2_resources[] = { static struct resource scif2_resources[] = {
...@@ -94,7 +94,7 @@ static struct plat_sci_port scif3_platform_data = { ...@@ -94,7 +94,7 @@ static struct plat_sci_port scif3_platform_data = {
.flags = UPF_BOOT_AUTOCONF, .flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
.type = PORT_SCIF, .type = PORT_SCIF,
.regtype = SCIx_SH4_SCIF_REGTYPE, .regtype = SCIx_SH4_SCIF_BRG_REGTYPE,
}; };
static struct resource scif3_resources[] = { static struct resource scif3_resources[] = {
...@@ -116,7 +116,7 @@ static struct plat_sci_port scif4_platform_data = { ...@@ -116,7 +116,7 @@ static struct plat_sci_port scif4_platform_data = {
.flags = UPF_BOOT_AUTOCONF, .flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCIF, .type = PORT_SCIF,
.regtype = SCIx_SH4_SCIF_REGTYPE, .regtype = SCIx_SH4_SCIF_BRG_REGTYPE,
}; };
static struct resource scif4_resources[] = { static struct resource scif4_resources[] = {
...@@ -138,7 +138,7 @@ static struct plat_sci_port scif5_platform_data = { ...@@ -138,7 +138,7 @@ static struct plat_sci_port scif5_platform_data = {
.flags = UPF_BOOT_AUTOCONF, .flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCIF, .type = PORT_SCIF,
.regtype = SCIx_SH4_SCIF_REGTYPE, .regtype = SCIx_SH4_SCIF_BRG_REGTYPE,
}; };
static struct resource scif5_resources[] = { static struct resource scif5_resources[] = {
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO)
* *
* Copyright (C) 2002 - 2011 Paul Mundt * Copyright (C) 2002 - 2011 Paul Mundt
* Copyright (C) 2015 Glider bvba
* Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007). * Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007).
* *
* based off of the old drivers/char/sh-sci.c by: * based off of the old drivers/char/sh-sci.c by:
...@@ -76,6 +77,14 @@ enum { ...@@ -76,6 +77,14 @@ enum {
((port)->irqs[SCIx_ERI_IRQ] && \ ((port)->irqs[SCIx_ERI_IRQ] && \
((port)->irqs[SCIx_RXI_IRQ] < 0)) ((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 sci_port {
struct uart_port port; struct uart_port port;
...@@ -92,10 +101,9 @@ struct sci_port { ...@@ -92,10 +101,9 @@ struct sci_port {
struct timer_list break_timer; struct timer_list break_timer;
int break_flag; int break_flag;
/* Interface clock */ /* Clocks */
struct clk *iclk; struct clk *clks[SCI_NUM_CLKS];
/* Function clock */ unsigned long clk_rates[SCI_NUM_CLKS];
struct clk *fclk;
int irqs[SCIx_NR_IRQS]; int irqs[SCIx_NR_IRQS];
char *irqstr[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] = { ...@@ -163,6 +171,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid, [SCPCR] = sci_reg_invalid,
[SCPDR] = 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] = { ...@@ -185,6 +195,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid, [SCPCR] = sci_reg_invalid,
[SCPDR] = 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] = { ...@@ -206,6 +218,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid,
[SCPCR] = { 0x30, 16 }, [SCPCR] = { 0x30, 16 },
[SCPDR] = { 0x34, 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] = { ...@@ -227,6 +241,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid,
[SCPCR] = { 0x30, 16 }, [SCPCR] = { 0x30, 16 },
[SCPDR] = { 0x34, 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] = { ...@@ -249,6 +265,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid, [SCPCR] = sci_reg_invalid,
[SCPDR] = 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] = { ...@@ -270,6 +288,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid, [SCPCR] = sci_reg_invalid,
[SCPDR] = 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] = { ...@@ -291,6 +311,32 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid, [SCPCR] = sci_reg_invalid,
[SCPDR] = 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] = { ...@@ -312,6 +358,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = { 0x40, 16 }, [HSSRR] = { 0x40, 16 },
[SCPCR] = sci_reg_invalid, [SCPCR] = sci_reg_invalid,
[SCPDR] = 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] = { ...@@ -334,6 +382,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid, [SCPCR] = sci_reg_invalid,
[SCPDR] = 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] = { ...@@ -356,6 +406,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid, [SCPCR] = sci_reg_invalid,
[SCPDR] = 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] = { ...@@ -378,6 +430,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid, [SCPCR] = sci_reg_invalid,
[SCPDR] = 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) ...@@ -452,18 +506,24 @@ static int sci_probe_regmap(struct plat_sci_port *cfg)
static void sci_port_enable(struct sci_port *sci_port) static void sci_port_enable(struct sci_port *sci_port)
{ {
unsigned int i;
if (!sci_port->port.dev) if (!sci_port->port.dev)
return; return;
pm_runtime_get_sync(sci_port->port.dev); pm_runtime_get_sync(sci_port->port.dev);
clk_prepare_enable(sci_port->iclk); for (i = 0; i < SCI_NUM_CLKS; i++) {
sci_port->port.uartclk = clk_get_rate(sci_port->iclk); clk_prepare_enable(sci_port->clks[i]);
clk_prepare_enable(sci_port->fclk); 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) static void sci_port_disable(struct sci_port *sci_port)
{ {
unsigned int i;
if (!sci_port->port.dev) if (!sci_port->port.dev)
return; return;
...@@ -475,8 +535,8 @@ static void sci_port_disable(struct sci_port *sci_port) ...@@ -475,8 +535,8 @@ static void sci_port_disable(struct sci_port *sci_port)
del_timer_sync(&sci_port->break_timer); del_timer_sync(&sci_port->break_timer);
sci_port->break_flag = 0; sci_port->break_flag = 0;
clk_disable_unprepare(sci_port->fclk); for (i = SCI_NUM_CLKS; i-- > 0; )
clk_disable_unprepare(sci_port->iclk); clk_disable_unprepare(sci_port->clks[i]);
pm_runtime_put_sync(sci_port->port.dev); pm_runtime_put_sync(sci_port->port.dev);
} }
...@@ -1615,6 +1675,7 @@ static int sci_notifier(struct notifier_block *self, ...@@ -1615,6 +1675,7 @@ static int sci_notifier(struct notifier_block *self,
{ {
struct sci_port *sci_port; struct sci_port *sci_port;
unsigned long flags; unsigned long flags;
unsigned int i;
sci_port = container_of(self, struct sci_port, freq_transition); sci_port = container_of(self, struct sci_port, freq_transition);
...@@ -1622,7 +1683,9 @@ static int sci_notifier(struct notifier_block *self, ...@@ -1622,7 +1683,9 @@ static int sci_notifier(struct notifier_block *self,
struct uart_port *port = &sci_port->port; struct uart_port *port = &sci_port->port;
spin_lock_irqsave(&port->lock, flags); 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); spin_unlock_irqrestore(&port->lock, flags);
} }
...@@ -1864,90 +1927,149 @@ static void sci_shutdown(struct uart_port *port) ...@@ -1864,90 +1927,149 @@ static void sci_shutdown(struct uart_port *port)
sci_free_irq(s); sci_free_irq(s);
} }
static unsigned int sci_scbrr_calc(struct sci_port *s, unsigned int bps, static int sci_sck_calc(struct sci_port *s, unsigned int bps,
unsigned long freq) unsigned int *srr)
{ {
if (s->sampling_rate) unsigned long freq = s->clk_rates[SCI_SCK];
return DIV_ROUND_CLOSEST(freq, s->sampling_rate * bps) - 1; 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 */ if (!err)
WARN_ON(1); 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_brg_calc(struct sci_port *s, unsigned int bps,
static int sci_baud_calc_frame_len(unsigned int smr_val) 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) if (s->sampling_rate) {
len--; /* SCIF has a fixed sampling rate */
if (smr_val & SCSMR_PE) min_sr = max_sr = s->sampling_rate / 2;
len++; } else {
if (smr_val & SCSMR_STOP) /* HSCIF has a variable 1/(8..32) sampling rate */
len++; 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 */ /* calculate sample rate, BRR, and clock select */
static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq, static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
int *brr, unsigned int *srr, unsigned int *brr, unsigned int *srr,
unsigned int *cks, int frame_len) unsigned int *cks)
{ {
int sr, c, br, err, recv_margin; unsigned int min_sr, max_sr, shift, sr, br, prediv, scrate, c;
int min_err = 1000; /* 100% */ unsigned long freq = s->clk_rates[SCI_FCK];
int recv_max_margin = 0; int err, min_err = INT_MAX;
/* Find the combination of sample rate and clock select with the if (s->sampling_rate) {
smallest deviation from the desired baud rate. */ min_sr = max_sr = s->sampling_rate;
for (sr = 8; sr <= 32; sr++) { 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++) { for (c = 0; c <= 3; c++) {
/* integerized formulas from HSCIF documentation */ /* integerized formulas from HSCIF documentation */
br = DIV_ROUND_CLOSEST(freq, (sr * prediv = sr * (1 << (2 * c + shift));
(1 << (2 * c + 1)) * bps)) - 1;
br = clamp(br, 0, 255); /*
err = DIV_ROUND_CLOSEST(freq, ((br + 1) * bps * sr * * We need to calculate:
(1 << (2 * c + 1)) / 1000)) - *
1000; * br = freq / (prediv * bps) clamped to [1..256]
/* Calc recv margin * err = freq / (br * prediv) - bps
* 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) - * Watch out for overflow when calculating the desired
* (|D - 0.5| / N * (1 + F))| * sampling clock rate!
* NOTE: Usually, treat D for 0.5, F is 0 by this
* calculation.
*/ */
recv_margin = abs((500 - if (bps > UINT_MAX / prediv)
DIV_ROUND_CLOSEST(1000, sr << 1)) / 10); break;
if (abs(min_err) > abs(err)) {
min_err = err; scrate = prediv * bps;
recv_max_margin = recv_margin; br = DIV_ROUND_CLOSEST(freq, scrate);
} else if ((min_err == err) && br = clamp(br, 1U, 256U);
(recv_margin > recv_max_margin))
recv_max_margin = recv_margin; err = DIV_ROUND_CLOSEST(freq, br * prediv) - bps;
else if (abs(err) >= abs(min_err))
continue; continue;
*brr = br; min_err = err;
*brr = br - 1;
*srr = sr - 1; *srr = sr - 1;
*cks = c; *cks = c;
if (!err)
goto found;
} }
} }
if (min_err == 1000) { found:
WARN_ON(1); dev_dbg(s->port.dev, "BRR: %u%+d bps using N %u SR %u cks %u\n", bps,
/* use defaults */ min_err, *brr, *srr + 1, *cks);
*brr = 255; return min_err;
*srr = 15;
*cks = 0;
}
} }
static void sci_reset(struct uart_port *port) static void sci_reset(struct uart_port *port)
...@@ -1969,11 +2091,14 @@ 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, static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old) 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); struct sci_port *s = to_sci_port(port);
const struct plat_sci_reg *reg; const struct plat_sci_reg *reg;
unsigned int baud, smr_val = 0, max_baud, cks = 0; int min_err = INT_MAX, err;
int t = -1; unsigned long max_freq = 0;
unsigned int srr = 15; int best_clk = -1;
if ((termios->c_cflag & CSIZE) == CS7) if ((termios->c_cflag & CSIZE) == CS7)
smr_val |= SCSMR_CHR; smr_val |= SCSMR_CHR;
...@@ -1992,41 +2117,123 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, ...@@ -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 * that the previous boot loader has enabled required clocks and
* setup the baud rate generator hardware for us already. * setup the baud rate generator hardware for us already.
*/ */
max_baud = port->uartclk ? port->uartclk / 16 : 115200; if (!port->uartclk) {
baud = uart_get_baud_rate(port, termios, old, 0, 115200);
baud = uart_get_baud_rate(port, termios, old, 0, max_baud); goto done;
if (likely(baud && port->uartclk)) { }
if (s->cfg->type == PORT_HSCIF) {
int frame_len = sci_baud_calc_frame_len(smr_val); for (i = 0; i < SCI_NUM_CLKS; i++)
sci_baud_calc_hscif(baud, port->uartclk, &t, &srr, max_freq = max(max_freq, s->clk_rates[i]);
&cks, frame_len);
} else { baud = uart_get_baud_rate(port, termios, old, 0,
t = sci_scbrr_calc(s, baud, port->uartclk); max_freq / max(s->sampling_rate, 8U));
for (cks = 0; t >= 256 && cks <= 3; cks++) if (!baud)
t >>= 2; 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_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); uart_update_timeout(port, termios->c_cflag, baud);
dev_dbg(port->dev, "%s: SMR %x, cks %x, t %x, SCSCR %x\n", if (best_clk >= 0) {
__func__, smr_val, cks, t, s->cfg->scscr); smr_val |= cks;
dev_dbg(port->dev,
if (t >= 0) { "SCR 0x%x SMR 0x%x BRR %u CKS 0x%x DL %u SRR %u\n",
serial_port_out(port, SCSMR, (smr_val & ~SCSMR_CKS) | cks); scr_val, smr_val, brr, sccks, dl, srr);
serial_port_out(port, SCBRR, t); serial_port_out(port, SCSCR, scr_val);
reg = sci_getreg(port, HSSRR); serial_port_out(port, SCSMR, smr_val);
if (reg->size) serial_port_out(port, SCBRR, brr);
if (sci_getreg(port, HSSRR)->size)
serial_port_out(port, HSSRR, srr | HSCIF_SRE); 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); serial_port_out(port, SCSMR, smr_val);
}
sci_init_pins(port, termios->c_cflag); sci_init_pins(port, termios->c_cflag);
...@@ -2051,7 +2258,9 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, ...@@ -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, 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 #ifdef CONFIG_SERIAL_SH_SCI_DMA
/* /*
...@@ -2241,6 +2450,63 @@ static struct uart_ops sci_uart_ops = { ...@@ -2241,6 +2450,63 @@ static struct uart_ops sci_uart_ops = {
#endif #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, static int sci_init_single(struct platform_device *dev,
struct sci_port *sci_port, unsigned int index, struct sci_port *sci_port, unsigned int index,
struct plat_sci_port *p, bool early) struct plat_sci_port *p, bool early)
...@@ -2333,22 +2599,9 @@ static int sci_init_single(struct platform_device *dev, ...@@ -2333,22 +2599,9 @@ static int sci_init_single(struct platform_device *dev,
sci_port->sampling_rate = p->sampling_rate; sci_port->sampling_rate = p->sampling_rate;
if (!early) { if (!early) {
sci_port->iclk = clk_get(&dev->dev, "sci_ick"); ret = sci_init_clocks(sci_port, &dev->dev);
if (IS_ERR(sci_port->iclk)) { if (ret < 0)
sci_port->iclk = clk_get(&dev->dev, "peripheral_clk"); return ret;
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;
port->dev = &dev->dev; port->dev = &dev->dev;
...@@ -2405,9 +2658,6 @@ static int sci_init_single(struct platform_device *dev, ...@@ -2405,9 +2658,6 @@ static int sci_init_single(struct platform_device *dev,
static void sci_cleanup_single(struct sci_port *port) static void sci_cleanup_single(struct sci_port *port)
{ {
clk_put(port->iclk);
clk_put(port->fclk);
pm_runtime_disable(port->port.dev); pm_runtime_disable(port->port.dev);
} }
...@@ -2426,7 +2676,7 @@ static void serial_console_write(struct console *co, const char *s, ...@@ -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 sci_port *sci_port = &sci_ports[co->index];
struct uart_port *port = &sci_port->port; struct uart_port *port = &sci_port->port;
unsigned short bits, ctrl; unsigned short bits, ctrl, ctrl_temp;
unsigned long flags; unsigned long flags;
int locked = 1; int locked = 1;
...@@ -2438,9 +2688,11 @@ static void serial_console_write(struct console *co, const char *s, ...@@ -2438,9 +2688,11 @@ static void serial_console_write(struct console *co, const char *s,
else else
spin_lock(&port->lock); 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); 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); uart_console_write(port, s, count, serial_console_putchar);
...@@ -2569,42 +2821,44 @@ static int sci_remove(struct platform_device *dev) ...@@ -2569,42 +2821,44 @@ static int sci_remove(struct platform_device *dev)
return 0; return 0;
} }
struct sci_port_info {
unsigned int type; #define SCI_OF_DATA(type, regtype) (void *)((type) << 16 | (regtype))
unsigned int 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[] = { 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", .compatible = "renesas,scif",
.data = &(const struct sci_port_info) { .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_REGTYPE),
.type = PORT_SCIF,
.regtype = SCIx_SH4_SCIF_REGTYPE,
},
}, { }, {
.compatible = "renesas,scifa", .compatible = "renesas,scifa",
.data = &(const struct sci_port_info) { .data = SCI_OF_DATA(PORT_SCIFA, SCIx_SCIFA_REGTYPE),
.type = PORT_SCIFA,
.regtype = SCIx_SCIFA_REGTYPE,
},
}, { }, {
.compatible = "renesas,scifb", .compatible = "renesas,scifb",
.data = &(const struct sci_port_info) { .data = SCI_OF_DATA(PORT_SCIFB, SCIx_SCIFB_REGTYPE),
.type = PORT_SCIFB,
.regtype = SCIx_SCIFB_REGTYPE,
},
}, { }, {
.compatible = "renesas,hscif", .compatible = "renesas,hscif",
.data = &(const struct sci_port_info) { .data = SCI_OF_DATA(PORT_HSCIF, SCIx_HSCIF_REGTYPE),
.type = PORT_HSCIF,
.regtype = SCIx_HSCIF_REGTYPE,
},
}, { }, {
.compatible = "renesas,sci", .compatible = "renesas,sci",
.data = &(const struct sci_port_info) { .data = SCI_OF_DATA(PORT_SCI, SCIx_SCI_REGTYPE),
.type = PORT_SCI,
.regtype = SCIx_SCI_REGTYPE,
},
}, { }, {
/* Terminator */ /* Terminator */
}, },
...@@ -2616,24 +2870,21 @@ sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id) ...@@ -2616,24 +2870,21 @@ sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match; const struct of_device_id *match;
const struct sci_port_info *info;
struct plat_sci_port *p; struct plat_sci_port *p;
int id; int id;
if (!IS_ENABLED(CONFIG_OF) || !np) if (!IS_ENABLED(CONFIG_OF) || !np)
return NULL; return NULL;
match = of_match_node(of_sci_match, pdev->dev.of_node); match = of_match_node(of_sci_match, np);
if (!match) if (!match)
return NULL; return NULL;
info = match->data;
p = devm_kzalloc(&pdev->dev, sizeof(struct plat_sci_port), GFP_KERNEL); p = devm_kzalloc(&pdev->dev, sizeof(struct plat_sci_port), GFP_KERNEL);
if (!p) if (!p)
return NULL; 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"); id = of_alias_get_id(np, "serial");
if (id < 0) { if (id < 0) {
dev_err(&pdev->dev, "failed to get alias id (%d)\n", id); 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) ...@@ -2643,8 +2894,8 @@ sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id)
*dev_id = id; *dev_id = id;
p->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; p->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
p->type = info->type; p->type = SCI_OF_TYPE(match->data);
p->regtype = info->regtype; p->regtype = SCI_OF_REGTYPE(match->data);
p->scscr = SCSCR_RE | SCSCR_TE; p->scscr = SCSCR_RE | SCSCR_TE;
return p; return p;
......
...@@ -27,6 +27,8 @@ enum { ...@@ -27,6 +27,8 @@ enum {
HSSRR, /* Sampling Rate Register */ HSSRR, /* Sampling Rate Register */
SCPCR, /* Serial Port Control Register */ SCPCR, /* Serial Port Control Register */
SCPDR, /* Serial Port Data Register */ SCPDR, /* Serial Port Data Register */
SCDL, /* BRG Frequency Division Register */
SCCKS, /* BRG Clock Select Register */
SCIx_NR_REGS, SCIx_NR_REGS,
}; };
...@@ -109,6 +111,14 @@ enum { ...@@ -109,6 +111,14 @@ enum {
#define SCPDR_RTSD BIT(4) /* Serial Port RTS Output Pin Data */ #define SCPDR_RTSD BIT(4) /* Serial Port RTS Output Pin Data */
#define SCPDR_CTSD BIT(3) /* Serial Port CTS Input 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_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND)
#define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF) #define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF)
......
...@@ -32,6 +32,7 @@ enum { ...@@ -32,6 +32,7 @@ enum {
SCIx_SH2_SCIF_FIFODATA_REGTYPE, SCIx_SH2_SCIF_FIFODATA_REGTYPE,
SCIx_SH3_SCIF_REGTYPE, SCIx_SH3_SCIF_REGTYPE,
SCIx_SH4_SCIF_REGTYPE, SCIx_SH4_SCIF_REGTYPE,
SCIx_SH4_SCIF_BRG_REGTYPE,
SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE, SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
SCIx_SH4_SCIF_FIFODATA_REGTYPE, SCIx_SH4_SCIF_FIFODATA_REGTYPE,
SCIx_SH7705_SCIF_REGTYPE, SCIx_SH7705_SCIF_REGTYPE,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment