Merge branch 'for-linus' of git://git.kernel.dk/linux-block
Pull followup block layer updates from Jens Axboe:
"Two things in this pull request:
- A block throttle oops fix (marked for stable) from Thadeu.
- The NVMe fixes/features queued up for 3.20, but merged later in the
process. From Keith. We should have gotten this merged earlier,
we're ironing out the kinks in the process. Will be ready for the
initial pull next series"
* 'for-linus' of git://git.kernel.dk/linux-block:
blk-throttle: check stats_cpu before reading it from sysfs
NVMe: Fix potential corruption on sync commands
NVMe: Remove unused variables
NVMe: Fix scsi mode select llbaa setting
NVMe: Fix potential corruption during shutdown
NVMe: Asynchronous controller probe
NVMe: Register management handle under nvme class
NVMe: Update SCSI Inquiry VPD 83h translation
NVMe: Metadata format support
diff --git a/Documentation/DocBook/kgdb.tmpl b/Documentation/DocBook/kgdb.tmpl
index 2428cc0..f3abca7 100644
--- a/Documentation/DocBook/kgdb.tmpl
+++ b/Documentation/DocBook/kgdb.tmpl
@@ -197,6 +197,7 @@
may be configured as a kernel built-in or a kernel loadable module.
You can only make use of <constant>kgdbwait</constant> and early
debugging if you build kgdboc into the kernel as a built-in.
+ </para>
<para>Optionally you can elect to activate kms (Kernel Mode
Setting) integration. When you use kms with kgdboc and you have a
video driver that has atomic mode setting hooks, it is possible to
@@ -206,7 +207,6 @@
crashes or doing analysis of memory with kdb while allowing the
full graphics console applications to run.
</para>
- </para>
<sect2 id="kgdbocArgs">
<title>kgdboc arguments</title>
<para>Usage: <constant>kgdboc=[kms][[,]kbd][[,]serial_device][,baud]</constant></para>
@@ -284,7 +284,6 @@
</listitem>
</orderedlist>
</para>
- </sect3>
<para>NOTE: Kgdboc does not support interrupting the target via the
gdb remote protocol. You must manually send a sysrq-g unless you
have a proxy that splits console output to a terminal program.
@@ -305,6 +304,7 @@
as well as on the initial connect, or to use a debugger proxy that
allows an unmodified gdb to do the debugging.
</para>
+ </sect3>
</sect2>
</sect1>
<sect1 id="kgdbwait">
@@ -350,12 +350,12 @@
</para>
</listitem>
</orderedlist>
+ </para>
<para>IMPORTANT NOTE: You cannot use kgdboc + kgdbcon on a tty that is an
active system console. An example of incorrect usage is <constant>console=ttyS0,115200 kgdboc=ttyS0 kgdbcon</constant>
</para>
<para>It is possible to use this option with kgdboc on a tty that is not a system console.
</para>
- </para>
</sect1>
<sect1 id="kgdbreboot">
<title>Run time parameter: kgdbreboot</title>
diff --git a/Documentation/clk.txt b/Documentation/clk.txt
index 4ff8462..0e4f90a 100644
--- a/Documentation/clk.txt
+++ b/Documentation/clk.txt
@@ -73,6 +73,8 @@
unsigned long *parent_rate);
long (*determine_rate)(struct clk_hw *hw,
unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk);
int (*set_parent)(struct clk_hw *hw, u8 index);
diff --git a/Documentation/device-mapper/dm-crypt.txt b/Documentation/device-mapper/dm-crypt.txt
index c81839b..ad69778 100644
--- a/Documentation/device-mapper/dm-crypt.txt
+++ b/Documentation/device-mapper/dm-crypt.txt
@@ -51,7 +51,7 @@
Otherwise #opt_params is the number of following arguments.
Example of optional parameters section:
- 1 allow_discards
+ 3 allow_discards same_cpu_crypt submit_from_crypt_cpus
allow_discards
Block discard requests (a.k.a. TRIM) are passed through the crypt device.
@@ -63,6 +63,19 @@
used space etc.) if the discarded blocks can be located easily on the
device later.
+same_cpu_crypt
+ Perform encryption using the same cpu that IO was submitted on.
+ The default is to use an unbound workqueue so that encryption work
+ is automatically balanced between available CPUs.
+
+submit_from_crypt_cpus
+ Disable offloading writes to a separate thread after encryption.
+ There are some situations where offloading write bios from the
+ encryption threads to a single thread degrades performance
+ significantly. The default is to offload write bios to the same
+ thread because it benefits CFQ to have writes submitted using the
+ same context.
+
Example scripts
===============
LUKS (Linux Unified Key Setup) is now the preferred way to set up disk
diff --git a/Documentation/devicetree/bindings/clock/exynos7-clock.txt b/Documentation/devicetree/bindings/clock/exynos7-clock.txt
index 6d3d5f8..6bf1e74 100644
--- a/Documentation/devicetree/bindings/clock/exynos7-clock.txt
+++ b/Documentation/devicetree/bindings/clock/exynos7-clock.txt
@@ -34,6 +34,8 @@
- "samsung,exynos7-clock-peris"
- "samsung,exynos7-clock-fsys0"
- "samsung,exynos7-clock-fsys1"
+ - "samsung,exynos7-clock-mscl"
+ - "samsung,exynos7-clock-aud"
- reg: physical base address of the controller and the length of
memory mapped region.
@@ -53,6 +55,7 @@
- dout_sclk_bus1_pll
- dout_sclk_cc_pll
- dout_sclk_mfc_pll
+ - dout_sclk_aud_pll
Input clocks for top1 clock controller:
- fin_pll
@@ -76,6 +79,14 @@
- sclk_uart1
- sclk_uart2
- sclk_uart3
+ - sclk_spi0
+ - sclk_spi1
+ - sclk_spi2
+ - sclk_spi3
+ - sclk_spi4
+ - sclk_i2s1
+ - sclk_pcm1
+ - sclk_spdif
Input clocks for peris clock controller:
- fin_pll
@@ -91,3 +102,7 @@
- dout_aclk_fsys1_200
- dout_sclk_mmc0
- dout_sclk_mmc1
+
+Input clocks for aud clock controller:
+ - fin_pll
+ - fout_aud_pll
diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt
index ded5d62..c6620bc 100644
--- a/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt
+++ b/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt
@@ -1,4 +1,4 @@
-NVIDIA Tegra124 Clock And Reset Controller
+NVIDIA Tegra124 and Tegra132 Clock And Reset Controller
This binding uses the common clock binding:
Documentation/devicetree/bindings/clock/clock-bindings.txt
@@ -7,14 +7,16 @@
for muxing and gating Tegra's clocks, and setting their rates.
Required properties :
-- compatible : Should be "nvidia,tegra124-car"
+- compatible : Should be "nvidia,tegra124-car" or "nvidia,tegra132-car"
- reg : Should contain CAR registers location and length
- clocks : Should contain phandle and clock specifiers for two clocks:
the 32 KHz "32k_in", and the board-specific oscillator "osc".
- #clock-cells : Should be 1.
In clock consumers, this cell represents the clock ID exposed by the
- CAR. The assignments may be found in header file
- <dt-bindings/clock/tegra124-car.h>.
+ CAR. The assignments may be found in the header files
+ <dt-bindings/clock/tegra124-car-common.h> (which covers IDs common
+ to Tegra124 and Tegra132) and <dt-bindings/clock/tegra124-car.h>
+ (for Tegra124-specific clocks).
- #reset-cells : Should be 1.
In clock consumers, this cell represents the bit number in the CAR's
array of CLK_RST_CONTROLLER_RST_DEVICES_* registers.
diff --git a/Documentation/devicetree/bindings/clock/qcom,lcc.txt b/Documentation/devicetree/bindings/clock/qcom,lcc.txt
new file mode 100644
index 0000000..dd755be
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,lcc.txt
@@ -0,0 +1,21 @@
+Qualcomm LPASS Clock & Reset Controller Binding
+------------------------------------------------
+
+Required properties :
+- compatible : shall contain only one of the following:
+
+ "qcom,lcc-msm8960"
+ "qcom,lcc-apq8064"
+ "qcom,lcc-ipq8064"
+
+- reg : shall contain base register location and length
+- #clock-cells : shall contain 1
+- #reset-cells : shall contain 1
+
+Example:
+ clock-controller@28000000 {
+ compatible = "qcom,lcc-ipq8064";
+ reg = <0x28000000 0x1000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/clock/qoriq-clock.txt b/Documentation/devicetree/bindings/clock/qoriq-clock.txt
index 266ff9d..df4a259 100644
--- a/Documentation/devicetree/bindings/clock/qoriq-clock.txt
+++ b/Documentation/devicetree/bindings/clock/qoriq-clock.txt
@@ -1,6 +1,6 @@
-* Clock Block on Freescale CoreNet Platforms
+* Clock Block on Freescale QorIQ Platforms
-Freescale CoreNet chips take primary clocking input from the external
+Freescale qoriq chips take primary clocking input from the external
SYSCLK signal. The SYSCLK input (frequency) is multiplied using
multiple phase locked loops (PLL) to create a variety of frequencies
which can then be passed to a variety of internal logic, including
@@ -29,6 +29,7 @@
* "fsl,t4240-clockgen"
* "fsl,b4420-clockgen"
* "fsl,b4860-clockgen"
+ * "fsl,ls1021a-clockgen"
Chassis clock strings include:
* "fsl,qoriq-clockgen-1.0": for chassis 1.0 clocks
* "fsl,qoriq-clockgen-2.0": for chassis 2.0 clocks
diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
index 2e18676..0a80fa7 100644
--- a/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
+++ b/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
@@ -11,6 +11,7 @@
- compatible: Must be one of the following
- "renesas,r7s72100-mstp-clocks" for R7S72100 (RZ) MSTP gate clocks
+ - "renesas,r8a73a4-mstp-clocks" for R8A73A4 (R-Mobile APE6) MSTP gate clocks
- "renesas,r8a7740-mstp-clocks" for R8A7740 (R-Mobile A1) MSTP gate clocks
- "renesas,r8a7779-mstp-clocks" for R8A7779 (R-Car H1) MSTP gate clocks
- "renesas,r8a7790-mstp-clocks" for R8A7790 (R-Car H2) MSTP gate clocks
diff --git a/Documentation/devicetree/bindings/clock/renesas,r8a73a4-cpg-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,r8a73a4-cpg-clocks.txt
new file mode 100644
index 0000000..ece9239
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/renesas,r8a73a4-cpg-clocks.txt
@@ -0,0 +1,33 @@
+* Renesas R8A73A4 Clock Pulse Generator (CPG)
+
+The CPG generates core clocks for the R8A73A4 SoC. It includes five PLLs
+and several fixed ratio dividers.
+
+Required Properties:
+
+ - compatible: Must be "renesas,r8a73a4-cpg-clocks"
+
+ - reg: Base address and length of the memory resource used by the CPG
+
+ - clocks: Reference to the parent clocks ("extal1" and "extal2")
+
+ - #clock-cells: Must be 1
+
+ - clock-output-names: The names of the clocks. Supported clocks are "main",
+ "pll0", "pll1", "pll2", "pll2s", "pll2h", "z", "z2", "i", "m3", "b",
+ "m1", "m2", "zx", "zs", and "hp".
+
+
+Example
+-------
+
+ cpg_clocks: cpg_clocks@e6150000 {
+ compatible = "renesas,r8a73a4-cpg-clocks";
+ reg = <0 0xe6150000 0 0x10000>;
+ clocks = <&extal1_clk>, <&extal2_clk>;
+ #clock-cells = <1>;
+ clock-output-names = "main", "pll0", "pll1", "pll2",
+ "pll2s", "pll2h", "z", "z2",
+ "i", "m3", "b", "m1", "m2",
+ "zx", "zs", "hp";
+ };
diff --git a/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt
index e6ad35b..b02944f 100644
--- a/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt
+++ b/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt
@@ -8,15 +8,18 @@
- compatible: Must be one of
- "renesas,r8a7790-cpg-clocks" for the r8a7790 CPG
- "renesas,r8a7791-cpg-clocks" for the r8a7791 CPG
+ - "renesas,r8a7793-cpg-clocks" for the r8a7793 CPG
- "renesas,r8a7794-cpg-clocks" for the r8a7794 CPG
- "renesas,rcar-gen2-cpg-clocks" for the generic R-Car Gen2 CPG
- reg: Base address and length of the memory resource used by the CPG
- - clocks: Reference to the parent clock
+ - clocks: References to the parent clocks: first to the EXTAL clock, second
+ to the USB_EXTAL clock
- #clock-cells: Must be 1
- clock-output-names: The names of the clocks. Supported clocks are "main",
- "pll0", "pll1", "pll3", "lb", "qspi", "sdh", "sd0", "sd1" and "z"
+ "pll0", "pll1", "pll3", "lb", "qspi", "sdh", "sd0", "sd1", "z", "rcan", and
+ "adsp"
Example
@@ -26,8 +29,9 @@
compatible = "renesas,r8a7790-cpg-clocks",
"renesas,rcar-gen2-cpg-clocks";
reg = <0 0xe6150000 0 0x1000>;
- clocks = <&extal_clk>;
+ clocks = <&extal_clk &usb_extal_clk>;
#clock-cells = <1>;
clock-output-names = "main", "pll0, "pll1", "pll3",
- "lb", "qspi", "sdh", "sd0", "sd1", "z";
+ "lb", "qspi", "sdh", "sd0", "sd1", "z",
+ "rcan", "adsp";
};
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index 67b2b99..60b4428 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -26,7 +26,7 @@
"allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s
"allwinner,sun7i-a20-ahb-gates-clk" - for the AHB gates on A20
"allwinner,sun6i-a31-ar100-clk" - for the AR100 on A31
- "allwinner,sun6i-a31-ahb1-mux-clk" - for the AHB1 multiplexer on A31
+ "allwinner,sun6i-a31-ahb1-clk" - for the AHB1 clock on A31
"allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31
"allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23
"allwinner,sun9i-a80-ahb0-gates-clk" - for the AHB0 gates on A80
@@ -55,9 +55,11 @@
"allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
"allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
"allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13
- "allwinner,sun4i-a10-mmc-output-clk" - for the MMC output clock on A10
- "allwinner,sun4i-a10-mmc-sample-clk" - for the MMC sample clock on A10
+ "allwinner,sun4i-a10-mmc-clk" - for the MMC clock
+ "allwinner,sun9i-a80-mmc-clk" - for mmc module clocks on A80
+ "allwinner,sun9i-a80-mmc-config-clk" - for mmc gates + resets on A80
"allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks
+ "allwinner,sun9i-a80-mod0-clk" - for module 0 (storage) clocks on A80
"allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23
"allwinner,sun7i-a20-out-clk" - for the external output clocks
"allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
@@ -73,7 +75,9 @@
- #clock-cells : from common clock binding; shall be set to 0 except for
the following compatibles where it shall be set to 1:
"allwinner,*-gates-clk", "allwinner,sun4i-pll5-clk",
- "allwinner,sun4i-pll6-clk", "allwinner,sun6i-a31-pll6-clk"
+ "allwinner,sun4i-pll6-clk", "allwinner,sun6i-a31-pll6-clk",
+ "allwinner,*-usb-clk", "allwinner,*-mmc-clk",
+ "allwinner,*-mmc-config-clk"
- clock-output-names : shall be the corresponding names of the outputs.
If the clock module only has one output, the name shall be the
module name.
@@ -81,6 +85,10 @@
And "allwinner,*-usb-clk" clocks also require:
- reset-cells : shall be set to 1
+The "allwinner,sun9i-a80-mmc-config-clk" clock also requires:
+- #reset-cells : shall be set to 1
+- resets : shall be the reset control phandle for the mmc block.
+
For "allwinner,sun7i-a20-gmac-clk", the parent clocks shall be fixed rate
dummy clocks at 25 MHz and 125 MHz, respectively. See example.
@@ -95,6 +103,14 @@
is the normal PLL6 output, or "pll6". The second output is rate doubled
PLL6, or "pll6x2".
+The "allwinner,*-mmc-clk" clocks have three different outputs: the
+main clock, with the ID 0, and the output and sample clocks, with the
+IDs 1 and 2, respectively.
+
+The "allwinner,sun9i-a80-mmc-config-clk" clock has one clock/reset output
+per mmc controller. The number of outputs is determined by the size of
+the address block, which is related to the overall mmc block.
+
For example:
osc24M: clk@01c20050 {
@@ -138,11 +154,11 @@
};
mmc0_clk: clk@01c20088 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c20088 0x4>;
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "mmc0";
+ clock-output-names = "mmc0", "mmc0_output", "mmc0_sample";
};
mii_phy_tx_clk: clk@2 {
@@ -170,3 +186,16 @@
clocks = <&mii_phy_tx_clk>, <&gmac_int_tx_clk>;
clock-output-names = "gmac";
};
+
+mmc_config_clk: clk@01c13000 {
+ compatible = "allwinner,sun9i-a80-mmc-config-clk";
+ reg = <0x01c13000 0x10>;
+ clocks = <&ahb0_gates 8>;
+ clock-names = "ahb";
+ resets = <&ahb0_resets 8>;
+ reset-names = "ahb";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ clock-output-names = "mmc0_config", "mmc1_config",
+ "mmc2_config", "mmc3_config";
+};
diff --git a/Documentation/devicetree/bindings/clock/ti,cdce706.txt b/Documentation/devicetree/bindings/clock/ti,cdce706.txt
new file mode 100644
index 0000000..616836e
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/ti,cdce706.txt
@@ -0,0 +1,42 @@
+Bindings for Texas Instruments CDCE706 programmable 3-PLL clock
+synthesizer/multiplier/divider.
+
+Reference: http://www.ti.com/lit/ds/symlink/cdce706.pdf
+
+I2C device node required properties:
+- compatible: shall be "ti,cdce706".
+- reg: i2c device address, shall be in range [0x68...0x6b].
+- #clock-cells: from common clock binding; shall be set to 1.
+- clocks: from common clock binding; list of parent clock
+ handles, shall be reference clock(s) connected to CLK_IN0
+ and CLK_IN1 pins.
+- clock-names: shall be clk_in0 and/or clk_in1. Use clk_in0
+ in case of crystal oscillator or differential signal input
+ configuration. Use clk_in0 and clk_in1 in case of independent
+ single-ended LVCMOS inputs configuration.
+
+Example:
+
+ clocks {
+ clk54: clk54 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <54000000>;
+ };
+ };
+ ...
+ i2c0: i2c-master@0d090000 {
+ ...
+ cdce706: clock-synth@69 {
+ compatible = "ti,cdce706";
+ #clock-cells = <1>;
+ reg = <0x69>;
+ clocks = <&clk54>;
+ clock-names = "clk_in0";
+ };
+ };
+ ...
+ simple-audio-card,codec {
+ ...
+ clocks = <&cdce706 4>;
+ };
diff --git a/Documentation/devicetree/bindings/clock/ti/fapll.txt b/Documentation/devicetree/bindings/clock/ti/fapll.txt
new file mode 100644
index 0000000..c19b3f2
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/ti/fapll.txt
@@ -0,0 +1,33 @@
+Binding for Texas Instruments FAPLL clock.
+
+Binding status: Unstable - ABI compatibility may be broken in the future
+
+This binding uses the common clock binding[1]. It assumes a
+register-mapped FAPLL with usually two selectable input clocks
+(reference clock and bypass clock), and one or more child
+syntesizers.
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be "ti,dm816-fapll-clock"
+- #clock-cells : from common clock binding; shall be set to 0.
+- clocks : link phandles of parent clocks (clk-ref and clk-bypass)
+- reg : address and length of the register set for controlling the FAPLL.
+
+Examples:
+ main_fapll: main_fapll {
+ #clock-cells = <1>;
+ compatible = "ti,dm816-fapll-clock";
+ reg = <0x400 0x40>;
+ clocks = <&sys_clkin_ck &sys_clkin_ck>;
+ clock-indices = <1>, <2>, <3>, <4>, <5>,
+ <6>, <7>;
+ clock-output-names = "main_pll_clk1",
+ "main_pll_clk2",
+ "main_pll_clk3",
+ "main_pll_clk4",
+ "main_pll_clk5",
+ "main_pll_clk6",
+ "main_pll_clk7";
+ };
diff --git a/Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt b/Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt
new file mode 100644
index 0000000..81f982c
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt
@@ -0,0 +1,37 @@
+Broadcom iProc I2C controller
+
+Required properties:
+
+- compatible:
+ Must be "brcm,iproc-i2c"
+
+- reg:
+ Define the base and range of the I/O address space that contain the iProc
+ I2C controller registers
+
+- interrupts:
+ Should contain the I2C interrupt
+
+- clock-frequency:
+ This is the I2C bus clock. Need to be either 100000 or 400000
+
+- #address-cells:
+ Always 1 (for I2C addresses)
+
+- #size-cells:
+ Always 0
+
+Example:
+ i2c0: i2c@18008000 {
+ compatible = "brcm,iproc-i2c";
+ reg = <0x18008000 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>;
+ clock-frequency = <100000>;
+
+ codec: wm8750@1a {
+ compatible = "wlf,wm8750";
+ reg = <0x1a>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt
index 34a3fb6..cf53d5f 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt
@@ -16,6 +16,9 @@
Optional Properties:
- reset-gpios: Reference to the GPIO connected to the reset input.
+ - i2c-mux-idle-disconnect: Boolean; if defined, forces mux to disconnect all
+ children in idle state. This is necessary for example, if there are several
+ multiplexers on the bus and the devices behind them use same I2C addresses.
Example:
diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
index 1637c29..17bef9a 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
@@ -4,16 +4,34 @@
- compatible : "opencores,i2c-ocores" or "aeroflexgaisler,i2cmst"
- reg : bus address start and address range size of device
- interrupts : interrupt number
-- clock-frequency : frequency of bus clock in Hz
+- clocks : handle to the controller clock; see the note below.
+ Mutually exclusive with opencores,ip-clock-frequency
+- opencores,ip-clock-frequency: frequency of the controller clock in Hz;
+ see the note below. Mutually exclusive with clocks
- #address-cells : should be <1>
- #size-cells : should be <0>
Optional properties:
+- clock-frequency : frequency of bus clock in Hz; see the note below.
+ Defaults to 100 KHz when the property is not specified
- reg-shift : device register offsets are shifted by this value
- reg-io-width : io register width in bytes (1, 2 or 4)
- regstep : deprecated, use reg-shift above
-Example:
+Note
+clock-frequency property is meant to control the bus frequency for i2c bus
+drivers, but it was incorrectly used to specify i2c controller input clock
+frequency. So the following rules are set to fix this situation:
+- if clock-frequency is present and neither opencores,ip-clock-frequency nor
+ clocks are, then clock-frequency specifies i2c controller clock frequency.
+ This is to keep backwards compatibility with setups using old DTB. i2c bus
+ frequency is fixed at 100 KHz.
+- if clocks is present it specifies i2c controller clock. clock-frequency
+ property specifies i2c bus frequency.
+- if opencores,ip-clock-frequency is present it specifies i2c controller
+ clock frequency. clock-frequency property specifies i2c bus frequency.
+
+Examples:
i2c0: ocores@a0000000 {
#address-cells = <1>;
@@ -21,7 +39,25 @@
compatible = "opencores,i2c-ocores";
reg = <0xa0000000 0x8>;
interrupts = <10>;
- clock-frequency = <20000000>;
+ opencores,ip-clock-frequency = <20000000>;
+
+ reg-shift = <0>; /* 8 bit registers */
+ reg-io-width = <1>; /* 8 bit read/write */
+
+ dummy@60 {
+ compatible = "dummy";
+ reg = <0x60>;
+ };
+ };
+or
+ i2c0: ocores@a0000000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "opencores,i2c-ocores";
+ reg = <0xa0000000 0x8>;
+ interrupts = <10>;
+ clocks = <&osc>;
+ clock-frequency = <400000>; /* i2c bus frequency 400 KHz */
reg-shift = <0>; /* 8 bit registers */
reg-io-width = <1>; /* 8 bit read/write */
diff --git a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
index dde6c22..f0d71bc 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
@@ -21,6 +21,17 @@
Optional properties :
- clock-frequency : SCL frequency to use (in Hz). If omitted, 100kHz is used.
+ - i2c-scl-rising-time-ns : Number of nanoseconds the SCL signal takes to rise
+ (t(r) in I2C specification). If not specified this is assumed to be
+ the maximum the specification allows(1000 ns for Standard-mode,
+ 300 ns for Fast-mode) which might cause slightly slower communication.
+ - i2c-scl-falling-time-ns : Number of nanoseconds the SCL signal takes to fall
+ (t(f) in the I2C specification). If not specified this is assumed to
+ be the maximum the specification allows (300 ns) which might cause
+ slightly slower communication.
+ - i2c-sda-falling-time-ns : Number of nanoseconds the SDA signal takes to fall
+ (t(f) in the I2C specification). If not specified we'll use the SCL
+ value since they are the same in nearly all cases.
Example:
@@ -39,4 +50,7 @@
clock-names = "i2c";
clocks = <&cru PCLK_I2C0>;
+
+ i2c-scl-rising-time-ns = <800>;
+ i2c-scl-falling-time-ns = <100>;
};
diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
index 4dcd88d..aaa8325 100644
--- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt
+++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
@@ -61,9 +61,8 @@
gmt,g751 G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface
infineon,slb9635tt Infineon SLB9635 (Soft-) I2C TPM (old protocol, max 100khz)
infineon,slb9645tt Infineon SLB9645 I2C TPM (new protocol, max 400khz)
-isl,isl12057 Intersil ISL12057 I2C RTC Chip
-isil,isl29028 (deprecated, use isl)
-isl,isl29028 Intersil ISL29028 Ambient Light and Proximity Sensor
+isil,isl12057 Intersil ISL12057 I2C RTC Chip
+isil,isl29028 Intersil ISL29028 Ambient Light and Proximity Sensor
maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator
maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs
maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface
diff --git a/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt b/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt
index 91b3a34..4bf41d8 100644
--- a/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt
@@ -10,8 +10,8 @@
Required properties:
- compatible : "allwinner,sun4i-a10-mmc" or "allwinner,sun5i-a13-mmc"
- reg : mmc controller base registers
- - clocks : a list with 2 phandle + clock specifier pairs
- - clock-names : must contain "ahb" and "mmc"
+ - clocks : a list with 4 phandle + clock specifier pairs
+ - clock-names : must contain "ahb", "mmc", "output" and "sample"
- interrupts : mmc controller interrupt
Optional properties:
@@ -25,8 +25,8 @@
mmc0: mmc@01c0f000 {
compatible = "allwinner,sun5i-a13-mmc";
reg = <0x01c0f000 0x1000>;
- clocks = <&ahb_gates 8>, <&mmc0_clk>;
- clock-names = "ahb", "mod";
+ clocks = <&ahb_gates 8>, <&mmc0_clk>, <&mmc0_output_clk>, <&mmc0_sample_clk>;
+ clock-names = "ahb", "mod", "output", "sample";
interrupts = <0 32 4>;
status = "disabled";
};
diff --git a/Documentation/i2c/functionality b/Documentation/i2c/functionality
index 4556a3e..4aae8ed 100644
--- a/Documentation/i2c/functionality
+++ b/Documentation/i2c/functionality
@@ -12,7 +12,7 @@
-----------------------
For the most up-to-date list of functionality constants, please check
-<linux/i2c.h>!
+<uapi/linux/i2c.h>!
I2C_FUNC_I2C Plain i2c-level commands (Pure SMBus
adapters typically can not do these)
diff --git a/Documentation/input/alps.txt b/Documentation/input/alps.txt
index 90bca6f..a63e5e0 100644
--- a/Documentation/input/alps.txt
+++ b/Documentation/input/alps.txt
@@ -3,8 +3,8 @@
Introduction
------------
-Currently the ALPS touchpad driver supports five protocol versions in use by
-ALPS touchpads, called versions 1, 2, 3, 4 and 5.
+Currently the ALPS touchpad driver supports seven protocol versions in use by
+ALPS touchpads, called versions 1, 2, 3, 4, 5, 6 and 7.
Since roughly mid-2010 several new ALPS touchpads have been released and
integrated into a variety of laptops and netbooks. These new touchpads
@@ -240,3 +240,67 @@
byte 3: 0 x23 x22 x21 x20 x19 x18 x17
byte 4: 0 x9 x8 x7 x6 x5 x4 x3
byte 5: 0 x16 x15 x14 x13 x12 x11 x10
+
+ALPS Absolute Mode - Protocol Version 6
+---------------------------------------
+
+For trackstick packet, the format is:
+
+ byte 0: 1 1 1 1 1 1 1 1
+ byte 1: 0 X6 X5 X4 X3 X2 X1 X0
+ byte 2: 0 Y6 Y5 Y4 Y3 Y2 Y1 Y0
+ byte 3: ? Y7 X7 ? ? M R L
+ byte 4: Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0
+ byte 5: 0 1 1 1 1 1 1 1
+
+For touchpad packet, the format is:
+
+ byte 0: 1 1 1 1 1 1 1 1
+ byte 1: 0 0 0 0 x3 x2 x1 x0
+ byte 2: 0 0 0 0 y3 y2 y1 y0
+ byte 3: ? x7 x6 x5 x4 ? r l
+ byte 4: ? y7 y6 y5 y4 ? ? ?
+ byte 5: z7 z6 z5 z4 z3 z2 z1 z0
+
+(v6 touchpad does not have middle button)
+
+ALPS Absolute Mode - Protocol Version 7
+---------------------------------------
+
+For trackstick packet, the format is:
+
+ byte 0: 0 1 0 0 1 0 0 0
+ byte 1: 1 1 * * 1 M R L
+ byte 2: X7 1 X5 X4 X3 X2 X1 X0
+ byte 3: Z6 1 Y6 X6 1 Y2 Y1 Y0
+ byte 4: Y7 0 Y5 Y4 Y3 1 1 0
+ byte 5: T&P 0 Z5 Z4 Z3 Z2 Z1 Z0
+
+For touchpad packet, the format is:
+
+ packet-fmt b7 b6 b5 b4 b3 b2 b1 b0
+ byte 0: TWO & MULTI L 1 R M 1 Y0-2 Y0-1 Y0-0
+ byte 0: NEW L 1 X1-5 1 1 Y0-2 Y0-1 Y0-0
+ byte 1: Y0-10 Y0-9 Y0-8 Y0-7 Y0-6 Y0-5 Y0-4 Y0-3
+ byte 2: X0-11 1 X0-10 X0-9 X0-8 X0-7 X0-6 X0-5
+ byte 3: X1-11 1 X0-4 X0-3 1 X0-2 X0-1 X0-0
+ byte 4: TWO X1-10 TWO X1-9 X1-8 X1-7 X1-6 X1-5 X1-4
+ byte 4: MULTI X1-10 TWO X1-9 X1-8 X1-7 X1-6 Y1-5 1
+ byte 4: NEW X1-10 TWO X1-9 X1-8 X1-7 X1-6 0 0
+ byte 5: TWO & NEW Y1-10 0 Y1-9 Y1-8 Y1-7 Y1-6 Y1-5 Y1-4
+ byte 5: MULTI Y1-10 0 Y1-9 Y1-8 Y1-7 Y1-6 F-1 F-0
+
+ L: Left button
+ R / M: Non-clickpads: Right / Middle button
+ Clickpads: When > 2 fingers are down, and some fingers
+ are in the button area, then the 2 coordinates reported
+ are for fingers outside the button area and these report
+ extra fingers being present in the right / left button
+ area. Note these fingers are not added to the F field!
+ so if a TWO packet is received and R = 1 then there are
+ 3 fingers down, etc.
+ TWO: 1: Two touches present, byte 0/4/5 are in TWO fmt
+ 0: If byte 4 bit 0 is 1, then byte 0/4/5 are in MULTI fmt
+ otherwise byte 0 bit 4 must be set and byte 0/4/5 are
+ in NEW fmt
+ F: Number of fingers - 3, 0 means 3 fingers, 1 means 4 ...
diff --git a/Documentation/x86/zero-page.txt b/Documentation/x86/zero-page.txt
index 199f453..82fbdbc 100644
--- a/Documentation/x86/zero-page.txt
+++ b/Documentation/x86/zero-page.txt
@@ -3,7 +3,7 @@
real-mode setup code of the kernel. References/settings to it mainly
are in:
- arch/x86/include/asm/bootparam.h
+ arch/x86/include/uapi/asm/bootparam.h
Offset Proto Name Meaning
diff --git a/MAINTAINERS b/MAINTAINERS
index 7cfcee4..63d83bd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8567,7 +8567,7 @@
F: drivers/scsi/sr*
SCSI RDMA PROTOCOL (SRP) INITIATOR
-M: Bart Van Assche <bvanassche@acm.org>
+M: Bart Van Assche <bart.vanassche@sandisk.com>
L: linux-rdma@vger.kernel.org
S: Supported
W: http://www.openfabrics.org
@@ -9719,6 +9719,11 @@
S: Maintained
F: drivers/thermal/ti-soc-thermal/
+TI CDCE706 CLOCK DRIVER
+M: Max Filippov <jcmvbkbc@gmail.com>
+S: Maintained
+F: drivers/clk/clk-cdce706.c
+
TI CLOCK DRIVER
M: Tero Kristo <t-kristo@ti.com>
L: linux-omap@vger.kernel.org
diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index 8ca3c1a..5c29258 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -294,35 +294,43 @@
};
mmc0_clk: clk@01c20088 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c20088 0x4>;
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "mmc0";
+ clock-output-names = "mmc0",
+ "mmc0_output",
+ "mmc0_sample";
};
mmc1_clk: clk@01c2008c {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c2008c 0x4>;
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "mmc1";
+ clock-output-names = "mmc1",
+ "mmc1_output",
+ "mmc1_sample";
};
mmc2_clk: clk@01c20090 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c20090 0x4>;
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "mmc2";
+ clock-output-names = "mmc2",
+ "mmc2_output",
+ "mmc2_sample";
};
mmc3_clk: clk@01c20094 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c20094 0x4>;
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "mmc3";
+ clock-output-names = "mmc3",
+ "mmc3_output",
+ "mmc3_sample";
};
ts_clk: clk@01c20098 {
@@ -468,8 +476,14 @@
mmc0: mmc@01c0f000 {
compatible = "allwinner,sun4i-a10-mmc";
reg = <0x01c0f000 0x1000>;
- clocks = <&ahb_gates 8>, <&mmc0_clk>;
- clock-names = "ahb", "mmc";
+ clocks = <&ahb_gates 8>,
+ <&mmc0_clk 0>,
+ <&mmc0_clk 1>,
+ <&mmc0_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
interrupts = <32>;
status = "disabled";
};
@@ -477,8 +491,14 @@
mmc1: mmc@01c10000 {
compatible = "allwinner,sun4i-a10-mmc";
reg = <0x01c10000 0x1000>;
- clocks = <&ahb_gates 9>, <&mmc1_clk>;
- clock-names = "ahb", "mmc";
+ clocks = <&ahb_gates 9>,
+ <&mmc1_clk 0>,
+ <&mmc1_clk 1>,
+ <&mmc1_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
interrupts = <33>;
status = "disabled";
};
@@ -486,8 +506,14 @@
mmc2: mmc@01c11000 {
compatible = "allwinner,sun4i-a10-mmc";
reg = <0x01c11000 0x1000>;
- clocks = <&ahb_gates 10>, <&mmc2_clk>;
- clock-names = "ahb", "mmc";
+ clocks = <&ahb_gates 10>,
+ <&mmc2_clk 0>,
+ <&mmc2_clk 1>,
+ <&mmc2_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
interrupts = <34>;
status = "disabled";
};
@@ -495,8 +521,14 @@
mmc3: mmc@01c12000 {
compatible = "allwinner,sun4i-a10-mmc";
reg = <0x01c12000 0x1000>;
- clocks = <&ahb_gates 11>, <&mmc3_clk>;
- clock-names = "ahb", "mmc";
+ clocks = <&ahb_gates 11>,
+ <&mmc3_clk 0>,
+ <&mmc3_clk 1>,
+ <&mmc3_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
interrupts = <35>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
index 905f84d..2fd8988 100644
--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
+++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
@@ -218,27 +218,33 @@
};
mmc0_clk: clk@01c20088 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c20088 0x4>;
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "mmc0";
+ clock-output-names = "mmc0",
+ "mmc0_output",
+ "mmc0_sample";
};
mmc1_clk: clk@01c2008c {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c2008c 0x4>;
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "mmc1";
+ clock-output-names = "mmc1",
+ "mmc1_output",
+ "mmc1_sample";
};
mmc2_clk: clk@01c20090 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c20090 0x4>;
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "mmc2";
+ clock-output-names = "mmc2",
+ "mmc2_output",
+ "mmc2_sample";
};
ts_clk: clk@01c20098 {
@@ -368,8 +374,14 @@
mmc0: mmc@01c0f000 {
compatible = "allwinner,sun5i-a13-mmc";
reg = <0x01c0f000 0x1000>;
- clocks = <&ahb_gates 8>, <&mmc0_clk>;
- clock-names = "ahb", "mmc";
+ clocks = <&ahb_gates 8>,
+ <&mmc0_clk 0>,
+ <&mmc0_clk 1>,
+ <&mmc0_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
interrupts = <32>;
status = "disabled";
};
@@ -377,8 +389,14 @@
mmc1: mmc@01c10000 {
compatible = "allwinner,sun5i-a13-mmc";
reg = <0x01c10000 0x1000>;
- clocks = <&ahb_gates 9>, <&mmc1_clk>;
- clock-names = "ahb", "mmc";
+ clocks = <&ahb_gates 9>,
+ <&mmc1_clk 0>,
+ <&mmc1_clk 1>,
+ <&mmc1_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
interrupts = <33>;
status = "disabled";
};
@@ -386,8 +404,14 @@
mmc2: mmc@01c11000 {
compatible = "allwinner,sun5i-a13-mmc";
reg = <0x01c11000 0x1000>;
- clocks = <&ahb_gates 10>, <&mmc2_clk>;
- clock-names = "ahb", "mmc";
+ clocks = <&ahb_gates 10>,
+ <&mmc2_clk 0>,
+ <&mmc2_clk 1>,
+ <&mmc2_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
interrupts = <34>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
index 4910393..f8818f1 100644
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -257,27 +257,33 @@
};
mmc0_clk: clk@01c20088 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c20088 0x4>;
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "mmc0";
+ clock-output-names = "mmc0",
+ "mmc0_output",
+ "mmc0_sample";
};
mmc1_clk: clk@01c2008c {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c2008c 0x4>;
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "mmc1";
+ clock-output-names = "mmc1",
+ "mmc1_output",
+ "mmc1_sample";
};
mmc2_clk: clk@01c20090 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c20090 0x4>;
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "mmc2";
+ clock-output-names = "mmc2",
+ "mmc2_output",
+ "mmc2_sample";
};
ts_clk: clk@01c20098 {
@@ -391,8 +397,14 @@
mmc0: mmc@01c0f000 {
compatible = "allwinner,sun5i-a13-mmc";
reg = <0x01c0f000 0x1000>;
- clocks = <&ahb_gates 8>, <&mmc0_clk>;
- clock-names = "ahb", "mmc";
+ clocks = <&ahb_gates 8>,
+ <&mmc0_clk 0>,
+ <&mmc0_clk 1>,
+ <&mmc0_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
interrupts = <32>;
status = "disabled";
};
@@ -400,8 +412,14 @@
mmc2: mmc@01c11000 {
compatible = "allwinner,sun5i-a13-mmc";
reg = <0x01c11000 0x1000>;
- clocks = <&ahb_gates 10>, <&mmc2_clk>;
- clock-names = "ahb", "mmc";
+ clocks = <&ahb_gates 10>,
+ <&mmc2_clk 0>,
+ <&mmc2_clk 1>,
+ <&mmc2_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
interrupts = <34>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index 47e5576..fa2f403 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -190,19 +190,11 @@
clock-output-names = "axi";
};
- ahb1_mux: ahb1_mux@01c20054 {
- #clock-cells = <0>;
- compatible = "allwinner,sun6i-a31-ahb1-mux-clk";
- reg = <0x01c20054 0x4>;
- clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6 0>;
- clock-output-names = "ahb1_mux";
- };
-
ahb1: ahb1@01c20054 {
#clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-ahb-clk";
+ compatible = "allwinner,sun6i-a31-ahb1-clk";
reg = <0x01c20054 0x4>;
- clocks = <&ahb1_mux>;
+ clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6 0>;
clock-output-names = "ahb1";
};
@@ -265,35 +257,43 @@
};
mmc0_clk: clk@01c20088 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c20088 0x4>;
clocks = <&osc24M>, <&pll6 0>;
- clock-output-names = "mmc0";
+ clock-output-names = "mmc0",
+ "mmc0_output",
+ "mmc0_sample";
};
mmc1_clk: clk@01c2008c {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c2008c 0x4>;
clocks = <&osc24M>, <&pll6 0>;
- clock-output-names = "mmc1";
+ clock-output-names = "mmc1",
+ "mmc1_output",
+ "mmc1_sample";
};
mmc2_clk: clk@01c20090 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c20090 0x4>;
clocks = <&osc24M>, <&pll6 0>;
- clock-output-names = "mmc2";
+ clock-output-names = "mmc2",
+ "mmc2_output",
+ "mmc2_sample";
};
mmc3_clk: clk@01c20094 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c20094 0x4>;
clocks = <&osc24M>, <&pll6 0>;
- clock-output-names = "mmc3";
+ clock-output-names = "mmc3",
+ "mmc3_output",
+ "mmc3_sample";
};
spi0_clk: clk@01c200a0 {
@@ -383,15 +383,21 @@
#dma-cells = <1>;
/* DMA controller requires AHB1 clocked from PLL6 */
- assigned-clocks = <&ahb1_mux>;
+ assigned-clocks = <&ahb1>;
assigned-clock-parents = <&pll6 0>;
};
mmc0: mmc@01c0f000 {
compatible = "allwinner,sun5i-a13-mmc";
reg = <0x01c0f000 0x1000>;
- clocks = <&ahb1_gates 8>, <&mmc0_clk>;
- clock-names = "ahb", "mmc";
+ clocks = <&ahb1_gates 8>,
+ <&mmc0_clk 0>,
+ <&mmc0_clk 1>,
+ <&mmc0_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
resets = <&ahb1_rst 8>;
reset-names = "ahb";
interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
@@ -401,8 +407,14 @@
mmc1: mmc@01c10000 {
compatible = "allwinner,sun5i-a13-mmc";
reg = <0x01c10000 0x1000>;
- clocks = <&ahb1_gates 9>, <&mmc1_clk>;
- clock-names = "ahb", "mmc";
+ clocks = <&ahb1_gates 9>,
+ <&mmc1_clk 0>,
+ <&mmc1_clk 1>,
+ <&mmc1_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
resets = <&ahb1_rst 9>;
reset-names = "ahb";
interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
@@ -412,8 +424,14 @@
mmc2: mmc@01c11000 {
compatible = "allwinner,sun5i-a13-mmc";
reg = <0x01c11000 0x1000>;
- clocks = <&ahb1_gates 10>, <&mmc2_clk>;
- clock-names = "ahb", "mmc";
+ clocks = <&ahb1_gates 10>,
+ <&mmc2_clk 0>,
+ <&mmc2_clk 1>,
+ <&mmc2_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
resets = <&ahb1_rst 10>;
reset-names = "ahb";
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
@@ -423,8 +441,14 @@
mmc3: mmc@01c12000 {
compatible = "allwinner,sun5i-a13-mmc";
reg = <0x01c12000 0x1000>;
- clocks = <&ahb1_gates 11>, <&mmc3_clk>;
- clock-names = "ahb", "mmc";
+ clocks = <&ahb1_gates 11>,
+ <&mmc3_clk 0>,
+ <&mmc3_clk 1>,
+ <&mmc3_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
resets = <&ahb1_rst 11>;
reset-names = "ahb";
interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index 786d491..3a8530b 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -337,35 +337,43 @@
};
mmc0_clk: clk@01c20088 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c20088 0x4>;
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "mmc0";
+ clock-output-names = "mmc0",
+ "mmc0_output",
+ "mmc0_sample";
};
mmc1_clk: clk@01c2008c {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c2008c 0x4>;
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "mmc1";
+ clock-output-names = "mmc1",
+ "mmc1_output",
+ "mmc1_sample";
};
mmc2_clk: clk@01c20090 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c20090 0x4>;
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "mmc2";
+ clock-output-names = "mmc2",
+ "mmc2_output",
+ "mmc2_sample";
};
mmc3_clk: clk@01c20094 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c20094 0x4>;
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "mmc3";
+ clock-output-names = "mmc3",
+ "mmc3_output",
+ "mmc3_sample";
};
ts_clk: clk@01c20098 {
@@ -583,8 +591,14 @@
mmc0: mmc@01c0f000 {
compatible = "allwinner,sun5i-a13-mmc";
reg = <0x01c0f000 0x1000>;
- clocks = <&ahb_gates 8>, <&mmc0_clk>;
- clock-names = "ahb", "mmc";
+ clocks = <&ahb_gates 8>,
+ <&mmc0_clk 0>,
+ <&mmc0_clk 1>,
+ <&mmc0_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
@@ -592,8 +606,14 @@
mmc1: mmc@01c10000 {
compatible = "allwinner,sun5i-a13-mmc";
reg = <0x01c10000 0x1000>;
- clocks = <&ahb_gates 9>, <&mmc1_clk>;
- clock-names = "ahb", "mmc";
+ clocks = <&ahb_gates 9>,
+ <&mmc1_clk 0>,
+ <&mmc1_clk 1>,
+ <&mmc1_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
@@ -601,8 +621,14 @@
mmc2: mmc@01c11000 {
compatible = "allwinner,sun5i-a13-mmc";
reg = <0x01c11000 0x1000>;
- clocks = <&ahb_gates 10>, <&mmc2_clk>;
- clock-names = "ahb", "mmc";
+ clocks = <&ahb_gates 10>,
+ <&mmc2_clk 0>,
+ <&mmc2_clk 1>,
+ <&mmc2_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
@@ -610,8 +636,14 @@
mmc3: mmc@01c12000 {
compatible = "allwinner,sun5i-a13-mmc";
reg = <0x01c12000 0x1000>;
- clocks = <&ahb_gates 11>, <&mmc3_clk>;
- clock-names = "ahb", "mmc";
+ clocks = <&ahb_gates 11>,
+ <&mmc3_clk 0>,
+ <&mmc3_clk 1>,
+ <&mmc3_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/sun8i-a23.dtsi b/arch/arm/boot/dts/sun8i-a23.dtsi
index dd34527..382ebd1 100644
--- a/arch/arm/boot/dts/sun8i-a23.dtsi
+++ b/arch/arm/boot/dts/sun8i-a23.dtsi
@@ -119,11 +119,19 @@
};
/* dummy clock until actually implemented */
- pll6: pll6_clk {
+ pll5: pll5_clk {
#clock-cells = <0>;
compatible = "fixed-clock";
- clock-frequency = <600000000>;
- clock-output-names = "pll6";
+ clock-frequency = <0>;
+ clock-output-names = "pll5";
+ };
+
+ pll6: clk@01c20028 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun6i-a31-pll6-clk";
+ reg = <0x01c20028 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll6", "pll6x2";
};
cpu: cpu_clk@01c20050 {
@@ -149,19 +157,11 @@
clock-output-names = "axi";
};
- ahb1_mux: ahb1_mux_clk@01c20054 {
- #clock-cells = <0>;
- compatible = "allwinner,sun6i-a31-ahb1-mux-clk";
- reg = <0x01c20054 0x4>;
- clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6>;
- clock-output-names = "ahb1_mux";
- };
-
ahb1: ahb1_clk@01c20054 {
#clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-ahb-clk";
+ compatible = "allwinner,sun6i-a31-ahb1-clk";
reg = <0x01c20054 0x4>;
- clocks = <&ahb1_mux>;
+ clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6 0>;
clock-output-names = "ahb1";
};
@@ -202,7 +202,7 @@
#clock-cells = <0>;
compatible = "allwinner,sun4i-a10-apb1-clk";
reg = <0x01c20058 0x4>;
- clocks = <&osc32k>, <&osc24M>, <&pll6>, <&pll6>;
+ clocks = <&osc32k>, <&osc24M>, <&pll6 0>, <&pll6 0>;
clock-output-names = "apb2";
};
@@ -218,27 +218,41 @@
};
mmc0_clk: clk@01c20088 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c20088 0x4>;
- clocks = <&osc24M>, <&pll6>;
- clock-output-names = "mmc0";
+ clocks = <&osc24M>, <&pll6 0>;
+ clock-output-names = "mmc0",
+ "mmc0_output",
+ "mmc0_sample";
};
mmc1_clk: clk@01c2008c {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c2008c 0x4>;
- clocks = <&osc24M>, <&pll6>;
- clock-output-names = "mmc1";
+ clocks = <&osc24M>, <&pll6 0>;
+ clock-output-names = "mmc1",
+ "mmc1_output",
+ "mmc1_sample";
};
mmc2_clk: clk@01c20090 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c20090 0x4>;
- clocks = <&osc24M>, <&pll6>;
- clock-output-names = "mmc2";
+ clocks = <&osc24M>, <&pll6 0>;
+ clock-output-names = "mmc2",
+ "mmc2_output",
+ "mmc2_sample";
+ };
+
+ mbus_clk: clk@01c2015c {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun8i-a23-mbus-clk";
+ reg = <0x01c2015c 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5>;
+ clock-output-names = "mbus";
};
};
@@ -260,8 +274,14 @@
mmc0: mmc@01c0f000 {
compatible = "allwinner,sun5i-a13-mmc";
reg = <0x01c0f000 0x1000>;
- clocks = <&ahb1_gates 8>, <&mmc0_clk>;
- clock-names = "ahb", "mmc";
+ clocks = <&ahb1_gates 8>,
+ <&mmc0_clk 0>,
+ <&mmc0_clk 1>,
+ <&mmc0_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
resets = <&ahb1_rst 8>;
reset-names = "ahb";
interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
@@ -271,8 +291,14 @@
mmc1: mmc@01c10000 {
compatible = "allwinner,sun5i-a13-mmc";
reg = <0x01c10000 0x1000>;
- clocks = <&ahb1_gates 9>, <&mmc1_clk>;
- clock-names = "ahb", "mmc";
+ clocks = <&ahb1_gates 9>,
+ <&mmc1_clk 0>,
+ <&mmc1_clk 1>,
+ <&mmc1_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
resets = <&ahb1_rst 9>;
reset-names = "ahb";
interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
@@ -282,8 +308,14 @@
mmc2: mmc@01c11000 {
compatible = "allwinner,sun5i-a13-mmc";
reg = <0x01c11000 0x1000>;
- clocks = <&ahb1_gates 10>, <&mmc2_clk>;
- clock-names = "ahb", "mmc";
+ clocks = <&ahb1_gates 10>,
+ <&mmc2_clk 0>,
+ <&mmc2_clk 1>,
+ <&mmc2_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
resets = <&ahb1_rst 10>;
reset-names = "ahb";
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 00d5d8f..b83f18f 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -190,7 +190,7 @@
obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) clock3xxx.o
obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o clkt34xx_dpll3m2.o
obj-$(CONFIG_ARCH_OMAP3) += clock3517.o clock36xx.o
-obj-$(CONFIG_ARCH_OMAP3) += dpll3xxx.o cclock3xxx_data.o
+obj-$(CONFIG_ARCH_OMAP3) += dpll3xxx.o
obj-$(CONFIG_ARCH_OMAP3) += clkt_iclk.o
obj-$(CONFIG_ARCH_OMAP4) += $(clock-common)
obj-$(CONFIG_ARCH_OMAP4) += dpll3xxx.o dpll44xx.o
diff --git a/arch/arm/mach-omap2/cclock3xxx_data.c b/arch/arm/mach-omap2/cclock3xxx_data.c
deleted file mode 100644
index e79c80b..0000000
--- a/arch/arm/mach-omap2/cclock3xxx_data.c
+++ /dev/null
@@ -1,3688 +0,0 @@
-/*
- * OMAP3 clock data
- *
- * Copyright (C) 2007-2012 Texas Instruments, Inc.
- * Copyright (C) 2007-2011 Nokia Corporation
- *
- * Written by Paul Walmsley
- * Updated to COMMON clk data format by Rajendra Nayak <rnayak@ti.com>
- * With many device clock fixes by Kevin Hilman and Jouni Högander
- * DPLL bypass clock support added by Roman Tereshonkov
- *
- */
-
-/*
- * Virtual clocks are introduced as convenient tools.
- * They are sources for other clocks and not supposed
- * to be requested from drivers directly.
- */
-
-#include <linux/kernel.h>
-#include <linux/clk.h>
-#include <linux/clk-private.h>
-#include <linux/list.h>
-#include <linux/io.h>
-
-#include "soc.h"
-#include "iomap.h"
-#include "clock.h"
-#include "clock3xxx.h"
-#include "clock34xx.h"
-#include "clock36xx.h"
-#include "clock3517.h"
-#include "cm3xxx.h"
-#include "cm-regbits-34xx.h"
-#include "prm3xxx.h"
-#include "prm-regbits-34xx.h"
-#include "control.h"
-
-/*
- * clocks
- */
-
-#define OMAP_CM_REGADDR OMAP34XX_CM_REGADDR
-
-/* Maximum DPLL multiplier, divider values for OMAP3 */
-#define OMAP3_MAX_DPLL_MULT 2047
-#define OMAP3630_MAX_JTYPE_DPLL_MULT 4095
-#define OMAP3_MAX_DPLL_DIV 128
-
-DEFINE_CLK_FIXED_RATE(dummy_apb_pclk, CLK_IS_ROOT, 0x0, 0x0);
-
-DEFINE_CLK_FIXED_RATE(mcbsp_clks, CLK_IS_ROOT, 0x0, 0x0);
-
-DEFINE_CLK_FIXED_RATE(omap_32k_fck, CLK_IS_ROOT, 32768, 0x0);
-
-DEFINE_CLK_FIXED_RATE(pclk_ck, CLK_IS_ROOT, 27000000, 0x0);
-
-DEFINE_CLK_FIXED_RATE(rmii_ck, CLK_IS_ROOT, 50000000, 0x0);
-
-DEFINE_CLK_FIXED_RATE(secure_32k_fck, CLK_IS_ROOT, 32768, 0x0);
-
-DEFINE_CLK_FIXED_RATE(sys_altclk, CLK_IS_ROOT, 0x0, 0x0);
-
-DEFINE_CLK_FIXED_RATE(virt_12m_ck, CLK_IS_ROOT, 12000000, 0x0);
-
-DEFINE_CLK_FIXED_RATE(virt_13m_ck, CLK_IS_ROOT, 13000000, 0x0);
-
-DEFINE_CLK_FIXED_RATE(virt_16_8m_ck, CLK_IS_ROOT, 16800000, 0x0);
-
-DEFINE_CLK_FIXED_RATE(virt_19200000_ck, CLK_IS_ROOT, 19200000, 0x0);
-
-DEFINE_CLK_FIXED_RATE(virt_26000000_ck, CLK_IS_ROOT, 26000000, 0x0);
-
-DEFINE_CLK_FIXED_RATE(virt_38_4m_ck, CLK_IS_ROOT, 38400000, 0x0);
-
-static const char *osc_sys_ck_parent_names[] = {
- "virt_12m_ck", "virt_13m_ck", "virt_19200000_ck", "virt_26000000_ck",
- "virt_38_4m_ck", "virt_16_8m_ck",
-};
-
-DEFINE_CLK_MUX(osc_sys_ck, osc_sys_ck_parent_names, NULL, 0x0,
- OMAP3430_PRM_CLKSEL, OMAP3430_SYS_CLKIN_SEL_SHIFT,
- OMAP3430_SYS_CLKIN_SEL_WIDTH, 0x0, NULL);
-
-DEFINE_CLK_DIVIDER(sys_ck, "osc_sys_ck", &osc_sys_ck, 0x0,
- OMAP3430_PRM_CLKSRC_CTRL, OMAP_SYSCLKDIV_SHIFT,
- OMAP_SYSCLKDIV_WIDTH, CLK_DIVIDER_ONE_BASED, NULL);
-
-static struct dpll_data dpll3_dd = {
- .mult_div1_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
- .mult_mask = OMAP3430_CORE_DPLL_MULT_MASK,
- .div1_mask = OMAP3430_CORE_DPLL_DIV_MASK,
- .clk_bypass = &sys_ck,
- .clk_ref = &sys_ck,
- .freqsel_mask = OMAP3430_CORE_DPLL_FREQSEL_MASK,
- .control_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
- .enable_mask = OMAP3430_EN_CORE_DPLL_MASK,
- .auto_recal_bit = OMAP3430_EN_CORE_DPLL_DRIFTGUARD_SHIFT,
- .recal_en_bit = OMAP3430_CORE_DPLL_RECAL_EN_SHIFT,
- .recal_st_bit = OMAP3430_CORE_DPLL_ST_SHIFT,
- .autoidle_reg = OMAP_CM_REGADDR(PLL_MOD, CM_AUTOIDLE),
- .autoidle_mask = OMAP3430_AUTO_CORE_DPLL_MASK,
- .idlest_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
- .idlest_mask = OMAP3430_ST_CORE_CLK_MASK,
- .max_multiplier = OMAP3_MAX_DPLL_MULT,
- .min_divider = 1,
- .max_divider = OMAP3_MAX_DPLL_DIV,
-};
-
-static struct clk dpll3_ck;
-
-static const char *dpll3_ck_parent_names[] = {
- "sys_ck",
- "sys_ck",
-};
-
-static const struct clk_ops dpll3_ck_ops = {
- .init = &omap2_init_clk_clkdm,
- .get_parent = &omap2_init_dpll_parent,
- .recalc_rate = &omap3_dpll_recalc,
- .round_rate = &omap2_dpll_round_rate,
-};
-
-static struct clk_hw_omap dpll3_ck_hw = {
- .hw = {
- .clk = &dpll3_ck,
- },
- .ops = &clkhwops_omap3_dpll,
- .dpll_data = &dpll3_dd,
- .clkdm_name = "dpll3_clkdm",
-};
-
-DEFINE_STRUCT_CLK(dpll3_ck, dpll3_ck_parent_names, dpll3_ck_ops);
-
-DEFINE_CLK_DIVIDER(dpll3_m2_ck, "dpll3_ck", &dpll3_ck, 0x0,
- OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
- OMAP3430_CORE_DPLL_CLKOUT_DIV_SHIFT,
- OMAP3430_CORE_DPLL_CLKOUT_DIV_WIDTH,
- CLK_DIVIDER_ONE_BASED, NULL);
-
-static struct clk core_ck;
-
-static const char *core_ck_parent_names[] = {
- "dpll3_m2_ck",
-};
-
-static const struct clk_ops core_ck_ops = {};
-
-DEFINE_STRUCT_CLK_HW_OMAP(core_ck, NULL);
-DEFINE_STRUCT_CLK(core_ck, core_ck_parent_names, core_ck_ops);
-
-DEFINE_CLK_DIVIDER(l3_ick, "core_ck", &core_ck, 0x0,
- OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
- OMAP3430_CLKSEL_L3_SHIFT, OMAP3430_CLKSEL_L3_WIDTH,
- CLK_DIVIDER_ONE_BASED, NULL);
-
-DEFINE_CLK_DIVIDER(l4_ick, "l3_ick", &l3_ick, 0x0,
- OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
- OMAP3430_CLKSEL_L4_SHIFT, OMAP3430_CLKSEL_L4_WIDTH,
- CLK_DIVIDER_ONE_BASED, NULL);
-
-static struct clk security_l4_ick2;
-
-static const char *security_l4_ick2_parent_names[] = {
- "l4_ick",
-};
-
-DEFINE_STRUCT_CLK_HW_OMAP(security_l4_ick2, NULL);
-DEFINE_STRUCT_CLK(security_l4_ick2, security_l4_ick2_parent_names, core_ck_ops);
-
-static struct clk aes1_ick;
-
-static const char *aes1_ick_parent_names[] = {
- "security_l4_ick2",
-};
-
-static const struct clk_ops aes1_ick_ops = {
- .enable = &omap2_dflt_clk_enable,
- .disable = &omap2_dflt_clk_disable,
- .is_enabled = &omap2_dflt_clk_is_enabled,
-};
-
-static struct clk_hw_omap aes1_ick_hw = {
- .hw = {
- .clk = &aes1_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
- .enable_bit = OMAP3430_EN_AES1_SHIFT,
-};
-
-DEFINE_STRUCT_CLK(aes1_ick, aes1_ick_parent_names, aes1_ick_ops);
-
-static struct clk core_l4_ick;
-
-static const struct clk_ops core_l4_ick_ops = {
- .init = &omap2_init_clk_clkdm,
-};
-
-DEFINE_STRUCT_CLK_HW_OMAP(core_l4_ick, "core_l4_clkdm");
-DEFINE_STRUCT_CLK(core_l4_ick, security_l4_ick2_parent_names, core_l4_ick_ops);
-
-static struct clk aes2_ick;
-
-static const char *aes2_ick_parent_names[] = {
- "core_l4_ick",
-};
-
-static const struct clk_ops aes2_ick_ops = {
- .init = &omap2_init_clk_clkdm,
- .enable = &omap2_dflt_clk_enable,
- .disable = &omap2_dflt_clk_disable,
- .is_enabled = &omap2_dflt_clk_is_enabled,
-};
-
-static struct clk_hw_omap aes2_ick_hw = {
- .hw = {
- .clk = &aes2_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_AES2_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(aes2_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static struct clk dpll1_fck;
-
-static struct dpll_data dpll1_dd = {
- .mult_div1_reg = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_CLKSEL1_PLL),
- .mult_mask = OMAP3430_MPU_DPLL_MULT_MASK,
- .div1_mask = OMAP3430_MPU_DPLL_DIV_MASK,
- .clk_bypass = &dpll1_fck,
- .clk_ref = &sys_ck,
- .freqsel_mask = OMAP3430_MPU_DPLL_FREQSEL_MASK,
- .control_reg = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_CLKEN_PLL),
- .enable_mask = OMAP3430_EN_MPU_DPLL_MASK,
- .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
- .auto_recal_bit = OMAP3430_EN_MPU_DPLL_DRIFTGUARD_SHIFT,
- .recal_en_bit = OMAP3430_MPU_DPLL_RECAL_EN_SHIFT,
- .recal_st_bit = OMAP3430_MPU_DPLL_ST_SHIFT,
- .autoidle_reg = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_AUTOIDLE_PLL),
- .autoidle_mask = OMAP3430_AUTO_MPU_DPLL_MASK,
- .idlest_reg = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_IDLEST_PLL),
- .idlest_mask = OMAP3430_ST_MPU_CLK_MASK,
- .max_multiplier = OMAP3_MAX_DPLL_MULT,
- .min_divider = 1,
- .max_divider = OMAP3_MAX_DPLL_DIV,
-};
-
-static struct clk dpll1_ck;
-
-static const struct clk_ops dpll1_ck_ops = {
- .init = &omap2_init_clk_clkdm,
- .enable = &omap3_noncore_dpll_enable,
- .disable = &omap3_noncore_dpll_disable,
- .get_parent = &omap2_init_dpll_parent,
- .recalc_rate = &omap3_dpll_recalc,
- .set_rate = &omap3_noncore_dpll_set_rate,
- .set_parent = &omap3_noncore_dpll_set_parent,
- .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
- .determine_rate = &omap3_noncore_dpll_determine_rate,
- .round_rate = &omap2_dpll_round_rate,
-};
-
-static struct clk_hw_omap dpll1_ck_hw = {
- .hw = {
- .clk = &dpll1_ck,
- },
- .ops = &clkhwops_omap3_dpll,
- .dpll_data = &dpll1_dd,
- .clkdm_name = "dpll1_clkdm",
-};
-
-DEFINE_STRUCT_CLK(dpll1_ck, dpll3_ck_parent_names, dpll1_ck_ops);
-
-DEFINE_CLK_FIXED_FACTOR(dpll1_x2_ck, "dpll1_ck", &dpll1_ck, 0x0, 2, 1);
-
-DEFINE_CLK_DIVIDER(dpll1_x2m2_ck, "dpll1_x2_ck", &dpll1_x2_ck, 0x0,
- OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_CLKSEL2_PLL),
- OMAP3430_MPU_DPLL_CLKOUT_DIV_SHIFT,
- OMAP3430_MPU_DPLL_CLKOUT_DIV_WIDTH,
- CLK_DIVIDER_ONE_BASED, NULL);
-
-static struct clk mpu_ck;
-
-static const char *mpu_ck_parent_names[] = {
- "dpll1_x2m2_ck",
-};
-
-DEFINE_STRUCT_CLK_HW_OMAP(mpu_ck, "mpu_clkdm");
-DEFINE_STRUCT_CLK(mpu_ck, mpu_ck_parent_names, core_l4_ick_ops);
-
-DEFINE_CLK_DIVIDER(arm_fck, "mpu_ck", &mpu_ck, 0x0,
- OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_IDLEST_PLL),
- OMAP3430_ST_MPU_CLK_SHIFT, OMAP3430_ST_MPU_CLK_WIDTH,
- 0x0, NULL);
-
-static struct clk cam_ick;
-
-static struct clk_hw_omap cam_ick_hw = {
- .hw = {
- .clk = &cam_ick,
- },
- .ops = &clkhwops_iclk,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_CAM_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_CAM_SHIFT,
- .clkdm_name = "cam_clkdm",
-};
-
-DEFINE_STRUCT_CLK(cam_ick, security_l4_ick2_parent_names, aes2_ick_ops);
-
-/* DPLL4 */
-/* Supplies 96MHz, 54Mhz TV DAC, DSS fclk, CAM sensor clock, emul trace clk */
-/* Type: DPLL */
-static struct dpll_data dpll4_dd;
-
-static struct dpll_data dpll4_dd_34xx __initdata = {
- .mult_div1_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL2),
- .mult_mask = OMAP3430_PERIPH_DPLL_MULT_MASK,
- .div1_mask = OMAP3430_PERIPH_DPLL_DIV_MASK,
- .clk_bypass = &sys_ck,
- .clk_ref = &sys_ck,
- .freqsel_mask = OMAP3430_PERIPH_DPLL_FREQSEL_MASK,
- .control_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
- .enable_mask = OMAP3430_EN_PERIPH_DPLL_MASK,
- .modes = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED),
- .auto_recal_bit = OMAP3430_EN_PERIPH_DPLL_DRIFTGUARD_SHIFT,
- .recal_en_bit = OMAP3430_PERIPH_DPLL_RECAL_EN_SHIFT,
- .recal_st_bit = OMAP3430_PERIPH_DPLL_ST_SHIFT,
- .autoidle_reg = OMAP_CM_REGADDR(PLL_MOD, CM_AUTOIDLE),
- .autoidle_mask = OMAP3430_AUTO_PERIPH_DPLL_MASK,
- .idlest_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
- .idlest_mask = OMAP3430_ST_PERIPH_CLK_MASK,
- .max_multiplier = OMAP3_MAX_DPLL_MULT,
- .min_divider = 1,
- .max_divider = OMAP3_MAX_DPLL_DIV,
-};
-
-static struct dpll_data dpll4_dd_3630 __initdata = {
- .mult_div1_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL2),
- .mult_mask = OMAP3630_PERIPH_DPLL_MULT_MASK,
- .div1_mask = OMAP3430_PERIPH_DPLL_DIV_MASK,
- .clk_bypass = &sys_ck,
- .clk_ref = &sys_ck,
- .control_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
- .enable_mask = OMAP3430_EN_PERIPH_DPLL_MASK,
- .modes = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED),
- .auto_recal_bit = OMAP3430_EN_PERIPH_DPLL_DRIFTGUARD_SHIFT,
- .recal_en_bit = OMAP3430_PERIPH_DPLL_RECAL_EN_SHIFT,
- .recal_st_bit = OMAP3430_PERIPH_DPLL_ST_SHIFT,
- .autoidle_reg = OMAP_CM_REGADDR(PLL_MOD, CM_AUTOIDLE),
- .autoidle_mask = OMAP3430_AUTO_PERIPH_DPLL_MASK,
- .idlest_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
- .idlest_mask = OMAP3430_ST_PERIPH_CLK_MASK,
- .dco_mask = OMAP3630_PERIPH_DPLL_DCO_SEL_MASK,
- .sddiv_mask = OMAP3630_PERIPH_DPLL_SD_DIV_MASK,
- .max_multiplier = OMAP3630_MAX_JTYPE_DPLL_MULT,
- .min_divider = 1,
- .max_divider = OMAP3_MAX_DPLL_DIV,
- .flags = DPLL_J_TYPE
-};
-
-static struct clk dpll4_ck;
-
-static const struct clk_ops dpll4_ck_ops = {
- .init = &omap2_init_clk_clkdm,
- .enable = &omap3_noncore_dpll_enable,
- .disable = &omap3_noncore_dpll_disable,
- .get_parent = &omap2_init_dpll_parent,
- .recalc_rate = &omap3_dpll_recalc,
- .set_rate = &omap3_dpll4_set_rate,
- .set_parent = &omap3_noncore_dpll_set_parent,
- .set_rate_and_parent = &omap3_dpll4_set_rate_and_parent,
- .determine_rate = &omap3_noncore_dpll_determine_rate,
- .round_rate = &omap2_dpll_round_rate,
-};
-
-static struct clk_hw_omap dpll4_ck_hw = {
- .hw = {
- .clk = &dpll4_ck,
- },
- .dpll_data = &dpll4_dd,
- .ops = &clkhwops_omap3_dpll,
- .clkdm_name = "dpll4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(dpll4_ck, dpll3_ck_parent_names, dpll4_ck_ops);
-
-static const struct clk_div_table dpll4_mx_ck_div_table[] = {
- { .div = 1, .val = 1 },
- { .div = 2, .val = 2 },
- { .div = 3, .val = 3 },
- { .div = 4, .val = 4 },
- { .div = 5, .val = 5 },
- { .div = 6, .val = 6 },
- { .div = 7, .val = 7 },
- { .div = 8, .val = 8 },
- { .div = 9, .val = 9 },
- { .div = 10, .val = 10 },
- { .div = 11, .val = 11 },
- { .div = 12, .val = 12 },
- { .div = 13, .val = 13 },
- { .div = 14, .val = 14 },
- { .div = 15, .val = 15 },
- { .div = 16, .val = 16 },
- { .div = 17, .val = 17 },
- { .div = 18, .val = 18 },
- { .div = 19, .val = 19 },
- { .div = 20, .val = 20 },
- { .div = 21, .val = 21 },
- { .div = 22, .val = 22 },
- { .div = 23, .val = 23 },
- { .div = 24, .val = 24 },
- { .div = 25, .val = 25 },
- { .div = 26, .val = 26 },
- { .div = 27, .val = 27 },
- { .div = 28, .val = 28 },
- { .div = 29, .val = 29 },
- { .div = 30, .val = 30 },
- { .div = 31, .val = 31 },
- { .div = 32, .val = 32 },
- { .div = 0 },
-};
-
-DEFINE_CLK_DIVIDER(dpll4_m5_ck, "dpll4_ck", &dpll4_ck, 0x0,
- OMAP_CM_REGADDR(OMAP3430_CAM_MOD, CM_CLKSEL),
- OMAP3430_CLKSEL_CAM_SHIFT, OMAP3630_CLKSEL_CAM_WIDTH,
- CLK_DIVIDER_ONE_BASED, NULL);
-
-static struct clk dpll4_m5x2_ck;
-
-static const char *dpll4_m5x2_ck_parent_names[] = {
- "dpll4_m5_ck",
-};
-
-static const struct clk_ops dpll4_m5x2_ck_ops = {
- .init = &omap2_init_clk_clkdm,
- .enable = &omap2_dflt_clk_enable,
- .disable = &omap2_dflt_clk_disable,
- .is_enabled = &omap2_dflt_clk_is_enabled,
- .set_rate = &omap3_clkoutx2_set_rate,
- .recalc_rate = &omap3_clkoutx2_recalc,
- .round_rate = &omap3_clkoutx2_round_rate,
-};
-
-static const struct clk_ops dpll4_m5x2_ck_3630_ops = {
- .init = &omap2_init_clk_clkdm,
- .enable = &omap36xx_pwrdn_clk_enable_with_hsdiv_restore,
- .disable = &omap2_dflt_clk_disable,
- .recalc_rate = &omap3_clkoutx2_recalc,
-};
-
-static struct clk_hw_omap dpll4_m5x2_ck_hw = {
- .hw = {
- .clk = &dpll4_m5x2_ck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
- .enable_bit = OMAP3430_PWRDN_CAM_SHIFT,
- .flags = INVERT_ENABLE,
- .clkdm_name = "dpll4_clkdm",
-};
-
-DEFINE_STRUCT_CLK_FLAGS(dpll4_m5x2_ck, dpll4_m5x2_ck_parent_names,
- dpll4_m5x2_ck_ops, CLK_SET_RATE_PARENT);
-
-static struct clk dpll4_m5x2_ck_3630 = {
- .name = "dpll4_m5x2_ck",
- .hw = &dpll4_m5x2_ck_hw.hw,
- .parent_names = dpll4_m5x2_ck_parent_names,
- .num_parents = ARRAY_SIZE(dpll4_m5x2_ck_parent_names),
- .ops = &dpll4_m5x2_ck_3630_ops,
- .flags = CLK_SET_RATE_PARENT,
-};
-
-static struct clk cam_mclk;
-
-static const char *cam_mclk_parent_names[] = {
- "dpll4_m5x2_ck",
-};
-
-static struct clk_hw_omap cam_mclk_hw = {
- .hw = {
- .clk = &cam_mclk,
- },
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_CAM_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_CAM_SHIFT,
- .clkdm_name = "cam_clkdm",
-};
-
-static struct clk cam_mclk = {
- .name = "cam_mclk",
- .hw = &cam_mclk_hw.hw,
- .parent_names = cam_mclk_parent_names,
- .num_parents = ARRAY_SIZE(cam_mclk_parent_names),
- .ops = &aes2_ick_ops,
- .flags = CLK_SET_RATE_PARENT,
-};
-
-static const struct clksel_rate clkout2_src_core_rates[] = {
- { .div = 1, .val = 0, .flags = RATE_IN_3XXX },
- { .div = 0 }
-};
-
-static const struct clksel_rate clkout2_src_sys_rates[] = {
- { .div = 1, .val = 1, .flags = RATE_IN_3XXX },
- { .div = 0 }
-};
-
-static const struct clksel_rate clkout2_src_96m_rates[] = {
- { .div = 1, .val = 2, .flags = RATE_IN_3XXX },
- { .div = 0 }
-};
-
-DEFINE_CLK_DIVIDER(dpll4_m2_ck, "dpll4_ck", &dpll4_ck, 0x0,
- OMAP_CM_REGADDR(PLL_MOD, OMAP3430_CM_CLKSEL3),
- OMAP3430_DIV_96M_SHIFT, OMAP3630_DIV_96M_WIDTH,
- CLK_DIVIDER_ONE_BASED, NULL);
-
-static struct clk dpll4_m2x2_ck;
-
-static const char *dpll4_m2x2_ck_parent_names[] = {
- "dpll4_m2_ck",
-};
-
-static struct clk_hw_omap dpll4_m2x2_ck_hw = {
- .hw = {
- .clk = &dpll4_m2x2_ck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
- .enable_bit = OMAP3430_PWRDN_96M_SHIFT,
- .flags = INVERT_ENABLE,
- .clkdm_name = "dpll4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(dpll4_m2x2_ck, dpll4_m2x2_ck_parent_names, dpll4_m5x2_ck_ops);
-
-static struct clk dpll4_m2x2_ck_3630 = {
- .name = "dpll4_m2x2_ck",
- .hw = &dpll4_m2x2_ck_hw.hw,
- .parent_names = dpll4_m2x2_ck_parent_names,
- .num_parents = ARRAY_SIZE(dpll4_m2x2_ck_parent_names),
- .ops = &dpll4_m5x2_ck_3630_ops,
-};
-
-static struct clk omap_96m_alwon_fck;
-
-static const char *omap_96m_alwon_fck_parent_names[] = {
- "dpll4_m2x2_ck",
-};
-
-DEFINE_STRUCT_CLK_HW_OMAP(omap_96m_alwon_fck, NULL);
-DEFINE_STRUCT_CLK(omap_96m_alwon_fck, omap_96m_alwon_fck_parent_names,
- core_ck_ops);
-
-static struct clk cm_96m_fck;
-
-static const char *cm_96m_fck_parent_names[] = {
- "omap_96m_alwon_fck",
-};
-
-DEFINE_STRUCT_CLK_HW_OMAP(cm_96m_fck, NULL);
-DEFINE_STRUCT_CLK(cm_96m_fck, cm_96m_fck_parent_names, core_ck_ops);
-
-static const struct clksel_rate clkout2_src_54m_rates[] = {
- { .div = 1, .val = 3, .flags = RATE_IN_3XXX },
- { .div = 0 }
-};
-
-DEFINE_CLK_DIVIDER_TABLE(dpll4_m3_ck, "dpll4_ck", &dpll4_ck, 0x0,
- OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_CLKSEL),
- OMAP3430_CLKSEL_TV_SHIFT, OMAP3630_CLKSEL_TV_WIDTH,
- 0, dpll4_mx_ck_div_table, NULL);
-
-static struct clk dpll4_m3x2_ck;
-
-static const char *dpll4_m3x2_ck_parent_names[] = {
- "dpll4_m3_ck",
-};
-
-static struct clk_hw_omap dpll4_m3x2_ck_hw = {
- .hw = {
- .clk = &dpll4_m3x2_ck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
- .enable_bit = OMAP3430_PWRDN_TV_SHIFT,
- .flags = INVERT_ENABLE,
- .clkdm_name = "dpll4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(dpll4_m3x2_ck, dpll4_m3x2_ck_parent_names, dpll4_m5x2_ck_ops);
-
-static struct clk dpll4_m3x2_ck_3630 = {
- .name = "dpll4_m3x2_ck",
- .hw = &dpll4_m3x2_ck_hw.hw,
- .parent_names = dpll4_m3x2_ck_parent_names,
- .num_parents = ARRAY_SIZE(dpll4_m3x2_ck_parent_names),
- .ops = &dpll4_m5x2_ck_3630_ops,
-};
-
-static const char *omap_54m_fck_parent_names[] = {
- "dpll4_m3x2_ck", "sys_altclk",
-};
-
-DEFINE_CLK_MUX(omap_54m_fck, omap_54m_fck_parent_names, NULL, 0x0,
- OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1), OMAP3430_SOURCE_54M_SHIFT,
- OMAP3430_SOURCE_54M_WIDTH, 0x0, NULL);
-
-static const struct clksel clkout2_src_clksel[] = {
- { .parent = &core_ck, .rates = clkout2_src_core_rates },
- { .parent = &sys_ck, .rates = clkout2_src_sys_rates },
- { .parent = &cm_96m_fck, .rates = clkout2_src_96m_rates },
- { .parent = &omap_54m_fck, .rates = clkout2_src_54m_rates },
- { .parent = NULL },
-};
-
-static const char *clkout2_src_ck_parent_names[] = {
- "core_ck", "sys_ck", "cm_96m_fck", "omap_54m_fck",
-};
-
-static const struct clk_ops clkout2_src_ck_ops = {
- .init = &omap2_init_clk_clkdm,
- .enable = &omap2_dflt_clk_enable,
- .disable = &omap2_dflt_clk_disable,
- .is_enabled = &omap2_dflt_clk_is_enabled,
- .recalc_rate = &omap2_clksel_recalc,
- .get_parent = &omap2_clksel_find_parent_index,
- .set_parent = &omap2_clksel_set_parent,
-};
-
-DEFINE_CLK_OMAP_MUX_GATE(clkout2_src_ck, "core_clkdm",
- clkout2_src_clksel, OMAP3430_CM_CLKOUT_CTRL,
- OMAP3430_CLKOUT2SOURCE_MASK,
- OMAP3430_CM_CLKOUT_CTRL, OMAP3430_CLKOUT2_EN_SHIFT,
- NULL, clkout2_src_ck_parent_names, clkout2_src_ck_ops);
-
-static const struct clksel_rate omap_48m_cm96m_rates[] = {
- { .div = 2, .val = 0, .flags = RATE_IN_3XXX },
- { .div = 0 }
-};
-
-static const struct clksel_rate omap_48m_alt_rates[] = {
- { .div = 1, .val = 1, .flags = RATE_IN_3XXX },
- { .div = 0 }
-};
-
-static const struct clksel omap_48m_clksel[] = {
- { .parent = &cm_96m_fck, .rates = omap_48m_cm96m_rates },
- { .parent = &sys_altclk, .rates = omap_48m_alt_rates },
- { .parent = NULL },
-};
-
-static const char *omap_48m_fck_parent_names[] = {
- "cm_96m_fck", "sys_altclk",
-};
-
-static struct clk omap_48m_fck;
-
-static const struct clk_ops omap_48m_fck_ops = {
- .recalc_rate = &omap2_clksel_recalc,
- .get_parent = &omap2_clksel_find_parent_index,
- .set_parent = &omap2_clksel_set_parent,
-};
-
-static struct clk_hw_omap omap_48m_fck_hw = {
- .hw = {
- .clk = &omap_48m_fck,
- },
- .clksel = omap_48m_clksel,
- .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
- .clksel_mask = OMAP3430_SOURCE_48M_MASK,
-};
-
-DEFINE_STRUCT_CLK(omap_48m_fck, omap_48m_fck_parent_names, omap_48m_fck_ops);
-
-DEFINE_CLK_FIXED_FACTOR(omap_12m_fck, "omap_48m_fck", &omap_48m_fck, 0x0, 1, 4);
-
-static struct clk core_12m_fck;
-
-static const char *core_12m_fck_parent_names[] = {
- "omap_12m_fck",
-};
-
-DEFINE_STRUCT_CLK_HW_OMAP(core_12m_fck, "core_l4_clkdm");
-DEFINE_STRUCT_CLK(core_12m_fck, core_12m_fck_parent_names, core_l4_ick_ops);
-
-static struct clk core_48m_fck;
-
-static const char *core_48m_fck_parent_names[] = {
- "omap_48m_fck",
-};
-
-DEFINE_STRUCT_CLK_HW_OMAP(core_48m_fck, "core_l4_clkdm");
-DEFINE_STRUCT_CLK(core_48m_fck, core_48m_fck_parent_names, core_l4_ick_ops);
-
-static const char *omap_96m_fck_parent_names[] = {
- "cm_96m_fck", "sys_ck",
-};
-
-DEFINE_CLK_MUX(omap_96m_fck, omap_96m_fck_parent_names, NULL, 0x0,
- OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
- OMAP3430_SOURCE_96M_SHIFT, OMAP3430_SOURCE_96M_WIDTH, 0x0, NULL);
-
-static struct clk core_96m_fck;
-
-static const char *core_96m_fck_parent_names[] = {
- "omap_96m_fck",
-};
-
-DEFINE_STRUCT_CLK_HW_OMAP(core_96m_fck, "core_l4_clkdm");
-DEFINE_STRUCT_CLK(core_96m_fck, core_96m_fck_parent_names, core_l4_ick_ops);
-
-static struct clk core_l3_ick;
-
-static const char *core_l3_ick_parent_names[] = {
- "l3_ick",
-};
-
-DEFINE_STRUCT_CLK_HW_OMAP(core_l3_ick, "core_l3_clkdm");
-DEFINE_STRUCT_CLK(core_l3_ick, core_l3_ick_parent_names, core_l4_ick_ops);
-
-DEFINE_CLK_FIXED_FACTOR(dpll3_m2x2_ck, "dpll3_m2_ck", &dpll3_m2_ck, 0x0, 2, 1);
-
-static struct clk corex2_fck;
-
-static const char *corex2_fck_parent_names[] = {
- "dpll3_m2x2_ck",
-};
-
-DEFINE_STRUCT_CLK_HW_OMAP(corex2_fck, NULL);
-DEFINE_STRUCT_CLK(corex2_fck, corex2_fck_parent_names, core_ck_ops);
-
-static const char *cpefuse_fck_parent_names[] = {
- "sys_ck",
-};
-
-static struct clk cpefuse_fck;
-
-static struct clk_hw_omap cpefuse_fck_hw = {
- .hw = {
- .clk = &cpefuse_fck,
- },
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP3430ES2_CM_FCLKEN3),
- .enable_bit = OMAP3430ES2_EN_CPEFUSE_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(cpefuse_fck, cpefuse_fck_parent_names, aes2_ick_ops);
-
-static struct clk csi2_96m_fck;
-
-static const char *csi2_96m_fck_parent_names[] = {
- "core_96m_fck",
-};
-
-static struct clk_hw_omap csi2_96m_fck_hw = {
- .hw = {
- .clk = &csi2_96m_fck,
- },
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_CAM_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_CSI2_SHIFT,
- .clkdm_name = "cam_clkdm",
-};
-
-DEFINE_STRUCT_CLK(csi2_96m_fck, csi2_96m_fck_parent_names, aes2_ick_ops);
-
-static struct clk d2d_26m_fck;
-
-static struct clk_hw_omap d2d_26m_fck_hw = {
- .hw = {
- .clk = &d2d_26m_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- .enable_bit = OMAP3430ES1_EN_D2D_SHIFT,
- .clkdm_name = "d2d_clkdm",
-};
-
-DEFINE_STRUCT_CLK(d2d_26m_fck, cpefuse_fck_parent_names, aes2_ick_ops);
-
-static struct clk des1_ick;
-
-static struct clk_hw_omap des1_ick_hw = {
- .hw = {
- .clk = &des1_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
- .enable_bit = OMAP3430_EN_DES1_SHIFT,
-};
-
-DEFINE_STRUCT_CLK(des1_ick, aes1_ick_parent_names, aes1_ick_ops);
-
-static struct clk des2_ick;
-
-static struct clk_hw_omap des2_ick_hw = {
- .hw = {
- .clk = &des2_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_DES2_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(des2_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-DEFINE_CLK_DIVIDER(dpll1_fck, "core_ck", &core_ck, 0x0,
- OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_CLKSEL1_PLL),
- OMAP3430_MPU_CLK_SRC_SHIFT, OMAP3430_MPU_CLK_SRC_WIDTH,
- CLK_DIVIDER_ONE_BASED, NULL);
-
-static struct clk dpll2_fck;
-
-static struct dpll_data dpll2_dd = {
- .mult_div1_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSEL1_PLL),
- .mult_mask = OMAP3430_IVA2_DPLL_MULT_MASK,
- .div1_mask = OMAP3430_IVA2_DPLL_DIV_MASK,
- .clk_bypass = &dpll2_fck,
- .clk_ref = &sys_ck,
- .freqsel_mask = OMAP3430_IVA2_DPLL_FREQSEL_MASK,
- .control_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKEN_PLL),
- .enable_mask = OMAP3430_EN_IVA2_DPLL_MASK,
- .modes = ((1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED) |
- (1 << DPLL_LOW_POWER_BYPASS)),
- .auto_recal_bit = OMAP3430_EN_IVA2_DPLL_DRIFTGUARD_SHIFT,
- .recal_en_bit = OMAP3430_PRM_IRQENABLE_MPU_IVA2_DPLL_RECAL_EN_SHIFT,
- .recal_st_bit = OMAP3430_PRM_IRQSTATUS_MPU_IVA2_DPLL_ST_SHIFT,
- .autoidle_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_AUTOIDLE_PLL),
- .autoidle_mask = OMAP3430_AUTO_IVA2_DPLL_MASK,
- .idlest_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_IDLEST_PLL),
- .idlest_mask = OMAP3430_ST_IVA2_CLK_MASK,
- .max_multiplier = OMAP3_MAX_DPLL_MULT,
- .min_divider = 1,
- .max_divider = OMAP3_MAX_DPLL_DIV,
-};
-
-static struct clk dpll2_ck;
-
-static struct clk_hw_omap dpll2_ck_hw = {
- .hw = {
- .clk = &dpll2_ck,
- },
- .ops = &clkhwops_omap3_dpll,
- .dpll_data = &dpll2_dd,
- .clkdm_name = "dpll2_clkdm",
-};
-
-DEFINE_STRUCT_CLK(dpll2_ck, dpll3_ck_parent_names, dpll1_ck_ops);
-
-DEFINE_CLK_DIVIDER(dpll2_fck, "core_ck", &core_ck, 0x0,
- OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSEL1_PLL),
- OMAP3430_IVA2_CLK_SRC_SHIFT, OMAP3430_IVA2_CLK_SRC_WIDTH,
- CLK_DIVIDER_ONE_BASED, NULL);
-
-DEFINE_CLK_DIVIDER(dpll2_m2_ck, "dpll2_ck", &dpll2_ck, 0x0,
- OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSEL2_PLL),
- OMAP3430_IVA2_DPLL_CLKOUT_DIV_SHIFT,
- OMAP3430_IVA2_DPLL_CLKOUT_DIV_WIDTH,
- CLK_DIVIDER_ONE_BASED, NULL);
-
-DEFINE_CLK_DIVIDER(dpll3_m3_ck, "dpll3_ck", &dpll3_ck, 0x0,
- OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
- OMAP3430_DIV_DPLL3_SHIFT, OMAP3430_DIV_DPLL3_WIDTH,
- CLK_DIVIDER_ONE_BASED, NULL);
-
-static struct clk dpll3_m3x2_ck;
-
-static const char *dpll3_m3x2_ck_parent_names[] = {
- "dpll3_m3_ck",
-};
-
-static struct clk_hw_omap dpll3_m3x2_ck_hw = {
- .hw = {
- .clk = &dpll3_m3x2_ck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
- .enable_bit = OMAP3430_PWRDN_EMU_CORE_SHIFT,
- .flags = INVERT_ENABLE,
- .clkdm_name = "dpll3_clkdm",
-};
-
-DEFINE_STRUCT_CLK(dpll3_m3x2_ck, dpll3_m3x2_ck_parent_names, dpll4_m5x2_ck_ops);
-
-static struct clk dpll3_m3x2_ck_3630 = {
- .name = "dpll3_m3x2_ck",
- .hw = &dpll3_m3x2_ck_hw.hw,
- .parent_names = dpll3_m3x2_ck_parent_names,
- .num_parents = ARRAY_SIZE(dpll3_m3x2_ck_parent_names),
- .ops = &dpll4_m5x2_ck_3630_ops,
-};
-
-DEFINE_CLK_FIXED_FACTOR(dpll3_x2_ck, "dpll3_ck", &dpll3_ck, 0x0, 2, 1);
-
-DEFINE_CLK_DIVIDER_TABLE(dpll4_m4_ck, "dpll4_ck", &dpll4_ck, 0x0,
- OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_CLKSEL),
- OMAP3430_CLKSEL_DSS1_SHIFT, OMAP3630_CLKSEL_DSS1_WIDTH,
- 0, dpll4_mx_ck_div_table, NULL);
-
-static struct clk dpll4_m4x2_ck;
-
-static const char *dpll4_m4x2_ck_parent_names[] = {
- "dpll4_m4_ck",
-};
-
-static struct clk_hw_omap dpll4_m4x2_ck_hw = {
- .hw = {
- .clk = &dpll4_m4x2_ck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
- .enable_bit = OMAP3430_PWRDN_DSS1_SHIFT,
- .flags = INVERT_ENABLE,
- .clkdm_name = "dpll4_clkdm",
-};
-
-DEFINE_STRUCT_CLK_FLAGS(dpll4_m4x2_ck, dpll4_m4x2_ck_parent_names,
- dpll4_m5x2_ck_ops, CLK_SET_RATE_PARENT);
-
-static struct clk dpll4_m4x2_ck_3630 = {
- .name = "dpll4_m4x2_ck",
- .hw = &dpll4_m4x2_ck_hw.hw,
- .parent_names = dpll4_m4x2_ck_parent_names,
- .num_parents = ARRAY_SIZE(dpll4_m4x2_ck_parent_names),
- .ops = &dpll4_m5x2_ck_3630_ops,
- .flags = CLK_SET_RATE_PARENT,
-};
-
-DEFINE_CLK_DIVIDER(dpll4_m6_ck, "dpll4_ck", &dpll4_ck, 0x0,
- OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
- OMAP3430_DIV_DPLL4_SHIFT, OMAP3630_DIV_DPLL4_WIDTH,
- CLK_DIVIDER_ONE_BASED, NULL);
-
-static struct clk dpll4_m6x2_ck;
-
-static const char *dpll4_m6x2_ck_parent_names[] = {
- "dpll4_m6_ck",
-};
-
-static struct clk_hw_omap dpll4_m6x2_ck_hw = {
- .hw = {
- .clk = &dpll4_m6x2_ck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
- .enable_bit = OMAP3430_PWRDN_EMU_PERIPH_SHIFT,
- .flags = INVERT_ENABLE,
- .clkdm_name = "dpll4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(dpll4_m6x2_ck, dpll4_m6x2_ck_parent_names, dpll4_m5x2_ck_ops);
-
-static struct clk dpll4_m6x2_ck_3630 = {
- .name = "dpll4_m6x2_ck",
- .hw = &dpll4_m6x2_ck_hw.hw,
- .parent_names = dpll4_m6x2_ck_parent_names,
- .num_parents = ARRAY_SIZE(dpll4_m6x2_ck_parent_names),
- .ops = &dpll4_m5x2_ck_3630_ops,
-};
-
-DEFINE_CLK_FIXED_FACTOR(dpll4_x2_ck, "dpll4_ck", &dpll4_ck, 0x0, 2, 1);
-
-static struct dpll_data dpll5_dd = {
- .mult_div1_reg = OMAP_CM_REGADDR(PLL_MOD, OMAP3430ES2_CM_CLKSEL4),
- .mult_mask = OMAP3430ES2_PERIPH2_DPLL_MULT_MASK,
- .div1_mask = OMAP3430ES2_PERIPH2_DPLL_DIV_MASK,
- .clk_bypass = &sys_ck,
- .clk_ref = &sys_ck,
- .freqsel_mask = OMAP3430ES2_PERIPH2_DPLL_FREQSEL_MASK,
- .control_reg = OMAP_CM_REGADDR(PLL_MOD, OMAP3430ES2_CM_CLKEN2),
- .enable_mask = OMAP3430ES2_EN_PERIPH2_DPLL_MASK,
- .modes = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED),
- .auto_recal_bit = OMAP3430ES2_EN_PERIPH2_DPLL_DRIFTGUARD_SHIFT,
- .recal_en_bit = OMAP3430ES2_SND_PERIPH_DPLL_RECAL_EN_SHIFT,
- .recal_st_bit = OMAP3430ES2_SND_PERIPH_DPLL_ST_SHIFT,
- .autoidle_reg = OMAP_CM_REGADDR(PLL_MOD, OMAP3430ES2_CM_AUTOIDLE2_PLL),
- .autoidle_mask = OMAP3430ES2_AUTO_PERIPH2_DPLL_MASK,
- .idlest_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST2),
- .idlest_mask = OMAP3430ES2_ST_PERIPH2_CLK_MASK,
- .max_multiplier = OMAP3_MAX_DPLL_MULT,
- .min_divider = 1,
- .max_divider = OMAP3_MAX_DPLL_DIV,
-};
-
-static struct clk dpll5_ck;
-
-static struct clk_hw_omap dpll5_ck_hw = {
- .hw = {
- .clk = &dpll5_ck,
- },
- .ops = &clkhwops_omap3_dpll,
- .dpll_data = &dpll5_dd,
- .clkdm_name = "dpll5_clkdm",
-};
-
-DEFINE_STRUCT_CLK(dpll5_ck, dpll3_ck_parent_names, dpll1_ck_ops);
-
-DEFINE_CLK_DIVIDER(dpll5_m2_ck, "dpll5_ck", &dpll5_ck, 0x0,
- OMAP_CM_REGADDR(PLL_MOD, OMAP3430ES2_CM_CLKSEL5),
- OMAP3430ES2_DIV_120M_SHIFT, OMAP3430ES2_DIV_120M_WIDTH,
- CLK_DIVIDER_ONE_BASED, NULL);
-
-static struct clk dss1_alwon_fck_3430es1;
-
-static const char *dss1_alwon_fck_3430es1_parent_names[] = {
- "dpll4_m4x2_ck",
-};
-
-static struct clk_hw_omap dss1_alwon_fck_3430es1_hw = {
- .hw = {
- .clk = &dss1_alwon_fck_3430es1,
- },
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_DSS1_SHIFT,
- .clkdm_name = "dss_clkdm",
-};
-
-DEFINE_STRUCT_CLK_FLAGS(dss1_alwon_fck_3430es1,
- dss1_alwon_fck_3430es1_parent_names, aes2_ick_ops,
- CLK_SET_RATE_PARENT);
-
-static struct clk dss1_alwon_fck_3430es2;
-
-static struct clk_hw_omap dss1_alwon_fck_3430es2_hw = {
- .hw = {
- .clk = &dss1_alwon_fck_3430es2,
- },
- .ops = &clkhwops_omap3430es2_dss_usbhost_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_DSS1_SHIFT,
- .clkdm_name = "dss_clkdm",
-};
-
-DEFINE_STRUCT_CLK_FLAGS(dss1_alwon_fck_3430es2,
- dss1_alwon_fck_3430es1_parent_names, aes2_ick_ops,
- CLK_SET_RATE_PARENT);
-
-static struct clk dss2_alwon_fck;
-
-static struct clk_hw_omap dss2_alwon_fck_hw = {
- .hw = {
- .clk = &dss2_alwon_fck,
- },
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_DSS2_SHIFT,
- .clkdm_name = "dss_clkdm",
-};
-
-DEFINE_STRUCT_CLK(dss2_alwon_fck, cpefuse_fck_parent_names, aes2_ick_ops);
-
-static struct clk dss_96m_fck;
-
-static struct clk_hw_omap dss_96m_fck_hw = {
- .hw = {
- .clk = &dss_96m_fck,
- },
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_TV_SHIFT,
- .clkdm_name = "dss_clkdm",
-};
-
-DEFINE_STRUCT_CLK(dss_96m_fck, core_96m_fck_parent_names, aes2_ick_ops);
-
-static struct clk dss_ick_3430es1;
-
-static struct clk_hw_omap dss_ick_3430es1_hw = {
- .hw = {
- .clk = &dss_ick_3430es1,
- },
- .ops = &clkhwops_iclk,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_CM_ICLKEN_DSS_EN_DSS_SHIFT,
- .clkdm_name = "dss_clkdm",
-};
-
-DEFINE_STRUCT_CLK(dss_ick_3430es1, security_l4_ick2_parent_names, aes2_ick_ops);
-
-static struct clk dss_ick_3430es2;
-
-static struct clk_hw_omap dss_ick_3430es2_hw = {
- .hw = {
- .clk = &dss_ick_3430es2,
- },
- .ops = &clkhwops_omap3430es2_iclk_dss_usbhost_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_CM_ICLKEN_DSS_EN_DSS_SHIFT,
- .clkdm_name = "dss_clkdm",
-};
-
-DEFINE_STRUCT_CLK(dss_ick_3430es2, security_l4_ick2_parent_names, aes2_ick_ops);
-
-static struct clk dss_tv_fck;
-
-static const char *dss_tv_fck_parent_names[] = {
- "omap_54m_fck",
-};
-
-static struct clk_hw_omap dss_tv_fck_hw = {
- .hw = {
- .clk = &dss_tv_fck,
- },
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_TV_SHIFT,
- .clkdm_name = "dss_clkdm",
-};
-
-DEFINE_STRUCT_CLK(dss_tv_fck, dss_tv_fck_parent_names, aes2_ick_ops);
-
-static struct clk emac_fck;
-
-static const char *emac_fck_parent_names[] = {
- "rmii_ck",
-};
-
-static struct clk_hw_omap emac_fck_hw = {
- .hw = {
- .clk = &emac_fck,
- },
- .enable_reg = OMAP343X_CTRL_REGADDR(AM35XX_CONTROL_IPSS_CLK_CTRL),
- .enable_bit = AM35XX_CPGMAC_FCLK_SHIFT,
-};
-
-DEFINE_STRUCT_CLK(emac_fck, emac_fck_parent_names, aes1_ick_ops);
-
-static struct clk ipss_ick;
-
-static const char *ipss_ick_parent_names[] = {
- "core_l3_ick",
-};
-
-static struct clk_hw_omap ipss_ick_hw = {
- .hw = {
- .clk = &ipss_ick,
- },
- .ops = &clkhwops_am35xx_ipss_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = AM35XX_EN_IPSS_SHIFT,
- .clkdm_name = "core_l3_clkdm",
-};
-
-DEFINE_STRUCT_CLK(ipss_ick, ipss_ick_parent_names, aes2_ick_ops);
-
-static struct clk emac_ick;
-
-static const char *emac_ick_parent_names[] = {
- "ipss_ick",
-};
-
-static struct clk_hw_omap emac_ick_hw = {
- .hw = {
- .clk = &emac_ick,
- },
- .ops = &clkhwops_am35xx_ipss_module_wait,
- .enable_reg = OMAP343X_CTRL_REGADDR(AM35XX_CONTROL_IPSS_CLK_CTRL),
- .enable_bit = AM35XX_CPGMAC_VBUSP_CLK_SHIFT,
- .clkdm_name = "core_l3_clkdm",
-};
-
-DEFINE_STRUCT_CLK(emac_ick, emac_ick_parent_names, aes2_ick_ops);
-
-static struct clk emu_core_alwon_ck;
-
-static const char *emu_core_alwon_ck_parent_names[] = {
- "dpll3_m3x2_ck",
-};
-
-DEFINE_STRUCT_CLK_HW_OMAP(emu_core_alwon_ck, "dpll3_clkdm");
-DEFINE_STRUCT_CLK(emu_core_alwon_ck, emu_core_alwon_ck_parent_names,
- core_l4_ick_ops);
-
-static struct clk emu_mpu_alwon_ck;
-
-static const char *emu_mpu_alwon_ck_parent_names[] = {
- "mpu_ck",
-};
-
-DEFINE_STRUCT_CLK_HW_OMAP(emu_mpu_alwon_ck, NULL);
-DEFINE_STRUCT_CLK(emu_mpu_alwon_ck, emu_mpu_alwon_ck_parent_names, core_ck_ops);
-
-static struct clk emu_per_alwon_ck;
-
-static const char *emu_per_alwon_ck_parent_names[] = {
- "dpll4_m6x2_ck",
-};
-
-DEFINE_STRUCT_CLK_HW_OMAP(emu_per_alwon_ck, "dpll4_clkdm");
-DEFINE_STRUCT_CLK(emu_per_alwon_ck, emu_per_alwon_ck_parent_names,
- core_l4_ick_ops);
-
-static const char *emu_src_ck_parent_names[] = {
- "sys_ck", "emu_core_alwon_ck", "emu_per_alwon_ck", "emu_mpu_alwon_ck",
-};
-
-static const struct clksel_rate emu_src_sys_rates[] = {
- { .div = 1, .val = 0, .flags = RATE_IN_3XXX },
- { .div = 0 },
-};
-
-static const struct clksel_rate emu_src_core_rates[] = {
- { .div = 1, .val = 1, .flags = RATE_IN_3XXX },
- { .div = 0 },
-};
-
-static const struct clksel_rate emu_src_per_rates[] = {
- { .div = 1, .val = 2, .flags = RATE_IN_3XXX },
- { .div = 0 },
-};
-
-static const struct clksel_rate emu_src_mpu_rates[] = {
- { .div = 1, .val = 3, .flags = RATE_IN_3XXX },
- { .div = 0 },
-};
-
-static const struct clksel emu_src_clksel[] = {
- { .parent = &sys_ck, .rates = emu_src_sys_rates },
- { .parent = &emu_core_alwon_ck, .rates = emu_src_core_rates },
- { .parent = &emu_per_alwon_ck, .rates = emu_src_per_rates },
- { .parent = &emu_mpu_alwon_ck, .rates = emu_src_mpu_rates },
- { .parent = NULL },
-};
-
-static const struct clk_ops emu_src_ck_ops = {
- .init = &omap2_init_clk_clkdm,
- .recalc_rate = &omap2_clksel_recalc,
- .get_parent = &omap2_clksel_find_parent_index,
- .set_parent = &omap2_clksel_set_parent,
- .enable = &omap2_clkops_enable_clkdm,
- .disable = &omap2_clkops_disable_clkdm,
-};
-
-static struct clk emu_src_ck;
-
-static struct clk_hw_omap emu_src_ck_hw = {
- .hw = {
- .clk = &emu_src_ck,
- },
- .clksel = emu_src_clksel,
- .clksel_reg = OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
- .clksel_mask = OMAP3430_MUX_CTRL_MASK,
- .clkdm_name = "emu_clkdm",
-};
-
-DEFINE_STRUCT_CLK(emu_src_ck, emu_src_ck_parent_names, emu_src_ck_ops);
-
-DEFINE_CLK_DIVIDER(atclk_fck, "emu_src_ck", &emu_src_ck, 0x0,
- OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
- OMAP3430_CLKSEL_ATCLK_SHIFT, OMAP3430_CLKSEL_ATCLK_WIDTH,
- CLK_DIVIDER_ONE_BASED, NULL);
-
-static struct clk fac_ick;
-
-static struct clk_hw_omap fac_ick_hw = {
- .hw = {
- .clk = &fac_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430ES1_EN_FAC_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(fac_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static struct clk fshostusb_fck;
-
-static const char *fshostusb_fck_parent_names[] = {
- "core_48m_fck",
-};
-
-static struct clk_hw_omap fshostusb_fck_hw = {
- .hw = {
- .clk = &fshostusb_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- .enable_bit = OMAP3430ES1_EN_FSHOSTUSB_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(fshostusb_fck, fshostusb_fck_parent_names, aes2_ick_ops);
-
-static struct clk gfx_l3_ck;
-
-static struct clk_hw_omap gfx_l3_ck_hw = {
- .hw = {
- .clk = &gfx_l3_ck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(GFX_MOD, CM_ICLKEN),
- .enable_bit = OMAP_EN_GFX_SHIFT,
- .clkdm_name = "gfx_3430es1_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gfx_l3_ck, core_l3_ick_parent_names, aes1_ick_ops);
-
-DEFINE_CLK_DIVIDER(gfx_l3_fck, "l3_ick", &l3_ick, 0x0,
- OMAP_CM_REGADDR(GFX_MOD, CM_CLKSEL),
- OMAP_CLKSEL_GFX_SHIFT, OMAP_CLKSEL_GFX_WIDTH,
- CLK_DIVIDER_ONE_BASED, NULL);
-
-static struct clk gfx_cg1_ck;
-
-static const char *gfx_cg1_ck_parent_names[] = {
- "gfx_l3_fck",
-};
-
-static struct clk_hw_omap gfx_cg1_ck_hw = {
- .hw = {
- .clk = &gfx_cg1_ck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(GFX_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430ES1_EN_2D_SHIFT,
- .clkdm_name = "gfx_3430es1_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gfx_cg1_ck, gfx_cg1_ck_parent_names, aes2_ick_ops);
-
-static struct clk gfx_cg2_ck;
-
-static struct clk_hw_omap gfx_cg2_ck_hw = {
- .hw = {
- .clk = &gfx_cg2_ck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(GFX_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430ES1_EN_3D_SHIFT,
- .clkdm_name = "gfx_3430es1_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gfx_cg2_ck, gfx_cg1_ck_parent_names, aes2_ick_ops);
-
-static struct clk gfx_l3_ick;
-
-static const char *gfx_l3_ick_parent_names[] = {
- "gfx_l3_ck",
-};
-
-DEFINE_STRUCT_CLK_HW_OMAP(gfx_l3_ick, "gfx_3430es1_clkdm");
-DEFINE_STRUCT_CLK(gfx_l3_ick, gfx_l3_ick_parent_names, core_l4_ick_ops);
-
-static struct clk wkup_32k_fck;
-
-static const char *wkup_32k_fck_parent_names[] = {
- "omap_32k_fck",
-};
-
-DEFINE_STRUCT_CLK_HW_OMAP(wkup_32k_fck, "wkup_clkdm");
-DEFINE_STRUCT_CLK(wkup_32k_fck, wkup_32k_fck_parent_names, core_l4_ick_ops);
-
-static struct clk gpio1_dbck;
-
-static const char *gpio1_dbck_parent_names[] = {
- "wkup_32k_fck",
-};
-
-static struct clk_hw_omap gpio1_dbck_hw = {
- .hw = {
- .clk = &gpio1_dbck,
- },
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_GPIO1_SHIFT,
- .clkdm_name = "wkup_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpio1_dbck, gpio1_dbck_parent_names, aes2_ick_ops);
-
-static struct clk wkup_l4_ick;
-
-DEFINE_STRUCT_CLK_HW_OMAP(wkup_l4_ick, "wkup_clkdm");
-DEFINE_STRUCT_CLK(wkup_l4_ick, cpefuse_fck_parent_names, core_l4_ick_ops);
-
-static struct clk gpio1_ick;
-
-static const char *gpio1_ick_parent_names[] = {
- "wkup_l4_ick",
-};
-
-static struct clk_hw_omap gpio1_ick_hw = {
- .hw = {
- .clk = &gpio1_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_GPIO1_SHIFT,
- .clkdm_name = "wkup_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpio1_ick, gpio1_ick_parent_names, aes2_ick_ops);
-
-static struct clk per_32k_alwon_fck;
-
-DEFINE_STRUCT_CLK_HW_OMAP(per_32k_alwon_fck, "per_clkdm");
-DEFINE_STRUCT_CLK(per_32k_alwon_fck, wkup_32k_fck_parent_names,
- core_l4_ick_ops);
-
-static struct clk gpio2_dbck;
-
-static const char *gpio2_dbck_parent_names[] = {
- "per_32k_alwon_fck",
-};
-
-static struct clk_hw_omap gpio2_dbck_hw = {
- .hw = {
- .clk = &gpio2_dbck,
- },
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_GPIO2_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpio2_dbck, gpio2_dbck_parent_names, aes2_ick_ops);
-
-static struct clk per_l4_ick;
-
-DEFINE_STRUCT_CLK_HW_OMAP(per_l4_ick, "per_clkdm");
-DEFINE_STRUCT_CLK(per_l4_ick, security_l4_ick2_parent_names, core_l4_ick_ops);
-
-static struct clk gpio2_ick;
-
-static const char *gpio2_ick_parent_names[] = {
- "per_l4_ick",
-};
-
-static struct clk_hw_omap gpio2_ick_hw = {
- .hw = {
- .clk = &gpio2_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_GPIO2_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpio2_ick, gpio2_ick_parent_names, aes2_ick_ops);
-
-static struct clk gpio3_dbck;
-
-static struct clk_hw_omap gpio3_dbck_hw = {
- .hw = {
- .clk = &gpio3_dbck,
- },
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_GPIO3_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpio3_dbck, gpio2_dbck_parent_names, aes2_ick_ops);
-
-static struct clk gpio3_ick;
-
-static struct clk_hw_omap gpio3_ick_hw = {
- .hw = {
- .clk = &gpio3_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_GPIO3_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpio3_ick, gpio2_ick_parent_names, aes2_ick_ops);
-
-static struct clk gpio4_dbck;
-
-static struct clk_hw_omap gpio4_dbck_hw = {
- .hw = {
- .clk = &gpio4_dbck,
- },
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_GPIO4_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpio4_dbck, gpio2_dbck_parent_names, aes2_ick_ops);
-
-static struct clk gpio4_ick;
-
-static struct clk_hw_omap gpio4_ick_hw = {
- .hw = {
- .clk = &gpio4_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_GPIO4_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpio4_ick, gpio2_ick_parent_names, aes2_ick_ops);
-
-static struct clk gpio5_dbck;
-
-static struct clk_hw_omap gpio5_dbck_hw = {
- .hw = {
- .clk = &gpio5_dbck,
- },
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_GPIO5_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpio5_dbck, gpio2_dbck_parent_names, aes2_ick_ops);
-
-static struct clk gpio5_ick;
-
-static struct clk_hw_omap gpio5_ick_hw = {
- .hw = {
- .clk = &gpio5_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_GPIO5_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpio5_ick, gpio2_ick_parent_names, aes2_ick_ops);
-
-static struct clk gpio6_dbck;
-
-static struct clk_hw_omap gpio6_dbck_hw = {
- .hw = {
- .clk = &gpio6_dbck,
- },
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_GPIO6_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpio6_dbck, gpio2_dbck_parent_names, aes2_ick_ops);
-
-static struct clk gpio6_ick;
-
-static struct clk_hw_omap gpio6_ick_hw = {
- .hw = {
- .clk = &gpio6_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_GPIO6_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpio6_ick, gpio2_ick_parent_names, aes2_ick_ops);
-
-static struct clk gpmc_fck;
-
-static struct clk_hw_omap gpmc_fck_hw = {
- .hw = {
- .clk = &gpmc_fck,
- },
- .flags = ENABLE_ON_INIT,
- .clkdm_name = "core_l3_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpmc_fck, ipss_ick_parent_names, core_l4_ick_ops);
-
-static const struct clksel omap343x_gpt_clksel[] = {
- { .parent = &omap_32k_fck, .rates = gpt_32k_rates },
- { .parent = &sys_ck, .rates = gpt_sys_rates },
- { .parent = NULL },
-};
-
-static const char *gpt10_fck_parent_names[] = {
- "omap_32k_fck", "sys_ck",
-};
-
-DEFINE_CLK_OMAP_MUX_GATE(gpt10_fck, "core_l4_clkdm", omap343x_gpt_clksel,
- OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
- OMAP3430_CLKSEL_GPT10_MASK,
- OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- OMAP3430_EN_GPT10_SHIFT, &clkhwops_wait,
- gpt10_fck_parent_names, clkout2_src_ck_ops);
-
-static struct clk gpt10_ick;
-
-static struct clk_hw_omap gpt10_ick_hw = {
- .hw = {
- .clk = &gpt10_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_GPT10_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpt10_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-DEFINE_CLK_OMAP_MUX_GATE(gpt11_fck, "core_l4_clkdm", omap343x_gpt_clksel,
- OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
- OMAP3430_CLKSEL_GPT11_MASK,
- OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- OMAP3430_EN_GPT11_SHIFT, &clkhwops_wait,
- gpt10_fck_parent_names, clkout2_src_ck_ops);
-
-static struct clk gpt11_ick;
-
-static struct clk_hw_omap gpt11_ick_hw = {
- .hw = {
- .clk = &gpt11_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_GPT11_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpt11_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static struct clk gpt12_fck;
-
-static const char *gpt12_fck_parent_names[] = {
- "secure_32k_fck",
-};
-
-DEFINE_STRUCT_CLK_HW_OMAP(gpt12_fck, "wkup_clkdm");
-DEFINE_STRUCT_CLK(gpt12_fck, gpt12_fck_parent_names, core_l4_ick_ops);
-
-static struct clk gpt12_ick;
-
-static struct clk_hw_omap gpt12_ick_hw = {
- .hw = {
- .clk = &gpt12_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_GPT12_SHIFT,
- .clkdm_name = "wkup_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpt12_ick, gpio1_ick_parent_names, aes2_ick_ops);
-
-DEFINE_CLK_OMAP_MUX_GATE(gpt1_fck, "wkup_clkdm", omap343x_gpt_clksel,
- OMAP_CM_REGADDR(WKUP_MOD, CM_CLKSEL),
- OMAP3430_CLKSEL_GPT1_MASK,
- OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
- OMAP3430_EN_GPT1_SHIFT, &clkhwops_wait,
- gpt10_fck_parent_names, clkout2_src_ck_ops);
-
-static struct clk gpt1_ick;
-
-static struct clk_hw_omap gpt1_ick_hw = {
- .hw = {
- .clk = &gpt1_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_GPT1_SHIFT,
- .clkdm_name = "wkup_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpt1_ick, gpio1_ick_parent_names, aes2_ick_ops);
-
-DEFINE_CLK_OMAP_MUX_GATE(gpt2_fck, "per_clkdm", omap343x_gpt_clksel,
- OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
- OMAP3430_CLKSEL_GPT2_MASK,
- OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- OMAP3430_EN_GPT2_SHIFT, &clkhwops_wait,
- gpt10_fck_parent_names, clkout2_src_ck_ops);
-
-static struct clk gpt2_ick;
-
-static struct clk_hw_omap gpt2_ick_hw = {
- .hw = {
- .clk = &gpt2_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_GPT2_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpt2_ick, gpio2_ick_parent_names, aes2_ick_ops);
-
-DEFINE_CLK_OMAP_MUX_GATE(gpt3_fck, "per_clkdm", omap343x_gpt_clksel,
- OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
- OMAP3430_CLKSEL_GPT3_MASK,
- OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- OMAP3430_EN_GPT3_SHIFT, &clkhwops_wait,
- gpt10_fck_parent_names, clkout2_src_ck_ops);
-
-static struct clk gpt3_ick;
-
-static struct clk_hw_omap gpt3_ick_hw = {
- .hw = {
- .clk = &gpt3_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_GPT3_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpt3_ick, gpio2_ick_parent_names, aes2_ick_ops);
-
-DEFINE_CLK_OMAP_MUX_GATE(gpt4_fck, "per_clkdm", omap343x_gpt_clksel,
- OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
- OMAP3430_CLKSEL_GPT4_MASK,
- OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- OMAP3430_EN_GPT4_SHIFT, &clkhwops_wait,
- gpt10_fck_parent_names, clkout2_src_ck_ops);
-
-static struct clk gpt4_ick;
-
-static struct clk_hw_omap gpt4_ick_hw = {
- .hw = {
- .clk = &gpt4_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_GPT4_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpt4_ick, gpio2_ick_parent_names, aes2_ick_ops);
-
-DEFINE_CLK_OMAP_MUX_GATE(gpt5_fck, "per_clkdm", omap343x_gpt_clksel,
- OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
- OMAP3430_CLKSEL_GPT5_MASK,
- OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- OMAP3430_EN_GPT5_SHIFT, &clkhwops_wait,
- gpt10_fck_parent_names, clkout2_src_ck_ops);
-
-static struct clk gpt5_ick;
-
-static struct clk_hw_omap gpt5_ick_hw = {
- .hw = {
- .clk = &gpt5_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_GPT5_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpt5_ick, gpio2_ick_parent_names, aes2_ick_ops);
-
-DEFINE_CLK_OMAP_MUX_GATE(gpt6_fck, "per_clkdm", omap343x_gpt_clksel,
- OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
- OMAP3430_CLKSEL_GPT6_MASK,
- OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- OMAP3430_EN_GPT6_SHIFT, &clkhwops_wait,
- gpt10_fck_parent_names, clkout2_src_ck_ops);
-
-static struct clk gpt6_ick;
-
-static struct clk_hw_omap gpt6_ick_hw = {
- .hw = {
- .clk = &gpt6_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_GPT6_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpt6_ick, gpio2_ick_parent_names, aes2_ick_ops);
-
-DEFINE_CLK_OMAP_MUX_GATE(gpt7_fck, "per_clkdm", omap343x_gpt_clksel,
- OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
- OMAP3430_CLKSEL_GPT7_MASK,
- OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- OMAP3430_EN_GPT7_SHIFT, &clkhwops_wait,
- gpt10_fck_parent_names, clkout2_src_ck_ops);
-
-static struct clk gpt7_ick;
-
-static struct clk_hw_omap gpt7_ick_hw = {
- .hw = {
- .clk = &gpt7_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_GPT7_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpt7_ick, gpio2_ick_parent_names, aes2_ick_ops);
-
-DEFINE_CLK_OMAP_MUX_GATE(gpt8_fck, "per_clkdm", omap343x_gpt_clksel,
- OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
- OMAP3430_CLKSEL_GPT8_MASK,
- OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- OMAP3430_EN_GPT8_SHIFT, &clkhwops_wait,
- gpt10_fck_parent_names, clkout2_src_ck_ops);
-
-static struct clk gpt8_ick;
-
-static struct clk_hw_omap gpt8_ick_hw = {
- .hw = {
- .clk = &gpt8_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_GPT8_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpt8_ick, gpio2_ick_parent_names, aes2_ick_ops);
-
-DEFINE_CLK_OMAP_MUX_GATE(gpt9_fck, "per_clkdm", omap343x_gpt_clksel,
- OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
- OMAP3430_CLKSEL_GPT9_MASK,
- OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- OMAP3430_EN_GPT9_SHIFT, &clkhwops_wait,
- gpt10_fck_parent_names, clkout2_src_ck_ops);
-
-static struct clk gpt9_ick;
-
-static struct clk_hw_omap gpt9_ick_hw = {
- .hw = {
- .clk = &gpt9_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_GPT9_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(gpt9_ick, gpio2_ick_parent_names, aes2_ick_ops);
-
-static struct clk hdq_fck;
-
-static const char *hdq_fck_parent_names[] = {
- "core_12m_fck",
-};
-
-static struct clk_hw_omap hdq_fck_hw = {
- .hw = {
- .clk = &hdq_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- .enable_bit = OMAP3430_EN_HDQ_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(hdq_fck, hdq_fck_parent_names, aes2_ick_ops);
-
-static struct clk hdq_ick;
-
-static struct clk_hw_omap hdq_ick_hw = {
- .hw = {
- .clk = &hdq_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_HDQ_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(hdq_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static struct clk hecc_ck;
-
-static struct clk_hw_omap hecc_ck_hw = {
- .hw = {
- .clk = &hecc_ck,
- },
- .ops = &clkhwops_am35xx_ipss_module_wait,
- .enable_reg = OMAP343X_CTRL_REGADDR(AM35XX_CONTROL_IPSS_CLK_CTRL),
- .enable_bit = AM35XX_HECC_VBUSP_CLK_SHIFT,
- .clkdm_name = "core_l3_clkdm",
-};
-
-DEFINE_STRUCT_CLK(hecc_ck, cpefuse_fck_parent_names, aes2_ick_ops);
-
-static struct clk hsotgusb_fck_am35xx;
-
-static struct clk_hw_omap hsotgusb_fck_am35xx_hw = {
- .hw = {
- .clk = &hsotgusb_fck_am35xx,
- },
- .enable_reg = OMAP343X_CTRL_REGADDR(AM35XX_CONTROL_IPSS_CLK_CTRL),
- .enable_bit = AM35XX_USBOTG_FCLK_SHIFT,
- .clkdm_name = "core_l3_clkdm",
-};
-
-DEFINE_STRUCT_CLK(hsotgusb_fck_am35xx, cpefuse_fck_parent_names, aes2_ick_ops);
-
-static struct clk hsotgusb_ick_3430es1;
-
-static struct clk_hw_omap hsotgusb_ick_3430es1_hw = {
- .hw = {
- .clk = &hsotgusb_ick_3430es1,
- },
- .ops = &clkhwops_iclk,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_HSOTGUSB_SHIFT,
- .clkdm_name = "core_l3_clkdm",
-};
-
-DEFINE_STRUCT_CLK(hsotgusb_ick_3430es1, ipss_ick_parent_names, aes2_ick_ops);
-
-static struct clk hsotgusb_ick_3430es2;
-
-static struct clk_hw_omap hsotgusb_ick_3430es2_hw = {
- .hw = {
- .clk = &hsotgusb_ick_3430es2,
- },
- .ops = &clkhwops_omap3430es2_iclk_hsotgusb_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_HSOTGUSB_SHIFT,
- .clkdm_name = "core_l3_clkdm",
-};
-
-DEFINE_STRUCT_CLK(hsotgusb_ick_3430es2, ipss_ick_parent_names, aes2_ick_ops);
-
-static struct clk hsotgusb_ick_am35xx;
-
-static struct clk_hw_omap hsotgusb_ick_am35xx_hw = {
- .hw = {
- .clk = &hsotgusb_ick_am35xx,
- },
- .ops = &clkhwops_am35xx_ipss_module_wait,
- .enable_reg = OMAP343X_CTRL_REGADDR(AM35XX_CONTROL_IPSS_CLK_CTRL),
- .enable_bit = AM35XX_USBOTG_VBUSP_CLK_SHIFT,
- .clkdm_name = "core_l3_clkdm",
-};
-
-DEFINE_STRUCT_CLK(hsotgusb_ick_am35xx, emac_ick_parent_names, aes2_ick_ops);
-
-static struct clk i2c1_fck;
-
-static struct clk_hw_omap i2c1_fck_hw = {
- .hw = {
- .clk = &i2c1_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- .enable_bit = OMAP3430_EN_I2C1_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(i2c1_fck, csi2_96m_fck_parent_names, aes2_ick_ops);
-
-static struct clk i2c1_ick;
-
-static struct clk_hw_omap i2c1_ick_hw = {
- .hw = {
- .clk = &i2c1_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_I2C1_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(i2c1_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static struct clk i2c2_fck;
-
-static struct clk_hw_omap i2c2_fck_hw = {
- .hw = {
- .clk = &i2c2_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- .enable_bit = OMAP3430_EN_I2C2_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(i2c2_fck, csi2_96m_fck_parent_names, aes2_ick_ops);
-
-static struct clk i2c2_ick;
-
-static struct clk_hw_omap i2c2_ick_hw = {
- .hw = {
- .clk = &i2c2_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_I2C2_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(i2c2_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static struct clk i2c3_fck;
-
-static struct clk_hw_omap i2c3_fck_hw = {
- .hw = {
- .clk = &i2c3_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- .enable_bit = OMAP3430_EN_I2C3_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(i2c3_fck, csi2_96m_fck_parent_names, aes2_ick_ops);
-
-static struct clk i2c3_ick;
-
-static struct clk_hw_omap i2c3_ick_hw = {
- .hw = {
- .clk = &i2c3_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_I2C3_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(i2c3_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static struct clk icr_ick;
-
-static struct clk_hw_omap icr_ick_hw = {
- .hw = {
- .clk = &icr_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_ICR_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(icr_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static struct clk iva2_ck;
-
-static const char *iva2_ck_parent_names[] = {
- "dpll2_m2_ck",
-};
-
-static struct clk_hw_omap iva2_ck_hw = {
- .hw = {
- .clk = &iva2_ck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_CM_FCLKEN_IVA2_EN_IVA2_SHIFT,
- .clkdm_name = "iva2_clkdm",
-};
-
-DEFINE_STRUCT_CLK(iva2_ck, iva2_ck_parent_names, aes2_ick_ops);
-
-static struct clk mad2d_ick;
-
-static struct clk_hw_omap mad2d_ick_hw = {
- .hw = {
- .clk = &mad2d_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3),
- .enable_bit = OMAP3430_EN_MAD2D_SHIFT,
- .clkdm_name = "d2d_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mad2d_ick, core_l3_ick_parent_names, aes2_ick_ops);
-
-static struct clk mailboxes_ick;
-
-static struct clk_hw_omap mailboxes_ick_hw = {
- .hw = {
- .clk = &mailboxes_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_MAILBOXES_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mailboxes_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static const struct clksel_rate common_mcbsp_96m_rates[] = {
- { .div = 1, .val = 0, .flags = RATE_IN_3XXX },
- { .div = 0 }
-};
-
-static const struct clksel_rate common_mcbsp_mcbsp_rates[] = {
- { .div = 1, .val = 1, .flags = RATE_IN_3XXX },
- { .div = 0 }
-};
-
-static const struct clksel mcbsp_15_clksel[] = {
- { .parent = &core_96m_fck, .rates = common_mcbsp_96m_rates },
- { .parent = &mcbsp_clks, .rates = common_mcbsp_mcbsp_rates },
- { .parent = NULL },
-};
-
-static const char *mcbsp1_fck_parent_names[] = {
- "core_96m_fck", "mcbsp_clks",
-};
-
-DEFINE_CLK_OMAP_MUX_GATE(mcbsp1_fck, "core_l4_clkdm", mcbsp_15_clksel,
- OMAP343X_CTRL_REGADDR(OMAP2_CONTROL_DEVCONF0),
- OMAP2_MCBSP1_CLKS_MASK,
- OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- OMAP3430_EN_MCBSP1_SHIFT, &clkhwops_wait,
- mcbsp1_fck_parent_names, clkout2_src_ck_ops);
-
-static struct clk mcbsp1_ick;
-
-static struct clk_hw_omap mcbsp1_ick_hw = {
- .hw = {
- .clk = &mcbsp1_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_MCBSP1_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mcbsp1_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static struct clk per_96m_fck;
-
-DEFINE_STRUCT_CLK_HW_OMAP(per_96m_fck, "per_clkdm");
-DEFINE_STRUCT_CLK(per_96m_fck, cm_96m_fck_parent_names, core_l4_ick_ops);
-
-static const struct clksel mcbsp_234_clksel[] = {
- { .parent = &per_96m_fck, .rates = common_mcbsp_96m_rates },
- { .parent = &mcbsp_clks, .rates = common_mcbsp_mcbsp_rates },
- { .parent = NULL },
-};
-
-static const char *mcbsp2_fck_parent_names[] = {
- "per_96m_fck", "mcbsp_clks",
-};
-
-DEFINE_CLK_OMAP_MUX_GATE(mcbsp2_fck, "per_clkdm", mcbsp_234_clksel,
- OMAP343X_CTRL_REGADDR(OMAP2_CONTROL_DEVCONF0),
- OMAP2_MCBSP2_CLKS_MASK,
- OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- OMAP3430_EN_MCBSP2_SHIFT, &clkhwops_wait,
- mcbsp2_fck_parent_names, clkout2_src_ck_ops);
-
-static struct clk mcbsp2_ick;
-
-static struct clk_hw_omap mcbsp2_ick_hw = {
- .hw = {
- .clk = &mcbsp2_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_MCBSP2_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mcbsp2_ick, gpio2_ick_parent_names, aes2_ick_ops);
-
-DEFINE_CLK_OMAP_MUX_GATE(mcbsp3_fck, "per_clkdm", mcbsp_234_clksel,
- OMAP343X_CTRL_REGADDR(OMAP343X_CONTROL_DEVCONF1),
- OMAP2_MCBSP3_CLKS_MASK,
- OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- OMAP3430_EN_MCBSP3_SHIFT, &clkhwops_wait,
- mcbsp2_fck_parent_names, clkout2_src_ck_ops);
-
-static struct clk mcbsp3_ick;
-
-static struct clk_hw_omap mcbsp3_ick_hw = {
- .hw = {
- .clk = &mcbsp3_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_MCBSP3_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mcbsp3_ick, gpio2_ick_parent_names, aes2_ick_ops);
-
-DEFINE_CLK_OMAP_MUX_GATE(mcbsp4_fck, "per_clkdm", mcbsp_234_clksel,
- OMAP343X_CTRL_REGADDR(OMAP343X_CONTROL_DEVCONF1),
- OMAP2_MCBSP4_CLKS_MASK,
- OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- OMAP3430_EN_MCBSP4_SHIFT, &clkhwops_wait,
- mcbsp2_fck_parent_names, clkout2_src_ck_ops);
-
-static struct clk mcbsp4_ick;
-
-static struct clk_hw_omap mcbsp4_ick_hw = {
- .hw = {
- .clk = &mcbsp4_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_MCBSP4_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mcbsp4_ick, gpio2_ick_parent_names, aes2_ick_ops);
-
-DEFINE_CLK_OMAP_MUX_GATE(mcbsp5_fck, "core_l4_clkdm", mcbsp_15_clksel,
- OMAP343X_CTRL_REGADDR(OMAP343X_CONTROL_DEVCONF1),
- OMAP2_MCBSP5_CLKS_MASK,
- OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- OMAP3430_EN_MCBSP5_SHIFT, &clkhwops_wait,
- mcbsp1_fck_parent_names, clkout2_src_ck_ops);
-
-static struct clk mcbsp5_ick;
-
-static struct clk_hw_omap mcbsp5_ick_hw = {
- .hw = {
- .clk = &mcbsp5_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_MCBSP5_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mcbsp5_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static struct clk mcspi1_fck;
-
-static struct clk_hw_omap mcspi1_fck_hw = {
- .hw = {
- .clk = &mcspi1_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- .enable_bit = OMAP3430_EN_MCSPI1_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mcspi1_fck, fshostusb_fck_parent_names, aes2_ick_ops);
-
-static struct clk mcspi1_ick;
-
-static struct clk_hw_omap mcspi1_ick_hw = {
- .hw = {
- .clk = &mcspi1_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_MCSPI1_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mcspi1_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static struct clk mcspi2_fck;
-
-static struct clk_hw_omap mcspi2_fck_hw = {
- .hw = {
- .clk = &mcspi2_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- .enable_bit = OMAP3430_EN_MCSPI2_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mcspi2_fck, fshostusb_fck_parent_names, aes2_ick_ops);
-
-static struct clk mcspi2_ick;
-
-static struct clk_hw_omap mcspi2_ick_hw = {
- .hw = {
- .clk = &mcspi2_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_MCSPI2_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mcspi2_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static struct clk mcspi3_fck;
-
-static struct clk_hw_omap mcspi3_fck_hw = {
- .hw = {
- .clk = &mcspi3_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- .enable_bit = OMAP3430_EN_MCSPI3_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mcspi3_fck, fshostusb_fck_parent_names, aes2_ick_ops);
-
-static struct clk mcspi3_ick;
-
-static struct clk_hw_omap mcspi3_ick_hw = {
- .hw = {
- .clk = &mcspi3_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_MCSPI3_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mcspi3_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static struct clk mcspi4_fck;
-
-static struct clk_hw_omap mcspi4_fck_hw = {
- .hw = {
- .clk = &mcspi4_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- .enable_bit = OMAP3430_EN_MCSPI4_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mcspi4_fck, fshostusb_fck_parent_names, aes2_ick_ops);
-
-static struct clk mcspi4_ick;
-
-static struct clk_hw_omap mcspi4_ick_hw = {
- .hw = {
- .clk = &mcspi4_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_MCSPI4_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mcspi4_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static struct clk mmchs1_fck;
-
-static struct clk_hw_omap mmchs1_fck_hw = {
- .hw = {
- .clk = &mmchs1_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- .enable_bit = OMAP3430_EN_MMC1_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mmchs1_fck, csi2_96m_fck_parent_names, aes2_ick_ops);
-
-static struct clk mmchs1_ick;
-
-static struct clk_hw_omap mmchs1_ick_hw = {
- .hw = {
- .clk = &mmchs1_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_MMC1_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mmchs1_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static struct clk mmchs2_fck;
-
-static struct clk_hw_omap mmchs2_fck_hw = {
- .hw = {
- .clk = &mmchs2_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- .enable_bit = OMAP3430_EN_MMC2_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mmchs2_fck, csi2_96m_fck_parent_names, aes2_ick_ops);
-
-static struct clk mmchs2_ick;
-
-static struct clk_hw_omap mmchs2_ick_hw = {
- .hw = {
- .clk = &mmchs2_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_MMC2_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mmchs2_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static struct clk mmchs3_fck;
-
-static struct clk_hw_omap mmchs3_fck_hw = {
- .hw = {
- .clk = &mmchs3_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- .enable_bit = OMAP3430ES2_EN_MMC3_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mmchs3_fck, csi2_96m_fck_parent_names, aes2_ick_ops);
-
-static struct clk mmchs3_ick;
-
-static struct clk_hw_omap mmchs3_ick_hw = {
- .hw = {
- .clk = &mmchs3_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430ES2_EN_MMC3_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mmchs3_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static struct clk modem_fck;
-
-static struct clk_hw_omap modem_fck_hw = {
- .hw = {
- .clk = &modem_fck,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- .enable_bit = OMAP3430_EN_MODEM_SHIFT,
- .clkdm_name = "d2d_clkdm",
-};
-
-DEFINE_STRUCT_CLK(modem_fck, cpefuse_fck_parent_names, aes2_ick_ops);
-
-static struct clk mspro_fck;
-
-static struct clk_hw_omap mspro_fck_hw = {
- .hw = {
- .clk = &mspro_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- .enable_bit = OMAP3430_EN_MSPRO_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mspro_fck, csi2_96m_fck_parent_names, aes2_ick_ops);
-
-static struct clk mspro_ick;
-
-static struct clk_hw_omap mspro_ick_hw = {
- .hw = {
- .clk = &mspro_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_MSPRO_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(mspro_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static struct clk omap_192m_alwon_fck;
-
-DEFINE_STRUCT_CLK_HW_OMAP(omap_192m_alwon_fck, NULL);
-DEFINE_STRUCT_CLK(omap_192m_alwon_fck, omap_96m_alwon_fck_parent_names,
- core_ck_ops);
-
-static struct clk omap_32ksync_ick;
-
-static struct clk_hw_omap omap_32ksync_ick_hw = {
- .hw = {
- .clk = &omap_32ksync_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_32KSYNC_SHIFT,
- .clkdm_name = "wkup_clkdm",
-};
-
-DEFINE_STRUCT_CLK(omap_32ksync_ick, gpio1_ick_parent_names, aes2_ick_ops);
-
-static const struct clksel_rate omap_96m_alwon_fck_rates[] = {
- { .div = 1, .val = 1, .flags = RATE_IN_36XX },
- { .div = 2, .val = 2, .flags = RATE_IN_36XX },
- { .div = 0 }
-};
-
-static const struct clksel omap_96m_alwon_fck_clksel[] = {
- { .parent = &omap_192m_alwon_fck, .rates = omap_96m_alwon_fck_rates },
- { .parent = NULL }
-};
-
-static struct clk omap_96m_alwon_fck_3630;
-
-static const char *omap_96m_alwon_fck_3630_parent_names[] = {
- "omap_192m_alwon_fck",
-};
-
-static const struct clk_ops omap_96m_alwon_fck_3630_ops = {
- .set_rate = &omap2_clksel_set_rate,
- .recalc_rate = &omap2_clksel_recalc,
- .round_rate = &omap2_clksel_round_rate,
-};
-
-static struct clk_hw_omap omap_96m_alwon_fck_3630_hw = {
- .hw = {
- .clk = &omap_96m_alwon_fck_3630,
- },
- .clksel = omap_96m_alwon_fck_clksel,
- .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
- .clksel_mask = OMAP3630_CLKSEL_96M_MASK,
-};
-
-static struct clk omap_96m_alwon_fck_3630 = {
- .name = "omap_96m_alwon_fck",
- .hw = &omap_96m_alwon_fck_3630_hw.hw,
- .parent_names = omap_96m_alwon_fck_3630_parent_names,
- .num_parents = ARRAY_SIZE(omap_96m_alwon_fck_3630_parent_names),
- .ops = &omap_96m_alwon_fck_3630_ops,
-};
-
-static struct clk omapctrl_ick;
-
-static struct clk_hw_omap omapctrl_ick_hw = {
- .hw = {
- .clk = &omapctrl_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_OMAPCTRL_SHIFT,
- .flags = ENABLE_ON_INIT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(omapctrl_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-DEFINE_CLK_DIVIDER(pclk_fck, "emu_src_ck", &emu_src_ck, 0x0,
- OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
- OMAP3430_CLKSEL_PCLK_SHIFT, OMAP3430_CLKSEL_PCLK_WIDTH,
- CLK_DIVIDER_ONE_BASED, NULL);
-
-DEFINE_CLK_DIVIDER(pclkx2_fck, "emu_src_ck", &emu_src_ck, 0x0,
- OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
- OMAP3430_CLKSEL_PCLKX2_SHIFT, OMAP3430_CLKSEL_PCLKX2_WIDTH,
- CLK_DIVIDER_ONE_BASED, NULL);
-
-static struct clk per_48m_fck;
-
-DEFINE_STRUCT_CLK_HW_OMAP(per_48m_fck, "per_clkdm");
-DEFINE_STRUCT_CLK(per_48m_fck, core_48m_fck_parent_names, core_l4_ick_ops);
-
-static struct clk security_l3_ick;
-
-DEFINE_STRUCT_CLK_HW_OMAP(security_l3_ick, NULL);
-DEFINE_STRUCT_CLK(security_l3_ick, core_l3_ick_parent_names, core_ck_ops);
-
-static struct clk pka_ick;
-
-static const char *pka_ick_parent_names[] = {
- "security_l3_ick",
-};
-
-static struct clk_hw_omap pka_ick_hw = {
- .hw = {
- .clk = &pka_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
- .enable_bit = OMAP3430_EN_PKA_SHIFT,
-};
-
-DEFINE_STRUCT_CLK(pka_ick, pka_ick_parent_names, aes1_ick_ops);
-
-DEFINE_CLK_DIVIDER(rm_ick, "l4_ick", &l4_ick, 0x0,
- OMAP_CM_REGADDR(WKUP_MOD, CM_CLKSEL),
- OMAP3430_CLKSEL_RM_SHIFT, OMAP3430_CLKSEL_RM_WIDTH,
- CLK_DIVIDER_ONE_BASED, NULL);
-
-static struct clk rng_ick;
-
-static struct clk_hw_omap rng_ick_hw = {
- .hw = {
- .clk = &rng_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
- .enable_bit = OMAP3430_EN_RNG_SHIFT,
-};
-
-DEFINE_STRUCT_CLK(rng_ick, aes1_ick_parent_names, aes1_ick_ops);
-
-static struct clk sad2d_ick;
-
-static struct clk_hw_omap sad2d_ick_hw = {
- .hw = {
- .clk = &sad2d_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_SAD2D_SHIFT,
- .clkdm_name = "d2d_clkdm",
-};
-
-DEFINE_STRUCT_CLK(sad2d_ick, core_l3_ick_parent_names, aes2_ick_ops);
-
-static struct clk sdrc_ick;
-
-static struct clk_hw_omap sdrc_ick_hw = {
- .hw = {
- .clk = &sdrc_ick,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_SDRC_SHIFT,
- .flags = ENABLE_ON_INIT,
- .clkdm_name = "core_l3_clkdm",
-};
-
-DEFINE_STRUCT_CLK(sdrc_ick, ipss_ick_parent_names, aes2_ick_ops);
-
-static const struct clksel_rate sgx_core_rates[] = {
- { .div = 2, .val = 5, .flags = RATE_IN_36XX },
- { .div = 3, .val = 0, .flags = RATE_IN_3XXX },
- { .div = 4, .val = 1, .flags = RATE_IN_3XXX },
- { .div = 6, .val = 2, .flags = RATE_IN_3XXX },
- { .div = 0 }
-};
-
-static const struct clksel_rate sgx_96m_rates[] = {
- { .div = 1, .val = 3, .flags = RATE_IN_3XXX },
- { .div = 0 }
-};
-
-static const struct clksel_rate sgx_192m_rates[] = {
- { .div = 1, .val = 4, .flags = RATE_IN_36XX },
- { .div = 0 }
-};
-
-static const struct clksel_rate sgx_corex2_rates[] = {
- { .div = 3, .val = 6, .flags = RATE_IN_36XX },
- { .div = 5, .val = 7, .flags = RATE_IN_36XX },
- { .div = 0 }
-};
-
-static const struct clksel sgx_clksel[] = {
- { .parent = &core_ck, .rates = sgx_core_rates },
- { .parent = &cm_96m_fck, .rates = sgx_96m_rates },
- { .parent = &omap_192m_alwon_fck, .rates = sgx_192m_rates },
- { .parent = &corex2_fck, .rates = sgx_corex2_rates },
- { .parent = NULL },
-};
-
-static const char *sgx_fck_parent_names[] = {
- "core_ck", "cm_96m_fck", "omap_192m_alwon_fck", "corex2_fck",
-};
-
-static struct clk sgx_fck;
-
-static const struct clk_ops sgx_fck_ops = {
- .init = &omap2_init_clk_clkdm,
- .enable = &omap2_dflt_clk_enable,
- .disable = &omap2_dflt_clk_disable,
- .is_enabled = &omap2_dflt_clk_is_enabled,
- .recalc_rate = &omap2_clksel_recalc,
- .set_rate = &omap2_clksel_set_rate,
- .round_rate = &omap2_clksel_round_rate,
- .get_parent = &omap2_clksel_find_parent_index,
- .set_parent = &omap2_clksel_set_parent,
-};
-
-DEFINE_CLK_OMAP_MUX_GATE(sgx_fck, "sgx_clkdm", sgx_clksel,
- OMAP_CM_REGADDR(OMAP3430ES2_SGX_MOD, CM_CLKSEL),
- OMAP3430ES2_CLKSEL_SGX_MASK,
- OMAP_CM_REGADDR(OMAP3430ES2_SGX_MOD, CM_FCLKEN),
- OMAP3430ES2_CM_FCLKEN_SGX_EN_SGX_SHIFT,
- &clkhwops_wait, sgx_fck_parent_names, sgx_fck_ops);
-
-static struct clk sgx_ick;
-
-static struct clk_hw_omap sgx_ick_hw = {
- .hw = {
- .clk = &sgx_ick,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430ES2_SGX_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430ES2_CM_ICLKEN_SGX_EN_SGX_SHIFT,
- .clkdm_name = "sgx_clkdm",
-};
-
-DEFINE_STRUCT_CLK(sgx_ick, core_l3_ick_parent_names, aes2_ick_ops);
-
-static struct clk sha11_ick;
-
-static struct clk_hw_omap sha11_ick_hw = {
- .hw = {
- .clk = &sha11_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
- .enable_bit = OMAP3430_EN_SHA11_SHIFT,
-};
-
-DEFINE_STRUCT_CLK(sha11_ick, aes1_ick_parent_names, aes1_ick_ops);
-
-static struct clk sha12_ick;
-
-static struct clk_hw_omap sha12_ick_hw = {
- .hw = {
- .clk = &sha12_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_SHA12_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(sha12_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static struct clk sr1_fck;
-
-static struct clk_hw_omap sr1_fck_hw = {
- .hw = {
- .clk = &sr1_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_SR1_SHIFT,
- .clkdm_name = "wkup_clkdm",
-};
-
-DEFINE_STRUCT_CLK(sr1_fck, cpefuse_fck_parent_names, aes2_ick_ops);
-
-static struct clk sr2_fck;
-
-static struct clk_hw_omap sr2_fck_hw = {
- .hw = {
- .clk = &sr2_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_SR2_SHIFT,
- .clkdm_name = "wkup_clkdm",
-};
-
-DEFINE_STRUCT_CLK(sr2_fck, cpefuse_fck_parent_names, aes2_ick_ops);
-
-static struct clk sr_l4_ick;
-
-DEFINE_STRUCT_CLK_HW_OMAP(sr_l4_ick, "core_l4_clkdm");
-DEFINE_STRUCT_CLK(sr_l4_ick, security_l4_ick2_parent_names, core_l4_ick_ops);
-
-static struct clk ssi_l4_ick;
-
-DEFINE_STRUCT_CLK_HW_OMAP(ssi_l4_ick, "core_l4_clkdm");
-DEFINE_STRUCT_CLK(ssi_l4_ick, security_l4_ick2_parent_names, core_l4_ick_ops);
-
-static struct clk ssi_ick_3430es1;
-
-static const char *ssi_ick_3430es1_parent_names[] = {
- "ssi_l4_ick",
-};
-
-static struct clk_hw_omap ssi_ick_3430es1_hw = {
- .hw = {
- .clk = &ssi_ick_3430es1,
- },
- .ops = &clkhwops_iclk,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_SSI_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(ssi_ick_3430es1, ssi_ick_3430es1_parent_names, aes2_ick_ops);
-
-static struct clk ssi_ick_3430es2;
-
-static struct clk_hw_omap ssi_ick_3430es2_hw = {
- .hw = {
- .clk = &ssi_ick_3430es2,
- },
- .ops = &clkhwops_omap3430es2_iclk_ssi_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_SSI_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(ssi_ick_3430es2, ssi_ick_3430es1_parent_names, aes2_ick_ops);
-
-static const struct clksel_rate ssi_ssr_corex2_rates[] = {
- { .div = 1, .val = 1, .flags = RATE_IN_3XXX },
- { .div = 2, .val = 2, .flags = RATE_IN_3XXX },
- { .div = 3, .val = 3, .flags = RATE_IN_3XXX },
- { .div = 4, .val = 4, .flags = RATE_IN_3XXX },
- { .div = 6, .val = 6, .flags = RATE_IN_3XXX },
- { .div = 8, .val = 8, .flags = RATE_IN_3XXX },
- { .div = 0 }
-};
-
-static const struct clksel ssi_ssr_clksel[] = {
- { .parent = &corex2_fck, .rates = ssi_ssr_corex2_rates },
- { .parent = NULL },
-};
-
-static const char *ssi_ssr_fck_3430es1_parent_names[] = {
- "corex2_fck",
-};
-
-static const struct clk_ops ssi_ssr_fck_3430es1_ops = {
- .init = &omap2_init_clk_clkdm,
- .enable = &omap2_dflt_clk_enable,
- .disable = &omap2_dflt_clk_disable,
- .is_enabled = &omap2_dflt_clk_is_enabled,
- .recalc_rate = &omap2_clksel_recalc,
- .set_rate = &omap2_clksel_set_rate,
- .round_rate = &omap2_clksel_round_rate,
-};
-
-DEFINE_CLK_OMAP_MUX_GATE(ssi_ssr_fck_3430es1, "core_l4_clkdm",
- ssi_ssr_clksel, OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
- OMAP3430_CLKSEL_SSI_MASK,
- OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- OMAP3430_EN_SSI_SHIFT,
- NULL, ssi_ssr_fck_3430es1_parent_names,
- ssi_ssr_fck_3430es1_ops);
-
-DEFINE_CLK_OMAP_MUX_GATE(ssi_ssr_fck_3430es2, "core_l4_clkdm",
- ssi_ssr_clksel, OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
- OMAP3430_CLKSEL_SSI_MASK,
- OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- OMAP3430_EN_SSI_SHIFT,
- NULL, ssi_ssr_fck_3430es1_parent_names,
- ssi_ssr_fck_3430es1_ops);
-
-DEFINE_CLK_FIXED_FACTOR(ssi_sst_fck_3430es1, "ssi_ssr_fck_3430es1",
- &ssi_ssr_fck_3430es1, 0x0, 1, 2);
-
-DEFINE_CLK_FIXED_FACTOR(ssi_sst_fck_3430es2, "ssi_ssr_fck_3430es2",
- &ssi_ssr_fck_3430es2, 0x0, 1, 2);
-
-static struct clk sys_clkout1;
-
-static const char *sys_clkout1_parent_names[] = {
- "osc_sys_ck",
-};
-
-static struct clk_hw_omap sys_clkout1_hw = {
- .hw = {
- .clk = &sys_clkout1,
- },
- .enable_reg = OMAP3430_PRM_CLKOUT_CTRL,
- .enable_bit = OMAP3430_CLKOUT_EN_SHIFT,
-};
-
-DEFINE_STRUCT_CLK(sys_clkout1, sys_clkout1_parent_names, aes1_ick_ops);
-
-DEFINE_CLK_DIVIDER(sys_clkout2, "clkout2_src_ck", &clkout2_src_ck, 0x0,
- OMAP3430_CM_CLKOUT_CTRL, OMAP3430_CLKOUT2_DIV_SHIFT,
- OMAP3430_CLKOUT2_DIV_WIDTH, CLK_DIVIDER_POWER_OF_TWO, NULL);
-
-DEFINE_CLK_MUX(traceclk_src_fck, emu_src_ck_parent_names, NULL, 0x0,
- OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
- OMAP3430_TRACE_MUX_CTRL_SHIFT, OMAP3430_TRACE_MUX_CTRL_WIDTH,
- 0x0, NULL);
-
-DEFINE_CLK_DIVIDER(traceclk_fck, "traceclk_src_fck", &traceclk_src_fck, 0x0,
- OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
- OMAP3430_CLKSEL_TRACECLK_SHIFT,
- OMAP3430_CLKSEL_TRACECLK_WIDTH, CLK_DIVIDER_ONE_BASED, NULL);
-
-static struct clk ts_fck;
-
-static struct clk_hw_omap ts_fck_hw = {
- .hw = {
- .clk = &ts_fck,
- },
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP3430ES2_CM_FCLKEN3),
- .enable_bit = OMAP3430ES2_EN_TS_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(ts_fck, wkup_32k_fck_parent_names, aes2_ick_ops);
-
-static struct clk uart1_fck;
-
-static struct clk_hw_omap uart1_fck_hw = {
- .hw = {
- .clk = &uart1_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- .enable_bit = OMAP3430_EN_UART1_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(uart1_fck, fshostusb_fck_parent_names, aes2_ick_ops);
-
-static struct clk uart1_ick;
-
-static struct clk_hw_omap uart1_ick_hw = {
- .hw = {
- .clk = &uart1_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_UART1_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(uart1_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static struct clk uart2_fck;
-
-static struct clk_hw_omap uart2_fck_hw = {
- .hw = {
- .clk = &uart2_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- .enable_bit = OMAP3430_EN_UART2_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(uart2_fck, fshostusb_fck_parent_names, aes2_ick_ops);
-
-static struct clk uart2_ick;
-
-static struct clk_hw_omap uart2_ick_hw = {
- .hw = {
- .clk = &uart2_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = OMAP3430_EN_UART2_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(uart2_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static struct clk uart3_fck;
-
-static const char *uart3_fck_parent_names[] = {
- "per_48m_fck",
-};
-
-static struct clk_hw_omap uart3_fck_hw = {
- .hw = {
- .clk = &uart3_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_UART3_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(uart3_fck, uart3_fck_parent_names, aes2_ick_ops);
-
-static struct clk uart3_ick;
-
-static struct clk_hw_omap uart3_ick_hw = {
- .hw = {
- .clk = &uart3_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_UART3_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(uart3_ick, gpio2_ick_parent_names, aes2_ick_ops);
-
-static struct clk uart4_fck;
-
-static struct clk_hw_omap uart4_fck_hw = {
- .hw = {
- .clk = &uart4_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- .enable_bit = OMAP3630_EN_UART4_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(uart4_fck, uart3_fck_parent_names, aes2_ick_ops);
-
-static struct clk uart4_fck_am35xx;
-
-static struct clk_hw_omap uart4_fck_am35xx_hw = {
- .hw = {
- .clk = &uart4_fck_am35xx,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
- .enable_bit = AM35XX_EN_UART4_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(uart4_fck_am35xx, fshostusb_fck_parent_names, aes2_ick_ops);
-
-static struct clk uart4_ick;
-
-static struct clk_hw_omap uart4_ick_hw = {
- .hw = {
- .clk = &uart4_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
- .enable_bit = OMAP3630_EN_UART4_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(uart4_ick, gpio2_ick_parent_names, aes2_ick_ops);
-
-static struct clk uart4_ick_am35xx;
-
-static struct clk_hw_omap uart4_ick_am35xx_hw = {
- .hw = {
- .clk = &uart4_ick_am35xx,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- .enable_bit = AM35XX_EN_UART4_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(uart4_ick_am35xx, aes2_ick_parent_names, aes2_ick_ops);
-
-static const struct clksel_rate div2_rates[] = {
- { .div = 1, .val = 1, .flags = RATE_IN_3XXX },
- { .div = 2, .val = 2, .flags = RATE_IN_3XXX },
- { .div = 0 }
-};
-
-static const struct clksel usb_l4_clksel[] = {
- { .parent = &l4_ick, .rates = div2_rates },
- { .parent = NULL },
-};
-
-static const char *usb_l4_ick_parent_names[] = {
- "l4_ick",
-};
-
-DEFINE_CLK_OMAP_MUX_GATE(usb_l4_ick, "core_l4_clkdm", usb_l4_clksel,
- OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
- OMAP3430ES1_CLKSEL_FSHOSTUSB_MASK,
- OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
- OMAP3430ES1_EN_FSHOSTUSB_SHIFT,
- &clkhwops_iclk_wait, usb_l4_ick_parent_names,
- ssi_ssr_fck_3430es1_ops);
-
-static struct clk usbhost_120m_fck;
-
-static const char *usbhost_120m_fck_parent_names[] = {
- "dpll5_m2_ck",
-};
-
-static struct clk_hw_omap usbhost_120m_fck_hw = {
- .hw = {
- .clk = &usbhost_120m_fck,
- },
- .enable_reg = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430ES2_EN_USBHOST2_SHIFT,
- .clkdm_name = "usbhost_clkdm",
-};
-
-DEFINE_STRUCT_CLK(usbhost_120m_fck, usbhost_120m_fck_parent_names,
- aes2_ick_ops);
-
-static struct clk usbhost_48m_fck;
-
-static struct clk_hw_omap usbhost_48m_fck_hw = {
- .hw = {
- .clk = &usbhost_48m_fck,
- },
- .ops = &clkhwops_omap3430es2_dss_usbhost_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430ES2_EN_USBHOST1_SHIFT,
- .clkdm_name = "usbhost_clkdm",
-};
-
-DEFINE_STRUCT_CLK(usbhost_48m_fck, core_48m_fck_parent_names, aes2_ick_ops);
-
-static struct clk usbhost_ick;
-
-static struct clk_hw_omap usbhost_ick_hw = {
- .hw = {
- .clk = &usbhost_ick,
- },
- .ops = &clkhwops_omap3430es2_iclk_dss_usbhost_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430ES2_EN_USBHOST_SHIFT,
- .clkdm_name = "usbhost_clkdm",
-};
-
-DEFINE_STRUCT_CLK(usbhost_ick, security_l4_ick2_parent_names, aes2_ick_ops);
-
-static struct clk usbtll_fck;
-
-static struct clk_hw_omap usbtll_fck_hw = {
- .hw = {
- .clk = &usbtll_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP3430ES2_CM_FCLKEN3),
- .enable_bit = OMAP3430ES2_EN_USBTLL_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(usbtll_fck, usbhost_120m_fck_parent_names, aes2_ick_ops);
-
-static struct clk usbtll_ick;
-
-static struct clk_hw_omap usbtll_ick_hw = {
- .hw = {
- .clk = &usbtll_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3),
- .enable_bit = OMAP3430ES2_EN_USBTLL_SHIFT,
- .clkdm_name = "core_l4_clkdm",
-};
-
-DEFINE_STRUCT_CLK(usbtll_ick, aes2_ick_parent_names, aes2_ick_ops);
-
-static const struct clksel_rate usim_96m_rates[] = {
- { .div = 2, .val = 3, .flags = RATE_IN_3XXX },
- { .div = 4, .val = 4, .flags = RATE_IN_3XXX },
- { .div = 8, .val = 5, .flags = RATE_IN_3XXX },
- { .div = 10, .val = 6, .flags = RATE_IN_3XXX },
- { .div = 0 }
-};
-
-static const struct clksel_rate usim_120m_rates[] = {
- { .div = 4, .val = 7, .flags = RATE_IN_3XXX },
- { .div = 8, .val = 8, .flags = RATE_IN_3XXX },
- { .div = 16, .val = 9, .flags = RATE_IN_3XXX },
- { .div = 20, .val = 10, .flags = RATE_IN_3XXX },
- { .div = 0 }
-};
-
-static const struct clksel usim_clksel[] = {
- { .parent = &omap_96m_fck, .rates = usim_96m_rates },
- { .parent = &dpll5_m2_ck, .rates = usim_120m_rates },
- { .parent = &sys_ck, .rates = div2_rates },
- { .parent = NULL },
-};
-
-static const char *usim_fck_parent_names[] = {
- "omap_96m_fck", "dpll5_m2_ck", "sys_ck",
-};
-
-static struct clk usim_fck;
-
-static const struct clk_ops usim_fck_ops = {
- .enable = &omap2_dflt_clk_enable,
- .disable = &omap2_dflt_clk_disable,
- .is_enabled = &omap2_dflt_clk_is_enabled,
- .recalc_rate = &omap2_clksel_recalc,
- .get_parent = &omap2_clksel_find_parent_index,
- .set_parent = &omap2_clksel_set_parent,
-};
-
-DEFINE_CLK_OMAP_MUX_GATE(usim_fck, NULL, usim_clksel,
- OMAP_CM_REGADDR(WKUP_MOD, CM_CLKSEL),
- OMAP3430ES2_CLKSEL_USIMOCP_MASK,
- OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
- OMAP3430ES2_EN_USIMOCP_SHIFT, &clkhwops_wait,
- usim_fck_parent_names, usim_fck_ops);
-
-static struct clk usim_ick;
-
-static struct clk_hw_omap usim_ick_hw = {
- .hw = {
- .clk = &usim_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430ES2_EN_USIMOCP_SHIFT,
- .clkdm_name = "wkup_clkdm",
-};
-
-DEFINE_STRUCT_CLK(usim_ick, gpio1_ick_parent_names, aes2_ick_ops);
-
-static struct clk vpfe_fck;
-
-static const char *vpfe_fck_parent_names[] = {
- "pclk_ck",
-};
-
-static struct clk_hw_omap vpfe_fck_hw = {
- .hw = {
- .clk = &vpfe_fck,
- },
- .enable_reg = OMAP343X_CTRL_REGADDR(AM35XX_CONTROL_IPSS_CLK_CTRL),
- .enable_bit = AM35XX_VPFE_FCLK_SHIFT,
-};
-
-DEFINE_STRUCT_CLK(vpfe_fck, vpfe_fck_parent_names, aes1_ick_ops);
-
-static struct clk vpfe_ick;
-
-static struct clk_hw_omap vpfe_ick_hw = {
- .hw = {
- .clk = &vpfe_ick,
- },
- .ops = &clkhwops_am35xx_ipss_module_wait,
- .enable_reg = OMAP343X_CTRL_REGADDR(AM35XX_CONTROL_IPSS_CLK_CTRL),
- .enable_bit = AM35XX_VPFE_VBUSP_CLK_SHIFT,
- .clkdm_name = "core_l3_clkdm",
-};
-
-DEFINE_STRUCT_CLK(vpfe_ick, emac_ick_parent_names, aes2_ick_ops);
-
-static struct clk wdt1_fck;
-
-DEFINE_STRUCT_CLK_HW_OMAP(wdt1_fck, "wkup_clkdm");
-DEFINE_STRUCT_CLK(wdt1_fck, gpt12_fck_parent_names, core_l4_ick_ops);
-
-static struct clk wdt1_ick;
-
-static struct clk_hw_omap wdt1_ick_hw = {
- .hw = {
- .clk = &wdt1_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_WDT1_SHIFT,
- .clkdm_name = "wkup_clkdm",
-};
-
-DEFINE_STRUCT_CLK(wdt1_ick, gpio1_ick_parent_names, aes2_ick_ops);
-
-static struct clk wdt2_fck;
-
-static struct clk_hw_omap wdt2_fck_hw = {
- .hw = {
- .clk = &wdt2_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_WDT2_SHIFT,
- .clkdm_name = "wkup_clkdm",
-};
-
-DEFINE_STRUCT_CLK(wdt2_fck, gpio1_dbck_parent_names, aes2_ick_ops);
-
-static struct clk wdt2_ick;
-
-static struct clk_hw_omap wdt2_ick_hw = {
- .hw = {
- .clk = &wdt2_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_WDT2_SHIFT,
- .clkdm_name = "wkup_clkdm",
-};
-
-DEFINE_STRUCT_CLK(wdt2_ick, gpio1_ick_parent_names, aes2_ick_ops);
-
-static struct clk wdt3_fck;
-
-static struct clk_hw_omap wdt3_fck_hw = {
- .hw = {
- .clk = &wdt3_fck,
- },
- .ops = &clkhwops_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
- .enable_bit = OMAP3430_EN_WDT3_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(wdt3_fck, gpio2_dbck_parent_names, aes2_ick_ops);
-
-static struct clk wdt3_ick;
-
-static struct clk_hw_omap wdt3_ick_hw = {
- .hw = {
- .clk = &wdt3_ick,
- },
- .ops = &clkhwops_iclk_wait,
- .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
- .enable_bit = OMAP3430_EN_WDT3_SHIFT,
- .clkdm_name = "per_clkdm",
-};
-
-DEFINE_STRUCT_CLK(wdt3_ick, gpio2_ick_parent_names, aes2_ick_ops);
-
-/*
- * clocks specific to omap3430es1
- */
-static struct omap_clk omap3430es1_clks[] = {
- CLK(NULL, "gfx_l3_ck", &gfx_l3_ck),
- CLK(NULL, "gfx_l3_fck", &gfx_l3_fck),
- CLK(NULL, "gfx_l3_ick", &gfx_l3_ick),
- CLK(NULL, "gfx_cg1_ck", &gfx_cg1_ck),
- CLK(NULL, "gfx_cg2_ck", &gfx_cg2_ck),
- CLK(NULL, "d2d_26m_fck", &d2d_26m_fck),
- CLK(NULL, "fshostusb_fck", &fshostusb_fck),
- CLK(NULL, "ssi_ssr_fck", &ssi_ssr_fck_3430es1),
- CLK(NULL, "ssi_sst_fck", &ssi_sst_fck_3430es1),
- CLK("musb-omap2430", "ick", &hsotgusb_ick_3430es1),
- CLK(NULL, "hsotgusb_ick", &hsotgusb_ick_3430es1),
- CLK(NULL, "fac_ick", &fac_ick),
- CLK(NULL, "ssi_ick", &ssi_ick_3430es1),
- CLK(NULL, "usb_l4_ick", &usb_l4_ick),
- CLK(NULL, "dss1_alwon_fck", &dss1_alwon_fck_3430es1),
- CLK("omapdss_dss", "ick", &dss_ick_3430es1),
- CLK(NULL, "dss_ick", &dss_ick_3430es1),
-};
-
-/*
- * clocks specific to am35xx
- */
-static struct omap_clk am35xx_clks[] = {
- CLK(NULL, "ipss_ick", &ipss_ick),
- CLK(NULL, "rmii_ck", &rmii_ck),
- CLK(NULL, "pclk_ck", &pclk_ck),
- CLK(NULL, "emac_ick", &emac_ick),
- CLK(NULL, "emac_fck", &emac_fck),
- CLK("davinci_emac.0", NULL, &emac_ick),
- CLK("davinci_mdio.0", NULL, &emac_fck),
- CLK("vpfe-capture", "master", &vpfe_ick),
- CLK("vpfe-capture", "slave", &vpfe_fck),
- CLK(NULL, "hsotgusb_ick", &hsotgusb_ick_am35xx),
- CLK(NULL, "hsotgusb_fck", &hsotgusb_fck_am35xx),
- CLK(NULL, "hecc_ck", &hecc_ck),
- CLK(NULL, "uart4_ick", &uart4_ick_am35xx),
- CLK(NULL, "uart4_fck", &uart4_fck_am35xx),
-};
-
-/*
- * clocks specific to omap36xx
- */
-static struct omap_clk omap36xx_clks[] = {
- CLK(NULL, "omap_192m_alwon_fck", &omap_192m_alwon_fck),
- CLK(NULL, "uart4_fck", &uart4_fck),
-};
-
-/*
- * clocks common to omap36xx omap34xx
- */
-static struct omap_clk omap34xx_omap36xx_clks[] = {
- CLK(NULL, "aes1_ick", &aes1_ick),
- CLK("omap_rng", "ick", &rng_ick),
- CLK("omap3-rom-rng", "ick", &rng_ick),
- CLK(NULL, "sha11_ick", &sha11_ick),
- CLK(NULL, "des1_ick", &des1_ick),
- CLK(NULL, "cam_mclk", &cam_mclk),
- CLK(NULL, "cam_ick", &cam_ick),
- CLK(NULL, "csi2_96m_fck", &csi2_96m_fck),
- CLK(NULL, "security_l3_ick", &security_l3_ick),
- CLK(NULL, "pka_ick", &pka_ick),
- CLK(NULL, "icr_ick", &icr_ick),
- CLK("omap-aes", "ick", &aes2_ick),
- CLK("omap-sham", "ick", &sha12_ick),
- CLK(NULL, "des2_ick", &des2_ick),
- CLK(NULL, "mspro_ick", &mspro_ick),
- CLK(NULL, "mailboxes_ick", &mailboxes_ick),
- CLK(NULL, "ssi_l4_ick", &ssi_l4_ick),
- CLK(NULL, "sr1_fck", &sr1_fck),
- CLK(NULL, "sr2_fck", &sr2_fck),
- CLK(NULL, "sr_l4_ick", &sr_l4_ick),
- CLK(NULL, "security_l4_ick2", &security_l4_ick2),
- CLK(NULL, "wkup_l4_ick", &wkup_l4_ick),
- CLK(NULL, "dpll2_fck", &dpll2_fck),
- CLK(NULL, "iva2_ck", &iva2_ck),
- CLK(NULL, "modem_fck", &modem_fck),
- CLK(NULL, "sad2d_ick", &sad2d_ick),
- CLK(NULL, "mad2d_ick", &mad2d_ick),
- CLK(NULL, "mspro_fck", &mspro_fck),
- CLK(NULL, "dpll2_ck", &dpll2_ck),
- CLK(NULL, "dpll2_m2_ck", &dpll2_m2_ck),
-};
-
-/*
- * clocks common to omap36xx and omap3430es2plus
- */
-static struct omap_clk omap36xx_omap3430es2plus_clks[] = {
- CLK(NULL, "ssi_ssr_fck", &ssi_ssr_fck_3430es2),
- CLK(NULL, "ssi_sst_fck", &ssi_sst_fck_3430es2),
- CLK("musb-omap2430", "ick", &hsotgusb_ick_3430es2),
- CLK(NULL, "hsotgusb_ick", &hsotgusb_ick_3430es2),
- CLK(NULL, "ssi_ick", &ssi_ick_3430es2),
- CLK(NULL, "usim_fck", &usim_fck),
- CLK(NULL, "usim_ick", &usim_ick),
-};
-
-/*
- * clocks common to am35xx omap36xx and omap3430es2plus
- */
-static struct omap_clk omap36xx_am35xx_omap3430es2plus_clks[] = {
- CLK(NULL, "virt_16_8m_ck", &virt_16_8m_ck),
- CLK(NULL, "dpll5_ck", &dpll5_ck),
- CLK(NULL, "dpll5_m2_ck", &dpll5_m2_ck),
- CLK(NULL, "sgx_fck", &sgx_fck),
- CLK(NULL, "sgx_ick", &sgx_ick),
- CLK(NULL, "cpefuse_fck", &cpefuse_fck),
- CLK(NULL, "ts_fck", &ts_fck),
- CLK(NULL, "usbtll_fck", &usbtll_fck),
- CLK(NULL, "usbtll_ick", &usbtll_ick),
- CLK("omap_hsmmc.2", "ick", &mmchs3_ick),
- CLK(NULL, "mmchs3_ick", &mmchs3_ick),
- CLK(NULL, "mmchs3_fck", &mmchs3_fck),
- CLK(NULL, "dss1_alwon_fck", &dss1_alwon_fck_3430es2),
- CLK("omapdss_dss", "ick", &dss_ick_3430es2),
- CLK(NULL, "dss_ick", &dss_ick_3430es2),
- CLK(NULL, "usbhost_120m_fck", &usbhost_120m_fck),
- CLK(NULL, "usbhost_48m_fck", &usbhost_48m_fck),
- CLK(NULL, "usbhost_ick", &usbhost_ick),
-};
-
-/*
- * common clocks
- */
-static struct omap_clk omap3xxx_clks[] = {
- CLK(NULL, "apb_pclk", &dummy_apb_pclk),
- CLK(NULL, "omap_32k_fck", &omap_32k_fck),
- CLK(NULL, "virt_12m_ck", &virt_12m_ck),
- CLK(NULL, "virt_13m_ck", &virt_13m_ck),
- CLK(NULL, "virt_19200000_ck", &virt_19200000_ck),
- CLK(NULL, "virt_26000000_ck", &virt_26000000_ck),
- CLK(NULL, "virt_38_4m_ck", &virt_38_4m_ck),
- CLK(NULL, "osc_sys_ck", &osc_sys_ck),
- CLK("twl", "fck", &osc_sys_ck),
- CLK(NULL, "sys_ck", &sys_ck),
- CLK(NULL, "omap_96m_alwon_fck", &omap_96m_alwon_fck),
- CLK("etb", "emu_core_alwon_ck", &emu_core_alwon_ck),
- CLK(NULL, "sys_altclk", &sys_altclk),
- CLK(NULL, "mcbsp_clks", &mcbsp_clks),
- CLK(NULL, "sys_clkout1", &sys_clkout1),
- CLK(NULL, "dpll1_ck", &dpll1_ck),
- CLK(NULL, "dpll1_x2_ck", &dpll1_x2_ck),
- CLK(NULL, "dpll1_x2m2_ck", &dpll1_x2m2_ck),
- CLK(NULL, "dpll3_ck", &dpll3_ck),
- CLK(NULL, "core_ck", &core_ck),
- CLK(NULL, "dpll3_x2_ck", &dpll3_x2_ck),
- CLK(NULL, "dpll3_m2_ck", &dpll3_m2_ck),
- CLK(NULL, "dpll3_m2x2_ck", &dpll3_m2x2_ck),
- CLK(NULL, "dpll3_m3_ck", &dpll3_m3_ck),
- CLK(NULL, "dpll3_m3x2_ck", &dpll3_m3x2_ck),
- CLK(NULL, "dpll4_ck", &dpll4_ck),
- CLK(NULL, "dpll4_x2_ck", &dpll4_x2_ck),
- CLK(NULL, "omap_96m_fck", &omap_96m_fck),
- CLK(NULL, "cm_96m_fck", &cm_96m_fck),
- CLK(NULL, "omap_54m_fck", &omap_54m_fck),
- CLK(NULL, "omap_48m_fck", &omap_48m_fck),
- CLK(NULL, "omap_12m_fck", &omap_12m_fck),
- CLK(NULL, "dpll4_m2_ck", &dpll4_m2_ck),
- CLK(NULL, "dpll4_m2x2_ck", &dpll4_m2x2_ck),
- CLK(NULL, "dpll4_m3_ck", &dpll4_m3_ck),
- CLK(NULL, "dpll4_m3x2_ck", &dpll4_m3x2_ck),
- CLK(NULL, "dpll4_m4_ck", &dpll4_m4_ck),
- CLK(NULL, "dpll4_m4x2_ck", &dpll4_m4x2_ck),
- CLK(NULL, "dpll4_m5_ck", &dpll4_m5_ck),
- CLK(NULL, "dpll4_m5x2_ck", &dpll4_m5x2_ck),
- CLK(NULL, "dpll4_m6_ck", &dpll4_m6_ck),
- CLK(NULL, "dpll4_m6x2_ck", &dpll4_m6x2_ck),
- CLK("etb", "emu_per_alwon_ck", &emu_per_alwon_ck),
- CLK(NULL, "clkout2_src_ck", &clkout2_src_ck),
- CLK(NULL, "sys_clkout2", &sys_clkout2),
- CLK(NULL, "corex2_fck", &corex2_fck),
- CLK(NULL, "dpll1_fck", &dpll1_fck),
- CLK(NULL, "mpu_ck", &mpu_ck),
- CLK(NULL, "arm_fck", &arm_fck),
- CLK("etb", "emu_mpu_alwon_ck", &emu_mpu_alwon_ck),
- CLK(NULL, "l3_ick", &l3_ick),
- CLK(NULL, "l4_ick", &l4_ick),
- CLK(NULL, "rm_ick", &rm_ick),
- CLK(NULL, "gpt10_fck", &gpt10_fck),
- CLK(NULL, "gpt11_fck", &gpt11_fck),
- CLK(NULL, "core_96m_fck", &core_96m_fck),
- CLK(NULL, "mmchs2_fck", &mmchs2_fck),
- CLK(NULL, "mmchs1_fck", &mmchs1_fck),
- CLK(NULL, "i2c3_fck", &i2c3_fck),
- CLK(NULL, "i2c2_fck", &i2c2_fck),
- CLK(NULL, "i2c1_fck", &i2c1_fck),
- CLK(NULL, "mcbsp5_fck", &mcbsp5_fck),
- CLK(NULL, "mcbsp1_fck", &mcbsp1_fck),
- CLK(NULL, "core_48m_fck", &core_48m_fck),
- CLK(NULL, "mcspi4_fck", &mcspi4_fck),
- CLK(NULL, "mcspi3_fck", &mcspi3_fck),
- CLK(NULL, "mcspi2_fck", &mcspi2_fck),
- CLK(NULL, "mcspi1_fck", &mcspi1_fck),
- CLK(NULL, "uart2_fck", &uart2_fck),
- CLK(NULL, "uart1_fck", &uart1_fck),
- CLK(NULL, "core_12m_fck", &core_12m_fck),
- CLK("omap_hdq.0", "fck", &hdq_fck),
- CLK(NULL, "hdq_fck", &hdq_fck),
- CLK(NULL, "core_l3_ick", &core_l3_ick),
- CLK(NULL, "sdrc_ick", &sdrc_ick),
- CLK(NULL, "gpmc_fck", &gpmc_fck),
- CLK(NULL, "core_l4_ick", &core_l4_ick),
- CLK("omap_hsmmc.1", "ick", &mmchs2_ick),
- CLK("omap_hsmmc.0", "ick", &mmchs1_ick),
- CLK(NULL, "mmchs2_ick", &mmchs2_ick),
- CLK(NULL, "mmchs1_ick", &mmchs1_ick),
- CLK("omap_hdq.0", "ick", &hdq_ick),
- CLK(NULL, "hdq_ick", &hdq_ick),
- CLK("omap2_mcspi.4", "ick", &mcspi4_ick),
- CLK("omap2_mcspi.3", "ick", &mcspi3_ick),
- CLK("omap2_mcspi.2", "ick", &mcspi2_ick),
- CLK("omap2_mcspi.1", "ick", &mcspi1_ick),
- CLK(NULL, "mcspi4_ick", &mcspi4_ick),
- CLK(NULL, "mcspi3_ick", &mcspi3_ick),
- CLK(NULL, "mcspi2_ick", &mcspi2_ick),
- CLK(NULL, "mcspi1_ick", &mcspi1_ick),
- CLK("omap_i2c.3", "ick", &i2c3_ick),
- CLK("omap_i2c.2", "ick", &i2c2_ick),
- CLK("omap_i2c.1", "ick", &i2c1_ick),
- CLK(NULL, "i2c3_ick", &i2c3_ick),
- CLK(NULL, "i2c2_ick", &i2c2_ick),
- CLK(NULL, "i2c1_ick", &i2c1_ick),
- CLK(NULL, "uart2_ick", &uart2_ick),
- CLK(NULL, "uart1_ick", &uart1_ick),
- CLK(NULL, "gpt11_ick", &gpt11_ick),
- CLK(NULL, "gpt10_ick", &gpt10_ick),
- CLK("omap-mcbsp.5", "ick", &mcbsp5_ick),
- CLK("omap-mcbsp.1", "ick", &mcbsp1_ick),
- CLK(NULL, "mcbsp5_ick", &mcbsp5_ick),
- CLK(NULL, "mcbsp1_ick", &mcbsp1_ick),
- CLK(NULL, "omapctrl_ick", &omapctrl_ick),
- CLK(NULL, "dss_tv_fck", &dss_tv_fck),
- CLK(NULL, "dss_96m_fck", &dss_96m_fck),
- CLK(NULL, "dss2_alwon_fck", &dss2_alwon_fck),
- CLK(NULL, "init_60m_fclk", &dummy_ck),
- CLK(NULL, "gpt1_fck", &gpt1_fck),
- CLK(NULL, "aes2_ick", &aes2_ick),
- CLK(NULL, "wkup_32k_fck", &wkup_32k_fck),
- CLK(NULL, "gpio1_dbck", &gpio1_dbck),
- CLK(NULL, "sha12_ick", &sha12_ick),
- CLK(NULL, "wdt2_fck", &wdt2_fck),
- CLK("omap_wdt", "ick", &wdt2_ick),
- CLK(NULL, "wdt2_ick", &wdt2_ick),
- CLK(NULL, "wdt1_ick", &wdt1_ick),
- CLK(NULL, "gpio1_ick", &gpio1_ick),
- CLK(NULL, "omap_32ksync_ick", &omap_32ksync_ick),
- CLK(NULL, "gpt12_ick", &gpt12_ick),
- CLK(NULL, "gpt1_ick", &gpt1_ick),
- CLK(NULL, "per_96m_fck", &per_96m_fck),
- CLK(NULL, "per_48m_fck", &per_48m_fck),
- CLK(NULL, "uart3_fck", &uart3_fck),
- CLK(NULL, "gpt2_fck", &gpt2_fck),
- CLK(NULL, "gpt3_fck", &gpt3_fck),
- CLK(NULL, "gpt4_fck", &gpt4_fck),
- CLK(NULL, "gpt5_fck", &gpt5_fck),
- CLK(NULL, "gpt6_fck", &gpt6_fck),
- CLK(NULL, "gpt7_fck", &gpt7_fck),
- CLK(NULL, "gpt8_fck", &gpt8_fck),
- CLK(NULL, "gpt9_fck", &gpt9_fck),
- CLK(NULL, "per_32k_alwon_fck", &per_32k_alwon_fck),
- CLK(NULL, "gpio6_dbck", &gpio6_dbck),
- CLK(NULL, "gpio5_dbck", &gpio5_dbck),
- CLK(NULL, "gpio4_dbck", &gpio4_dbck),
- CLK(NULL, "gpio3_dbck", &gpio3_dbck),
- CLK(NULL, "gpio2_dbck", &gpio2_dbck),
- CLK(NULL, "wdt3_fck", &wdt3_fck),
- CLK(NULL, "per_l4_ick", &per_l4_ick),
- CLK(NULL, "gpio6_ick", &gpio6_ick),
- CLK(NULL, "gpio5_ick", &gpio5_ick),
- CLK(NULL, "gpio4_ick", &gpio4_ick),
- CLK(NULL, "gpio3_ick", &gpio3_ick),
- CLK(NULL, "gpio2_ick", &gpio2_ick),
- CLK(NULL, "wdt3_ick", &wdt3_ick),
- CLK(NULL, "uart3_ick", &uart3_ick),
- CLK(NULL, "uart4_ick", &uart4_ick),
- CLK(NULL, "gpt9_ick", &gpt9_ick),
- CLK(NULL, "gpt8_ick", &gpt8_ick),
- CLK(NULL, "gpt7_ick", &gpt7_ick),
- CLK(NULL, "gpt6_ick", &gpt6_ick),
- CLK(NULL, "gpt5_ick", &gpt5_ick),
- CLK(NULL, "gpt4_ick", &gpt4_ick),
- CLK(NULL, "gpt3_ick", &gpt3_ick),
- CLK(NULL, "gpt2_ick", &gpt2_ick),
- CLK("omap-mcbsp.2", "ick", &mcbsp2_ick),
- CLK("omap-mcbsp.3", "ick", &mcbsp3_ick),
- CLK("omap-mcbsp.4", "ick", &mcbsp4_ick),
- CLK(NULL, "mcbsp4_ick", &mcbsp2_ick),
- CLK(NULL, "mcbsp3_ick", &mcbsp3_ick),
- CLK(NULL, "mcbsp2_ick", &mcbsp4_ick),
- CLK(NULL, "mcbsp2_fck", &mcbsp2_fck),
- CLK(NULL, "mcbsp3_fck", &mcbsp3_fck),
- CLK(NULL, "mcbsp4_fck", &mcbsp4_fck),
- CLK("etb", "emu_src_ck", &emu_src_ck),
- CLK(NULL, "emu_src_ck", &emu_src_ck),
- CLK(NULL, "pclk_fck", &pclk_fck),
- CLK(NULL, "pclkx2_fck", &pclkx2_fck),
- CLK(NULL, "atclk_fck", &atclk_fck),
- CLK(NULL, "traceclk_src_fck", &traceclk_src_fck),
- CLK(NULL, "traceclk_fck", &traceclk_fck),
- CLK(NULL, "secure_32k_fck", &secure_32k_fck),
- CLK(NULL, "gpt12_fck", &gpt12_fck),
- CLK(NULL, "wdt1_fck", &wdt1_fck),
- CLK(NULL, "timer_32k_ck", &omap_32k_fck),
- CLK(NULL, "timer_sys_ck", &sys_ck),
- CLK(NULL, "cpufreq_ck", &dpll1_ck),
-};
-
-static const char *enable_init_clks[] = {
- "sdrc_ick",
- "gpmc_fck",
- "omapctrl_ick",
-};
-
-int __init omap3xxx_clk_init(void)
-{
- if (omap3_has_192mhz_clk())
- omap_96m_alwon_fck = omap_96m_alwon_fck_3630;
-
- if (cpu_is_omap3630()) {
- dpll3_m3x2_ck = dpll3_m3x2_ck_3630;
- dpll4_m2x2_ck = dpll4_m2x2_ck_3630;
- dpll4_m3x2_ck = dpll4_m3x2_ck_3630;
- dpll4_m4x2_ck = dpll4_m4x2_ck_3630;
- dpll4_m5x2_ck = dpll4_m5x2_ck_3630;
- dpll4_m6x2_ck = dpll4_m6x2_ck_3630;
- }
-
- /*
- * XXX This type of dynamic rewriting of the clock tree is
- * deprecated and should be revised soon.
- */
- if (cpu_is_omap3630())
- dpll4_dd = dpll4_dd_3630;
- else
- dpll4_dd = dpll4_dd_34xx;
-
-
- /*
- * 3505 must be tested before 3517, since 3517 returns true
- * for both AM3517 chips and AM3517 family chips, which
- * includes 3505. Unfortunately there's no obvious family
- * test for 3517/3505 :-(
- */
- if (soc_is_am35xx()) {
- cpu_mask = RATE_IN_34XX;
- omap_clocks_register(am35xx_clks, ARRAY_SIZE(am35xx_clks));
- omap_clocks_register(omap36xx_am35xx_omap3430es2plus_clks,
- ARRAY_SIZE(omap36xx_am35xx_omap3430es2plus_clks));
- omap_clocks_register(omap3xxx_clks, ARRAY_SIZE(omap3xxx_clks));
- } else if (cpu_is_omap3630()) {
- cpu_mask = (RATE_IN_34XX | RATE_IN_36XX);
- omap_clocks_register(omap36xx_clks, ARRAY_SIZE(omap36xx_clks));
- omap_clocks_register(omap36xx_omap3430es2plus_clks,
- ARRAY_SIZE(omap36xx_omap3430es2plus_clks));
- omap_clocks_register(omap34xx_omap36xx_clks,
- ARRAY_SIZE(omap34xx_omap36xx_clks));
- omap_clocks_register(omap36xx_am35xx_omap3430es2plus_clks,
- ARRAY_SIZE(omap36xx_am35xx_omap3430es2plus_clks));
- omap_clocks_register(omap3xxx_clks, ARRAY_SIZE(omap3xxx_clks));
- } else if (cpu_is_omap34xx()) {
- if (omap_rev() == OMAP3430_REV_ES1_0) {
- cpu_mask = RATE_IN_3430ES1;
- omap_clocks_register(omap3430es1_clks,
- ARRAY_SIZE(omap3430es1_clks));
- omap_clocks_register(omap34xx_omap36xx_clks,
- ARRAY_SIZE(omap34xx_omap36xx_clks));
- omap_clocks_register(omap3xxx_clks,
- ARRAY_SIZE(omap3xxx_clks));
- } else {
- /*
- * Assume that anything that we haven't matched yet
- * has 3430ES2-type clocks.
- */
- cpu_mask = RATE_IN_3430ES2PLUS;
- omap_clocks_register(omap34xx_omap36xx_clks,
- ARRAY_SIZE(omap34xx_omap36xx_clks));
- omap_clocks_register(omap36xx_omap3430es2plus_clks,
- ARRAY_SIZE(omap36xx_omap3430es2plus_clks));
- omap_clocks_register(omap36xx_am35xx_omap3430es2plus_clks,
- ARRAY_SIZE(omap36xx_am35xx_omap3430es2plus_clks));
- omap_clocks_register(omap3xxx_clks,
- ARRAY_SIZE(omap3xxx_clks));
- }
- } else {
- WARN(1, "clock: could not identify OMAP3 variant\n");
- }
-
- omap2_clk_disable_autoidle_all();
-
- omap2_clk_enable_init_clocks(enable_init_clks,
- ARRAY_SIZE(enable_init_clks));
-
- pr_info("Clocking rate (Crystal/Core/MPU): %ld.%01ld/%ld/%ld MHz\n",
- (clk_get_rate(&osc_sys_ck) / 1000000),
- (clk_get_rate(&osc_sys_ck) / 100000) % 10,
- (clk_get_rate(&core_ck) / 1000000),
- (clk_get_rate(&arm_fck) / 1000000));
-
- /*
- * Lock DPLL5 -- here only until other device init code can
- * handle this
- */
- if (omap_rev() >= OMAP3430_REV_ES2_0)
- omap3_clk_lock_dpll5();
-
- /* Avoid sleeping during omap3_core_dpll_m2_set_rate() */
- sdrc_ick_p = clk_get(NULL, "sdrc_ick");
- arm_fck_p = clk_get(NULL, "arm_fck");
-
- return 0;
-}
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index 4ae4cce..6124db5 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -23,7 +23,6 @@
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/bitops.h>
-#include <linux/clk-private.h>
#include <asm/cpu.h>
#include <trace/events/power.h>
@@ -633,21 +632,6 @@
};
/**
- * omap_clocks_register - register an array of omap_clk
- * @ocs: pointer to an array of omap_clk to register
- */
-void __init omap_clocks_register(struct omap_clk oclks[], int cnt)
-{
- struct omap_clk *c;
-
- for (c = oclks; c < oclks + cnt; c++) {
- clkdev_add(&c->lk);
- if (!__clk_init(NULL, c->lk.clk))
- omap2_init_clk_hw_omap_clocks(c->lk.clk);
- }
-}
-
-/**
* omap2_clk_switch_mpurate_at_boot - switch ARM MPU rate by boot-time argument
* @mpurate_ck_name: clk name of the clock to change rate
*
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
index 1cf9dd8..a56742f 100644
--- a/arch/arm/mach-omap2/clock.h
+++ b/arch/arm/mach-omap2/clock.h
@@ -40,23 +40,29 @@
struct clockdomain;
#define DEFINE_STRUCT_CLK(_name, _parent_array_name, _clkops_name) \
- static struct clk _name = { \
+ static struct clk_core _name##_core = { \
.name = #_name, \
.hw = &_name##_hw.hw, \
.parent_names = _parent_array_name, \
.num_parents = ARRAY_SIZE(_parent_array_name), \
.ops = &_clkops_name, \
+ }; \
+ static struct clk _name = { \
+ .core = &_name##_core, \
};
#define DEFINE_STRUCT_CLK_FLAGS(_name, _parent_array_name, \
_clkops_name, _flags) \
- static struct clk _name = { \
+ static struct clk_core _name##_core = { \
.name = #_name, \
.hw = &_name##_hw.hw, \
.parent_names = _parent_array_name, \
.num_parents = ARRAY_SIZE(_parent_array_name), \
.ops = &_clkops_name, \
.flags = _flags, \
+ }; \
+ static struct clk _name = { \
+ .core = &_name##_core, \
};
#define DEFINE_STRUCT_CLK_HW_OMAP(_name, _clkdm_name) \
@@ -238,7 +244,6 @@
extern struct ti_clk_features ti_clk_features;
extern const struct clkops clkops_omap2_dflt_wait;
-extern const struct clkops clkops_dummy;
extern const struct clkops clkops_omap2_dflt;
extern struct clk_functions omap2_clk_functions;
@@ -247,7 +252,6 @@
extern const struct clksel_rate gpt_sys_rates[];
extern const struct clksel_rate gfx_l3_rates[];
extern const struct clksel_rate dsp_ick_rates[];
-extern struct clk dummy_ck;
extern const struct clk_hw_omap_ops clkhwops_iclk_wait;
extern const struct clk_hw_omap_ops clkhwops_wait;
@@ -272,7 +276,5 @@
extern int omap2_clkops_enable_clkdm(struct clk_hw *hw);
extern void omap2_clkops_disable_clkdm(struct clk_hw *hw);
-extern void omap_clocks_register(struct omap_clk *oclks, int cnt);
-
void __init ti_clk_init_features(void);
#endif
diff --git a/arch/arm/mach-omap2/clock_common_data.c b/arch/arm/mach-omap2/clock_common_data.c
index ef4d21b..61b60df 100644
--- a/arch/arm/mach-omap2/clock_common_data.c
+++ b/arch/arm/mach-omap2/clock_common_data.c
@@ -16,7 +16,6 @@
* OMAP3xxx clock definition files.
*/
-#include <linux/clk-private.h>
#include "clock.h"
/* clksel_rate data common to 24xx/343x */
@@ -114,13 +113,3 @@
{ .div = 31, .val = 31, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 0 },
};
-
-/* Clocks shared between various OMAP SoCs */
-
-static struct clk_ops dummy_ck_ops = {};
-
-struct clk dummy_ck = {
- .name = "dummy_clk",
- .ops = &dummy_ck_ops,
- .flags = CLK_IS_BASIC,
-};
diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c
index c2da2a0..44e57ec 100644
--- a/arch/arm/mach-omap2/dpll3xxx.c
+++ b/arch/arm/mach-omap2/dpll3xxx.c
@@ -410,7 +410,7 @@
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
int r;
struct dpll_data *dd;
- struct clk *parent;
+ struct clk_hw *parent;
dd = clk->dpll_data;
if (!dd)
@@ -427,13 +427,13 @@
}
}
- parent = __clk_get_parent(hw->clk);
+ parent = __clk_get_hw(__clk_get_parent(hw->clk));
if (__clk_get_rate(hw->clk) == __clk_get_rate(dd->clk_bypass)) {
- WARN_ON(parent != dd->clk_bypass);
+ WARN_ON(parent != __clk_get_hw(dd->clk_bypass));
r = _omap3_noncore_dpll_bypass(clk);
} else {
- WARN_ON(parent != dd->clk_ref);
+ WARN_ON(parent != __clk_get_hw(dd->clk_ref));
r = _omap3_noncore_dpll_lock(clk);
}
@@ -473,6 +473,8 @@
* in failure.
*/
long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk)
{
@@ -549,7 +551,8 @@
if (!dd)
return -EINVAL;
- if (__clk_get_parent(hw->clk) != dd->clk_ref)
+ if (__clk_get_hw(__clk_get_parent(hw->clk)) !=
+ __clk_get_hw(dd->clk_ref))
return -EINVAL;
if (dd->last_rounded_rate == 0)
diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c
index fc71224..f231be0 100644
--- a/arch/arm/mach-omap2/dpll44xx.c
+++ b/arch/arm/mach-omap2/dpll44xx.c
@@ -202,6 +202,8 @@
* in failure.
*/
long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk)
{
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index e60780f..c4871c5 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -461,7 +461,17 @@
omap3xxx_clockdomains_init();
omap3xxx_hwmod_init();
omap_hwmod_init_postsetup();
- omap_clk_soc_init = omap3xxx_clk_init;
+ if (!of_have_populated_dt()) {
+ omap3_prcm_legacy_iomaps_init();
+ if (soc_is_am35xx())
+ omap_clk_soc_init = am35xx_clk_legacy_init;
+ else if (cpu_is_omap3630())
+ omap_clk_soc_init = omap36xx_clk_legacy_init;
+ else if (omap_rev() == OMAP3430_REV_ES1_0)
+ omap_clk_soc_init = omap3430es1_clk_legacy_init;
+ else
+ omap_clk_soc_init = omap3430_clk_legacy_init;
+ }
}
void __init omap3430_init_early(void)
@@ -753,15 +763,17 @@
ti_clk_init_features();
- ret = of_prcm_init();
- if (ret)
- return ret;
+ if (of_have_populated_dt()) {
+ ret = of_prcm_init();
+ if (ret)
+ return ret;
- of_clk_init(NULL);
+ of_clk_init(NULL);
- ti_dt_clk_init_retry_clks();
+ ti_dt_clk_init_retry_clks();
- ti_dt_clockdomains_setup();
+ ti_dt_clockdomains_setup();
+ }
ret = omap_clk_soc_init();
diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h
index 77752e4..b9061a6 100644
--- a/arch/arm/mach-omap2/prm.h
+++ b/arch/arm/mach-omap2/prm.h
@@ -20,6 +20,7 @@
extern u16 prm_features;
extern void omap2_set_globals_prm(void __iomem *prm);
int of_prcm_init(void);
+void omap3_prcm_legacy_iomaps_init(void);
# endif
/*
diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c
index 264b5e29..bfaa7ba 100644
--- a/arch/arm/mach-omap2/prm_common.c
+++ b/arch/arm/mach-omap2/prm_common.c
@@ -35,6 +35,8 @@
#include "prm44xx.h"
#include "common.h"
#include "clock.h"
+#include "cm.h"
+#include "control.h"
/*
* OMAP_PRCM_MAX_NR_PENDING_REG: maximum number of PRM_IRQ*_MPU regs
@@ -641,6 +643,15 @@
return 0;
}
+void __init omap3_prcm_legacy_iomaps_init(void)
+{
+ ti_clk_ll_ops = &omap_clk_ll_ops;
+
+ clk_memmaps[TI_CLKM_CM] = cm_base + OMAP3430_IVA2_MOD;
+ clk_memmaps[TI_CLKM_PRM] = prm_base + OMAP3430_IVA2_MOD;
+ clk_memmaps[TI_CLKM_SCRM] = omap_ctrl_base_get();
+}
+
static int __init prm_late_init(void)
{
if (prm_ll_data->late_init)
diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index ef016af..914341b 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -91,8 +91,6 @@
struct soc_device *soc_dev;
struct device *parent = NULL;
- tegra_clocks_apply_init_table();
-
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
if (!soc_dev_attr)
goto out;
diff --git a/arch/blackfin/mach-bf527/boards/ad7160eval.c b/arch/blackfin/mach-bf527/boards/ad7160eval.c
index 9501bd8..68f2a8a 100644
--- a/arch/blackfin/mach-bf527/boards/ad7160eval.c
+++ b/arch/blackfin/mach-bf527/boards/ad7160eval.c
@@ -666,7 +666,14 @@
#endif
#if IS_ENABLED(CONFIG_INPUT_BFIN_ROTARY)
-#include <asm/bfin_rotary.h>
+#include <linux/platform_data/bfin_rotary.h>
+
+static const u16 per_cnt[] = {
+ P_CNT_CUD,
+ P_CNT_CDG,
+ P_CNT_CZM,
+ 0
+};
static struct bfin_rotary_platform_data bfin_rotary_data = {
/*.rotary_up_key = KEY_UP,*/
@@ -676,10 +683,16 @@
.debounce = 10, /* 0..17 */
.mode = ROT_QUAD_ENC | ROT_DEBE,
.pm_wakeup = 1,
+ .pin_list = per_cnt,
};
static struct resource bfin_rotary_resources[] = {
{
+ .start = CNT_CONFIG,
+ .end = CNT_CONFIG + 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
.start = IRQ_CNT,
.end = IRQ_CNT,
.flags = IORESOURCE_IRQ,
diff --git a/arch/blackfin/mach-bf527/boards/ezkit.c b/arch/blackfin/mach-bf527/boards/ezkit.c
index d64f565..d4219e8 100644
--- a/arch/blackfin/mach-bf527/boards/ezkit.c
+++ b/arch/blackfin/mach-bf527/boards/ezkit.c
@@ -1092,7 +1092,14 @@
#endif
#if IS_ENABLED(CONFIG_INPUT_BFIN_ROTARY)
-#include <asm/bfin_rotary.h>
+#include <linux/platform_data/bfin_rotary.h>
+
+static const u16 per_cnt[] = {
+ P_CNT_CUD,
+ P_CNT_CDG,
+ P_CNT_CZM,
+ 0
+};
static struct bfin_rotary_platform_data bfin_rotary_data = {
/*.rotary_up_key = KEY_UP,*/
@@ -1102,10 +1109,16 @@
.debounce = 10, /* 0..17 */
.mode = ROT_QUAD_ENC | ROT_DEBE,
.pm_wakeup = 1,
+ .pin_list = per_cnt,
};
static struct resource bfin_rotary_resources[] = {
{
+ .start = CNT_CONFIG,
+ .end = CNT_CONFIG + 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
.start = IRQ_CNT,
.end = IRQ_CNT,
.flags = IORESOURCE_IRQ,
diff --git a/arch/blackfin/mach-bf548/boards/ezkit.c b/arch/blackfin/mach-bf548/boards/ezkit.c
index 1fe7ff2..4204b98 100644
--- a/arch/blackfin/mach-bf548/boards/ezkit.c
+++ b/arch/blackfin/mach-bf548/boards/ezkit.c
@@ -159,7 +159,7 @@
#endif
#if IS_ENABLED(CONFIG_INPUT_BFIN_ROTARY)
-#include <asm/bfin_rotary.h>
+#include <linux/platform_data/bfin_rotary.h>
static struct bfin_rotary_platform_data bfin_rotary_data = {
/*.rotary_up_key = KEY_UP,*/
@@ -173,6 +173,11 @@
static struct resource bfin_rotary_resources[] = {
{
+ .start = CNT_CONFIG,
+ .end = CNT_CONFIG + 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
.start = IRQ_CNT,
.end = IRQ_CNT,
.flags = IORESOURCE_IRQ,
diff --git a/arch/blackfin/mach-bf609/boards/ezkit.c b/arch/blackfin/mach-bf609/boards/ezkit.c
index e2c0b02..7f9fc27 100644
--- a/arch/blackfin/mach-bf609/boards/ezkit.c
+++ b/arch/blackfin/mach-bf609/boards/ezkit.c
@@ -75,7 +75,7 @@
#endif
#if IS_ENABLED(CONFIG_INPUT_BFIN_ROTARY)
-#include <asm/bfin_rotary.h>
+#include <linux/platform_data/bfin_rotary.h>
static struct bfin_rotary_platform_data bfin_rotary_data = {
/*.rotary_up_key = KEY_UP,*/
@@ -88,6 +88,11 @@
static struct resource bfin_rotary_resources[] = {
{
+ .start = CNT_CONFIG,
+ .end = CNT_CONFIG + 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
.start = IRQ_CNT,
.end = IRQ_CNT,
.flags = IORESOURCE_IRQ,
diff --git a/arch/mips/alchemy/common/clock.c b/arch/mips/alchemy/common/clock.c
index 48a9dfc..604b7d0 100644
--- a/arch/mips/alchemy/common/clock.c
+++ b/arch/mips/alchemy/common/clock.c
@@ -546,6 +546,8 @@
}
static long alchemy_clk_fgv1_detr(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk)
{
@@ -678,6 +680,8 @@
}
static long alchemy_clk_fgv2_detr(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk)
{
@@ -897,6 +901,8 @@
}
static long alchemy_clk_csrc_detr(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk)
{
diff --git a/arch/powerpc/configs/corenet32_smp_defconfig b/arch/powerpc/configs/corenet32_smp_defconfig
index 51866f1..ca7957b 100644
--- a/arch/powerpc/configs/corenet32_smp_defconfig
+++ b/arch/powerpc/configs/corenet32_smp_defconfig
@@ -142,6 +142,7 @@
CONFIG_FSL_HV_MANAGER=y
CONFIG_STAGING=y
CONFIG_FSL_CORENET_CF=y
+CONFIG_CLK_QORIQ=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
diff --git a/arch/powerpc/configs/corenet64_smp_defconfig b/arch/powerpc/configs/corenet64_smp_defconfig
index d6c0c81..04737aa 100644
--- a/arch/powerpc/configs/corenet64_smp_defconfig
+++ b/arch/powerpc/configs/corenet64_smp_defconfig
@@ -122,6 +122,7 @@
CONFIG_FSL_DMA=y
CONFIG_VIRT_DRIVERS=y
CONFIG_FSL_HV_MANAGER=y
+CONFIG_CLK_QORIQ=y
CONFIG_FSL_CORENET_CF=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 7316dd1..2d7b33f 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -54,6 +54,7 @@
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/irq_work.h>
+#include <linux/clk-provider.h>
#include <asm/trace.h>
#include <asm/io.h>
@@ -975,6 +976,10 @@
init_decrementer_clockevent();
tick_setup_hrtimer_broadcast();
+
+#ifdef CONFIG_COMMON_CLK
+ of_clk_init(NULL);
+#endif
}
diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c
index 6eb614a..f691bca 100644
--- a/arch/powerpc/platforms/512x/clock-commonclk.c
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -1168,6 +1168,11 @@
}
}
+/*
+ * The "fixed-clock" nodes (which includes the oscillator node if the board's
+ * DT provides one) has already been scanned by the of_clk_init() in
+ * time_init().
+ */
int __init mpc5121_clk_init(void)
{
struct device_node *clk_np;
@@ -1187,12 +1192,6 @@
mpc512x_clk_preset_data();
/*
- * have the device tree scanned for "fixed-clock" nodes (which
- * includes the oscillator node if the board's DT provides one)
- */
- of_clk_init(NULL);
-
- /*
* add a dummy clock for those situations where a clock spec is
* required yet no real clock is involved
*/
diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h
index c4fbb95..b1453a2 100644
--- a/arch/s390/include/asm/topology.h
+++ b/arch/s390/include/asm/topology.h
@@ -18,15 +18,15 @@
cpumask_t book_mask;
};
-extern struct cpu_topology_s390 cpu_topology[NR_CPUS];
+DECLARE_PER_CPU(struct cpu_topology_s390, cpu_topology);
-#define topology_physical_package_id(cpu) (cpu_topology[cpu].socket_id)
-#define topology_thread_id(cpu) (cpu_topology[cpu].thread_id)
-#define topology_thread_cpumask(cpu) (&cpu_topology[cpu].thread_mask)
-#define topology_core_id(cpu) (cpu_topology[cpu].core_id)
-#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_mask)
-#define topology_book_id(cpu) (cpu_topology[cpu].book_id)
-#define topology_book_cpumask(cpu) (&cpu_topology[cpu].book_mask)
+#define topology_physical_package_id(cpu) (per_cpu(cpu_topology, cpu).socket_id)
+#define topology_thread_id(cpu) (per_cpu(cpu_topology, cpu).thread_id)
+#define topology_thread_cpumask(cpu) (&per_cpu(cpu_topology, cpu).thread_mask)
+#define topology_core_id(cpu) (per_cpu(cpu_topology, cpu).core_id)
+#define topology_core_cpumask(cpu) (&per_cpu(cpu_topology, cpu).core_mask)
+#define topology_book_id(cpu) (per_cpu(cpu_topology, cpu).book_id)
+#define topology_book_cpumask(cpu) (&per_cpu(cpu_topology, cpu).book_mask)
#define mc_capable() 1
@@ -51,14 +51,6 @@
#define POLARIZATION_VM (2)
#define POLARIZATION_VH (3)
-#ifdef CONFIG_SCHED_BOOK
-void s390_init_cpu_topology(void);
-#else
-static inline void s390_init_cpu_topology(void)
-{
-};
-#endif
-
#include <asm-generic/topology.h>
#endif /* _ASM_S390_TOPOLOGY_H */
diff --git a/arch/s390/kernel/cache.c b/arch/s390/kernel/cache.c
index 632fa06..0969d113 100644
--- a/arch/s390/kernel/cache.c
+++ b/arch/s390/kernel/cache.c
@@ -91,12 +91,9 @@
{
if (level >= CACHE_MAX_LEVEL)
return CACHE_TYPE_NOCACHE;
-
ci += level;
-
if (ci->scope != CACHE_SCOPE_SHARED && ci->scope != CACHE_SCOPE_PRIVATE)
return CACHE_TYPE_NOCACHE;
-
return cache_type_map[ci->type];
}
@@ -111,23 +108,19 @@
}
static void ci_leaf_init(struct cacheinfo *this_leaf, int private,
- enum cache_type type, unsigned int level)
+ enum cache_type type, unsigned int level, int cpu)
{
int ti, num_sets;
- int cpu = smp_processor_id();
if (type == CACHE_TYPE_INST)
ti = CACHE_TI_INSTRUCTION;
else
ti = CACHE_TI_UNIFIED;
-
this_leaf->level = level + 1;
this_leaf->type = type;
this_leaf->coherency_line_size = ecag(EXTRACT_LINE_SIZE, level, ti);
- this_leaf->ways_of_associativity = ecag(EXTRACT_ASSOCIATIVITY,
- level, ti);
+ this_leaf->ways_of_associativity = ecag(EXTRACT_ASSOCIATIVITY, level, ti);
this_leaf->size = ecag(EXTRACT_SIZE, level, ti);
-
num_sets = this_leaf->size / this_leaf->coherency_line_size;
num_sets /= this_leaf->ways_of_associativity;
this_leaf->number_of_sets = num_sets;
@@ -145,7 +138,6 @@
if (!this_cpu_ci)
return -EINVAL;
-
ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0);
do {
ctype = get_cache_type(&ct.ci[0], level);
@@ -154,34 +146,31 @@
/* Separate instruction and data caches */
leaves += (ctype == CACHE_TYPE_SEPARATE) ? 2 : 1;
} while (++level < CACHE_MAX_LEVEL);
-
this_cpu_ci->num_levels = level;
this_cpu_ci->num_leaves = leaves;
-
return 0;
}
int populate_cache_leaves(unsigned int cpu)
{
+ struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+ struct cacheinfo *this_leaf = this_cpu_ci->info_list;
unsigned int level, idx, pvt;
union cache_topology ct;
enum cache_type ctype;
- struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
- struct cacheinfo *this_leaf = this_cpu_ci->info_list;
ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0);
for (idx = 0, level = 0; level < this_cpu_ci->num_levels &&
idx < this_cpu_ci->num_leaves; idx++, level++) {
if (!this_leaf)
return -EINVAL;
-
pvt = (ct.ci[level].scope == CACHE_SCOPE_PRIVATE) ? 1 : 0;
ctype = get_cache_type(&ct.ci[0], level);
if (ctype == CACHE_TYPE_SEPARATE) {
- ci_leaf_init(this_leaf++, pvt, CACHE_TYPE_DATA, level);
- ci_leaf_init(this_leaf++, pvt, CACHE_TYPE_INST, level);
+ ci_leaf_init(this_leaf++, pvt, CACHE_TYPE_DATA, level, cpu);
+ ci_leaf_init(this_leaf++, pvt, CACHE_TYPE_INST, level, cpu);
} else {
- ci_leaf_init(this_leaf++, pvt, ctype, level);
+ ci_leaf_init(this_leaf++, pvt, ctype, level, cpu);
}
}
return 0;
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index 70a3294..4427ab7 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -393,17 +393,19 @@
S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_LC;
if (test_facility(129))
S390_lowcore.machine_flags |= MACHINE_FLAG_VX;
- if (test_facility(128))
- S390_lowcore.machine_flags |= MACHINE_FLAG_CAD;
#endif
}
-static int __init nocad_setup(char *str)
+static int __init cad_setup(char *str)
{
- S390_lowcore.machine_flags &= ~MACHINE_FLAG_CAD;
+ int val;
+
+ get_option(&str, &val);
+ if (val && test_facility(128))
+ S390_lowcore.machine_flags |= MACHINE_FLAG_CAD;
return 0;
}
-early_param("nocad", nocad_setup);
+early_param("cad", cad_setup);
static int __init cad_init(void)
{
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index bfac77a..a5ea8bc 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -909,7 +909,6 @@
setup_lowcore();
smp_fill_possible_mask();
cpu_init();
- s390_init_cpu_topology();
/*
* Setup capabilities (ELF_HWCAP & ELF_PLATFORM).
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index a668993..db8f1115 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -59,14 +59,13 @@
CPU_STATE_CONFIGURED,
};
+static DEFINE_PER_CPU(struct cpu *, cpu_device);
+
struct pcpu {
- struct cpu *cpu;
struct _lowcore *lowcore; /* lowcore page(s) for the cpu */
- unsigned long async_stack; /* async stack for the cpu */
- unsigned long panic_stack; /* panic stack for the cpu */
unsigned long ec_mask; /* bit mask for ec_xxx functions */
- int state; /* physical cpu state */
- int polarization; /* physical polarization */
+ signed char state; /* physical cpu state */
+ signed char polarization; /* physical polarization */
u16 address; /* physical cpu address */
};
@@ -173,25 +172,30 @@
pcpu_sigp_retry(pcpu, order, 0);
}
+#define ASYNC_FRAME_OFFSET (ASYNC_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE)
+#define PANIC_FRAME_OFFSET (PAGE_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE)
+
static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
{
+ unsigned long async_stack, panic_stack;
struct _lowcore *lc;
if (pcpu != &pcpu_devices[0]) {
pcpu->lowcore = (struct _lowcore *)
__get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER);
- pcpu->async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER);
- pcpu->panic_stack = __get_free_page(GFP_KERNEL);
- if (!pcpu->lowcore || !pcpu->panic_stack || !pcpu->async_stack)
+ async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER);
+ panic_stack = __get_free_page(GFP_KERNEL);
+ if (!pcpu->lowcore || !panic_stack || !async_stack)
goto out;
+ } else {
+ async_stack = pcpu->lowcore->async_stack - ASYNC_FRAME_OFFSET;
+ panic_stack = pcpu->lowcore->panic_stack - PANIC_FRAME_OFFSET;
}
lc = pcpu->lowcore;
memcpy(lc, &S390_lowcore, 512);
memset((char *) lc + 512, 0, sizeof(*lc) - 512);
- lc->async_stack = pcpu->async_stack + ASYNC_SIZE
- - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
- lc->panic_stack = pcpu->panic_stack + PAGE_SIZE
- - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
+ lc->async_stack = async_stack + ASYNC_FRAME_OFFSET;
+ lc->panic_stack = panic_stack + PANIC_FRAME_OFFSET;
lc->cpu_nr = cpu;
lc->spinlock_lockval = arch_spin_lockval(cpu);
#ifndef CONFIG_64BIT
@@ -212,8 +216,8 @@
return 0;
out:
if (pcpu != &pcpu_devices[0]) {
- free_page(pcpu->panic_stack);
- free_pages(pcpu->async_stack, ASYNC_ORDER);
+ free_page(panic_stack);
+ free_pages(async_stack, ASYNC_ORDER);
free_pages((unsigned long) pcpu->lowcore, LC_ORDER);
}
return -ENOMEM;
@@ -235,11 +239,11 @@
#else
vdso_free_per_cpu(pcpu->lowcore);
#endif
- if (pcpu != &pcpu_devices[0]) {
- free_page(pcpu->panic_stack);
- free_pages(pcpu->async_stack, ASYNC_ORDER);
- free_pages((unsigned long) pcpu->lowcore, LC_ORDER);
- }
+ if (pcpu == &pcpu_devices[0])
+ return;
+ free_page(pcpu->lowcore->panic_stack-PANIC_FRAME_OFFSET);
+ free_pages(pcpu->lowcore->async_stack-ASYNC_FRAME_OFFSET, ASYNC_ORDER);
+ free_pages((unsigned long) pcpu->lowcore, LC_ORDER);
}
#endif /* CONFIG_HOTPLUG_CPU */
@@ -366,7 +370,8 @@
void smp_call_ipl_cpu(void (*func)(void *), void *data)
{
pcpu_delegate(&pcpu_devices[0], func, data,
- pcpu_devices->panic_stack + PAGE_SIZE);
+ pcpu_devices->lowcore->panic_stack -
+ PANIC_FRAME_OFFSET + PAGE_SIZE);
}
int smp_find_processor_id(u16 address)
@@ -935,10 +940,6 @@
pcpu->state = CPU_STATE_CONFIGURED;
pcpu->address = stap();
pcpu->lowcore = (struct _lowcore *)(unsigned long) store_prefix();
- pcpu->async_stack = S390_lowcore.async_stack - ASYNC_SIZE
- + STACK_FRAME_OVERHEAD + sizeof(struct pt_regs);
- pcpu->panic_stack = S390_lowcore.panic_stack - PAGE_SIZE
- + STACK_FRAME_OVERHEAD + sizeof(struct pt_regs);
S390_lowcore.percpu_offset = __per_cpu_offset[0];
smp_cpu_set_polarization(0, POLARIZATION_UNKNOWN);
set_cpu_present(0, true);
@@ -1078,8 +1079,7 @@
void *hcpu)
{
unsigned int cpu = (unsigned int)(long)hcpu;
- struct cpu *c = pcpu_devices[cpu].cpu;
- struct device *s = &c->dev;
+ struct device *s = &per_cpu(cpu_device, cpu)->dev;
int err = 0;
switch (action & ~CPU_TASKS_FROZEN) {
@@ -1102,7 +1102,7 @@
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c)
return -ENOMEM;
- pcpu_devices[cpu].cpu = c;
+ per_cpu(cpu_device, cpu) = c;
s = &c->dev;
c->hotpluggable = 1;
rc = register_cpu(c, cpu);
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c
index 24ee33f..14da43b 100644
--- a/arch/s390/kernel/topology.c
+++ b/arch/s390/kernel/topology.c
@@ -7,14 +7,14 @@
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/workqueue.h>
-#include <linux/bootmem.h>
#include <linux/cpuset.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/slab.h>
#include <linux/cpu.h>
#include <linux/smp.h>
#include <linux/mm.h>
@@ -42,8 +42,8 @@
static struct mask_info socket_info;
static struct mask_info book_info;
-struct cpu_topology_s390 cpu_topology[NR_CPUS];
-EXPORT_SYMBOL_GPL(cpu_topology);
+DEFINE_PER_CPU(struct cpu_topology_s390, cpu_topology);
+EXPORT_PER_CPU_SYMBOL_GPL(cpu_topology);
static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
{
@@ -90,15 +90,15 @@
if (lcpu < 0)
continue;
for (i = 0; i <= smp_cpu_mtid; i++) {
- cpu_topology[lcpu + i].book_id = book->id;
- cpu_topology[lcpu + i].core_id = rcore;
- cpu_topology[lcpu + i].thread_id = lcpu + i;
+ per_cpu(cpu_topology, lcpu + i).book_id = book->id;
+ per_cpu(cpu_topology, lcpu + i).core_id = rcore;
+ per_cpu(cpu_topology, lcpu + i).thread_id = lcpu + i;
cpumask_set_cpu(lcpu + i, &book->mask);
cpumask_set_cpu(lcpu + i, &socket->mask);
if (one_socket_per_cpu)
- cpu_topology[lcpu + i].socket_id = rcore;
+ per_cpu(cpu_topology, lcpu + i).socket_id = rcore;
else
- cpu_topology[lcpu + i].socket_id = socket->id;
+ per_cpu(cpu_topology, lcpu + i).socket_id = socket->id;
smp_cpu_set_polarization(lcpu + i, tl_core->pp);
}
if (one_socket_per_cpu)
@@ -249,14 +249,14 @@
spin_lock_irqsave(&topology_lock, flags);
for_each_possible_cpu(cpu) {
- cpu_topology[cpu].thread_mask = cpu_thread_map(cpu);
- cpu_topology[cpu].core_mask = cpu_group_map(&socket_info, cpu);
- cpu_topology[cpu].book_mask = cpu_group_map(&book_info, cpu);
+ per_cpu(cpu_topology, cpu).thread_mask = cpu_thread_map(cpu);
+ per_cpu(cpu_topology, cpu).core_mask = cpu_group_map(&socket_info, cpu);
+ per_cpu(cpu_topology, cpu).book_mask = cpu_group_map(&book_info, cpu);
if (!MACHINE_HAS_TOPOLOGY) {
- cpu_topology[cpu].thread_id = cpu;
- cpu_topology[cpu].core_id = cpu;
- cpu_topology[cpu].socket_id = cpu;
- cpu_topology[cpu].book_id = cpu;
+ per_cpu(cpu_topology, cpu).thread_id = cpu;
+ per_cpu(cpu_topology, cpu).core_id = cpu;
+ per_cpu(cpu_topology, cpu).socket_id = cpu;
+ per_cpu(cpu_topology, cpu).book_id = cpu;
}
}
spin_unlock_irqrestore(&topology_lock, flags);
@@ -334,50 +334,6 @@
set_topology_timer();
}
-static int __init early_parse_topology(char *p)
-{
- if (strncmp(p, "off", 3))
- return 0;
- topology_enabled = 0;
- return 0;
-}
-early_param("topology", early_parse_topology);
-
-static void __init alloc_masks(struct sysinfo_15_1_x *info,
- struct mask_info *mask, int offset)
-{
- int i, nr_masks;
-
- nr_masks = info->mag[TOPOLOGY_NR_MAG - offset];
- for (i = 0; i < info->mnest - offset; i++)
- nr_masks *= info->mag[TOPOLOGY_NR_MAG - offset - 1 - i];
- nr_masks = max(nr_masks, 1);
- for (i = 0; i < nr_masks; i++) {
- mask->next = alloc_bootmem_align(
- roundup_pow_of_two(sizeof(struct mask_info)),
- roundup_pow_of_two(sizeof(struct mask_info)));
- mask = mask->next;
- }
-}
-
-void __init s390_init_cpu_topology(void)
-{
- struct sysinfo_15_1_x *info;
- int i;
-
- if (!MACHINE_HAS_TOPOLOGY)
- return;
- tl_info = alloc_bootmem_pages(PAGE_SIZE);
- info = tl_info;
- store_topology(info);
- pr_info("The CPU configuration topology of the machine is:");
- for (i = 0; i < TOPOLOGY_NR_MAG; i++)
- printk(KERN_CONT " %d", info->mag[i]);
- printk(KERN_CONT " / %d\n", info->mnest);
- alloc_masks(info, &socket_info, 1);
- alloc_masks(info, &book_info, 2);
-}
-
static int cpu_management;
static ssize_t dispatching_show(struct device *dev,
@@ -467,20 +423,29 @@
const struct cpumask *cpu_thread_mask(int cpu)
{
- return &cpu_topology[cpu].thread_mask;
+ return &per_cpu(cpu_topology, cpu).thread_mask;
}
const struct cpumask *cpu_coregroup_mask(int cpu)
{
- return &cpu_topology[cpu].core_mask;
+ return &per_cpu(cpu_topology, cpu).core_mask;
}
static const struct cpumask *cpu_book_mask(int cpu)
{
- return &cpu_topology[cpu].book_mask;
+ return &per_cpu(cpu_topology, cpu).book_mask;
}
+static int __init early_parse_topology(char *p)
+{
+ if (strncmp(p, "off", 3))
+ return 0;
+ topology_enabled = 0;
+ return 0;
+}
+early_param("topology", early_parse_topology);
+
static struct sched_domain_topology_level s390_topology[] = {
{ cpu_thread_mask, cpu_smt_flags, SD_INIT_NAME(SMT) },
{ cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) },
@@ -489,6 +454,42 @@
{ NULL, },
};
+static void __init alloc_masks(struct sysinfo_15_1_x *info,
+ struct mask_info *mask, int offset)
+{
+ int i, nr_masks;
+
+ nr_masks = info->mag[TOPOLOGY_NR_MAG - offset];
+ for (i = 0; i < info->mnest - offset; i++)
+ nr_masks *= info->mag[TOPOLOGY_NR_MAG - offset - 1 - i];
+ nr_masks = max(nr_masks, 1);
+ for (i = 0; i < nr_masks; i++) {
+ mask->next = kzalloc(sizeof(*mask->next), GFP_KERNEL);
+ mask = mask->next;
+ }
+}
+
+static int __init s390_topology_init(void)
+{
+ struct sysinfo_15_1_x *info;
+ int i;
+
+ if (!MACHINE_HAS_TOPOLOGY)
+ return 0;
+ tl_info = (struct sysinfo_15_1_x *)__get_free_page(GFP_KERNEL);
+ info = tl_info;
+ store_topology(info);
+ pr_info("The CPU configuration topology of the machine is:");
+ for (i = 0; i < TOPOLOGY_NR_MAG; i++)
+ printk(KERN_CONT " %d", info->mag[i]);
+ printk(KERN_CONT " / %d\n", info->mnest);
+ alloc_masks(info, &socket_info, 1);
+ alloc_masks(info, &book_info, 2);
+ set_sched_topology(s390_topology);
+ return 0;
+}
+early_initcall(s390_topology_init);
+
static int __init topology_init(void)
{
if (MACHINE_HAS_TOPOLOGY)
@@ -498,10 +499,3 @@
return device_create_file(cpu_subsys.dev_root, &dev_attr_dispatching);
}
device_initcall(topology_init);
-
-static int __init early_topology_init(void)
-{
- set_sched_topology(s390_topology);
- return 0;
-}
-early_initcall(early_topology_init);
diff --git a/arch/s390/kernel/vdso64/clock_gettime.S b/arch/s390/kernel/vdso64/clock_gettime.S
index 7699e73..61541fb 100644
--- a/arch/s390/kernel/vdso64/clock_gettime.S
+++ b/arch/s390/kernel/vdso64/clock_gettime.S
@@ -25,9 +25,7 @@
je 4f
cghi %r2,__CLOCK_REALTIME
je 5f
- cghi %r2,__CLOCK_THREAD_CPUTIME_ID
- je 9f
- cghi %r2,-2 /* Per-thread CPUCLOCK with PID=0, VIRT=1 */
+ cghi %r2,-3 /* Per-thread CPUCLOCK with PID=0, VIRT=1 */
je 9f
cghi %r2,__CLOCK_MONOTONIC_COARSE
je 3f
@@ -106,7 +104,7 @@
aghi %r15,16
br %r14
- /* CLOCK_THREAD_CPUTIME_ID for this thread */
+ /* CPUCLOCK_VIRT for this thread */
9: icm %r0,15,__VDSO_ECTG_OK(%r5)
jz 12f
ear %r2,%a4
diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c
index d008f638..179a2c2 100644
--- a/arch/s390/mm/mmap.c
+++ b/arch/s390/mm/mmap.c
@@ -183,7 +183,10 @@
{
unsigned long base;
- base = (STACK_TOP / 3 * 2) & (~mmap_align_mask << PAGE_SHIFT);
+ base = STACK_TOP / 3 * 2;
+ if (!is_32bit_task())
+ /* Align to 4GB */
+ base &= ~((1UL << 32) - 1);
return base + mmap_rnd();
}
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index eb1cf89..c2fb8a8 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -488,6 +488,22 @@
Intel MID platforms are based on an Intel processor and chipset which
consume less power than most of the x86 derivatives.
+config X86_INTEL_QUARK
+ bool "Intel Quark platform support"
+ depends on X86_32
+ depends on X86_EXTENDED_PLATFORM
+ depends on X86_PLATFORM_DEVICES
+ depends on X86_TSC
+ depends on PCI
+ depends on PCI_GOANY
+ depends on X86_IO_APIC
+ select IOSF_MBI
+ select INTEL_IMR
+ ---help---
+ Select to include support for Quark X1000 SoC.
+ Say Y here if you have a Quark based system such as the Arduino
+ compatible Intel Galileo.
+
config X86_INTEL_LPSS
bool "Intel Low Power Subsystem Support"
depends on ACPI
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 61bd2ad..20028da 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -313,6 +313,19 @@
If unsure, say N.
+config DEBUG_IMR_SELFTEST
+ bool "Isolated Memory Region self test"
+ default n
+ depends on INTEL_IMR
+ ---help---
+ This option enables automated sanity testing of the IMR code.
+ Some simple tests are run to verify IMR bounds checking, alignment
+ and overlapping. This option is really only useful if you are
+ debugging an IMR memory map or are modifying the IMR code and want to
+ test your changes.
+
+ If unsure say N here.
+
config X86_DEBUG_STATIC_CPU_HAS
bool "Debug alternatives"
depends on DEBUG_KERNEL
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 843feb3..0a291cd 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -51,6 +51,7 @@
vmlinux-objs-$(CONFIG_EFI_STUB) += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o \
$(objtree)/drivers/firmware/efi/libstub/lib.a
+vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o
$(obj)/vmlinux: $(vmlinux-objs-y) FORCE
$(call if_changed,ld)
diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c
index bb13763..7083c16 100644
--- a/arch/x86/boot/compressed/aslr.c
+++ b/arch/x86/boot/compressed/aslr.c
@@ -14,6 +14,13 @@
static const char build_str[] = UTS_RELEASE " (" LINUX_COMPILE_BY "@"
LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION;
+struct kaslr_setup_data {
+ __u64 next;
+ __u32 type;
+ __u32 len;
+ __u8 data[1];
+} kaslr_setup_data;
+
#define I8254_PORT_CONTROL 0x43
#define I8254_PORT_COUNTER0 0x40
#define I8254_CMD_READBACK 0xC0
@@ -295,7 +302,29 @@
return slots_fetch_random();
}
-unsigned char *choose_kernel_location(unsigned char *input,
+static void add_kaslr_setup_data(struct boot_params *params, __u8 enabled)
+{
+ struct setup_data *data;
+
+ kaslr_setup_data.type = SETUP_KASLR;
+ kaslr_setup_data.len = 1;
+ kaslr_setup_data.next = 0;
+ kaslr_setup_data.data[0] = enabled;
+
+ data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
+
+ while (data && data->next)
+ data = (struct setup_data *)(unsigned long)data->next;
+
+ if (data)
+ data->next = (unsigned long)&kaslr_setup_data;
+ else
+ params->hdr.setup_data = (unsigned long)&kaslr_setup_data;
+
+}
+
+unsigned char *choose_kernel_location(struct boot_params *params,
+ unsigned char *input,
unsigned long input_size,
unsigned char *output,
unsigned long output_size)
@@ -306,14 +335,17 @@
#ifdef CONFIG_HIBERNATION
if (!cmdline_find_option_bool("kaslr")) {
debug_putstr("KASLR disabled by default...\n");
+ add_kaslr_setup_data(params, 0);
goto out;
}
#else
if (cmdline_find_option_bool("nokaslr")) {
debug_putstr("KASLR disabled by cmdline...\n");
+ add_kaslr_setup_data(params, 0);
goto out;
}
#endif
+ add_kaslr_setup_data(params, 1);
/* Record the various known unsafe memory ranges. */
mem_avoid_init((unsigned long)input, input_size,
diff --git a/arch/x86/boot/compressed/efi_stub_64.S b/arch/x86/boot/compressed/efi_stub_64.S
index 7ff3632..99494df 100644
--- a/arch/x86/boot/compressed/efi_stub_64.S
+++ b/arch/x86/boot/compressed/efi_stub_64.S
@@ -3,28 +3,3 @@
#include <asm/processor-flags.h>
#include "../../platform/efi/efi_stub_64.S"
-
-#ifdef CONFIG_EFI_MIXED
- .code64
- .text
-ENTRY(efi64_thunk)
- push %rbp
- push %rbx
-
- subq $16, %rsp
- leaq efi_exit32(%rip), %rax
- movl %eax, 8(%rsp)
- leaq efi_gdt64(%rip), %rax
- movl %eax, 4(%rsp)
- movl %eax, 2(%rax) /* Fixup the gdt base address */
- leaq efi32_boot_gdt(%rip), %rax
- movl %eax, (%rsp)
-
- call __efi64_thunk
-
- addq $16, %rsp
- pop %rbx
- pop %rbp
- ret
-ENDPROC(efi64_thunk)
-#endif /* CONFIG_EFI_MIXED */
diff --git a/arch/x86/boot/compressed/efi_thunk_64.S b/arch/x86/boot/compressed/efi_thunk_64.S
new file mode 100644
index 0000000..630384a
--- /dev/null
+++ b/arch/x86/boot/compressed/efi_thunk_64.S
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2014, 2015 Intel Corporation; author Matt Fleming
+ *
+ * Early support for invoking 32-bit EFI services from a 64-bit kernel.
+ *
+ * Because this thunking occurs before ExitBootServices() we have to
+ * restore the firmware's 32-bit GDT before we make EFI serivce calls,
+ * since the firmware's 32-bit IDT is still currently installed and it
+ * needs to be able to service interrupts.
+ *
+ * On the plus side, we don't have to worry about mangling 64-bit
+ * addresses into 32-bits because we're executing with an identify
+ * mapped pagetable and haven't transitioned to 64-bit virtual addresses
+ * yet.
+ */
+
+#include <linux/linkage.h>
+#include <asm/msr.h>
+#include <asm/page_types.h>
+#include <asm/processor-flags.h>
+#include <asm/segment.h>
+
+ .code64
+ .text
+ENTRY(efi64_thunk)
+ push %rbp
+ push %rbx
+
+ subq $8, %rsp
+ leaq efi_exit32(%rip), %rax
+ movl %eax, 4(%rsp)
+ leaq efi_gdt64(%rip), %rax
+ movl %eax, (%rsp)
+ movl %eax, 2(%rax) /* Fixup the gdt base address */
+
+ movl %ds, %eax
+ push %rax
+ movl %es, %eax
+ push %rax
+ movl %ss, %eax
+ push %rax
+
+ /*
+ * Convert x86-64 ABI params to i386 ABI
+ */
+ subq $32, %rsp
+ movl %esi, 0x0(%rsp)
+ movl %edx, 0x4(%rsp)
+ movl %ecx, 0x8(%rsp)
+ movq %r8, %rsi
+ movl %esi, 0xc(%rsp)
+ movq %r9, %rsi
+ movl %esi, 0x10(%rsp)
+
+ sgdt save_gdt(%rip)
+
+ leaq 1f(%rip), %rbx
+ movq %rbx, func_rt_ptr(%rip)
+
+ /*
+ * Switch to gdt with 32-bit segments. This is the firmware GDT
+ * that was installed when the kernel started executing. This
+ * pointer was saved at the EFI stub entry point in head_64.S.
+ */
+ leaq efi32_boot_gdt(%rip), %rax
+ lgdt (%rax)
+
+ pushq $__KERNEL_CS
+ leaq efi_enter32(%rip), %rax
+ pushq %rax
+ lretq
+
+1: addq $32, %rsp
+
+ lgdt save_gdt(%rip)
+
+ pop %rbx
+ movl %ebx, %ss
+ pop %rbx
+ movl %ebx, %es
+ pop %rbx
+ movl %ebx, %ds
+
+ /*
+ * Convert 32-bit status code into 64-bit.
+ */
+ test %rax, %rax
+ jz 1f
+ movl %eax, %ecx
+ andl $0x0fffffff, %ecx
+ andl $0xf0000000, %eax
+ shl $32, %rax
+ or %rcx, %rax
+1:
+ addq $8, %rsp
+ pop %rbx
+ pop %rbp
+ ret
+ENDPROC(efi64_thunk)
+
+ENTRY(efi_exit32)
+ movq func_rt_ptr(%rip), %rax
+ push %rax
+ mov %rdi, %rax
+ ret
+ENDPROC(efi_exit32)
+
+ .code32
+/*
+ * EFI service pointer must be in %edi.
+ *
+ * The stack should represent the 32-bit calling convention.
+ */
+ENTRY(efi_enter32)
+ movl $__KERNEL_DS, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %ss
+
+ /* Reload pgtables */
+ movl %cr3, %eax
+ movl %eax, %cr3
+
+ /* Disable paging */
+ movl %cr0, %eax
+ btrl $X86_CR0_PG_BIT, %eax
+ movl %eax, %cr0
+
+ /* Disable long mode via EFER */
+ movl $MSR_EFER, %ecx
+ rdmsr
+ btrl $_EFER_LME, %eax
+ wrmsr
+
+ call *%edi
+
+ /* We must preserve return value */
+ movl %eax, %edi
+
+ /*
+ * Some firmware will return with interrupts enabled. Be sure to
+ * disable them before we switch GDTs.
+ */
+ cli
+
+ movl 56(%esp), %eax
+ movl %eax, 2(%eax)
+ lgdtl (%eax)
+
+ movl %cr4, %eax
+ btsl $(X86_CR4_PAE_BIT), %eax
+ movl %eax, %cr4
+
+ movl %cr3, %eax
+ movl %eax, %cr3
+
+ movl $MSR_EFER, %ecx
+ rdmsr
+ btsl $_EFER_LME, %eax
+ wrmsr
+
+ xorl %eax, %eax
+ lldt %ax
+
+ movl 60(%esp), %eax
+ pushl $__KERNEL_CS
+ pushl %eax
+
+ /* Enable paging */
+ movl %cr0, %eax
+ btsl $X86_CR0_PG_BIT, %eax
+ movl %eax, %cr0
+ lret
+ENDPROC(efi_enter32)
+
+ .data
+ .balign 8
+ .global efi32_boot_gdt
+efi32_boot_gdt: .word 0
+ .quad 0
+
+save_gdt: .word 0
+ .quad 0
+func_rt_ptr: .quad 0
+
+ .global efi_gdt64
+efi_gdt64:
+ .word efi_gdt64_end - efi_gdt64
+ .long 0 /* Filled out by user */
+ .word 0
+ .quad 0x0000000000000000 /* NULL descriptor */
+ .quad 0x00af9a000000ffff /* __KERNEL_CS */
+ .quad 0x00cf92000000ffff /* __KERNEL_DS */
+ .quad 0x0080890000000000 /* TS descriptor */
+ .quad 0x0000000000000000 /* TS continued */
+efi_gdt64_end:
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index a950864..5903089 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -401,7 +401,8 @@
* the entire decompressed kernel plus relocation table, or the
* entire decompressed kernel plus .bss and .brk sections.
*/
- output = choose_kernel_location(input_data, input_len, output,
+ output = choose_kernel_location(real_mode, input_data, input_len,
+ output,
output_len > run_size ? output_len
: run_size);
diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h
index 04477d6..ee3576b 100644
--- a/arch/x86/boot/compressed/misc.h
+++ b/arch/x86/boot/compressed/misc.h
@@ -57,7 +57,8 @@
#if CONFIG_RANDOMIZE_BASE
/* aslr.c */
-unsigned char *choose_kernel_location(unsigned char *input,
+unsigned char *choose_kernel_location(struct boot_params *params,
+ unsigned char *input,
unsigned long input_size,
unsigned char *output,
unsigned long output_size);
@@ -65,7 +66,8 @@
bool has_cpuflag(int flag);
#else
static inline
-unsigned char *choose_kernel_location(unsigned char *input,
+unsigned char *choose_kernel_location(struct boot_params *params,
+ unsigned char *input,
unsigned long input_size,
unsigned char *output,
unsigned long output_size)
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index 92003f3..efc3b22 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -213,7 +213,15 @@
extern void setup_boot_APIC_clock(void);
extern void setup_secondary_APIC_clock(void);
extern int APIC_init_uniprocessor(void);
+
+#ifdef CONFIG_X86_64
+static inline int apic_force_enable(unsigned long addr)
+{
+ return -1;
+}
+#else
extern int apic_force_enable(unsigned long addr);
+#endif
extern int apic_bsp_setup(bool upmode);
extern void apic_ap_setup(void);
diff --git a/arch/x86/include/asm/imr.h b/arch/x86/include/asm/imr.h
new file mode 100644
index 0000000..cd2ce40
--- /dev/null
+++ b/arch/x86/include/asm/imr.h
@@ -0,0 +1,60 @@
+/*
+ * imr.h: Isolated Memory Region API
+ *
+ * Copyright(c) 2013 Intel Corporation.
+ * Copyright(c) 2015 Bryan O'Donoghue <pure.logic@nexus-software.ie>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+#ifndef _IMR_H
+#define _IMR_H
+
+#include <linux/types.h>
+
+/*
+ * IMR agent access mask bits
+ * See section 12.7.4.7 from quark-x1000-datasheet.pdf for register
+ * definitions.
+ */
+#define IMR_ESRAM_FLUSH BIT(31)
+#define IMR_CPU_SNOOP BIT(30) /* Applicable only to write */
+#define IMR_RMU BIT(29)
+#define IMR_VC1_SAI_ID3 BIT(15)
+#define IMR_VC1_SAI_ID2 BIT(14)
+#define IMR_VC1_SAI_ID1 BIT(13)
+#define IMR_VC1_SAI_ID0 BIT(12)
+#define IMR_VC0_SAI_ID3 BIT(11)
+#define IMR_VC0_SAI_ID2 BIT(10)
+#define IMR_VC0_SAI_ID1 BIT(9)
+#define IMR_VC0_SAI_ID0 BIT(8)
+#define IMR_CPU_0 BIT(1) /* SMM mode */
+#define IMR_CPU BIT(0) /* Non SMM mode */
+#define IMR_ACCESS_NONE 0
+
+/*
+ * Read/Write access-all bits here include some reserved bits
+ * These are the values firmware uses and are accepted by hardware.
+ * The kernel defines read/write access-all in the same way as firmware
+ * in order to have a consistent and crisp definition across firmware,
+ * bootloader and kernel.
+ */
+#define IMR_READ_ACCESS_ALL 0xBFFFFFFF
+#define IMR_WRITE_ACCESS_ALL 0xFFFFFFFF
+
+/* Number of IMRs provided by Quark X1000 SoC */
+#define QUARK_X1000_IMR_MAX 0x08
+#define QUARK_X1000_IMR_REGBASE 0x40
+
+/* IMR alignment bits - only bits 31:10 are checked for IMR validity */
+#define IMR_ALIGN 0x400
+#define IMR_MASK (IMR_ALIGN - 1)
+
+int imr_add_range(phys_addr_t base, size_t size,
+ unsigned int rmask, unsigned int wmask, bool lock);
+
+int imr_remove_range(phys_addr_t base, size_t size);
+
+#endif /* _IMR_H */
diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h
index f97fbe3..95e11f7 100644
--- a/arch/x86/include/asm/page_types.h
+++ b/arch/x86/include/asm/page_types.h
@@ -51,6 +51,8 @@
extern unsigned long max_low_pfn_mapped;
extern unsigned long max_pfn_mapped;
+extern bool kaslr_enabled;
+
static inline phys_addr_t get_max_mapped(void)
{
return (phys_addr_t)max_pfn_mapped << PAGE_SHIFT;
diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h
index 7050d86..cf87de3 100644
--- a/arch/x86/include/asm/spinlock.h
+++ b/arch/x86/include/asm/spinlock.h
@@ -46,7 +46,7 @@
static inline void __ticket_enter_slowpath(arch_spinlock_t *lock)
{
- set_bit(0, (volatile unsigned long *)&lock->tickets.tail);
+ set_bit(0, (volatile unsigned long *)&lock->tickets.head);
}
#else /* !CONFIG_PARAVIRT_SPINLOCKS */
@@ -60,10 +60,30 @@
}
#endif /* CONFIG_PARAVIRT_SPINLOCKS */
+static inline int __tickets_equal(__ticket_t one, __ticket_t two)
+{
+ return !((one ^ two) & ~TICKET_SLOWPATH_FLAG);
+}
+
+static inline void __ticket_check_and_clear_slowpath(arch_spinlock_t *lock,
+ __ticket_t head)
+{
+ if (head & TICKET_SLOWPATH_FLAG) {
+ arch_spinlock_t old, new;
+
+ old.tickets.head = head;
+ new.tickets.head = head & ~TICKET_SLOWPATH_FLAG;
+ old.tickets.tail = new.tickets.head + TICKET_LOCK_INC;
+ new.tickets.tail = old.tickets.tail;
+
+ /* try to clear slowpath flag when there are no contenders */
+ cmpxchg(&lock->head_tail, old.head_tail, new.head_tail);
+ }
+}
static __always_inline int arch_spin_value_unlocked(arch_spinlock_t lock)
{
- return lock.tickets.head == lock.tickets.tail;
+ return __tickets_equal(lock.tickets.head, lock.tickets.tail);
}
/*
@@ -87,18 +107,21 @@
if (likely(inc.head == inc.tail))
goto out;
- inc.tail &= ~TICKET_SLOWPATH_FLAG;
for (;;) {
unsigned count = SPIN_THRESHOLD;
do {
- if (READ_ONCE(lock->tickets.head) == inc.tail)
- goto out;
+ inc.head = READ_ONCE(lock->tickets.head);
+ if (__tickets_equal(inc.head, inc.tail))
+ goto clear_slowpath;
cpu_relax();
} while (--count);
__ticket_lock_spinning(lock, inc.tail);
}
-out: barrier(); /* make sure nothing creeps before the lock is taken */
+clear_slowpath:
+ __ticket_check_and_clear_slowpath(lock, inc.head);
+out:
+ barrier(); /* make sure nothing creeps before the lock is taken */
}
static __always_inline int arch_spin_trylock(arch_spinlock_t *lock)
@@ -106,56 +129,30 @@
arch_spinlock_t old, new;
old.tickets = READ_ONCE(lock->tickets);
- if (old.tickets.head != (old.tickets.tail & ~TICKET_SLOWPATH_FLAG))
+ if (!__tickets_equal(old.tickets.head, old.tickets.tail))
return 0;
new.head_tail = old.head_tail + (TICKET_LOCK_INC << TICKET_SHIFT);
+ new.head_tail &= ~TICKET_SLOWPATH_FLAG;
/* cmpxchg is a full barrier, so nothing can move before it */
return cmpxchg(&lock->head_tail, old.head_tail, new.head_tail) == old.head_tail;
}
-static inline void __ticket_unlock_slowpath(arch_spinlock_t *lock,
- arch_spinlock_t old)
-{
- arch_spinlock_t new;
-
- BUILD_BUG_ON(((__ticket_t)NR_CPUS) != NR_CPUS);
-
- /* Perform the unlock on the "before" copy */
- old.tickets.head += TICKET_LOCK_INC;
-
- /* Clear the slowpath flag */
- new.head_tail = old.head_tail & ~(TICKET_SLOWPATH_FLAG << TICKET_SHIFT);
-
- /*
- * If the lock is uncontended, clear the flag - use cmpxchg in
- * case it changes behind our back though.
- */
- if (new.tickets.head != new.tickets.tail ||
- cmpxchg(&lock->head_tail, old.head_tail,
- new.head_tail) != old.head_tail) {
- /*
- * Lock still has someone queued for it, so wake up an
- * appropriate waiter.
- */
- __ticket_unlock_kick(lock, old.tickets.head);
- }
-}
-
static __always_inline void arch_spin_unlock(arch_spinlock_t *lock)
{
if (TICKET_SLOWPATH_FLAG &&
- static_key_false(¶virt_ticketlocks_enabled)) {
- arch_spinlock_t prev;
+ static_key_false(¶virt_ticketlocks_enabled)) {
+ __ticket_t head;
- prev = *lock;
- add_smp(&lock->tickets.head, TICKET_LOCK_INC);
+ BUILD_BUG_ON(((__ticket_t)NR_CPUS) != NR_CPUS);
- /* add_smp() is a full mb() */
+ head = xadd(&lock->tickets.head, TICKET_LOCK_INC);
- if (unlikely(lock->tickets.tail & TICKET_SLOWPATH_FLAG))
- __ticket_unlock_slowpath(lock, prev);
+ if (unlikely(head & TICKET_SLOWPATH_FLAG)) {
+ head &= ~TICKET_SLOWPATH_FLAG;
+ __ticket_unlock_kick(lock, (head + TICKET_LOCK_INC));
+ }
} else
__add(&lock->tickets.head, TICKET_LOCK_INC, UNLOCK_LOCK_PREFIX);
}
@@ -164,14 +161,15 @@
{
struct __raw_tickets tmp = READ_ONCE(lock->tickets);
- return tmp.tail != tmp.head;
+ return !__tickets_equal(tmp.tail, tmp.head);
}
static inline int arch_spin_is_contended(arch_spinlock_t *lock)
{
struct __raw_tickets tmp = READ_ONCE(lock->tickets);
- return (__ticket_t)(tmp.tail - tmp.head) > TICKET_LOCK_INC;
+ tmp.head &= ~TICKET_SLOWPATH_FLAG;
+ return (tmp.tail - tmp.head) > TICKET_LOCK_INC;
}
#define arch_spin_is_contended arch_spin_is_contended
@@ -191,8 +189,8 @@
* We need to check "unlocked" in a loop, tmp.head == head
* can be false positive because of overflow.
*/
- if (tmp.head == (tmp.tail & ~TICKET_SLOWPATH_FLAG) ||
- tmp.head != head)
+ if (__tickets_equal(tmp.head, tmp.tail) ||
+ !__tickets_equal(tmp.head, head))
break;
cpu_relax();
diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
index 225b098..44e6dd7 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -7,6 +7,7 @@
#define SETUP_DTB 2
#define SETUP_PCI 3
#define SETUP_EFI 4
+#define SETUP_KASLR 5
/* ram_size flags */
#define RAMDISK_IMAGE_START_MASK 0x07FF
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index ae97ed0..3d525c6 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -613,6 +613,11 @@
{
int rc, irq, trigger, polarity;
+ if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) {
+ *irqp = gsi;
+ return 0;
+ }
+
rc = acpi_get_override_irq(gsi, &trigger, &polarity);
if (rc == 0) {
trigger = trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
index c6826d1..746e7fd 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -196,6 +196,11 @@
struct microcode_header_intel mc_header;
unsigned int mc_size;
+ if (leftover < sizeof(mc_header)) {
+ pr_err("error! Truncated header in microcode data file\n");
+ break;
+ }
+
if (get_ucode_data(&mc_header, ucode_ptr, sizeof(mc_header)))
break;
diff --git a/arch/x86/kernel/cpu/microcode/intel_early.c b/arch/x86/kernel/cpu/microcode/intel_early.c
index ec9df6f..420eb93 100644
--- a/arch/x86/kernel/cpu/microcode/intel_early.c
+++ b/arch/x86/kernel/cpu/microcode/intel_early.c
@@ -321,7 +321,11 @@
unsigned int mc_saved_count = mc_saved_data->mc_saved_count;
int i;
- while (leftover) {
+ while (leftover && mc_saved_count < ARRAY_SIZE(mc_saved_tmp)) {
+
+ if (leftover < sizeof(mc_header))
+ break;
+
mc_header = (struct microcode_header_intel *)ucode_ptr;
mc_size = get_totalsize(mc_header);
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index 705ef8d..67b1cbe 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -302,6 +302,9 @@
irq = __this_cpu_read(vector_irq[vector]);
if (irq >= 0) {
desc = irq_to_desc(irq);
+ if (!desc)
+ continue;
+
data = irq_desc_get_irq_data(desc);
cpumask_copy(&affinity_new, data->affinity);
cpu_clear(this_cpu, affinity_new);
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c
index 98f654d..6a1146e 100644
--- a/arch/x86/kernel/kprobes/core.c
+++ b/arch/x86/kernel/kprobes/core.c
@@ -84,7 +84,7 @@
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
/* ---------------------------------------------- */
W(0x00, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0) | /* 00 */
- W(0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 10 */
+ W(0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1) , /* 10 */
W(0x20, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* 20 */
W(0x30, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 30 */
W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 40 */
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index 94f6434..e354cc64 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -609,7 +609,7 @@
u8 ret;
u8 old;
- old = ACCESS_ONCE(zero_stats);
+ old = READ_ONCE(zero_stats);
if (unlikely(old)) {
ret = cmpxchg(&zero_stats, old, 0);
/* This ensures only one fellow resets the stat */
@@ -727,6 +727,7 @@
int cpu;
u64 start;
unsigned long flags;
+ __ticket_t head;
if (in_nmi())
return;
@@ -768,11 +769,15 @@
*/
__ticket_enter_slowpath(lock);
+ /* make sure enter_slowpath, which is atomic does not cross the read */
+ smp_mb__after_atomic();
+
/*
* check again make sure it didn't become free while
* we weren't looking.
*/
- if (ACCESS_ONCE(lock->tickets.head) == want) {
+ head = READ_ONCE(lock->tickets.head);
+ if (__tickets_equal(head, want)) {
add_stats(TAKEN_SLOW_PICKUP, 1);
goto out;
}
@@ -803,8 +808,8 @@
add_stats(RELEASED_SLOW, 1);
for_each_cpu(cpu, &waiting_cpus) {
const struct kvm_lock_waiting *w = &per_cpu(klock_waiting, cpu);
- if (ACCESS_ONCE(w->lock) == lock &&
- ACCESS_ONCE(w->want) == ticket) {
+ if (READ_ONCE(w->lock) == lock &&
+ READ_ONCE(w->want) == ticket) {
add_stats(RELEASED_SLOW_KICKED, 1);
kvm_kick_cpu(cpu);
break;
diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c
index d1ac80b..9bbb9b3 100644
--- a/arch/x86/kernel/module.c
+++ b/arch/x86/kernel/module.c
@@ -47,21 +47,13 @@
#ifdef CONFIG_RANDOMIZE_BASE
static unsigned long module_load_offset;
-static int randomize_modules = 1;
/* Mutex protects the module_load_offset. */
static DEFINE_MUTEX(module_kaslr_mutex);
-static int __init parse_nokaslr(char *p)
-{
- randomize_modules = 0;
- return 0;
-}
-early_param("nokaslr", parse_nokaslr);
-
static unsigned long int get_module_load_offset(void)
{
- if (randomize_modules) {
+ if (kaslr_enabled) {
mutex_lock(&module_kaslr_mutex);
/*
* Calculate the module_load_offset the first time this
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 0a2421c..98dc931 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -122,6 +122,8 @@
unsigned long max_low_pfn_mapped;
unsigned long max_pfn_mapped;
+bool __read_mostly kaslr_enabled = false;
+
#ifdef CONFIG_DMI
RESERVE_BRK(dmi_alloc, 65536);
#endif
@@ -425,6 +427,11 @@
}
#endif /* CONFIG_BLK_DEV_INITRD */
+static void __init parse_kaslr_setup(u64 pa_data, u32 data_len)
+{
+ kaslr_enabled = (bool)(pa_data + sizeof(struct setup_data));
+}
+
static void __init parse_setup_data(void)
{
struct setup_data *data;
@@ -450,6 +457,9 @@
case SETUP_EFI:
parse_efi_setup(pa_data, data_len);
break;
+ case SETUP_KASLR:
+ parse_kaslr_setup(pa_data, data_len);
+ break;
default:
break;
}
@@ -832,10 +842,14 @@
static int
dump_kernel_offset(struct notifier_block *self, unsigned long v, void *p)
{
- pr_emerg("Kernel Offset: 0x%lx from 0x%lx "
- "(relocation range: 0x%lx-0x%lx)\n",
- (unsigned long)&_text - __START_KERNEL, __START_KERNEL,
- __START_KERNEL_map, MODULES_VADDR-1);
+ if (kaslr_enabled)
+ pr_emerg("Kernel Offset: 0x%lx from 0x%lx (relocation range: 0x%lx-0x%lx)\n",
+ (unsigned long)&_text - __START_KERNEL,
+ __START_KERNEL,
+ __START_KERNEL_map,
+ MODULES_VADDR-1);
+ else
+ pr_emerg("Kernel Offset: disabled\n");
return 0;
}
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
index 8b96a947..81f8adb0 100644
--- a/arch/x86/kernel/uprobes.c
+++ b/arch/x86/kernel/uprobes.c
@@ -66,27 +66,54 @@
* Good-instruction tables for 32-bit apps. This is non-const and volatile
* to keep gcc from statically optimizing it out, as variable_test_bit makes
* some versions of gcc to think only *(unsigned long*) is used.
+ *
+ * Opcodes we'll probably never support:
+ * 6c-6f - ins,outs. SEGVs if used in userspace
+ * e4-e7 - in,out imm. SEGVs if used in userspace
+ * ec-ef - in,out acc. SEGVs if used in userspace
+ * cc - int3. SIGTRAP if used in userspace
+ * ce - into. Not used in userspace - no kernel support to make it useful. SEGVs
+ * (why we support bound (62) then? it's similar, and similarly unused...)
+ * f1 - int1. SIGTRAP if used in userspace
+ * f4 - hlt. SEGVs if used in userspace
+ * fa - cli. SEGVs if used in userspace
+ * fb - sti. SEGVs if used in userspace
+ *
+ * Opcodes which need some work to be supported:
+ * 07,17,1f - pop es/ss/ds
+ * Normally not used in userspace, but would execute if used.
+ * Can cause GP or stack exception if tries to load wrong segment descriptor.
+ * We hesitate to run them under single step since kernel's handling
+ * of userspace single-stepping (TF flag) is fragile.
+ * We can easily refuse to support push es/cs/ss/ds (06/0e/16/1e)
+ * on the same grounds that they are never used.
+ * cd - int N.
+ * Used by userspace for "int 80" syscall entry. (Other "int N"
+ * cause GP -> SEGV since their IDT gates don't allow calls from CPL 3).
+ * Not supported since kernel's handling of userspace single-stepping
+ * (TF flag) is fragile.
+ * cf - iret. Normally not used in userspace. Doesn't SEGV unless arguments are bad
*/
#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
static volatile u32 good_insns_32[256 / 32] = {
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
/* ---------------------------------------------- */
- W(0x00, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0) | /* 00 */
+ W(0x00, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1) | /* 00 */
W(0x10, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0) , /* 10 */
- W(0x20, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1) | /* 20 */
- W(0x30, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1) , /* 30 */
+ W(0x20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 20 */
+ W(0x30, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 30 */
W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 40 */
W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 50 */
- W(0x60, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* 60 */
+ W(0x60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0) | /* 60 */
W(0x70, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 70 */
W(0x80, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 80 */
W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 90 */
W(0xa0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* a0 */
W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* b0 */
W(0xc0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0) | /* c0 */
- W(0xd0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */
+ W(0xd0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */
W(0xe0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* e0 */
- W(0xf0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1) /* f0 */
+ W(0xf0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1) /* f0 */
/* ---------------------------------------------- */
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
};
@@ -94,27 +121,61 @@
#define good_insns_32 NULL
#endif
-/* Good-instruction tables for 64-bit apps */
+/* Good-instruction tables for 64-bit apps.
+ *
+ * Genuinely invalid opcodes:
+ * 06,07 - formerly push/pop es
+ * 0e - formerly push cs
+ * 16,17 - formerly push/pop ss
+ * 1e,1f - formerly push/pop ds
+ * 27,2f,37,3f - formerly daa/das/aaa/aas
+ * 60,61 - formerly pusha/popa
+ * 62 - formerly bound. EVEX prefix for AVX512 (not yet supported)
+ * 82 - formerly redundant encoding of Group1
+ * 9a - formerly call seg:ofs
+ * ce - formerly into
+ * d4,d5 - formerly aam/aad
+ * d6 - formerly undocumented salc
+ * ea - formerly jmp seg:ofs
+ *
+ * Opcodes we'll probably never support:
+ * 6c-6f - ins,outs. SEGVs if used in userspace
+ * e4-e7 - in,out imm. SEGVs if used in userspace
+ * ec-ef - in,out acc. SEGVs if used in userspace
+ * cc - int3. SIGTRAP if used in userspace
+ * f1 - int1. SIGTRAP if used in userspace
+ * f4 - hlt. SEGVs if used in userspace
+ * fa - cli. SEGVs if used in userspace
+ * fb - sti. SEGVs if used in userspace
+ *
+ * Opcodes which need some work to be supported:
+ * cd - int N.
+ * Used by userspace for "int 80" syscall entry. (Other "int N"
+ * cause GP -> SEGV since their IDT gates don't allow calls from CPL 3).
+ * Not supported since kernel's handling of userspace single-stepping
+ * (TF flag) is fragile.
+ * cf - iret. Normally not used in userspace. Doesn't SEGV unless arguments are bad
+ */
#if defined(CONFIG_X86_64)
static volatile u32 good_insns_64[256 / 32] = {
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
/* ---------------------------------------------- */
- W(0x00, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) | /* 00 */
+ W(0x00, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1) | /* 00 */
W(0x10, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) , /* 10 */
- W(0x20, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) | /* 20 */
- W(0x30, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) , /* 30 */
- W(0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* 40 */
+ W(0x20, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0) | /* 20 */
+ W(0x30, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0) , /* 30 */
+ W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 40 */
W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 50 */
- W(0x60, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* 60 */
+ W(0x60, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0) | /* 60 */
W(0x70, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 70 */
W(0x80, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 80 */
- W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 90 */
+ W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1) , /* 90 */
W(0xa0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* a0 */
W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* b0 */
- W(0xc0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0) | /* c0 */
+ W(0xc0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0) | /* c0 */
W(0xd0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */
- W(0xe0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* e0 */
- W(0xf0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1) /* f0 */
+ W(0xe0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0) | /* e0 */
+ W(0xf0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1) /* f0 */
/* ---------------------------------------------- */
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
};
@@ -122,49 +183,55 @@
#define good_insns_64 NULL
#endif
-/* Using this for both 64-bit and 32-bit apps */
+/* Using this for both 64-bit and 32-bit apps.
+ * Opcodes we don't support:
+ * 0f 00 - SLDT/STR/LLDT/LTR/VERR/VERW/-/- group. System insns
+ * 0f 01 - SGDT/SIDT/LGDT/LIDT/SMSW/-/LMSW/INVLPG group.
+ * Also encodes tons of other system insns if mod=11.
+ * Some are in fact non-system: xend, xtest, rdtscp, maybe more
+ * 0f 05 - syscall
+ * 0f 06 - clts (CPL0 insn)
+ * 0f 07 - sysret
+ * 0f 08 - invd (CPL0 insn)
+ * 0f 09 - wbinvd (CPL0 insn)
+ * 0f 0b - ud2
+ * 0f 30 - wrmsr (CPL0 insn) (then why rdmsr is allowed, it's also CPL0 insn?)
+ * 0f 34 - sysenter
+ * 0f 35 - sysexit
+ * 0f 37 - getsec
+ * 0f 78 - vmread (Intel VMX. CPL0 insn)
+ * 0f 79 - vmwrite (Intel VMX. CPL0 insn)
+ * Note: with prefixes, these two opcodes are
+ * extrq/insertq/AVX512 convert vector ops.
+ * 0f ae - group15: [f]xsave,[f]xrstor,[v]{ld,st}mxcsr,clflush[opt],
+ * {rd,wr}{fs,gs}base,{s,l,m}fence.
+ * Why? They are all user-executable.
+ */
static volatile u32 good_2byte_insns[256 / 32] = {
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
/* ---------------------------------------------- */
- W(0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1) | /* 00 */
- W(0x10, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1) , /* 10 */
- W(0x20, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1) | /* 20 */
- W(0x30, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 30 */
+ W(0x00, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1) | /* 00 */
+ W(0x10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 10 */
+ W(0x20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 20 */
+ W(0x30, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1) , /* 30 */
W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 40 */
W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 50 */
W(0x60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 60 */
- W(0x70, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1) , /* 70 */
+ W(0x70, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1) , /* 70 */
W(0x80, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 80 */
W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 90 */
- W(0xa0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1) | /* a0 */
- W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1) , /* b0 */
+ W(0xa0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1) | /* a0 */
+ W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* b0 */
W(0xc0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* c0 */
- W(0xd0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */
+ W(0xd0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */
W(0xe0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* e0 */
- W(0xf0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) /* f0 */
+ W(0xf0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) /* f0 */
/* ---------------------------------------------- */
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
};
#undef W
/*
- * opcodes we'll probably never support:
- *
- * 6c-6d, e4-e5, ec-ed - in
- * 6e-6f, e6-e7, ee-ef - out
- * cc, cd - int3, int
- * cf - iret
- * d6 - illegal instruction
- * f1 - int1/icebp
- * f4 - hlt
- * fa, fb - cli, sti
- * 0f - lar, lsl, syscall, clts, sysret, sysenter, sysexit, invd, wbinvd, ud2
- *
- * invalid opcodes in 64-bit mode:
- *
- * 06, 0e, 16, 1e, 27, 2f, 37, 3f, 60-62, 82, c4-c5, d4-d5
- * 63 - we support this opcode in x86_64 but not in i386.
- *
* opcodes we may need to refine support for:
*
* 0f - 2-byte instructions: For many of these instructions, the validity
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index 553c094..a110efc 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -238,6 +238,31 @@
}
}
+static const char *page_size_string(struct map_range *mr)
+{
+ static const char str_1g[] = "1G";
+ static const char str_2m[] = "2M";
+ static const char str_4m[] = "4M";
+ static const char str_4k[] = "4k";
+
+ if (mr->page_size_mask & (1<<PG_LEVEL_1G))
+ return str_1g;
+ /*
+ * 32-bit without PAE has a 4M large page size.
+ * PG_LEVEL_2M is misnamed, but we can at least
+ * print out the right size in the string.
+ */
+ if (IS_ENABLED(CONFIG_X86_32) &&
+ !IS_ENABLED(CONFIG_X86_PAE) &&
+ mr->page_size_mask & (1<<PG_LEVEL_2M))
+ return str_4m;
+
+ if (mr->page_size_mask & (1<<PG_LEVEL_2M))
+ return str_2m;
+
+ return str_4k;
+}
+
static int __meminit split_mem_range(struct map_range *mr, int nr_range,
unsigned long start,
unsigned long end)
@@ -333,8 +358,7 @@
for (i = 0; i < nr_range; i++)
printk(KERN_DEBUG " [mem %#010lx-%#010lx] page %s\n",
mr[i].start, mr[i].end - 1,
- (mr[i].page_size_mask & (1<<PG_LEVEL_1G))?"1G":(
- (mr[i].page_size_mask & (1<<PG_LEVEL_2M))?"2M":"4k"));
+ page_size_string(&mr[i]));
return nr_range;
}
diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c
index 919b912..df4552b 100644
--- a/arch/x86/mm/mmap.c
+++ b/arch/x86/mm/mmap.c
@@ -35,12 +35,12 @@
.flags = -1,
};
-static unsigned int stack_maxrandom_size(void)
+static unsigned long stack_maxrandom_size(void)
{
- unsigned int max = 0;
+ unsigned long max = 0;
if ((current->flags & PF_RANDOMIZE) &&
!(current->personality & ADDR_NO_RANDOMIZE)) {
- max = ((-1U) & STACK_RND_MASK) << PAGE_SHIFT;
+ max = ((-1UL) & STACK_RND_MASK) << PAGE_SHIFT;
}
return max;
diff --git a/arch/x86/platform/Makefile b/arch/x86/platform/Makefile
index 85afde1..a62e0be 100644
--- a/arch/x86/platform/Makefile
+++ b/arch/x86/platform/Makefile
@@ -5,6 +5,7 @@
obj-y += goldfish/
obj-y += iris/
obj-y += intel-mid/
+obj-y += intel-quark/
obj-y += olpc/
obj-y += scx200/
obj-y += sfi/
diff --git a/arch/x86/platform/efi/efi_stub_64.S b/arch/x86/platform/efi/efi_stub_64.S
index 5fcda72..86d0f9e 100644
--- a/arch/x86/platform/efi/efi_stub_64.S
+++ b/arch/x86/platform/efi/efi_stub_64.S
@@ -91,167 +91,6 @@
ret
ENDPROC(efi_call)
-#ifdef CONFIG_EFI_MIXED
-
-/*
- * We run this function from the 1:1 mapping.
- *
- * This function must be invoked with a 1:1 mapped stack.
- */
-ENTRY(__efi64_thunk)
- movl %ds, %eax
- push %rax
- movl %es, %eax
- push %rax
- movl %ss, %eax
- push %rax
-
- subq $32, %rsp
- movl %esi, 0x0(%rsp)
- movl %edx, 0x4(%rsp)
- movl %ecx, 0x8(%rsp)
- movq %r8, %rsi
- movl %esi, 0xc(%rsp)
- movq %r9, %rsi
- movl %esi, 0x10(%rsp)
-
- sgdt save_gdt(%rip)
-
- leaq 1f(%rip), %rbx
- movq %rbx, func_rt_ptr(%rip)
-
- /* Switch to gdt with 32-bit segments */
- movl 64(%rsp), %eax
- lgdt (%rax)
-
- leaq efi_enter32(%rip), %rax
- pushq $__KERNEL_CS
- pushq %rax
- lretq
-
-1: addq $32, %rsp
-
- lgdt save_gdt(%rip)
-
- pop %rbx
- movl %ebx, %ss
- pop %rbx
- movl %ebx, %es
- pop %rbx
- movl %ebx, %ds
-
- /*
- * Convert 32-bit status code into 64-bit.
- */
- test %rax, %rax
- jz 1f
- movl %eax, %ecx
- andl $0x0fffffff, %ecx
- andl $0xf0000000, %eax
- shl $32, %rax
- or %rcx, %rax
-1:
- ret
-ENDPROC(__efi64_thunk)
-
-ENTRY(efi_exit32)
- movq func_rt_ptr(%rip), %rax
- push %rax
- mov %rdi, %rax
- ret
-ENDPROC(efi_exit32)
-
- .code32
-/*
- * EFI service pointer must be in %edi.
- *
- * The stack should represent the 32-bit calling convention.
- */
-ENTRY(efi_enter32)
- movl $__KERNEL_DS, %eax
- movl %eax, %ds
- movl %eax, %es
- movl %eax, %ss
-
- /* Reload pgtables */
- movl %cr3, %eax
- movl %eax, %cr3
-
- /* Disable paging */
- movl %cr0, %eax
- btrl $X86_CR0_PG_BIT, %eax
- movl %eax, %cr0
-
- /* Disable long mode via EFER */
- movl $MSR_EFER, %ecx
- rdmsr
- btrl $_EFER_LME, %eax
- wrmsr
-
- call *%edi
-
- /* We must preserve return value */
- movl %eax, %edi
-
- /*
- * Some firmware will return with interrupts enabled. Be sure to
- * disable them before we switch GDTs.
- */
- cli
-
- movl 68(%esp), %eax
- movl %eax, 2(%eax)
- lgdtl (%eax)
-
- movl %cr4, %eax
- btsl $(X86_CR4_PAE_BIT), %eax
- movl %eax, %cr4
-
- movl %cr3, %eax
- movl %eax, %cr3
-
- movl $MSR_EFER, %ecx
- rdmsr
- btsl $_EFER_LME, %eax
- wrmsr
-
- xorl %eax, %eax
- lldt %ax
-
- movl 72(%esp), %eax
- pushl $__KERNEL_CS
- pushl %eax
-
- /* Enable paging */
- movl %cr0, %eax
- btsl $X86_CR0_PG_BIT, %eax
- movl %eax, %cr0
- lret
-ENDPROC(efi_enter32)
-
- .data
- .balign 8
- .global efi32_boot_gdt
-efi32_boot_gdt: .word 0
- .quad 0
-
-save_gdt: .word 0
- .quad 0
-func_rt_ptr: .quad 0
-
- .global efi_gdt64
-efi_gdt64:
- .word efi_gdt64_end - efi_gdt64
- .long 0 /* Filled out by user */
- .word 0
- .quad 0x0000000000000000 /* NULL descriptor */
- .quad 0x00af9a000000ffff /* __KERNEL_CS */
- .quad 0x00cf92000000ffff /* __KERNEL_DS */
- .quad 0x0080890000000000 /* TS descriptor */
- .quad 0x0000000000000000 /* TS continued */
-efi_gdt64_end:
-#endif /* CONFIG_EFI_MIXED */
-
.data
ENTRY(efi_scratch)
.fill 3,8,0
diff --git a/arch/x86/platform/efi/efi_thunk_64.S b/arch/x86/platform/efi/efi_thunk_64.S
index 8806fa7..ff85d28 100644
--- a/arch/x86/platform/efi/efi_thunk_64.S
+++ b/arch/x86/platform/efi/efi_thunk_64.S
@@ -1,9 +1,26 @@
/*
* Copyright (C) 2014 Intel Corporation; author Matt Fleming
+ *
+ * Support for invoking 32-bit EFI runtime services from a 64-bit
+ * kernel.
+ *
+ * The below thunking functions are only used after ExitBootServices()
+ * has been called. This simplifies things considerably as compared with
+ * the early EFI thunking because we can leave all the kernel state
+ * intact (GDT, IDT, etc) and simply invoke the the 32-bit EFI runtime
+ * services from __KERNEL32_CS. This means we can continue to service
+ * interrupts across an EFI mixed mode call.
+ *
+ * We do however, need to handle the fact that we're running in a full
+ * 64-bit virtual address space. Things like the stack and instruction
+ * addresses need to be accessible by the 32-bit firmware, so we rely on
+ * using the identity mappings in the EFI page table to access the stack
+ * and kernel text (see efi_setup_page_tables()).
*/
#include <linux/linkage.h>
#include <asm/page_types.h>
+#include <asm/segment.h>
.text
.code64
@@ -33,14 +50,6 @@
leaq efi_exit32(%rip), %rbx
subq %rax, %rbx
movl %ebx, 8(%rsp)
- leaq efi_gdt64(%rip), %rbx
- subq %rax, %rbx
- movl %ebx, 2(%ebx)
- movl %ebx, 4(%rsp)
- leaq efi_gdt32(%rip), %rbx
- subq %rax, %rbx
- movl %ebx, 2(%ebx)
- movl %ebx, (%rsp)
leaq __efi64_thunk(%rip), %rbx
subq %rax, %rbx
@@ -52,14 +61,92 @@
retq
ENDPROC(efi64_thunk)
- .data
-efi_gdt32:
- .word efi_gdt32_end - efi_gdt32
- .long 0 /* Filled out above */
- .word 0
- .quad 0x0000000000000000 /* NULL descriptor */
- .quad 0x00cf9a000000ffff /* __KERNEL_CS */
- .quad 0x00cf93000000ffff /* __KERNEL_DS */
-efi_gdt32_end:
+/*
+ * We run this function from the 1:1 mapping.
+ *
+ * This function must be invoked with a 1:1 mapped stack.
+ */
+ENTRY(__efi64_thunk)
+ movl %ds, %eax
+ push %rax
+ movl %es, %eax
+ push %rax
+ movl %ss, %eax
+ push %rax
+ subq $32, %rsp
+ movl %esi, 0x0(%rsp)
+ movl %edx, 0x4(%rsp)
+ movl %ecx, 0x8(%rsp)
+ movq %r8, %rsi
+ movl %esi, 0xc(%rsp)
+ movq %r9, %rsi
+ movl %esi, 0x10(%rsp)
+
+ leaq 1f(%rip), %rbx
+ movq %rbx, func_rt_ptr(%rip)
+
+ /* Switch to 32-bit descriptor */
+ pushq $__KERNEL32_CS
+ leaq efi_enter32(%rip), %rax
+ pushq %rax
+ lretq
+
+1: addq $32, %rsp
+
+ pop %rbx
+ movl %ebx, %ss
+ pop %rbx
+ movl %ebx, %es
+ pop %rbx
+ movl %ebx, %ds
+
+ /*
+ * Convert 32-bit status code into 64-bit.
+ */
+ test %rax, %rax
+ jz 1f
+ movl %eax, %ecx
+ andl $0x0fffffff, %ecx
+ andl $0xf0000000, %eax
+ shl $32, %rax
+ or %rcx, %rax
+1:
+ ret
+ENDPROC(__efi64_thunk)
+
+ENTRY(efi_exit32)
+ movq func_rt_ptr(%rip), %rax
+ push %rax
+ mov %rdi, %rax
+ ret
+ENDPROC(efi_exit32)
+
+ .code32
+/*
+ * EFI service pointer must be in %edi.
+ *
+ * The stack should represent the 32-bit calling convention.
+ */
+ENTRY(efi_enter32)
+ movl $__KERNEL_DS, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %ss
+
+ call *%edi
+
+ /* We must preserve return value */
+ movl %eax, %edi
+
+ movl 72(%esp), %eax
+ pushl $__KERNEL_CS
+ pushl %eax
+
+ lret
+ENDPROC(efi_enter32)
+
+ .data
+ .balign 8
+func_rt_ptr: .quad 0
efi_saved_sp: .quad 0
diff --git a/arch/x86/platform/intel-quark/Makefile b/arch/x86/platform/intel-quark/Makefile
new file mode 100644
index 0000000..9cc57ed
--- /dev/null
+++ b/arch/x86/platform/intel-quark/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_INTEL_IMR) += imr.o
+obj-$(CONFIG_DEBUG_IMR_SELFTEST) += imr_selftest.o
diff --git a/arch/x86/platform/intel-quark/imr.c b/arch/x86/platform/intel-quark/imr.c
new file mode 100644
index 0000000..0ee619f
--- /dev/null
+++ b/arch/x86/platform/intel-quark/imr.c
@@ -0,0 +1,661 @@
+/**
+ * imr.c
+ *
+ * Copyright(c) 2013 Intel Corporation.
+ * Copyright(c) 2015 Bryan O'Donoghue <pure.logic@nexus-software.ie>
+ *
+ * IMR registers define an isolated region of memory that can
+ * be masked to prohibit certain system agents from accessing memory.
+ * When a device behind a masked port performs an access - snooped or
+ * not, an IMR may optionally prevent that transaction from changing
+ * the state of memory or from getting correct data in response to the
+ * operation.
+ *
+ * Write data will be dropped and reads will return 0xFFFFFFFF, the
+ * system will reset and system BIOS will print out an error message to
+ * inform the user that an IMR has been violated.
+ *
+ * This code is based on the Linux MTRR code and reference code from
+ * Intel's Quark BSP EFI, Linux and grub code.
+ *
+ * See quark-x1000-datasheet.pdf for register definitions.
+ * http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/quark-x1000-datasheet.pdf
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <asm-generic/sections.h>
+#include <asm/cpu_device_id.h>
+#include <asm/imr.h>
+#include <asm/iosf_mbi.h>
+#include <linux/debugfs.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+struct imr_device {
+ struct dentry *file;
+ bool init;
+ struct mutex lock;
+ int max_imr;
+ int reg_base;
+};
+
+static struct imr_device imr_dev;
+
+/*
+ * IMR read/write mask control registers.
+ * See quark-x1000-datasheet.pdf sections 12.7.4.5 and 12.7.4.6 for
+ * bit definitions.
+ *
+ * addr_hi
+ * 31 Lock bit
+ * 30:24 Reserved
+ * 23:2 1 KiB aligned lo address
+ * 1:0 Reserved
+ *
+ * addr_hi
+ * 31:24 Reserved
+ * 23:2 1 KiB aligned hi address
+ * 1:0 Reserved
+ */
+#define IMR_LOCK BIT(31)
+
+struct imr_regs {
+ u32 addr_lo;
+ u32 addr_hi;
+ u32 rmask;
+ u32 wmask;
+};
+
+#define IMR_NUM_REGS (sizeof(struct imr_regs)/sizeof(u32))
+#define IMR_SHIFT 8
+#define imr_to_phys(x) ((x) << IMR_SHIFT)
+#define phys_to_imr(x) ((x) >> IMR_SHIFT)
+
+/**
+ * imr_is_enabled - true if an IMR is enabled false otherwise.
+ *
+ * Determines if an IMR is enabled based on address range and read/write
+ * mask. An IMR set with an address range set to zero and a read/write
+ * access mask set to all is considered to be disabled. An IMR in any
+ * other state - for example set to zero but without read/write access
+ * all is considered to be enabled. This definition of disabled is how
+ * firmware switches off an IMR and is maintained in kernel for
+ * consistency.
+ *
+ * @imr: pointer to IMR descriptor.
+ * @return: true if IMR enabled false if disabled.
+ */
+static inline int imr_is_enabled(struct imr_regs *imr)
+{
+ return !(imr->rmask == IMR_READ_ACCESS_ALL &&
+ imr->wmask == IMR_WRITE_ACCESS_ALL &&
+ imr_to_phys(imr->addr_lo) == 0 &&
+ imr_to_phys(imr->addr_hi) == 0);
+}
+
+/**
+ * imr_read - read an IMR at a given index.
+ *
+ * Requires caller to hold imr mutex.
+ *
+ * @idev: pointer to imr_device structure.
+ * @imr_id: IMR entry to read.
+ * @imr: IMR structure representing address and access masks.
+ * @return: 0 on success or error code passed from mbi_iosf on failure.
+ */
+static int imr_read(struct imr_device *idev, u32 imr_id, struct imr_regs *imr)
+{
+ u32 reg = imr_id * IMR_NUM_REGS + idev->reg_base;
+ int ret;
+
+ ret = iosf_mbi_read(QRK_MBI_UNIT_MM, QRK_MBI_MM_READ,
+ reg++, &imr->addr_lo);
+ if (ret)
+ return ret;
+
+ ret = iosf_mbi_read(QRK_MBI_UNIT_MM, QRK_MBI_MM_READ,
+ reg++, &imr->addr_hi);
+ if (ret)
+ return ret;
+
+ ret = iosf_mbi_read(QRK_MBI_UNIT_MM, QRK_MBI_MM_READ,
+ reg++, &imr->rmask);
+ if (ret)
+ return ret;
+
+ return iosf_mbi_read(QRK_MBI_UNIT_MM, QRK_MBI_MM_READ,
+ reg++, &imr->wmask);
+}
+
+/**
+ * imr_write - write an IMR at a given index.
+ *
+ * Requires caller to hold imr mutex.
+ * Note lock bits need to be written independently of address bits.
+ *
+ * @idev: pointer to imr_device structure.
+ * @imr_id: IMR entry to write.
+ * @imr: IMR structure representing address and access masks.
+ * @lock: indicates if the IMR lock bit should be applied.
+ * @return: 0 on success or error code passed from mbi_iosf on failure.
+ */
+static int imr_write(struct imr_device *idev, u32 imr_id,
+ struct imr_regs *imr, bool lock)
+{
+ unsigned long flags;
+ u32 reg = imr_id * IMR_NUM_REGS + idev->reg_base;
+ int ret;
+
+ local_irq_save(flags);
+
+ ret = iosf_mbi_write(QRK_MBI_UNIT_MM, QRK_MBI_MM_WRITE, reg++,
+ imr->addr_lo);
+ if (ret)
+ goto failed;
+
+ ret = iosf_mbi_write(QRK_MBI_UNIT_MM, QRK_MBI_MM_WRITE,
+ reg++, imr->addr_hi);
+ if (ret)
+ goto failed;
+
+ ret = iosf_mbi_write(QRK_MBI_UNIT_MM, QRK_MBI_MM_WRITE,
+ reg++, imr->rmask);
+ if (ret)
+ goto failed;
+
+ ret = iosf_mbi_write(QRK_MBI_UNIT_MM, QRK_MBI_MM_WRITE,
+ reg++, imr->wmask);
+ if (ret)
+ goto failed;
+
+ /* Lock bit must be set separately to addr_lo address bits. */
+ if (lock) {
+ imr->addr_lo |= IMR_LOCK;
+ ret = iosf_mbi_write(QRK_MBI_UNIT_MM, QRK_MBI_MM_WRITE,
+ reg - IMR_NUM_REGS, imr->addr_lo);
+ if (ret)
+ goto failed;
+ }
+
+ local_irq_restore(flags);
+ return 0;
+failed:
+ /*
+ * If writing to the IOSF failed then we're in an unknown state,
+ * likely a very bad state. An IMR in an invalid state will almost
+ * certainly lead to a memory access violation.
+ */
+ local_irq_restore(flags);
+ WARN(ret, "IOSF-MBI write fail range 0x%08x-0x%08x unreliable\n",
+ imr_to_phys(imr->addr_lo), imr_to_phys(imr->addr_hi) + IMR_MASK);
+
+ return ret;
+}
+
+/**
+ * imr_dbgfs_state_show - print state of IMR registers.
+ *
+ * @s: pointer to seq_file for output.
+ * @unused: unused parameter.
+ * @return: 0 on success or error code passed from mbi_iosf on failure.
+ */
+static int imr_dbgfs_state_show(struct seq_file *s, void *unused)
+{
+ phys_addr_t base;
+ phys_addr_t end;
+ int i;
+ struct imr_device *idev = s->private;
+ struct imr_regs imr;
+ size_t size;
+ int ret = -ENODEV;
+
+ mutex_lock(&idev->lock);
+
+ for (i = 0; i < idev->max_imr; i++) {
+
+ ret = imr_read(idev, i, &imr);
+ if (ret)
+ break;
+
+ /*
+ * Remember to add IMR_ALIGN bytes to size to indicate the
+ * inherent IMR_ALIGN size bytes contained in the masked away
+ * lower ten bits.
+ */
+ if (imr_is_enabled(&imr)) {
+ base = imr_to_phys(imr.addr_lo);
+ end = imr_to_phys(imr.addr_hi) + IMR_MASK;
+ } else {
+ base = 0;
+ end = 0;
+ }
+ size = end - base;
+ seq_printf(s, "imr%02i: base=%pa, end=%pa, size=0x%08zx "
+ "rmask=0x%08x, wmask=0x%08x, %s, %s\n", i,
+ &base, &end, size, imr.rmask, imr.wmask,
+ imr_is_enabled(&imr) ? "enabled " : "disabled",
+ imr.addr_lo & IMR_LOCK ? "locked" : "unlocked");
+ }
+
+ mutex_unlock(&idev->lock);
+ return ret;
+}
+
+/**
+ * imr_state_open - debugfs open callback.
+ *
+ * @inode: pointer to struct inode.
+ * @file: pointer to struct file.
+ * @return: result of single open.
+ */
+static int imr_state_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, imr_dbgfs_state_show, inode->i_private);
+}
+
+static const struct file_operations imr_state_ops = {
+ .open = imr_state_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+/**
+ * imr_debugfs_register - register debugfs hooks.
+ *
+ * @idev: pointer to imr_device structure.
+ * @return: 0 on success - errno on failure.
+ */
+static int imr_debugfs_register(struct imr_device *idev)
+{
+ idev->file = debugfs_create_file("imr_state", S_IFREG | S_IRUGO, NULL,
+ idev, &imr_state_ops);
+ return PTR_ERR_OR_ZERO(idev->file);
+}
+
+/**
+ * imr_debugfs_unregister - unregister debugfs hooks.
+ *
+ * @idev: pointer to imr_device structure.
+ * @return:
+ */
+static void imr_debugfs_unregister(struct imr_device *idev)
+{
+ debugfs_remove(idev->file);
+}
+
+/**
+ * imr_check_params - check passed address range IMR alignment and non-zero size
+ *
+ * @base: base address of intended IMR.
+ * @size: size of intended IMR.
+ * @return: zero on valid range -EINVAL on unaligned base/size.
+ */
+static int imr_check_params(phys_addr_t base, size_t size)
+{
+ if ((base & IMR_MASK) || (size & IMR_MASK)) {
+ pr_err("base %pa size 0x%08zx must align to 1KiB\n",
+ &base, size);
+ return -EINVAL;
+ }
+ if (size == 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * imr_raw_size - account for the IMR_ALIGN bytes that addr_hi appends.
+ *
+ * IMR addr_hi has a built in offset of plus IMR_ALIGN (0x400) bytes from the
+ * value in the register. We need to subtract IMR_ALIGN bytes from input sizes
+ * as a result.
+ *
+ * @size: input size bytes.
+ * @return: reduced size.
+ */
+static inline size_t imr_raw_size(size_t size)
+{
+ return size - IMR_ALIGN;
+}
+
+/**
+ * imr_address_overlap - detects an address overlap.
+ *
+ * @addr: address to check against an existing IMR.
+ * @imr: imr being checked.
+ * @return: true for overlap false for no overlap.
+ */
+static inline int imr_address_overlap(phys_addr_t addr, struct imr_regs *imr)
+{
+ return addr >= imr_to_phys(imr->addr_lo) && addr <= imr_to_phys(imr->addr_hi);
+}
+
+/**
+ * imr_add_range - add an Isolated Memory Region.
+ *
+ * @base: physical base address of region aligned to 1KiB.
+ * @size: physical size of region in bytes must be aligned to 1KiB.
+ * @read_mask: read access mask.
+ * @write_mask: write access mask.
+ * @lock: indicates whether or not to permanently lock this region.
+ * @return: zero on success or negative value indicating error.
+ */
+int imr_add_range(phys_addr_t base, size_t size,
+ unsigned int rmask, unsigned int wmask, bool lock)
+{
+ phys_addr_t end;
+ unsigned int i;
+ struct imr_device *idev = &imr_dev;
+ struct imr_regs imr;
+ size_t raw_size;
+ int reg;
+ int ret;
+
+ if (WARN_ONCE(idev->init == false, "driver not initialized"))
+ return -ENODEV;
+
+ ret = imr_check_params(base, size);
+ if (ret)
+ return ret;
+
+ /* Tweak the size value. */
+ raw_size = imr_raw_size(size);
+ end = base + raw_size;
+
+ /*
+ * Check for reserved IMR value common to firmware, kernel and grub
+ * indicating a disabled IMR.
+ */
+ imr.addr_lo = phys_to_imr(base);
+ imr.addr_hi = phys_to_imr(end);
+ imr.rmask = rmask;
+ imr.wmask = wmask;
+ if (!imr_is_enabled(&imr))
+ return -ENOTSUPP;
+
+ mutex_lock(&idev->lock);
+
+ /*
+ * Find a free IMR while checking for an existing overlapping range.
+ * Note there's no restriction in silicon to prevent IMR overlaps.
+ * For the sake of simplicity and ease in defining/debugging an IMR
+ * memory map we exclude IMR overlaps.
+ */
+ reg = -1;
+ for (i = 0; i < idev->max_imr; i++) {
+ ret = imr_read(idev, i, &imr);
+ if (ret)
+ goto failed;
+
+ /* Find overlap @ base or end of requested range. */
+ ret = -EINVAL;
+ if (imr_is_enabled(&imr)) {
+ if (imr_address_overlap(base, &imr))
+ goto failed;
+ if (imr_address_overlap(end, &imr))
+ goto failed;
+ } else {
+ reg = i;
+ }
+ }
+
+ /* Error out if we have no free IMR entries. */
+ if (reg == -1) {
+ ret = -ENOMEM;
+ goto failed;
+ }
+
+ pr_debug("add %d phys %pa-%pa size %zx mask 0x%08x wmask 0x%08x\n",
+ reg, &base, &end, raw_size, rmask, wmask);
+
+ /* Enable IMR at specified range and access mask. */
+ imr.addr_lo = phys_to_imr(base);
+ imr.addr_hi = phys_to_imr(end);
+ imr.rmask = rmask;
+ imr.wmask = wmask;
+
+ ret = imr_write(idev, reg, &imr, lock);
+ if (ret < 0) {
+ /*
+ * In the highly unlikely event iosf_mbi_write failed
+ * attempt to rollback the IMR setup skipping the trapping
+ * of further IOSF write failures.
+ */
+ imr.addr_lo = 0;
+ imr.addr_hi = 0;
+ imr.rmask = IMR_READ_ACCESS_ALL;
+ imr.wmask = IMR_WRITE_ACCESS_ALL;
+ imr_write(idev, reg, &imr, false);
+ }
+failed:
+ mutex_unlock(&idev->lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(imr_add_range);
+
+/**
+ * __imr_remove_range - delete an Isolated Memory Region.
+ *
+ * This function allows you to delete an IMR by its index specified by reg or
+ * by address range specified by base and size respectively. If you specify an
+ * index on its own the base and size parameters are ignored.
+ * imr_remove_range(0, base, size); delete IMR at index 0 base/size ignored.
+ * imr_remove_range(-1, base, size); delete IMR from base to base+size.
+ *
+ * @reg: imr index to remove.
+ * @base: physical base address of region aligned to 1 KiB.
+ * @size: physical size of region in bytes aligned to 1 KiB.
+ * @return: -EINVAL on invalid range or out or range id
+ * -ENODEV if reg is valid but no IMR exists or is locked
+ * 0 on success.
+ */
+static int __imr_remove_range(int reg, phys_addr_t base, size_t size)
+{
+ phys_addr_t end;
+ bool found = false;
+ unsigned int i;
+ struct imr_device *idev = &imr_dev;
+ struct imr_regs imr;
+ size_t raw_size;
+ int ret = 0;
+
+ if (WARN_ONCE(idev->init == false, "driver not initialized"))
+ return -ENODEV;
+
+ /*
+ * Validate address range if deleting by address, else we are
+ * deleting by index where base and size will be ignored.
+ */
+ if (reg == -1) {
+ ret = imr_check_params(base, size);
+ if (ret)
+ return ret;
+ }
+
+ /* Tweak the size value. */
+ raw_size = imr_raw_size(size);
+ end = base + raw_size;
+
+ mutex_lock(&idev->lock);
+
+ if (reg >= 0) {
+ /* If a specific IMR is given try to use it. */
+ ret = imr_read(idev, reg, &imr);
+ if (ret)
+ goto failed;
+
+ if (!imr_is_enabled(&imr) || imr.addr_lo & IMR_LOCK) {
+ ret = -ENODEV;
+ goto failed;
+ }
+ found = true;
+ } else {
+ /* Search for match based on address range. */
+ for (i = 0; i < idev->max_imr; i++) {
+ ret = imr_read(idev, i, &imr);
+ if (ret)
+ goto failed;
+
+ if (!imr_is_enabled(&imr) || imr.addr_lo & IMR_LOCK)
+ continue;
+
+ if ((imr_to_phys(imr.addr_lo) == base) &&
+ (imr_to_phys(imr.addr_hi) == end)) {
+ found = true;
+ reg = i;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ ret = -ENODEV;
+ goto failed;
+ }
+
+ pr_debug("remove %d phys %pa-%pa size %zx\n", reg, &base, &end, raw_size);
+
+ /* Tear down the IMR. */
+ imr.addr_lo = 0;
+ imr.addr_hi = 0;
+ imr.rmask = IMR_READ_ACCESS_ALL;
+ imr.wmask = IMR_WRITE_ACCESS_ALL;
+
+ ret = imr_write(idev, reg, &imr, false);
+
+failed:
+ mutex_unlock(&idev->lock);
+ return ret;
+}
+
+/**
+ * imr_remove_range - delete an Isolated Memory Region by address
+ *
+ * This function allows you to delete an IMR by an address range specified
+ * by base and size respectively.
+ * imr_remove_range(base, size); delete IMR from base to base+size.
+ *
+ * @base: physical base address of region aligned to 1 KiB.
+ * @size: physical size of region in bytes aligned to 1 KiB.
+ * @return: -EINVAL on invalid range or out or range id
+ * -ENODEV if reg is valid but no IMR exists or is locked
+ * 0 on success.
+ */
+int imr_remove_range(phys_addr_t base, size_t size)
+{
+ return __imr_remove_range(-1, base, size);
+}
+EXPORT_SYMBOL_GPL(imr_remove_range);
+
+/**
+ * imr_clear - delete an Isolated Memory Region by index
+ *
+ * This function allows you to delete an IMR by an address range specified
+ * by the index of the IMR. Useful for initial sanitization of the IMR
+ * address map.
+ * imr_ge(base, size); delete IMR from base to base+size.
+ *
+ * @reg: imr index to remove.
+ * @return: -EINVAL on invalid range or out or range id
+ * -ENODEV if reg is valid but no IMR exists or is locked
+ * 0 on success.
+ */
+static inline int imr_clear(int reg)
+{
+ return __imr_remove_range(reg, 0, 0);
+}
+
+/**
+ * imr_fixup_memmap - Tear down IMRs used during bootup.
+ *
+ * BIOS and Grub both setup IMRs around compressed kernel, initrd memory
+ * that need to be removed before the kernel hands out one of the IMR
+ * encased addresses to a downstream DMA agent such as the SD or Ethernet.
+ * IMRs on Galileo are setup to immediately reset the system on violation.
+ * As a result if you're running a root filesystem from SD - you'll need
+ * the boot-time IMRs torn down or you'll find seemingly random resets when
+ * using your filesystem.
+ *
+ * @idev: pointer to imr_device structure.
+ * @return:
+ */
+static void __init imr_fixup_memmap(struct imr_device *idev)
+{
+ phys_addr_t base = virt_to_phys(&_text);
+ size_t size = virt_to_phys(&__end_rodata) - base;
+ int i;
+ int ret;
+
+ /* Tear down all existing unlocked IMRs. */
+ for (i = 0; i < idev->max_imr; i++)
+ imr_clear(i);
+
+ /*
+ * Setup a locked IMR around the physical extent of the kernel
+ * from the beginning of the .text secton to the end of the
+ * .rodata section as one physically contiguous block.
+ */
+ ret = imr_add_range(base, size, IMR_CPU, IMR_CPU, true);
+ if (ret < 0) {
+ pr_err("unable to setup IMR for kernel: (%p - %p)\n",
+ &_text, &__end_rodata);
+ } else {
+ pr_info("protecting kernel .text - .rodata: %zu KiB (%p - %p)\n",
+ size / 1024, &_text, &__end_rodata);
+ }
+
+}
+
+static const struct x86_cpu_id imr_ids[] __initconst = {
+ { X86_VENDOR_INTEL, 5, 9 }, /* Intel Quark SoC X1000. */
+ {}
+};
+MODULE_DEVICE_TABLE(x86cpu, imr_ids);
+
+/**
+ * imr_init - entry point for IMR driver.
+ *
+ * return: -ENODEV for no IMR support 0 if good to go.
+ */
+static int __init imr_init(void)
+{
+ struct imr_device *idev = &imr_dev;
+ int ret;
+
+ if (!x86_match_cpu(imr_ids) || !iosf_mbi_available())
+ return -ENODEV;
+
+ idev->max_imr = QUARK_X1000_IMR_MAX;
+ idev->reg_base = QUARK_X1000_IMR_REGBASE;
+ idev->init = true;
+
+ mutex_init(&idev->lock);
+ ret = imr_debugfs_register(idev);
+ if (ret != 0)
+ pr_warn("debugfs register failed!\n");
+ imr_fixup_memmap(idev);
+ return 0;
+}
+
+/**
+ * imr_exit - exit point for IMR code.
+ *
+ * Deregisters debugfs, leave IMR state as-is.
+ *
+ * return:
+ */
+static void __exit imr_exit(void)
+{
+ imr_debugfs_unregister(&imr_dev);
+}
+
+module_init(imr_init);
+module_exit(imr_exit);
+
+MODULE_AUTHOR("Bryan O'Donoghue <pure.logic@nexus-software.ie>");
+MODULE_DESCRIPTION("Intel Isolated Memory Region driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/arch/x86/platform/intel-quark/imr_selftest.c b/arch/x86/platform/intel-quark/imr_selftest.c
new file mode 100644
index 0000000..c9a0838
--- /dev/null
+++ b/arch/x86/platform/intel-quark/imr_selftest.c
@@ -0,0 +1,129 @@
+/**
+ * imr_selftest.c
+ *
+ * Copyright(c) 2013 Intel Corporation.
+ * Copyright(c) 2015 Bryan O'Donoghue <pure.logic@nexus-software.ie>
+ *
+ * IMR self test. The purpose of this module is to run a set of tests on the
+ * IMR API to validate it's sanity. We check for overlapping, reserved
+ * addresses and setup/teardown sanity.
+ *
+ */
+
+#include <asm-generic/sections.h>
+#include <asm/imr.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+#define SELFTEST KBUILD_MODNAME ": "
+/**
+ * imr_self_test_result - Print result string for self test.
+ *
+ * @res: result code - true if test passed false otherwise.
+ * @fmt: format string.
+ * ... variadic argument list.
+ */
+static void __init imr_self_test_result(int res, const char *fmt, ...)
+{
+ va_list vlist;
+
+ /* Print pass/fail. */
+ if (res)
+ pr_info(SELFTEST "pass ");
+ else
+ pr_info(SELFTEST "fail ");
+
+ /* Print variable string. */
+ va_start(vlist, fmt);
+ vprintk(fmt, vlist);
+ va_end(vlist);
+
+ /* Optional warning. */
+ WARN(res == 0, "test failed");
+}
+#undef SELFTEST
+
+/**
+ * imr_self_test
+ *
+ * Verify IMR self_test with some simple tests to verify overlap,
+ * zero sized allocations and 1 KiB sized areas.
+ *
+ */
+static void __init imr_self_test(void)
+{
+ phys_addr_t base = virt_to_phys(&_text);
+ size_t size = virt_to_phys(&__end_rodata) - base;
+ const char *fmt_over = "overlapped IMR @ (0x%08lx - 0x%08lx)\n";
+ int ret;
+
+ /* Test zero zero. */
+ ret = imr_add_range(0, 0, 0, 0, false);
+ imr_self_test_result(ret < 0, "zero sized IMR\n");
+
+ /* Test exact overlap. */
+ ret = imr_add_range(base, size, IMR_CPU, IMR_CPU, false);
+ imr_self_test_result(ret < 0, fmt_over, __va(base), __va(base + size));
+
+ /* Test overlap with base inside of existing. */
+ base += size - IMR_ALIGN;
+ ret = imr_add_range(base, size, IMR_CPU, IMR_CPU, false);
+ imr_self_test_result(ret < 0, fmt_over, __va(base), __va(base + size));
+
+ /* Test overlap with end inside of existing. */
+ base -= size + IMR_ALIGN * 2;
+ ret = imr_add_range(base, size, IMR_CPU, IMR_CPU, false);
+ imr_self_test_result(ret < 0, fmt_over, __va(base), __va(base + size));
+
+ /* Test that a 1 KiB IMR @ zero with read/write all will bomb out. */
+ ret = imr_add_range(0, IMR_ALIGN, IMR_READ_ACCESS_ALL,
+ IMR_WRITE_ACCESS_ALL, false);
+ imr_self_test_result(ret < 0, "1KiB IMR @ 0x00000000 - access-all\n");
+
+ /* Test that a 1 KiB IMR @ zero with CPU only will work. */
+ ret = imr_add_range(0, IMR_ALIGN, IMR_CPU, IMR_CPU, false);
+ imr_self_test_result(ret >= 0, "1KiB IMR @ 0x00000000 - cpu-access\n");
+ if (ret >= 0) {
+ ret = imr_remove_range(0, IMR_ALIGN);
+ imr_self_test_result(ret == 0, "teardown - cpu-access\n");
+ }
+
+ /* Test 2 KiB works. */
+ size = IMR_ALIGN * 2;
+ ret = imr_add_range(0, size, IMR_READ_ACCESS_ALL,
+ IMR_WRITE_ACCESS_ALL, false);
+ imr_self_test_result(ret >= 0, "2KiB IMR @ 0x00000000\n");
+ if (ret >= 0) {
+ ret = imr_remove_range(0, size);
+ imr_self_test_result(ret == 0, "teardown 2KiB\n");
+ }
+}
+
+/**
+ * imr_self_test_init - entry point for IMR driver.
+ *
+ * return: -ENODEV for no IMR support 0 if good to go.
+ */
+static int __init imr_self_test_init(void)
+{
+ imr_self_test();
+ return 0;
+}
+
+/**
+ * imr_self_test_exit - exit point for IMR code.
+ *
+ * return:
+ */
+static void __exit imr_self_test_exit(void)
+{
+}
+
+module_init(imr_self_test_init);
+module_exit(imr_self_test_exit);
+
+MODULE_AUTHOR("Bryan O'Donoghue <pure.logic@nexus-software.ie>");
+MODULE_DESCRIPTION("Intel Isolated Memory Region self-test driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c
index 23b45eb..956374c 100644
--- a/arch/x86/xen/spinlock.c
+++ b/arch/x86/xen/spinlock.c
@@ -41,7 +41,7 @@
static inline void check_zero(void)
{
u8 ret;
- u8 old = ACCESS_ONCE(zero_stats);
+ u8 old = READ_ONCE(zero_stats);
if (unlikely(old)) {
ret = cmpxchg(&zero_stats, old, 0);
/* This ensures only one fellow resets the stat */
@@ -112,6 +112,7 @@
struct xen_lock_waiting *w = this_cpu_ptr(&lock_waiting);
int cpu = smp_processor_id();
u64 start;
+ __ticket_t head;
unsigned long flags;
/* If kicker interrupts not initialized yet, just spin */
@@ -159,11 +160,15 @@
*/
__ticket_enter_slowpath(lock);
+ /* make sure enter_slowpath, which is atomic does not cross the read */
+ smp_mb__after_atomic();
+
/*
* check again make sure it didn't become free while
* we weren't looking
*/
- if (ACCESS_ONCE(lock->tickets.head) == want) {
+ head = READ_ONCE(lock->tickets.head);
+ if (__tickets_equal(head, want)) {
add_stats(TAKEN_SLOW_PICKUP, 1);
goto out;
}
@@ -204,8 +209,8 @@
const struct xen_lock_waiting *w = &per_cpu(lock_waiting, cpu);
/* Make sure we read lock before want */
- if (ACCESS_ONCE(w->lock) == lock &&
- ACCESS_ONCE(w->want) == next) {
+ if (READ_ONCE(w->lock) == lock &&
+ READ_ONCE(w->want) == next) {
add_stats(RELEASED_SLOW_KICKED, 1);
xen_send_IPI_one(cpu, XEN_SPIN_UNLOCK_VECTOR);
break;
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index ec318bf..1786574 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -157,12 +157,16 @@
{
struct ipmi_file_private *priv = file->private_data;
int rv;
+ struct ipmi_recv_msg *msg, *next;
rv = ipmi_destroy_user(priv->user);
if (rv)
return rv;
- /* FIXME - free the messages in the list. */
+ list_for_each_entry_safe(msg, next, &priv->recv_msgs, link)
+ ipmi_free_recv_msg(msg);
+
+
kfree(priv);
return 0;
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 6b65fa4..9bb5928 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -1483,14 +1483,10 @@
smi_msg->msgid = msgid;
}
-static void smi_send(ipmi_smi_t intf, struct ipmi_smi_handlers *handlers,
- struct ipmi_smi_msg *smi_msg, int priority)
+static struct ipmi_smi_msg *smi_add_send_msg(ipmi_smi_t intf,
+ struct ipmi_smi_msg *smi_msg,
+ int priority)
{
- int run_to_completion = intf->run_to_completion;
- unsigned long flags;
-
- if (!run_to_completion)
- spin_lock_irqsave(&intf->xmit_msgs_lock, flags);
if (intf->curr_msg) {
if (priority > 0)
list_add_tail(&smi_msg->link, &intf->hp_xmit_msgs);
@@ -1500,8 +1496,25 @@
} else {
intf->curr_msg = smi_msg;
}
- if (!run_to_completion)
+
+ return smi_msg;
+}
+
+
+static void smi_send(ipmi_smi_t intf, struct ipmi_smi_handlers *handlers,
+ struct ipmi_smi_msg *smi_msg, int priority)
+{
+ int run_to_completion = intf->run_to_completion;
+
+ if (run_to_completion) {
+ smi_msg = smi_add_send_msg(intf, smi_msg, priority);
+ } else {
+ unsigned long flags;
+
+ spin_lock_irqsave(&intf->xmit_msgs_lock, flags);
+ smi_msg = smi_add_send_msg(intf, smi_msg, priority);
spin_unlock_irqrestore(&intf->xmit_msgs_lock, flags);
+ }
if (smi_msg)
handlers->sender(intf->send_info, smi_msg);
@@ -1985,7 +1998,9 @@
seq_printf(m, "%x", intf->channels[0].address);
for (i = 1; i < IPMI_MAX_CHANNELS; i++)
seq_printf(m, " %x", intf->channels[i].address);
- return seq_putc(m, '\n');
+ seq_putc(m, '\n');
+
+ return seq_has_overflowed(m);
}
static int smi_ipmb_proc_open(struct inode *inode, struct file *file)
@@ -2004,9 +2019,11 @@
{
ipmi_smi_t intf = m->private;
- return seq_printf(m, "%u.%u\n",
- ipmi_version_major(&intf->bmc->id),
- ipmi_version_minor(&intf->bmc->id));
+ seq_printf(m, "%u.%u\n",
+ ipmi_version_major(&intf->bmc->id),
+ ipmi_version_minor(&intf->bmc->id));
+
+ return seq_has_overflowed(m);
}
static int smi_version_proc_open(struct inode *inode, struct file *file)
@@ -2353,11 +2370,28 @@
&dev_attr_additional_device_support.attr,
&dev_attr_manufacturer_id.attr,
&dev_attr_product_id.attr,
+ &dev_attr_aux_firmware_revision.attr,
+ &dev_attr_guid.attr,
NULL
};
+static umode_t bmc_dev_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int idx)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct bmc_device *bmc = to_bmc_device(dev);
+ umode_t mode = attr->mode;
+
+ if (attr == &dev_attr_aux_firmware_revision.attr)
+ return bmc->id.aux_firmware_revision_set ? mode : 0;
+ if (attr == &dev_attr_guid.attr)
+ return bmc->guid_set ? mode : 0;
+ return mode;
+}
+
static struct attribute_group bmc_dev_attr_group = {
.attrs = bmc_dev_attrs,
+ .is_visible = bmc_dev_attr_is_visible,
};
static const struct attribute_group *bmc_dev_attr_groups[] = {
@@ -2380,13 +2414,6 @@
{
struct bmc_device *bmc = container_of(ref, struct bmc_device, usecount);
- if (bmc->id.aux_firmware_revision_set)
- device_remove_file(&bmc->pdev.dev,
- &dev_attr_aux_firmware_revision);
- if (bmc->guid_set)
- device_remove_file(&bmc->pdev.dev,
- &dev_attr_guid);
-
platform_device_unregister(&bmc->pdev);
}
@@ -2407,33 +2434,6 @@
mutex_unlock(&ipmidriver_mutex);
}
-static int create_bmc_files(struct bmc_device *bmc)
-{
- int err;
-
- if (bmc->id.aux_firmware_revision_set) {
- err = device_create_file(&bmc->pdev.dev,
- &dev_attr_aux_firmware_revision);
- if (err)
- goto out;
- }
- if (bmc->guid_set) {
- err = device_create_file(&bmc->pdev.dev,
- &dev_attr_guid);
- if (err)
- goto out_aux_firm;
- }
-
- return 0;
-
-out_aux_firm:
- if (bmc->id.aux_firmware_revision_set)
- device_remove_file(&bmc->pdev.dev,
- &dev_attr_aux_firmware_revision);
-out:
- return err;
-}
-
static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum)
{
int rv;
@@ -2522,15 +2522,6 @@
return rv;
}
- rv = create_bmc_files(bmc);
- if (rv) {
- mutex_lock(&ipmidriver_mutex);
- platform_device_unregister(&bmc->pdev);
- mutex_unlock(&ipmidriver_mutex);
-
- return rv;
- }
-
dev_info(intf->si_dev, "Found new BMC (man_id: 0x%6.6x, "
"prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
bmc->id.manufacturer_id,
@@ -4212,7 +4203,6 @@
static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);
static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);
-/* FIXME - convert these to slabs. */
static void free_smi_msg(struct ipmi_smi_msg *msg)
{
atomic_dec(&smi_msg_inuse_count);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 967b73a..f6646ed 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -321,6 +321,18 @@
static void cleanup_one_si(struct smi_info *to_clean);
static void cleanup_ipmi_si(void);
+#ifdef DEBUG_TIMING
+void debug_timestamp(char *msg)
+{
+ struct timespec64 t;
+
+ getnstimeofday64(&t);
+ pr_debug("**%s: %lld.%9.9ld\n", msg, (long long) t.tv_sec, t.tv_nsec);
+}
+#else
+#define debug_timestamp(x)
+#endif
+
static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list);
static int register_xaction_notifier(struct notifier_block *nb)
{
@@ -358,9 +370,6 @@
static enum si_sm_result start_next_msg(struct smi_info *smi_info)
{
int rv;
-#ifdef DEBUG_TIMING
- struct timeval t;
-#endif
if (!smi_info->waiting_msg) {
smi_info->curr_msg = NULL;
@@ -370,10 +379,7 @@
smi_info->curr_msg = smi_info->waiting_msg;
smi_info->waiting_msg = NULL;
-#ifdef DEBUG_TIMING
- do_gettimeofday(&t);
- printk(KERN_DEBUG "**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec);
-#endif
+ debug_timestamp("Start2");
err = atomic_notifier_call_chain(&xaction_notifier_list,
0, smi_info);
if (err & NOTIFY_STOP_MASK) {
@@ -582,12 +588,8 @@
static void handle_transaction_done(struct smi_info *smi_info)
{
struct ipmi_smi_msg *msg;
-#ifdef DEBUG_TIMING
- struct timeval t;
- do_gettimeofday(&t);
- printk(KERN_DEBUG "**Done: %d.%9.9d\n", t.tv_sec, t.tv_usec);
-#endif
+ debug_timestamp("Done");
switch (smi_info->si_state) {
case SI_NORMAL:
if (!smi_info->curr_msg)
@@ -929,24 +931,15 @@
struct smi_info *smi_info = send_info;
enum si_sm_result result;
unsigned long flags;
-#ifdef DEBUG_TIMING
- struct timeval t;
-#endif
- BUG_ON(smi_info->waiting_msg);
- smi_info->waiting_msg = msg;
-
-#ifdef DEBUG_TIMING
- do_gettimeofday(&t);
- printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);
-#endif
+ debug_timestamp("Enqueue");
if (smi_info->run_to_completion) {
/*
* If we are running to completion, start it and run
* transactions until everything is clear.
*/
- smi_info->curr_msg = smi_info->waiting_msg;
+ smi_info->curr_msg = msg;
smi_info->waiting_msg = NULL;
/*
@@ -964,6 +957,15 @@
}
spin_lock_irqsave(&smi_info->si_lock, flags);
+ /*
+ * The following two lines don't need to be under the lock for
+ * the lock's sake, but they do need SMP memory barriers to
+ * avoid getting things out of order. We are already claiming
+ * the lock, anyway, so just do it under the lock to avoid the
+ * ordering problem.
+ */
+ BUG_ON(smi_info->waiting_msg);
+ smi_info->waiting_msg = msg;
check_start_timer_thread(smi_info);
spin_unlock_irqrestore(&smi_info->si_lock, flags);
}
@@ -989,18 +991,18 @@
* we are spinning in kipmid looking for something and not delaying
* between checks
*/
-static inline void ipmi_si_set_not_busy(struct timespec *ts)
+static inline void ipmi_si_set_not_busy(struct timespec64 *ts)
{
ts->tv_nsec = -1;
}
-static inline int ipmi_si_is_busy(struct timespec *ts)
+static inline int ipmi_si_is_busy(struct timespec64 *ts)
{
return ts->tv_nsec != -1;
}
static inline int ipmi_thread_busy_wait(enum si_sm_result smi_result,
const struct smi_info *smi_info,
- struct timespec *busy_until)
+ struct timespec64 *busy_until)
{
unsigned int max_busy_us = 0;
@@ -1009,12 +1011,13 @@
if (max_busy_us == 0 || smi_result != SI_SM_CALL_WITH_DELAY)
ipmi_si_set_not_busy(busy_until);
else if (!ipmi_si_is_busy(busy_until)) {
- getnstimeofday(busy_until);
- timespec_add_ns(busy_until, max_busy_us*NSEC_PER_USEC);
+ getnstimeofday64(busy_until);
+ timespec64_add_ns(busy_until, max_busy_us*NSEC_PER_USEC);
} else {
- struct timespec now;
- getnstimeofday(&now);
- if (unlikely(timespec_compare(&now, busy_until) > 0)) {
+ struct timespec64 now;
+
+ getnstimeofday64(&now);
+ if (unlikely(timespec64_compare(&now, busy_until) > 0)) {
ipmi_si_set_not_busy(busy_until);
return 0;
}
@@ -1037,7 +1040,7 @@
struct smi_info *smi_info = data;
unsigned long flags;
enum si_sm_result smi_result;
- struct timespec busy_until;
+ struct timespec64 busy_until;
ipmi_si_set_not_busy(&busy_until);
set_user_nice(current, MAX_NICE);
@@ -1128,15 +1131,10 @@
unsigned long jiffies_now;
long time_diff;
long timeout;
-#ifdef DEBUG_TIMING
- struct timeval t;
-#endif
spin_lock_irqsave(&(smi_info->si_lock), flags);
-#ifdef DEBUG_TIMING
- do_gettimeofday(&t);
- printk(KERN_DEBUG "**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec);
-#endif
+ debug_timestamp("Timer");
+
jiffies_now = jiffies;
time_diff = (((long)jiffies_now - (long)smi_info->last_timeout_jiffies)
* SI_USEC_PER_JIFFY);
@@ -1173,18 +1171,13 @@
{
struct smi_info *smi_info = data;
unsigned long flags;
-#ifdef DEBUG_TIMING
- struct timeval t;
-#endif
spin_lock_irqsave(&(smi_info->si_lock), flags);
smi_inc_stat(smi_info, interrupts);
-#ifdef DEBUG_TIMING
- do_gettimeofday(&t);
- printk(KERN_DEBUG "**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec);
-#endif
+ debug_timestamp("Interrupt");
+
smi_event_handler(smi_info, 0);
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
return IRQ_HANDLED;
@@ -2038,18 +2031,13 @@
{
struct smi_info *smi_info = context;
unsigned long flags;
-#ifdef DEBUG_TIMING
- struct timeval t;
-#endif
spin_lock_irqsave(&(smi_info->si_lock), flags);
smi_inc_stat(smi_info, interrupts);
-#ifdef DEBUG_TIMING
- do_gettimeofday(&t);
- printk("**ACPI_GPE: %d.%9.9d\n", t.tv_sec, t.tv_usec);
-#endif
+ debug_timestamp("ACPI_GPE");
+
smi_event_handler(smi_info, 0);
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
@@ -2071,7 +2059,6 @@
if (!info->irq)
return 0;
- /* FIXME - is level triggered right? */
status = acpi_install_gpe_handler(NULL,
info->irq,
ACPI_GPE_LEVEL_TRIGGERED,
@@ -2998,7 +2985,9 @@
{
struct smi_info *smi = m->private;
- return seq_printf(m, "%s\n", si_to_str[smi->si_type]);
+ seq_printf(m, "%s\n", si_to_str[smi->si_type]);
+
+ return seq_has_overflowed(m);
}
static int smi_type_proc_open(struct inode *inode, struct file *file)
@@ -3060,16 +3049,18 @@
{
struct smi_info *smi = m->private;
- return seq_printf(m,
- "%s,%s,0x%lx,rsp=%d,rsi=%d,rsh=%d,irq=%d,ipmb=%d\n",
- si_to_str[smi->si_type],
- addr_space_to_str[smi->io.addr_type],
- smi->io.addr_data,
- smi->io.regspacing,
- smi->io.regsize,
- smi->io.regshift,
- smi->irq,
- smi->slave_addr);
+ seq_printf(m,
+ "%s,%s,0x%lx,rsp=%d,rsi=%d,rsh=%d,irq=%d,ipmb=%d\n",
+ si_to_str[smi->si_type],
+ addr_space_to_str[smi->io.addr_type],
+ smi->io.addr_data,
+ smi->io.regspacing,
+ smi->io.regsize,
+ smi->io.regshift,
+ smi->irq,
+ smi->slave_addr);
+
+ return seq_has_overflowed(m);
}
static int smi_params_proc_open(struct inode *inode, struct file *file)
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
index 982b963..f6e378d 100644
--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -1097,8 +1097,6 @@
if (!ssif_info)
return 0;
- i2c_set_clientdata(client, NULL);
-
/*
* After this point, we won't deliver anything asychronously
* to the message handler. We can unregister ourself.
@@ -1198,7 +1196,9 @@
static int smi_type_proc_show(struct seq_file *m, void *v)
{
- return seq_puts(m, "ssif\n");
+ seq_puts(m, "ssif\n");
+
+ return seq_has_overflowed(m);
}
static int smi_type_proc_open(struct inode *inode, struct file *file)
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 91f8613..0b474a0 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -102,12 +102,12 @@
Support for the Analog Devices axi-clkgen pcore clock generator for Xilinx
FPGAs. It is commonly used in Analog Devices' reference designs.
-config CLK_PPC_CORENET
- bool "Clock driver for PowerPC corenet platforms"
- depends on PPC_E500MC && OF
+config CLK_QORIQ
+ bool "Clock driver for Freescale QorIQ platforms"
+ depends on (PPC_E500MC || ARM) && OF
---help---
- This adds the clock driver support for Freescale PowerPC corenet
- platforms using common clock framework.
+ This adds the clock driver support for Freescale QorIQ platforms
+ using common clock framework.
config COMMON_CLK_XGENE
bool "Clock driver for APM XGene SoC"
@@ -135,6 +135,14 @@
---help---
Sypport for the Marvell PXA SoC.
+config COMMON_CLK_CDCE706
+ tristate "Clock driver for TI CDCE706 clock synthesizer"
+ depends on I2C
+ select REGMAP_I2C
+ select RATIONAL
+ ---help---
+ This driver supports TI CDCE706 programmable 3-PLL clock synthesizer.
+
source "drivers/clk/qcom/Kconfig"
endmenu
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index d5fba5b..d478ceb 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -16,9 +16,11 @@
# hardware specific clock types
# please keep this section sorted lexicographically by file/directory path name
+obj-$(CONFIG_MACH_ASM9260) += clk-asm9260.o
obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
obj-$(CONFIG_ARCH_AXXIA) += clk-axm5516.o
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
+obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-cdce706.o
obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
@@ -30,7 +32,7 @@
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o
-obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o
+obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o
obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o
obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o
obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c
index bbdb1b9..86c8a07 100644
--- a/drivers/clk/at91/clk-programmable.c
+++ b/drivers/clk/at91/clk-programmable.c
@@ -56,6 +56,8 @@
static long clk_programmable_determine_rate(struct clk_hw *hw,
unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_hw)
{
diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c
index 1c06f6f..05abae8 100644
--- a/drivers/clk/bcm/clk-kona.c
+++ b/drivers/clk/bcm/clk-kona.c
@@ -1032,6 +1032,8 @@
}
static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate, struct clk_hw **best_parent)
{
struct kona_clk *bcm_clk = to_kona_clk(hw);
diff --git a/drivers/clk/clk-asm9260.c b/drivers/clk/clk-asm9260.c
new file mode 100644
index 0000000..88f4ff6
--- /dev/null
+++ b/drivers/clk/clk-asm9260.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2014 Oleksij Rempel <linux@rempel-privat.de>.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <dt-bindings/clock/alphascale,asm9260.h>
+
+#define HW_AHBCLKCTRL0 0x0020
+#define HW_AHBCLKCTRL1 0x0030
+#define HW_SYSPLLCTRL 0x0100
+#define HW_MAINCLKSEL 0x0120
+#define HW_MAINCLKUEN 0x0124
+#define HW_UARTCLKSEL 0x0128
+#define HW_UARTCLKUEN 0x012c
+#define HW_I2S0CLKSEL 0x0130
+#define HW_I2S0CLKUEN 0x0134
+#define HW_I2S1CLKSEL 0x0138
+#define HW_I2S1CLKUEN 0x013c
+#define HW_WDTCLKSEL 0x0160
+#define HW_WDTCLKUEN 0x0164
+#define HW_CLKOUTCLKSEL 0x0170
+#define HW_CLKOUTCLKUEN 0x0174
+#define HW_CPUCLKDIV 0x017c
+#define HW_SYSAHBCLKDIV 0x0180
+#define HW_I2S0MCLKDIV 0x0190
+#define HW_I2S0SCLKDIV 0x0194
+#define HW_I2S1MCLKDIV 0x0188
+#define HW_I2S1SCLKDIV 0x018c
+#define HW_UART0CLKDIV 0x0198
+#define HW_UART1CLKDIV 0x019c
+#define HW_UART2CLKDIV 0x01a0
+#define HW_UART3CLKDIV 0x01a4
+#define HW_UART4CLKDIV 0x01a8
+#define HW_UART5CLKDIV 0x01ac
+#define HW_UART6CLKDIV 0x01b0
+#define HW_UART7CLKDIV 0x01b4
+#define HW_UART8CLKDIV 0x01b8
+#define HW_UART9CLKDIV 0x01bc
+#define HW_SPI0CLKDIV 0x01c0
+#define HW_SPI1CLKDIV 0x01c4
+#define HW_QUADSPICLKDIV 0x01c8
+#define HW_SSP0CLKDIV 0x01d0
+#define HW_NANDCLKDIV 0x01d4
+#define HW_TRACECLKDIV 0x01e0
+#define HW_CAMMCLKDIV 0x01e8
+#define HW_WDTCLKDIV 0x01ec
+#define HW_CLKOUTCLKDIV 0x01f4
+#define HW_MACCLKDIV 0x01f8
+#define HW_LCDCLKDIV 0x01fc
+#define HW_ADCANACLKDIV 0x0200
+
+static struct clk *clks[MAX_CLKS];
+static struct clk_onecell_data clk_data;
+static DEFINE_SPINLOCK(asm9260_clk_lock);
+
+struct asm9260_div_clk {
+ unsigned int idx;
+ const char *name;
+ const char *parent_name;
+ u32 reg;
+};
+
+struct asm9260_gate_data {
+ unsigned int idx;
+ const char *name;
+ const char *parent_name;
+ u32 reg;
+ u8 bit_idx;
+ unsigned long flags;
+};
+
+struct asm9260_mux_clock {
+ u8 mask;
+ u32 *table;
+ const char *name;
+ const char **parent_names;
+ u8 num_parents;
+ unsigned long offset;
+ unsigned long flags;
+};
+
+static void __iomem *base;
+
+static const struct asm9260_div_clk asm9260_div_clks[] __initconst = {
+ { CLKID_SYS_CPU, "cpu_div", "main_gate", HW_CPUCLKDIV },
+ { CLKID_SYS_AHB, "ahb_div", "cpu_div", HW_SYSAHBCLKDIV },
+
+ /* i2s has two deviders: one for only external mclk and internal
+ * devider for all clks. */
+ { CLKID_SYS_I2S0M, "i2s0m_div", "i2s0_mclk", HW_I2S0MCLKDIV },
+ { CLKID_SYS_I2S1M, "i2s1m_div", "i2s1_mclk", HW_I2S1MCLKDIV },
+ { CLKID_SYS_I2S0S, "i2s0s_div", "i2s0_gate", HW_I2S0SCLKDIV },
+ { CLKID_SYS_I2S1S, "i2s1s_div", "i2s0_gate", HW_I2S1SCLKDIV },
+
+ { CLKID_SYS_UART0, "uart0_div", "uart_gate", HW_UART0CLKDIV },
+ { CLKID_SYS_UART1, "uart1_div", "uart_gate", HW_UART1CLKDIV },
+ { CLKID_SYS_UART2, "uart2_div", "uart_gate", HW_UART2CLKDIV },
+ { CLKID_SYS_UART3, "uart3_div", "uart_gate", HW_UART3CLKDIV },
+ { CLKID_SYS_UART4, "uart4_div", "uart_gate", HW_UART4CLKDIV },
+ { CLKID_SYS_UART5, "uart5_div", "uart_gate", HW_UART5CLKDIV },
+ { CLKID_SYS_UART6, "uart6_div", "uart_gate", HW_UART6CLKDIV },
+ { CLKID_SYS_UART7, "uart7_div", "uart_gate", HW_UART7CLKDIV },
+ { CLKID_SYS_UART8, "uart8_div", "uart_gate", HW_UART8CLKDIV },
+ { CLKID_SYS_UART9, "uart9_div", "uart_gate", HW_UART9CLKDIV },
+
+ { CLKID_SYS_SPI0, "spi0_div", "main_gate", HW_SPI0CLKDIV },
+ { CLKID_SYS_SPI1, "spi1_div", "main_gate", HW_SPI1CLKDIV },
+ { CLKID_SYS_QUADSPI, "quadspi_div", "main_gate", HW_QUADSPICLKDIV },
+ { CLKID_SYS_SSP0, "ssp0_div", "main_gate", HW_SSP0CLKDIV },
+ { CLKID_SYS_NAND, "nand_div", "main_gate", HW_NANDCLKDIV },
+ { CLKID_SYS_TRACE, "trace_div", "main_gate", HW_TRACECLKDIV },
+ { CLKID_SYS_CAMM, "camm_div", "main_gate", HW_CAMMCLKDIV },
+ { CLKID_SYS_MAC, "mac_div", "main_gate", HW_MACCLKDIV },
+ { CLKID_SYS_LCD, "lcd_div", "main_gate", HW_LCDCLKDIV },
+ { CLKID_SYS_ADCANA, "adcana_div", "main_gate", HW_ADCANACLKDIV },
+
+ { CLKID_SYS_WDT, "wdt_div", "wdt_gate", HW_WDTCLKDIV },
+ { CLKID_SYS_CLKOUT, "clkout_div", "clkout_gate", HW_CLKOUTCLKDIV },
+};
+
+static const struct asm9260_gate_data asm9260_mux_gates[] __initconst = {
+ { 0, "main_gate", "main_mux", HW_MAINCLKUEN, 0 },
+ { 0, "uart_gate", "uart_mux", HW_UARTCLKUEN, 0 },
+ { 0, "i2s0_gate", "i2s0_mux", HW_I2S0CLKUEN, 0 },
+ { 0, "i2s1_gate", "i2s1_mux", HW_I2S1CLKUEN, 0 },
+ { 0, "wdt_gate", "wdt_mux", HW_WDTCLKUEN, 0 },
+ { 0, "clkout_gate", "clkout_mux", HW_CLKOUTCLKUEN, 0 },
+};
+static const struct asm9260_gate_data asm9260_ahb_gates[] __initconst = {
+ /* ahb gates */
+ { CLKID_AHB_ROM, "rom", "ahb_div",
+ HW_AHBCLKCTRL0, 1, CLK_IGNORE_UNUSED},
+ { CLKID_AHB_RAM, "ram", "ahb_div",
+ HW_AHBCLKCTRL0, 2, CLK_IGNORE_UNUSED},
+ { CLKID_AHB_GPIO, "gpio", "ahb_div",
+ HW_AHBCLKCTRL0, 4 },
+ { CLKID_AHB_MAC, "mac", "ahb_div",
+ HW_AHBCLKCTRL0, 5 },
+ { CLKID_AHB_EMI, "emi", "ahb_div",
+ HW_AHBCLKCTRL0, 6, CLK_IGNORE_UNUSED},
+ { CLKID_AHB_USB0, "usb0", "ahb_div",
+ HW_AHBCLKCTRL0, 7 },
+ { CLKID_AHB_USB1, "usb1", "ahb_div",
+ HW_AHBCLKCTRL0, 8 },
+ { CLKID_AHB_DMA0, "dma0", "ahb_div",
+ HW_AHBCLKCTRL0, 9 },
+ { CLKID_AHB_DMA1, "dma1", "ahb_div",
+ HW_AHBCLKCTRL0, 10 },
+ { CLKID_AHB_UART0, "uart0", "ahb_div",
+ HW_AHBCLKCTRL0, 11 },
+ { CLKID_AHB_UART1, "uart1", "ahb_div",
+ HW_AHBCLKCTRL0, 12 },
+ { CLKID_AHB_UART2, "uart2", "ahb_div",
+ HW_AHBCLKCTRL0, 13 },
+ { CLKID_AHB_UART3, "uart3", "ahb_div",
+ HW_AHBCLKCTRL0, 14 },
+ { CLKID_AHB_UART4, "uart4", "ahb_div",
+ HW_AHBCLKCTRL0, 15 },
+ { CLKID_AHB_UART5, "uart5", "ahb_div",
+ HW_AHBCLKCTRL0, 16 },
+ { CLKID_AHB_UART6, "uart6", "ahb_div",
+ HW_AHBCLKCTRL0, 17 },
+ { CLKID_AHB_UART7, "uart7", "ahb_div",
+ HW_AHBCLKCTRL0, 18 },
+ { CLKID_AHB_UART8, "uart8", "ahb_div",
+ HW_AHBCLKCTRL0, 19 },
+ { CLKID_AHB_UART9, "uart9", "ahb_div",
+ HW_AHBCLKCTRL0, 20 },
+ { CLKID_AHB_I2S0, "i2s0", "ahb_div",
+ HW_AHBCLKCTRL0, 21 },
+ { CLKID_AHB_I2C0, "i2c0", "ahb_div",
+ HW_AHBCLKCTRL0, 22 },
+ { CLKID_AHB_I2C1, "i2c1", "ahb_div",
+ HW_AHBCLKCTRL0, 23 },
+ { CLKID_AHB_SSP0, "ssp0", "ahb_div",
+ HW_AHBCLKCTRL0, 24 },
+ { CLKID_AHB_IOCONFIG, "ioconf", "ahb_div",
+ HW_AHBCLKCTRL0, 25 },
+ { CLKID_AHB_WDT, "wdt", "ahb_div",
+ HW_AHBCLKCTRL0, 26 },
+ { CLKID_AHB_CAN0, "can0", "ahb_div",
+ HW_AHBCLKCTRL0, 27 },
+ { CLKID_AHB_CAN1, "can1", "ahb_div",
+ HW_AHBCLKCTRL0, 28 },
+ { CLKID_AHB_MPWM, "mpwm", "ahb_div",
+ HW_AHBCLKCTRL0, 29 },
+ { CLKID_AHB_SPI0, "spi0", "ahb_div",
+ HW_AHBCLKCTRL0, 30 },
+ { CLKID_AHB_SPI1, "spi1", "ahb_div",
+ HW_AHBCLKCTRL0, 31 },
+
+ { CLKID_AHB_QEI, "qei", "ahb_div",
+ HW_AHBCLKCTRL1, 0 },
+ { CLKID_AHB_QUADSPI0, "quadspi0", "ahb_div",
+ HW_AHBCLKCTRL1, 1 },
+ { CLKID_AHB_CAMIF, "capmif", "ahb_div",
+ HW_AHBCLKCTRL1, 2 },
+ { CLKID_AHB_LCDIF, "lcdif", "ahb_div",
+ HW_AHBCLKCTRL1, 3 },
+ { CLKID_AHB_TIMER0, "timer0", "ahb_div",
+ HW_AHBCLKCTRL1, 4 },
+ { CLKID_AHB_TIMER1, "timer1", "ahb_div",
+ HW_AHBCLKCTRL1, 5 },
+ { CLKID_AHB_TIMER2, "timer2", "ahb_div",
+ HW_AHBCLKCTRL1, 6 },
+ { CLKID_AHB_TIMER3, "timer3", "ahb_div",
+ HW_AHBCLKCTRL1, 7 },
+ { CLKID_AHB_IRQ, "irq", "ahb_div",
+ HW_AHBCLKCTRL1, 8, CLK_IGNORE_UNUSED},
+ { CLKID_AHB_RTC, "rtc", "ahb_div",
+ HW_AHBCLKCTRL1, 9 },
+ { CLKID_AHB_NAND, "nand", "ahb_div",
+ HW_AHBCLKCTRL1, 10 },
+ { CLKID_AHB_ADC0, "adc0", "ahb_div",
+ HW_AHBCLKCTRL1, 11 },
+ { CLKID_AHB_LED, "led", "ahb_div",
+ HW_AHBCLKCTRL1, 12 },
+ { CLKID_AHB_DAC0, "dac0", "ahb_div",
+ HW_AHBCLKCTRL1, 13 },
+ { CLKID_AHB_LCD, "lcd", "ahb_div",
+ HW_AHBCLKCTRL1, 14 },
+ { CLKID_AHB_I2S1, "i2s1", "ahb_div",
+ HW_AHBCLKCTRL1, 15 },
+ { CLKID_AHB_MAC1, "mac1", "ahb_div",
+ HW_AHBCLKCTRL1, 16 },
+};
+
+static const char __initdata *main_mux_p[] = { NULL, NULL };
+static const char __initdata *i2s0_mux_p[] = { NULL, NULL, "i2s0m_div"};
+static const char __initdata *i2s1_mux_p[] = { NULL, NULL, "i2s1m_div"};
+static const char __initdata *clkout_mux_p[] = { NULL, NULL, "rtc"};
+static u32 three_mux_table[] = {0, 1, 3};
+
+static struct asm9260_mux_clock asm9260_mux_clks[] __initdata = {
+ { 1, three_mux_table, "main_mux", main_mux_p,
+ ARRAY_SIZE(main_mux_p), HW_MAINCLKSEL, },
+ { 1, three_mux_table, "uart_mux", main_mux_p,
+ ARRAY_SIZE(main_mux_p), HW_UARTCLKSEL, },
+ { 1, three_mux_table, "wdt_mux", main_mux_p,
+ ARRAY_SIZE(main_mux_p), HW_WDTCLKSEL, },
+ { 3, three_mux_table, "i2s0_mux", i2s0_mux_p,
+ ARRAY_SIZE(i2s0_mux_p), HW_I2S0CLKSEL, },
+ { 3, three_mux_table, "i2s1_mux", i2s1_mux_p,
+ ARRAY_SIZE(i2s1_mux_p), HW_I2S1CLKSEL, },
+ { 3, three_mux_table, "clkout_mux", clkout_mux_p,
+ ARRAY_SIZE(clkout_mux_p), HW_CLKOUTCLKSEL, },
+};
+
+static void __init asm9260_acc_init(struct device_node *np)
+{
+ struct clk *clk;
+ const char *ref_clk, *pll_clk = "pll";
+ u32 rate;
+ int n;
+ u32 accuracy = 0;
+
+ base = of_io_request_and_map(np, 0, np->name);
+ if (!base)
+ panic("%s: unable to map resource", np->name);
+
+ /* register pll */
+ rate = (ioread32(base + HW_SYSPLLCTRL) & 0xffff) * 1000000;
+
+ ref_clk = of_clk_get_parent_name(np, 0);
+ accuracy = clk_get_accuracy(__clk_lookup(ref_clk));
+ clk = clk_register_fixed_rate_with_accuracy(NULL, pll_clk,
+ ref_clk, 0, rate, accuracy);
+
+ if (IS_ERR(clk))
+ panic("%s: can't register REFCLK. Check DT!", np->name);
+
+ for (n = 0; n < ARRAY_SIZE(asm9260_mux_clks); n++) {
+ const struct asm9260_mux_clock *mc = &asm9260_mux_clks[n];
+
+ mc->parent_names[0] = ref_clk;
+ mc->parent_names[1] = pll_clk;
+ clk = clk_register_mux_table(NULL, mc->name, mc->parent_names,
+ mc->num_parents, mc->flags, base + mc->offset,
+ 0, mc->mask, 0, mc->table, &asm9260_clk_lock);
+ }
+
+ /* clock mux gate cells */
+ for (n = 0; n < ARRAY_SIZE(asm9260_mux_gates); n++) {
+ const struct asm9260_gate_data *gd = &asm9260_mux_gates[n];
+
+ clk = clk_register_gate(NULL, gd->name,
+ gd->parent_name, gd->flags | CLK_SET_RATE_PARENT,
+ base + gd->reg, gd->bit_idx, 0, &asm9260_clk_lock);
+ }
+
+ /* clock div cells */
+ for (n = 0; n < ARRAY_SIZE(asm9260_div_clks); n++) {
+ const struct asm9260_div_clk *dc = &asm9260_div_clks[n];
+
+ clks[dc->idx] = clk_register_divider(NULL, dc->name,
+ dc->parent_name, CLK_SET_RATE_PARENT,
+ base + dc->reg, 0, 8, CLK_DIVIDER_ONE_BASED,
+ &asm9260_clk_lock);
+ }
+
+ /* clock ahb gate cells */
+ for (n = 0; n < ARRAY_SIZE(asm9260_ahb_gates); n++) {
+ const struct asm9260_gate_data *gd = &asm9260_ahb_gates[n];
+
+ clks[gd->idx] = clk_register_gate(NULL, gd->name,
+ gd->parent_name, gd->flags, base + gd->reg,
+ gd->bit_idx, 0, &asm9260_clk_lock);
+ }
+
+ /* check for errors on leaf clocks */
+ for (n = 0; n < MAX_CLKS; n++) {
+ if (!IS_ERR(clks[n]))
+ continue;
+
+ pr_err("%s: Unable to register leaf clock %d\n",
+ np->full_name, n);
+ goto fail;
+ }
+
+ /* register clk-provider */
+ clk_data.clks = clks;
+ clk_data.clk_num = MAX_CLKS;
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+ return;
+fail:
+ iounmap(base);
+}
+CLK_OF_DECLARE(asm9260_acc, "alphascale,asm9260-clock-controller",
+ asm9260_acc_init);
diff --git a/drivers/clk/clk-cdce706.c b/drivers/clk/clk-cdce706.c
new file mode 100644
index 0000000..c386ad2
--- /dev/null
+++ b/drivers/clk/clk-cdce706.c
@@ -0,0 +1,700 @@
+/*
+ * TI CDCE706 programmable 3-PLL clock synthesizer driver
+ *
+ * Copyright (c) 2014 Cadence Design Systems Inc.
+ *
+ * Reference: http://www.ti.com/lit/ds/symlink/cdce706.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/rational.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define CDCE706_CLKIN_CLOCK 10
+#define CDCE706_CLKIN_SOURCE 11
+#define CDCE706_PLL_M_LOW(pll) (1 + 3 * (pll))
+#define CDCE706_PLL_N_LOW(pll) (2 + 3 * (pll))
+#define CDCE706_PLL_HI(pll) (3 + 3 * (pll))
+#define CDCE706_PLL_MUX 3
+#define CDCE706_PLL_FVCO 6
+#define CDCE706_DIVIDER(div) (13 + (div))
+#define CDCE706_CLKOUT(out) (19 + (out))
+
+#define CDCE706_CLKIN_CLOCK_MASK 0x10
+#define CDCE706_CLKIN_SOURCE_SHIFT 6
+#define CDCE706_CLKIN_SOURCE_MASK 0xc0
+#define CDCE706_CLKIN_SOURCE_LVCMOS 0x40
+
+#define CDCE706_PLL_MUX_MASK(pll) (0x80 >> (pll))
+#define CDCE706_PLL_LOW_M_MASK 0xff
+#define CDCE706_PLL_LOW_N_MASK 0xff
+#define CDCE706_PLL_HI_M_MASK 0x1
+#define CDCE706_PLL_HI_N_MASK 0x1e
+#define CDCE706_PLL_HI_N_SHIFT 1
+#define CDCE706_PLL_M_MAX 0x1ff
+#define CDCE706_PLL_N_MAX 0xfff
+#define CDCE706_PLL_FVCO_MASK(pll) (0x80 >> (pll))
+#define CDCE706_PLL_FREQ_MIN 80000000
+#define CDCE706_PLL_FREQ_MAX 300000000
+#define CDCE706_PLL_FREQ_HI 180000000
+
+#define CDCE706_DIVIDER_PLL(div) (9 + (div) - ((div) > 2) - ((div) > 4))
+#define CDCE706_DIVIDER_PLL_SHIFT(div) ((div) < 2 ? 5 : 3 * ((div) & 1))
+#define CDCE706_DIVIDER_PLL_MASK(div) (0x7 << CDCE706_DIVIDER_PLL_SHIFT(div))
+#define CDCE706_DIVIDER_DIVIDER_MASK 0x7f
+#define CDCE706_DIVIDER_DIVIDER_MAX 0x7f
+
+#define CDCE706_CLKOUT_DIVIDER_MASK 0x7
+#define CDCE706_CLKOUT_ENABLE_MASK 0x8
+
+static struct regmap_config cdce706_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .val_format_endian = REGMAP_ENDIAN_NATIVE,
+};
+
+#define to_hw_data(phw) (container_of((phw), struct cdce706_hw_data, hw))
+
+struct cdce706_hw_data {
+ struct cdce706_dev_data *dev_data;
+ unsigned idx;
+ unsigned parent;
+ struct clk *clk;
+ struct clk_hw hw;
+ unsigned div;
+ unsigned mul;
+ unsigned mux;
+};
+
+struct cdce706_dev_data {
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct clk_onecell_data onecell;
+ struct clk *clks[6];
+ struct clk *clkin_clk[2];
+ const char *clkin_name[2];
+ struct cdce706_hw_data clkin[1];
+ struct cdce706_hw_data pll[3];
+ struct cdce706_hw_data divider[6];
+ struct cdce706_hw_data clkout[6];
+};
+
+static const char * const cdce706_source_name[] = {
+ "clk_in0", "clk_in1",
+};
+
+static const char *cdce706_clkin_name[] = {
+ "clk_in",
+};
+
+static const char * const cdce706_pll_name[] = {
+ "pll1", "pll2", "pll3",
+};
+
+static const char *cdce706_divider_parent_name[] = {
+ "clk_in", "pll1", "pll2", "pll2", "pll3",
+};
+
+static const char *cdce706_divider_name[] = {
+ "p0", "p1", "p2", "p3", "p4", "p5",
+};
+
+static const char * const cdce706_clkout_name[] = {
+ "clk_out0", "clk_out1", "clk_out2", "clk_out3", "clk_out4", "clk_out5",
+};
+
+static int cdce706_reg_read(struct cdce706_dev_data *dev_data, unsigned reg,
+ unsigned *val)
+{
+ int rc = regmap_read(dev_data->regmap, reg | 0x80, val);
+
+ if (rc < 0)
+ dev_err(&dev_data->client->dev, "error reading reg %u", reg);
+ return rc;
+}
+
+static int cdce706_reg_write(struct cdce706_dev_data *dev_data, unsigned reg,
+ unsigned val)
+{
+ int rc = regmap_write(dev_data->regmap, reg | 0x80, val);
+
+ if (rc < 0)
+ dev_err(&dev_data->client->dev, "error writing reg %u", reg);
+ return rc;
+}
+
+static int cdce706_reg_update(struct cdce706_dev_data *dev_data, unsigned reg,
+ unsigned mask, unsigned val)
+{
+ int rc = regmap_update_bits(dev_data->regmap, reg | 0x80, mask, val);
+
+ if (rc < 0)
+ dev_err(&dev_data->client->dev, "error updating reg %u", reg);
+ return rc;
+}
+
+static int cdce706_clkin_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ hwd->parent = index;
+ return 0;
+}
+
+static u8 cdce706_clkin_get_parent(struct clk_hw *hw)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ return hwd->parent;
+}
+
+static const struct clk_ops cdce706_clkin_ops = {
+ .set_parent = cdce706_clkin_set_parent,
+ .get_parent = cdce706_clkin_get_parent,
+};
+
+static unsigned long cdce706_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, pll: %d, mux: %d, mul: %u, div: %u\n",
+ __func__, hwd->idx, hwd->mux, hwd->mul, hwd->div);
+
+ if (!hwd->mux) {
+ if (hwd->div && hwd->mul) {
+ u64 res = (u64)parent_rate * hwd->mul;
+
+ do_div(res, hwd->div);
+ return res;
+ }
+ } else {
+ if (hwd->div)
+ return parent_rate / hwd->div;
+ }
+ return 0;
+}
+
+static long cdce706_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+ unsigned long mul, div;
+ u64 res;
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, rate: %lu, parent_rate: %lu\n",
+ __func__, rate, *parent_rate);
+
+ rational_best_approximation(rate, *parent_rate,
+ CDCE706_PLL_N_MAX, CDCE706_PLL_M_MAX,
+ &mul, &div);
+ hwd->mul = mul;
+ hwd->div = div;
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, pll: %d, mul: %lu, div: %lu\n",
+ __func__, hwd->idx, mul, div);
+
+ res = (u64)*parent_rate * hwd->mul;
+ do_div(res, hwd->div);
+ return res;
+}
+
+static int cdce706_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+ unsigned long mul = hwd->mul, div = hwd->div;
+ int err;
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, pll: %d, mul: %lu, div: %lu\n",
+ __func__, hwd->idx, mul, div);
+
+ err = cdce706_reg_update(hwd->dev_data,
+ CDCE706_PLL_HI(hwd->idx),
+ CDCE706_PLL_HI_M_MASK | CDCE706_PLL_HI_N_MASK,
+ ((div >> 8) & CDCE706_PLL_HI_M_MASK) |
+ ((mul >> (8 - CDCE706_PLL_HI_N_SHIFT)) &
+ CDCE706_PLL_HI_N_MASK));
+ if (err < 0)
+ return err;
+
+ err = cdce706_reg_write(hwd->dev_data,
+ CDCE706_PLL_M_LOW(hwd->idx),
+ div & CDCE706_PLL_LOW_M_MASK);
+ if (err < 0)
+ return err;
+
+ err = cdce706_reg_write(hwd->dev_data,
+ CDCE706_PLL_N_LOW(hwd->idx),
+ mul & CDCE706_PLL_LOW_N_MASK);
+ if (err < 0)
+ return err;
+
+ err = cdce706_reg_update(hwd->dev_data,
+ CDCE706_PLL_FVCO,
+ CDCE706_PLL_FVCO_MASK(hwd->idx),
+ rate > CDCE706_PLL_FREQ_HI ?
+ CDCE706_PLL_FVCO_MASK(hwd->idx) : 0);
+ return err;
+}
+
+static const struct clk_ops cdce706_pll_ops = {
+ .recalc_rate = cdce706_pll_recalc_rate,
+ .round_rate = cdce706_pll_round_rate,
+ .set_rate = cdce706_pll_set_rate,
+};
+
+static int cdce706_divider_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ if (hwd->parent == index)
+ return 0;
+ hwd->parent = index;
+ return cdce706_reg_update(hwd->dev_data,
+ CDCE706_DIVIDER_PLL(hwd->idx),
+ CDCE706_DIVIDER_PLL_MASK(hwd->idx),
+ index << CDCE706_DIVIDER_PLL_SHIFT(hwd->idx));
+}
+
+static u8 cdce706_divider_get_parent(struct clk_hw *hw)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ return hwd->parent;
+}
+
+static unsigned long cdce706_divider_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, divider: %d, div: %u\n",
+ __func__, hwd->idx, hwd->div);
+ if (hwd->div)
+ return parent_rate / hwd->div;
+ return 0;
+}
+
+static long cdce706_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+ struct cdce706_dev_data *cdce = hwd->dev_data;
+ unsigned long mul, div;
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, rate: %lu, parent_rate: %lu\n",
+ __func__, rate, *parent_rate);
+
+ rational_best_approximation(rate, *parent_rate,
+ 1, CDCE706_DIVIDER_DIVIDER_MAX,
+ &mul, &div);
+ if (!mul)
+ div = CDCE706_DIVIDER_DIVIDER_MAX;
+
+ if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
+ unsigned long best_diff = rate;
+ unsigned long best_div = 0;
+ struct clk *gp_clk = cdce->clkin_clk[cdce->clkin[0].parent];
+ unsigned long gp_rate = gp_clk ? clk_get_rate(gp_clk) : 0;
+
+ for (div = CDCE706_PLL_FREQ_MIN / rate; best_diff &&
+ div <= CDCE706_PLL_FREQ_MAX / rate; ++div) {
+ unsigned long n, m;
+ unsigned long diff;
+ unsigned long div_rate;
+ u64 div_rate64;
+
+ if (rate * div < CDCE706_PLL_FREQ_MIN)
+ continue;
+
+ rational_best_approximation(rate * div, gp_rate,
+ CDCE706_PLL_N_MAX,
+ CDCE706_PLL_M_MAX,
+ &n, &m);
+ div_rate64 = (u64)gp_rate * n;
+ do_div(div_rate64, m);
+ do_div(div_rate64, div);
+ div_rate = div_rate64;
+ diff = max(div_rate, rate) - min(div_rate, rate);
+
+ if (diff < best_diff) {
+ best_diff = diff;
+ best_div = div;
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, %lu * %lu / %lu / %lu = %lu\n",
+ __func__, gp_rate, n, m, div, div_rate);
+ }
+ }
+
+ div = best_div;
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, altering parent rate: %lu -> %lu\n",
+ __func__, *parent_rate, rate * div);
+ *parent_rate = rate * div;
+ }
+ hwd->div = div;
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, divider: %d, div: %lu\n",
+ __func__, hwd->idx, div);
+
+ return *parent_rate / div;
+}
+
+static int cdce706_divider_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, divider: %d, div: %u\n",
+ __func__, hwd->idx, hwd->div);
+
+ return cdce706_reg_update(hwd->dev_data,
+ CDCE706_DIVIDER(hwd->idx),
+ CDCE706_DIVIDER_DIVIDER_MASK,
+ hwd->div);
+}
+
+static const struct clk_ops cdce706_divider_ops = {
+ .set_parent = cdce706_divider_set_parent,
+ .get_parent = cdce706_divider_get_parent,
+ .recalc_rate = cdce706_divider_recalc_rate,
+ .round_rate = cdce706_divider_round_rate,
+ .set_rate = cdce706_divider_set_rate,
+};
+
+static int cdce706_clkout_prepare(struct clk_hw *hw)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ return cdce706_reg_update(hwd->dev_data, CDCE706_CLKOUT(hwd->idx),
+ CDCE706_CLKOUT_ENABLE_MASK,
+ CDCE706_CLKOUT_ENABLE_MASK);
+}
+
+static void cdce706_clkout_unprepare(struct clk_hw *hw)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ cdce706_reg_update(hwd->dev_data, CDCE706_CLKOUT(hwd->idx),
+ CDCE706_CLKOUT_ENABLE_MASK, 0);
+}
+
+static int cdce706_clkout_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ if (hwd->parent == index)
+ return 0;
+ hwd->parent = index;
+ return cdce706_reg_update(hwd->dev_data,
+ CDCE706_CLKOUT(hwd->idx),
+ CDCE706_CLKOUT_ENABLE_MASK, index);
+}
+
+static u8 cdce706_clkout_get_parent(struct clk_hw *hw)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ return hwd->parent;
+}
+
+static unsigned long cdce706_clkout_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return parent_rate;
+}
+
+static long cdce706_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ *parent_rate = rate;
+ return rate;
+}
+
+static int cdce706_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ return 0;
+}
+
+static const struct clk_ops cdce706_clkout_ops = {
+ .prepare = cdce706_clkout_prepare,
+ .unprepare = cdce706_clkout_unprepare,
+ .set_parent = cdce706_clkout_set_parent,
+ .get_parent = cdce706_clkout_get_parent,
+ .recalc_rate = cdce706_clkout_recalc_rate,
+ .round_rate = cdce706_clkout_round_rate,
+ .set_rate = cdce706_clkout_set_rate,
+};
+
+static int cdce706_register_hw(struct cdce706_dev_data *cdce,
+ struct cdce706_hw_data *hw, unsigned num_hw,
+ const char * const *clk_names,
+ struct clk_init_data *init)
+{
+ unsigned i;
+
+ for (i = 0; i < num_hw; ++i, ++hw) {
+ init->name = clk_names[i];
+ hw->dev_data = cdce;
+ hw->idx = i;
+ hw->hw.init = init;
+ hw->clk = devm_clk_register(&cdce->client->dev,
+ &hw->hw);
+ if (IS_ERR(hw->clk)) {
+ dev_err(&cdce->client->dev, "Failed to register %s\n",
+ clk_names[i]);
+ return PTR_ERR(hw->clk);
+ }
+ }
+ return 0;
+}
+
+static int cdce706_register_clkin(struct cdce706_dev_data *cdce)
+{
+ struct clk_init_data init = {
+ .ops = &cdce706_clkin_ops,
+ .parent_names = cdce->clkin_name,
+ .num_parents = ARRAY_SIZE(cdce->clkin_name),
+ };
+ unsigned i;
+ int ret;
+ unsigned clock, source;
+
+ for (i = 0; i < ARRAY_SIZE(cdce->clkin_name); ++i) {
+ struct clk *parent = devm_clk_get(&cdce->client->dev,
+ cdce706_source_name[i]);
+
+ if (IS_ERR(parent)) {
+ cdce->clkin_name[i] = cdce706_source_name[i];
+ } else {
+ cdce->clkin_name[i] = __clk_get_name(parent);
+ cdce->clkin_clk[i] = parent;
+ }
+ }
+
+ ret = cdce706_reg_read(cdce, CDCE706_CLKIN_SOURCE, &source);
+ if (ret < 0)
+ return ret;
+ if ((source & CDCE706_CLKIN_SOURCE_MASK) ==
+ CDCE706_CLKIN_SOURCE_LVCMOS) {
+ ret = cdce706_reg_read(cdce, CDCE706_CLKIN_CLOCK, &clock);
+ if (ret < 0)
+ return ret;
+ cdce->clkin[0].parent = !!(clock & CDCE706_CLKIN_CLOCK_MASK);
+ }
+
+ ret = cdce706_register_hw(cdce, cdce->clkin,
+ ARRAY_SIZE(cdce->clkin),
+ cdce706_clkin_name, &init);
+ return ret;
+}
+
+static int cdce706_register_plls(struct cdce706_dev_data *cdce)
+{
+ struct clk_init_data init = {
+ .ops = &cdce706_pll_ops,
+ .parent_names = cdce706_clkin_name,
+ .num_parents = ARRAY_SIZE(cdce706_clkin_name),
+ };
+ unsigned i;
+ int ret;
+ unsigned mux;
+
+ ret = cdce706_reg_read(cdce, CDCE706_PLL_MUX, &mux);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(cdce->pll); ++i) {
+ unsigned m, n, v;
+
+ ret = cdce706_reg_read(cdce, CDCE706_PLL_M_LOW(i), &m);
+ if (ret < 0)
+ return ret;
+ ret = cdce706_reg_read(cdce, CDCE706_PLL_N_LOW(i), &n);
+ if (ret < 0)
+ return ret;
+ ret = cdce706_reg_read(cdce, CDCE706_PLL_HI(i), &v);
+ if (ret < 0)
+ return ret;
+ cdce->pll[i].div = m | ((v & CDCE706_PLL_HI_M_MASK) << 8);
+ cdce->pll[i].mul = n | ((v & CDCE706_PLL_HI_N_MASK) <<
+ (8 - CDCE706_PLL_HI_N_SHIFT));
+ cdce->pll[i].mux = mux & CDCE706_PLL_MUX_MASK(i);
+ dev_dbg(&cdce->client->dev,
+ "%s: i: %u, div: %u, mul: %u, mux: %d\n", __func__, i,
+ cdce->pll[i].div, cdce->pll[i].mul, cdce->pll[i].mux);
+ }
+
+ ret = cdce706_register_hw(cdce, cdce->pll,
+ ARRAY_SIZE(cdce->pll),
+ cdce706_pll_name, &init);
+ return ret;
+}
+
+static int cdce706_register_dividers(struct cdce706_dev_data *cdce)
+{
+ struct clk_init_data init = {
+ .ops = &cdce706_divider_ops,
+ .parent_names = cdce706_divider_parent_name,
+ .num_parents = ARRAY_SIZE(cdce706_divider_parent_name),
+ .flags = CLK_SET_RATE_PARENT,
+ };
+ unsigned i;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(cdce->divider); ++i) {
+ unsigned val;
+
+ ret = cdce706_reg_read(cdce, CDCE706_DIVIDER_PLL(i), &val);
+ if (ret < 0)
+ return ret;
+ cdce->divider[i].parent =
+ (val & CDCE706_DIVIDER_PLL_MASK(i)) >>
+ CDCE706_DIVIDER_PLL_SHIFT(i);
+
+ ret = cdce706_reg_read(cdce, CDCE706_DIVIDER(i), &val);
+ if (ret < 0)
+ return ret;
+ cdce->divider[i].div = val & CDCE706_DIVIDER_DIVIDER_MASK;
+ dev_dbg(&cdce->client->dev,
+ "%s: i: %u, parent: %u, div: %u\n", __func__, i,
+ cdce->divider[i].parent, cdce->divider[i].div);
+ }
+
+ ret = cdce706_register_hw(cdce, cdce->divider,
+ ARRAY_SIZE(cdce->divider),
+ cdce706_divider_name, &init);
+ return ret;
+}
+
+static int cdce706_register_clkouts(struct cdce706_dev_data *cdce)
+{
+ struct clk_init_data init = {
+ .ops = &cdce706_clkout_ops,
+ .parent_names = cdce706_divider_name,
+ .num_parents = ARRAY_SIZE(cdce706_divider_name),
+ .flags = CLK_SET_RATE_PARENT,
+ };
+ unsigned i;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(cdce->clkout); ++i) {
+ unsigned val;
+
+ ret = cdce706_reg_read(cdce, CDCE706_CLKOUT(i), &val);
+ if (ret < 0)
+ return ret;
+ cdce->clkout[i].parent = val & CDCE706_CLKOUT_DIVIDER_MASK;
+ dev_dbg(&cdce->client->dev,
+ "%s: i: %u, parent: %u\n", __func__, i,
+ cdce->clkout[i].parent);
+ }
+
+ ret = cdce706_register_hw(cdce, cdce->clkout,
+ ARRAY_SIZE(cdce->clkout),
+ cdce706_clkout_name, &init);
+ for (i = 0; i < ARRAY_SIZE(cdce->clkout); ++i)
+ cdce->clks[i] = cdce->clkout[i].clk;
+
+ return ret;
+}
+
+static int cdce706_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct cdce706_dev_data *cdce;
+ int ret;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ cdce = devm_kzalloc(&client->dev, sizeof(*cdce), GFP_KERNEL);
+ if (!cdce)
+ return -ENOMEM;
+
+ cdce->client = client;
+ cdce->regmap = devm_regmap_init_i2c(client, &cdce706_regmap_config);
+ if (IS_ERR(cdce->regmap)) {
+ dev_err(&client->dev, "Failed to initialize regmap\n");
+ return -EINVAL;
+ }
+
+ i2c_set_clientdata(client, cdce);
+
+ ret = cdce706_register_clkin(cdce);
+ if (ret < 0)
+ return ret;
+ ret = cdce706_register_plls(cdce);
+ if (ret < 0)
+ return ret;
+ ret = cdce706_register_dividers(cdce);
+ if (ret < 0)
+ return ret;
+ ret = cdce706_register_clkouts(cdce);
+ if (ret < 0)
+ return ret;
+ cdce->onecell.clks = cdce->clks;
+ cdce->onecell.clk_num = ARRAY_SIZE(cdce->clks);
+ ret = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get,
+ &cdce->onecell);
+
+ return ret;
+}
+
+static int cdce706_remove(struct i2c_client *client)
+{
+ return 0;
+}
+
+
+#ifdef CONFIG_OF
+static const struct of_device_id cdce706_dt_match[] = {
+ { .compatible = "ti,cdce706" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, cdce706_dt_match);
+#endif
+
+static const struct i2c_device_id cdce706_id[] = {
+ { "cdce706", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cdce706_id);
+
+static struct i2c_driver cdce706_i2c_driver = {
+ .driver = {
+ .name = "cdce706",
+ .of_match_table = of_match_ptr(cdce706_dt_match),
+ },
+ .probe = cdce706_probe,
+ .remove = cdce706_remove,
+ .id_table = cdce706_id,
+};
+module_i2c_driver(cdce706_i2c_driver);
+
+MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>");
+MODULE_DESCRIPTION("TI CDCE 706 clock synthesizer driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c
index 4386697..956b7e5 100644
--- a/drivers/clk/clk-composite.c
+++ b/drivers/clk/clk-composite.c
@@ -27,7 +27,7 @@
const struct clk_ops *mux_ops = composite->mux_ops;
struct clk_hw *mux_hw = composite->mux_hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
return mux_ops->get_parent(mux_hw);
}
@@ -38,7 +38,7 @@
const struct clk_ops *mux_ops = composite->mux_ops;
struct clk_hw *mux_hw = composite->mux_hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
return mux_ops->set_parent(mux_hw, index);
}
@@ -50,12 +50,14 @@
const struct clk_ops *rate_ops = composite->rate_ops;
struct clk_hw *rate_hw = composite->rate_hw;
- rate_hw->clk = hw->clk;
+ __clk_hw_set_clk(rate_hw, hw);
return rate_ops->recalc_rate(rate_hw, parent_rate);
}
static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_p)
{
@@ -72,8 +74,10 @@
int i;
if (rate_hw && rate_ops && rate_ops->determine_rate) {
- rate_hw->clk = hw->clk;
- return rate_ops->determine_rate(rate_hw, rate, best_parent_rate,
+ __clk_hw_set_clk(rate_hw, hw);
+ return rate_ops->determine_rate(rate_hw, rate, min_rate,
+ max_rate,
+ best_parent_rate,
best_parent_p);
} else if (rate_hw && rate_ops && rate_ops->round_rate &&
mux_hw && mux_ops && mux_ops->set_parent) {
@@ -116,8 +120,9 @@
return best_rate;
} else if (mux_hw && mux_ops && mux_ops->determine_rate) {
- mux_hw->clk = hw->clk;
- return mux_ops->determine_rate(mux_hw, rate, best_parent_rate,
+ __clk_hw_set_clk(mux_hw, hw);
+ return mux_ops->determine_rate(mux_hw, rate, min_rate,
+ max_rate, best_parent_rate,
best_parent_p);
} else {
pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n");
@@ -132,7 +137,7 @@
const struct clk_ops *rate_ops = composite->rate_ops;
struct clk_hw *rate_hw = composite->rate_hw;
- rate_hw->clk = hw->clk;
+ __clk_hw_set_clk(rate_hw, hw);
return rate_ops->round_rate(rate_hw, rate, prate);
}
@@ -144,7 +149,7 @@
const struct clk_ops *rate_ops = composite->rate_ops;
struct clk_hw *rate_hw = composite->rate_hw;
- rate_hw->clk = hw->clk;
+ __clk_hw_set_clk(rate_hw, hw);
return rate_ops->set_rate(rate_hw, rate, parent_rate);
}
@@ -155,7 +160,7 @@
const struct clk_ops *gate_ops = composite->gate_ops;
struct clk_hw *gate_hw = composite->gate_hw;
- gate_hw->clk = hw->clk;
+ __clk_hw_set_clk(gate_hw, hw);
return gate_ops->is_enabled(gate_hw);
}
@@ -166,7 +171,7 @@
const struct clk_ops *gate_ops = composite->gate_ops;
struct clk_hw *gate_hw = composite->gate_hw;
- gate_hw->clk = hw->clk;
+ __clk_hw_set_clk(gate_hw, hw);
return gate_ops->enable(gate_hw);
}
@@ -177,7 +182,7 @@
const struct clk_ops *gate_ops = composite->gate_ops;
struct clk_hw *gate_hw = composite->gate_hw;
- gate_hw->clk = hw->clk;
+ __clk_hw_set_clk(gate_hw, hw);
gate_ops->disable(gate_hw);
}
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index c0a842b..db7f8bc 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -30,7 +30,7 @@
#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
-#define div_mask(d) ((1 << ((d)->width)) - 1)
+#define div_mask(width) ((1 << (width)) - 1)
static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
{
@@ -54,15 +54,16 @@
return mindiv;
}
-static unsigned int _get_maxdiv(struct clk_divider *divider)
+static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width,
+ unsigned long flags)
{
- if (divider->flags & CLK_DIVIDER_ONE_BASED)
- return div_mask(divider);
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
- return 1 << div_mask(divider);
- if (divider->table)
- return _get_table_maxdiv(divider->table);
- return div_mask(divider) + 1;
+ if (flags & CLK_DIVIDER_ONE_BASED)
+ return div_mask(width);
+ if (flags & CLK_DIVIDER_POWER_OF_TWO)
+ return 1 << div_mask(width);
+ if (table)
+ return _get_table_maxdiv(table);
+ return div_mask(width) + 1;
}
static unsigned int _get_table_div(const struct clk_div_table *table,
@@ -76,14 +77,15 @@
return 0;
}
-static unsigned int _get_div(struct clk_divider *divider, unsigned int val)
+static unsigned int _get_div(const struct clk_div_table *table,
+ unsigned int val, unsigned long flags)
{
- if (divider->flags & CLK_DIVIDER_ONE_BASED)
+ if (flags & CLK_DIVIDER_ONE_BASED)
return val;
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+ if (flags & CLK_DIVIDER_POWER_OF_TWO)
return 1 << val;
- if (divider->table)
- return _get_table_div(divider->table, val);
+ if (table)
+ return _get_table_div(table, val);
return val + 1;
}
@@ -98,29 +100,28 @@
return 0;
}
-static unsigned int _get_val(struct clk_divider *divider, unsigned int div)
+static unsigned int _get_val(const struct clk_div_table *table,
+ unsigned int div, unsigned long flags)
{
- if (divider->flags & CLK_DIVIDER_ONE_BASED)
+ if (flags & CLK_DIVIDER_ONE_BASED)
return div;
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+ if (flags & CLK_DIVIDER_POWER_OF_TWO)
return __ffs(div);
- if (divider->table)
- return _get_table_val(divider->table, div);
+ if (table)
+ return _get_table_val(table, div);
return div - 1;
}
-static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
+unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate,
+ unsigned int val,
+ const struct clk_div_table *table,
+ unsigned long flags)
{
- struct clk_divider *divider = to_clk_divider(hw);
- unsigned int div, val;
+ unsigned int div;
- val = clk_readl(divider->reg) >> divider->shift;
- val &= div_mask(divider);
-
- div = _get_div(divider, val);
+ div = _get_div(table, val, flags);
if (!div) {
- WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO),
+ WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO),
"%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
__clk_get_name(hw->clk));
return parent_rate;
@@ -128,6 +129,20 @@
return DIV_ROUND_UP(parent_rate, div);
}
+EXPORT_SYMBOL_GPL(divider_recalc_rate);
+
+static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_divider *divider = to_clk_divider(hw);
+ unsigned int val;
+
+ val = clk_readl(divider->reg) >> divider->shift;
+ val &= div_mask(divider->width);
+
+ return divider_recalc_rate(hw, parent_rate, val, divider->table,
+ divider->flags);
+}
/*
* The reverse of DIV_ROUND_UP: The maximum number which
@@ -146,12 +161,13 @@
return false;
}
-static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
+static bool _is_valid_div(const struct clk_div_table *table, unsigned int div,
+ unsigned long flags)
{
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+ if (flags & CLK_DIVIDER_POWER_OF_TWO)
return is_power_of_2(div);
- if (divider->table)
- return _is_valid_table_div(divider->table, div);
+ if (table)
+ return _is_valid_table_div(table, div);
return true;
}
@@ -191,71 +207,76 @@
return down;
}
-static int _div_round_up(struct clk_divider *divider,
- unsigned long parent_rate, unsigned long rate)
+static int _div_round_up(const struct clk_div_table *table,
+ unsigned long parent_rate, unsigned long rate,
+ unsigned long flags)
{
int div = DIV_ROUND_UP(parent_rate, rate);
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+ if (flags & CLK_DIVIDER_POWER_OF_TWO)
div = __roundup_pow_of_two(div);
- if (divider->table)
- div = _round_up_table(divider->table, div);
+ if (table)
+ div = _round_up_table(table, div);
return div;
}
-static int _div_round_closest(struct clk_divider *divider,
- unsigned long parent_rate, unsigned long rate)
+static int _div_round_closest(const struct clk_div_table *table,
+ unsigned long parent_rate, unsigned long rate,
+ unsigned long flags)
{
int up, down, div;
up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate);
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) {
+ if (flags & CLK_DIVIDER_POWER_OF_TWO) {
up = __roundup_pow_of_two(div);
down = __rounddown_pow_of_two(div);
- } else if (divider->table) {
- up = _round_up_table(divider->table, div);
- down = _round_down_table(divider->table, div);
+ } else if (table) {
+ up = _round_up_table(table, div);
+ down = _round_down_table(table, div);
}
return (up - div) <= (div - down) ? up : down;
}
-static int _div_round(struct clk_divider *divider, unsigned long parent_rate,
- unsigned long rate)
+static int _div_round(const struct clk_div_table *table,
+ unsigned long parent_rate, unsigned long rate,
+ unsigned long flags)
{
- if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST)
- return _div_round_closest(divider, parent_rate, rate);
+ if (flags & CLK_DIVIDER_ROUND_CLOSEST)
+ return _div_round_closest(table, parent_rate, rate, flags);
- return _div_round_up(divider, parent_rate, rate);
+ return _div_round_up(table, parent_rate, rate, flags);
}
-static bool _is_best_div(struct clk_divider *divider,
- unsigned long rate, unsigned long now, unsigned long best)
+static bool _is_best_div(unsigned long rate, unsigned long now,
+ unsigned long best, unsigned long flags)
{
- if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST)
+ if (flags & CLK_DIVIDER_ROUND_CLOSEST)
return abs(rate - now) < abs(rate - best);
return now <= rate && now > best;
}
-static int _next_div(struct clk_divider *divider, int div)
+static int _next_div(const struct clk_div_table *table, int div,
+ unsigned long flags)
{
div++;
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+ if (flags & CLK_DIVIDER_POWER_OF_TWO)
return __roundup_pow_of_two(div);
- if (divider->table)
- return _round_up_table(divider->table, div);
+ if (table)
+ return _round_up_table(table, div);
return div;
}
static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
- unsigned long *best_parent_rate)
+ unsigned long *best_parent_rate,
+ const struct clk_div_table *table, u8 width,
+ unsigned long flags)
{
- struct clk_divider *divider = to_clk_divider(hw);
int i, bestdiv = 0;
unsigned long parent_rate, best = 0, now, maxdiv;
unsigned long parent_rate_saved = *best_parent_rate;
@@ -263,19 +284,11 @@
if (!rate)
rate = 1;
- /* if read only, just return current value */
- if (divider->flags & CLK_DIVIDER_READ_ONLY) {
- bestdiv = readl(divider->reg) >> divider->shift;
- bestdiv &= div_mask(divider);
- bestdiv = _get_div(divider, bestdiv);
- return bestdiv;
- }
-
- maxdiv = _get_maxdiv(divider);
+ maxdiv = _get_maxdiv(table, width, flags);
if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
parent_rate = *best_parent_rate;
- bestdiv = _div_round(divider, parent_rate, rate);
+ bestdiv = _div_round(table, parent_rate, rate, flags);
bestdiv = bestdiv == 0 ? 1 : bestdiv;
bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
return bestdiv;
@@ -287,8 +300,8 @@
*/
maxdiv = min(ULONG_MAX / rate, maxdiv);
- for (i = 1; i <= maxdiv; i = _next_div(divider, i)) {
- if (!_is_valid_div(divider, i))
+ for (i = 1; i <= maxdiv; i = _next_div(table, i, flags)) {
+ if (!_is_valid_div(table, i, flags))
continue;
if (rate * i == parent_rate_saved) {
/*
@@ -302,7 +315,7 @@
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
MULT_ROUND_UP(rate, i));
now = DIV_ROUND_UP(parent_rate, i);
- if (_is_best_div(divider, rate, now, best)) {
+ if (_is_best_div(rate, now, best, flags)) {
bestdiv = i;
best = now;
*best_parent_rate = parent_rate;
@@ -310,48 +323,79 @@
}
if (!bestdiv) {
- bestdiv = _get_maxdiv(divider);
+ bestdiv = _get_maxdiv(table, width, flags);
*best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
}
return bestdiv;
}
-static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+long divider_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate, const struct clk_div_table *table,
+ u8 width, unsigned long flags)
{
int div;
- div = clk_divider_bestdiv(hw, rate, prate);
+
+ div = clk_divider_bestdiv(hw, rate, prate, table, width, flags);
return DIV_ROUND_UP(*prate, div);
}
+EXPORT_SYMBOL_GPL(divider_round_rate);
+
+static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_divider *divider = to_clk_divider(hw);
+ int bestdiv;
+
+ /* if read only, just return current value */
+ if (divider->flags & CLK_DIVIDER_READ_ONLY) {
+ bestdiv = readl(divider->reg) >> divider->shift;
+ bestdiv &= div_mask(divider->width);
+ bestdiv = _get_div(divider->table, bestdiv, divider->flags);
+ return bestdiv;
+ }
+
+ return divider_round_rate(hw, rate, prate, divider->table,
+ divider->width, divider->flags);
+}
+
+int divider_get_val(unsigned long rate, unsigned long parent_rate,
+ const struct clk_div_table *table, u8 width,
+ unsigned long flags)
+{
+ unsigned int div, value;
+
+ div = DIV_ROUND_UP(parent_rate, rate);
+
+ if (!_is_valid_div(table, div, flags))
+ return -EINVAL;
+
+ value = _get_val(table, div, flags);
+
+ return min_t(unsigned int, value, div_mask(width));
+}
+EXPORT_SYMBOL_GPL(divider_get_val);
static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_divider *divider = to_clk_divider(hw);
- unsigned int div, value;
+ unsigned int value;
unsigned long flags = 0;
u32 val;
- div = DIV_ROUND_UP(parent_rate, rate);
-
- if (!_is_valid_div(divider, div))
- return -EINVAL;
-
- value = _get_val(divider, div);
-
- if (value > div_mask(divider))
- value = div_mask(divider);
+ value = divider_get_val(rate, parent_rate, divider->table,
+ divider->width, divider->flags);
if (divider->lock)
spin_lock_irqsave(divider->lock, flags);
if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
- val = div_mask(divider) << (divider->shift + 16);
+ val = div_mask(divider->width) << (divider->shift + 16);
} else {
val = clk_readl(divider->reg);
- val &= ~(div_mask(divider) << divider->shift);
+ val &= ~(div_mask(divider->width) << divider->shift);
}
val |= value << divider->shift;
clk_writel(val, divider->reg);
@@ -463,3 +507,19 @@
width, clk_divider_flags, table, lock);
}
EXPORT_SYMBOL_GPL(clk_register_divider_table);
+
+void clk_unregister_divider(struct clk *clk)
+{
+ struct clk_divider *div;
+ struct clk_hw *hw;
+
+ hw = __clk_get_hw(clk);
+ if (!hw)
+ return;
+
+ div = to_clk_divider(hw);
+
+ clk_unregister(clk);
+ kfree(div);
+}
+EXPORT_SYMBOL_GPL(clk_unregister_divider);
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index 51fd87f..3f0e420 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -128,7 +128,7 @@
struct clk_init_data init;
if (clk_gate_flags & CLK_GATE_HIWORD_MASK) {
- if (bit_idx > 16) {
+ if (bit_idx > 15) {
pr_err("gate bit exceeds LOWORD field\n");
return ERR_PTR(-EINVAL);
}
@@ -162,3 +162,19 @@
return clk;
}
EXPORT_SYMBOL_GPL(clk_register_gate);
+
+void clk_unregister_gate(struct clk *clk)
+{
+ struct clk_gate *gate;
+ struct clk_hw *hw;
+
+ hw = __clk_get_hw(clk);
+ if (!hw)
+ return;
+
+ gate = to_clk_gate(hw);
+
+ clk_unregister(clk);
+ kfree(gate);
+}
+EXPORT_SYMBOL_GPL(clk_unregister_gate);
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 6e1ecf9..69a094c 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -177,3 +177,19 @@
NULL, lock);
}
EXPORT_SYMBOL_GPL(clk_register_mux);
+
+void clk_unregister_mux(struct clk *clk)
+{
+ struct clk_mux *mux;
+ struct clk_hw *hw;
+
+ hw = __clk_get_hw(clk);
+ if (!hw)
+ return;
+
+ mux = to_clk_mux(hw);
+
+ clk_unregister(clk);
+ kfree(mux);
+}
+EXPORT_SYMBOL_GPL(clk_unregister_mux);
diff --git a/drivers/clk/clk-ppc-corenet.c b/drivers/clk/clk-ppc-corenet.c
deleted file mode 100644
index 0a47d6f..0000000
--- a/drivers/clk/clk-ppc-corenet.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright 2013 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * clock driver for Freescale PowerPC corenet SoCs.
- */
-#include <linux/clk-provider.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <linux/of.h>
-#include <linux/slab.h>
-
-struct cmux_clk {
- struct clk_hw hw;
- void __iomem *reg;
- u32 flags;
-};
-
-#define PLL_KILL BIT(31)
-#define CLKSEL_SHIFT 27
-#define CLKSEL_ADJUST BIT(0)
-#define to_cmux_clk(p) container_of(p, struct cmux_clk, hw)
-
-static unsigned int clocks_per_pll;
-
-static int cmux_set_parent(struct clk_hw *hw, u8 idx)
-{
- struct cmux_clk *clk = to_cmux_clk(hw);
- u32 clksel;
-
- clksel = ((idx / clocks_per_pll) << 2) + idx % clocks_per_pll;
- if (clk->flags & CLKSEL_ADJUST)
- clksel += 8;
- clksel = (clksel & 0xf) << CLKSEL_SHIFT;
- iowrite32be(clksel, clk->reg);
-
- return 0;
-}
-
-static u8 cmux_get_parent(struct clk_hw *hw)
-{
- struct cmux_clk *clk = to_cmux_clk(hw);
- u32 clksel;
-
- clksel = ioread32be(clk->reg);
- clksel = (clksel >> CLKSEL_SHIFT) & 0xf;
- if (clk->flags & CLKSEL_ADJUST)
- clksel -= 8;
- clksel = (clksel >> 2) * clocks_per_pll + clksel % 4;
-
- return clksel;
-}
-
-const struct clk_ops cmux_ops = {
- .get_parent = cmux_get_parent,
- .set_parent = cmux_set_parent,
-};
-
-static void __init core_mux_init(struct device_node *np)
-{
- struct clk *clk;
- struct clk_init_data init;
- struct cmux_clk *cmux_clk;
- struct device_node *node;
- int rc, count, i;
- u32 offset;
- const char *clk_name;
- const char **parent_names;
-
- rc = of_property_read_u32(np, "reg", &offset);
- if (rc) {
- pr_err("%s: could not get reg property\n", np->name);
- return;
- }
-
- /* get the input clock source count */
- count = of_property_count_strings(np, "clock-names");
- if (count < 0) {
- pr_err("%s: get clock count error\n", np->name);
- return;
- }
- parent_names = kzalloc((sizeof(char *) * count), GFP_KERNEL);
- if (!parent_names) {
- pr_err("%s: could not allocate parent_names\n", __func__);
- return;
- }
-
- for (i = 0; i < count; i++)
- parent_names[i] = of_clk_get_parent_name(np, i);
-
- cmux_clk = kzalloc(sizeof(struct cmux_clk), GFP_KERNEL);
- if (!cmux_clk) {
- pr_err("%s: could not allocate cmux_clk\n", __func__);
- goto err_name;
- }
- cmux_clk->reg = of_iomap(np, 0);
- if (!cmux_clk->reg) {
- pr_err("%s: could not map register\n", __func__);
- goto err_clk;
- }
-
- node = of_find_compatible_node(NULL, NULL, "fsl,p4080-clockgen");
- if (node && (offset >= 0x80))
- cmux_clk->flags = CLKSEL_ADJUST;
-
- rc = of_property_read_string_index(np, "clock-output-names",
- 0, &clk_name);
- if (rc) {
- pr_err("%s: read clock names error\n", np->name);
- goto err_clk;
- }
-
- init.name = clk_name;
- init.ops = &cmux_ops;
- init.parent_names = parent_names;
- init.num_parents = count;
- init.flags = 0;
- cmux_clk->hw.init = &init;
-
- clk = clk_register(NULL, &cmux_clk->hw);
- if (IS_ERR(clk)) {
- pr_err("%s: could not register clock\n", clk_name);
- goto err_clk;
- }
-
- rc = of_clk_add_provider(np, of_clk_src_simple_get, clk);
- if (rc) {
- pr_err("Could not register clock provider for node:%s\n",
- np->name);
- goto err_clk;
- }
- goto err_name;
-
-err_clk:
- kfree(cmux_clk);
-err_name:
- /* free *_names because they are reallocated when registered */
- kfree(parent_names);
-}
-
-static void __init core_pll_init(struct device_node *np)
-{
- u32 mult;
- int i, rc, count;
- const char *clk_name, *parent_name;
- struct clk_onecell_data *onecell_data;
- struct clk **subclks;
- void __iomem *base;
-
- base = of_iomap(np, 0);
- if (!base) {
- pr_err("clk-ppc: iomap error\n");
- return;
- }
-
- /* get the multiple of PLL */
- mult = ioread32be(base);
-
- /* check if this PLL is disabled */
- if (mult & PLL_KILL) {
- pr_debug("PLL:%s is disabled\n", np->name);
- goto err_map;
- }
- mult = (mult >> 1) & 0x3f;
-
- parent_name = of_clk_get_parent_name(np, 0);
- if (!parent_name) {
- pr_err("PLL: %s must have a parent\n", np->name);
- goto err_map;
- }
-
- count = of_property_count_strings(np, "clock-output-names");
- if (count < 0 || count > 4) {
- pr_err("%s: clock is not supported\n", np->name);
- goto err_map;
- }
-
- /* output clock number per PLL */
- clocks_per_pll = count;
-
- subclks = kzalloc(sizeof(struct clk *) * count, GFP_KERNEL);
- if (!subclks) {
- pr_err("%s: could not allocate subclks\n", __func__);
- goto err_map;
- }
-
- onecell_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
- if (!onecell_data) {
- pr_err("%s: could not allocate onecell_data\n", __func__);
- goto err_clks;
- }
-
- for (i = 0; i < count; i++) {
- rc = of_property_read_string_index(np, "clock-output-names",
- i, &clk_name);
- if (rc) {
- pr_err("%s: could not get clock names\n", np->name);
- goto err_cell;
- }
-
- /*
- * when count == 4, there are 4 output clocks:
- * /1, /2, /3, /4 respectively
- * when count < 4, there are at least 2 output clocks:
- * /1, /2, (/4, if count == 3) respectively.
- */
- if (count == 4)
- subclks[i] = clk_register_fixed_factor(NULL, clk_name,
- parent_name, 0, mult, 1 + i);
- else
-
- subclks[i] = clk_register_fixed_factor(NULL, clk_name,
- parent_name, 0, mult, 1 << i);
-
- if (IS_ERR(subclks[i])) {
- pr_err("%s: could not register clock\n", clk_name);
- goto err_cell;
- }
- }
-
- onecell_data->clks = subclks;
- onecell_data->clk_num = count;
-
- rc = of_clk_add_provider(np, of_clk_src_onecell_get, onecell_data);
- if (rc) {
- pr_err("Could not register clk provider for node:%s\n",
- np->name);
- goto err_cell;
- }
-
- iounmap(base);
- return;
-err_cell:
- kfree(onecell_data);
-err_clks:
- kfree(subclks);
-err_map:
- iounmap(base);
-}
-
-static void __init sysclk_init(struct device_node *node)
-{
- struct clk *clk;
- const char *clk_name = node->name;
- struct device_node *np = of_get_parent(node);
- u32 rate;
-
- if (!np) {
- pr_err("ppc-clk: could not get parent node\n");
- return;
- }
-
- if (of_property_read_u32(np, "clock-frequency", &rate)) {
- of_node_put(node);
- return;
- }
-
- of_property_read_string(np, "clock-output-names", &clk_name);
-
- clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT, rate);
- if (!IS_ERR(clk))
- of_clk_add_provider(np, of_clk_src_simple_get, clk);
-}
-
-static const struct of_device_id clk_match[] __initconst = {
- { .compatible = "fsl,qoriq-sysclk-1.0", .data = sysclk_init, },
- { .compatible = "fsl,qoriq-sysclk-2.0", .data = sysclk_init, },
- { .compatible = "fsl,qoriq-core-pll-1.0", .data = core_pll_init, },
- { .compatible = "fsl,qoriq-core-pll-2.0", .data = core_pll_init, },
- { .compatible = "fsl,qoriq-core-mux-1.0", .data = core_mux_init, },
- { .compatible = "fsl,qoriq-core-mux-2.0", .data = core_mux_init, },
- {}
-};
-
-static int __init ppc_corenet_clk_probe(struct platform_device *pdev)
-{
- of_clk_init(clk_match);
-
- return 0;
-}
-
-static const struct of_device_id ppc_clk_ids[] __initconst = {
- { .compatible = "fsl,qoriq-clockgen-1.0", },
- { .compatible = "fsl,qoriq-clockgen-2.0", },
- {}
-};
-
-static struct platform_driver ppc_corenet_clk_driver = {
- .driver = {
- .name = "ppc_corenet_clock",
- .of_match_table = ppc_clk_ids,
- },
- .probe = ppc_corenet_clk_probe,
-};
-
-static int __init ppc_corenet_clk_init(void)
-{
- return platform_driver_register(&ppc_corenet_clk_driver);
-}
-subsys_initcall(ppc_corenet_clk_init);
diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c
new file mode 100644
index 0000000..cda90a9
--- /dev/null
+++ b/drivers/clk/clk-qoriq.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * clock driver for Freescale QorIQ SoCs.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+struct cmux_clk {
+ struct clk_hw hw;
+ void __iomem *reg;
+ unsigned int clk_per_pll;
+ u32 flags;
+};
+
+#define PLL_KILL BIT(31)
+#define CLKSEL_SHIFT 27
+#define CLKSEL_ADJUST BIT(0)
+#define to_cmux_clk(p) container_of(p, struct cmux_clk, hw)
+
+static int cmux_set_parent(struct clk_hw *hw, u8 idx)
+{
+ struct cmux_clk *clk = to_cmux_clk(hw);
+ u32 clksel;
+
+ clksel = ((idx / clk->clk_per_pll) << 2) + idx % clk->clk_per_pll;
+ if (clk->flags & CLKSEL_ADJUST)
+ clksel += 8;
+ clksel = (clksel & 0xf) << CLKSEL_SHIFT;
+ iowrite32be(clksel, clk->reg);
+
+ return 0;
+}
+
+static u8 cmux_get_parent(struct clk_hw *hw)
+{
+ struct cmux_clk *clk = to_cmux_clk(hw);
+ u32 clksel;
+
+ clksel = ioread32be(clk->reg);
+ clksel = (clksel >> CLKSEL_SHIFT) & 0xf;
+ if (clk->flags & CLKSEL_ADJUST)
+ clksel -= 8;
+ clksel = (clksel >> 2) * clk->clk_per_pll + clksel % 4;
+
+ return clksel;
+}
+
+static const struct clk_ops cmux_ops = {
+ .get_parent = cmux_get_parent,
+ .set_parent = cmux_set_parent,
+};
+
+static void __init core_mux_init(struct device_node *np)
+{
+ struct clk *clk;
+ struct clk_init_data init;
+ struct cmux_clk *cmux_clk;
+ struct device_node *node;
+ int rc, count, i;
+ u32 offset;
+ const char *clk_name;
+ const char **parent_names;
+ struct of_phandle_args clkspec;
+
+ rc = of_property_read_u32(np, "reg", &offset);
+ if (rc) {
+ pr_err("%s: could not get reg property\n", np->name);
+ return;
+ }
+
+ /* get the input clock source count */
+ count = of_property_count_strings(np, "clock-names");
+ if (count < 0) {
+ pr_err("%s: get clock count error\n", np->name);
+ return;
+ }
+ parent_names = kcalloc(count, sizeof(char *), GFP_KERNEL);
+ if (!parent_names)
+ return;
+
+ for (i = 0; i < count; i++)
+ parent_names[i] = of_clk_get_parent_name(np, i);
+
+ cmux_clk = kzalloc(sizeof(*cmux_clk), GFP_KERNEL);
+ if (!cmux_clk)
+ goto err_name;
+
+ cmux_clk->reg = of_iomap(np, 0);
+ if (!cmux_clk->reg) {
+ pr_err("%s: could not map register\n", __func__);
+ goto err_clk;
+ }
+
+ rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", 0,
+ &clkspec);
+ if (rc) {
+ pr_err("%s: parse clock node error\n", __func__);
+ goto err_clk;
+ }
+
+ cmux_clk->clk_per_pll = of_property_count_strings(clkspec.np,
+ "clock-output-names");
+ of_node_put(clkspec.np);
+
+ node = of_find_compatible_node(NULL, NULL, "fsl,p4080-clockgen");
+ if (node && (offset >= 0x80))
+ cmux_clk->flags = CLKSEL_ADJUST;
+
+ rc = of_property_read_string_index(np, "clock-output-names",
+ 0, &clk_name);
+ if (rc) {
+ pr_err("%s: read clock names error\n", np->name);
+ goto err_clk;
+ }
+
+ init.name = clk_name;
+ init.ops = &cmux_ops;
+ init.parent_names = parent_names;
+ init.num_parents = count;
+ init.flags = 0;
+ cmux_clk->hw.init = &init;
+
+ clk = clk_register(NULL, &cmux_clk->hw);
+ if (IS_ERR(clk)) {
+ pr_err("%s: could not register clock\n", clk_name);
+ goto err_clk;
+ }
+
+ rc = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ if (rc) {
+ pr_err("Could not register clock provider for node:%s\n",
+ np->name);
+ goto err_clk;
+ }
+ goto err_name;
+
+err_clk:
+ kfree(cmux_clk);
+err_name:
+ /* free *_names because they are reallocated when registered */
+ kfree(parent_names);
+}
+
+static void __init core_pll_init(struct device_node *np)
+{
+ u32 mult;
+ int i, rc, count;
+ const char *clk_name, *parent_name;
+ struct clk_onecell_data *onecell_data;
+ struct clk **subclks;
+ void __iomem *base;
+
+ base = of_iomap(np, 0);
+ if (!base) {
+ pr_err("iomap error\n");
+ return;
+ }
+
+ /* get the multiple of PLL */
+ mult = ioread32be(base);
+
+ /* check if this PLL is disabled */
+ if (mult & PLL_KILL) {
+ pr_debug("PLL:%s is disabled\n", np->name);
+ goto err_map;
+ }
+ mult = (mult >> 1) & 0x3f;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+ if (!parent_name) {
+ pr_err("PLL: %s must have a parent\n", np->name);
+ goto err_map;
+ }
+
+ count = of_property_count_strings(np, "clock-output-names");
+ if (count < 0 || count > 4) {
+ pr_err("%s: clock is not supported\n", np->name);
+ goto err_map;
+ }
+
+ subclks = kcalloc(count, sizeof(struct clk *), GFP_KERNEL);
+ if (!subclks)
+ goto err_map;
+
+ onecell_data = kmalloc(sizeof(*onecell_data), GFP_KERNEL);
+ if (!onecell_data)
+ goto err_clks;
+
+ for (i = 0; i < count; i++) {
+ rc = of_property_read_string_index(np, "clock-output-names",
+ i, &clk_name);
+ if (rc) {
+ pr_err("%s: could not get clock names\n", np->name);
+ goto err_cell;
+ }
+
+ /*
+ * when count == 4, there are 4 output clocks:
+ * /1, /2, /3, /4 respectively
+ * when count < 4, there are at least 2 output clocks:
+ * /1, /2, (/4, if count == 3) respectively.
+ */
+ if (count == 4)
+ subclks[i] = clk_register_fixed_factor(NULL, clk_name,
+ parent_name, 0, mult, 1 + i);
+ else
+
+ subclks[i] = clk_register_fixed_factor(NULL, clk_name,
+ parent_name, 0, mult, 1 << i);
+
+ if (IS_ERR(subclks[i])) {
+ pr_err("%s: could not register clock\n", clk_name);
+ goto err_cell;
+ }
+ }
+
+ onecell_data->clks = subclks;
+ onecell_data->clk_num = count;
+
+ rc = of_clk_add_provider(np, of_clk_src_onecell_get, onecell_data);
+ if (rc) {
+ pr_err("Could not register clk provider for node:%s\n",
+ np->name);
+ goto err_cell;
+ }
+
+ iounmap(base);
+ return;
+err_cell:
+ kfree(onecell_data);
+err_clks:
+ kfree(subclks);
+err_map:
+ iounmap(base);
+}
+
+static void __init sysclk_init(struct device_node *node)
+{
+ struct clk *clk;
+ const char *clk_name = node->name;
+ struct device_node *np = of_get_parent(node);
+ u32 rate;
+
+ if (!np) {
+ pr_err("could not get parent node\n");
+ return;
+ }
+
+ if (of_property_read_u32(np, "clock-frequency", &rate)) {
+ of_node_put(node);
+ return;
+ }
+
+ of_property_read_string(np, "clock-output-names", &clk_name);
+
+ clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT, rate);
+ if (!IS_ERR(clk))
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+
+static void __init pltfrm_pll_init(struct device_node *np)
+{
+ void __iomem *base;
+ uint32_t mult;
+ const char *parent_name, *clk_name;
+ int i, _errno;
+ struct clk_onecell_data *cod;
+
+ base = of_iomap(np, 0);
+ if (!base) {
+ pr_err("%s(): %s: of_iomap() failed\n", __func__, np->name);
+ return;
+ }
+
+ /* Get the multiple of PLL */
+ mult = ioread32be(base);
+
+ iounmap(base);
+
+ /* Check if this PLL is disabled */
+ if (mult & PLL_KILL) {
+ pr_debug("%s(): %s: Disabled\n", __func__, np->name);
+ return;
+ }
+ mult = (mult & GENMASK(6, 1)) >> 1;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+ if (!parent_name) {
+ pr_err("%s(): %s: of_clk_get_parent_name() failed\n",
+ __func__, np->name);
+ return;
+ }
+
+ i = of_property_count_strings(np, "clock-output-names");
+ if (i < 0) {
+ pr_err("%s(): %s: of_property_count_strings(clock-output-names) = %d\n",
+ __func__, np->name, i);
+ return;
+ }
+
+ cod = kmalloc(sizeof(*cod) + i * sizeof(struct clk *), GFP_KERNEL);
+ if (!cod)
+ return;
+ cod->clks = (struct clk **)(cod + 1);
+ cod->clk_num = i;
+
+ for (i = 0; i < cod->clk_num; i++) {
+ _errno = of_property_read_string_index(np, "clock-output-names",
+ i, &clk_name);
+ if (_errno < 0) {
+ pr_err("%s(): %s: of_property_read_string_index(clock-output-names) = %d\n",
+ __func__, np->name, _errno);
+ goto return_clk_unregister;
+ }
+
+ cod->clks[i] = clk_register_fixed_factor(NULL, clk_name,
+ parent_name, 0, mult, 1 + i);
+ if (IS_ERR(cod->clks[i])) {
+ pr_err("%s(): %s: clk_register_fixed_factor(%s) = %ld\n",
+ __func__, np->name,
+ clk_name, PTR_ERR(cod->clks[i]));
+ goto return_clk_unregister;
+ }
+ }
+
+ _errno = of_clk_add_provider(np, of_clk_src_onecell_get, cod);
+ if (_errno < 0) {
+ pr_err("%s(): %s: of_clk_add_provider() = %d\n",
+ __func__, np->name, _errno);
+ goto return_clk_unregister;
+ }
+
+ return;
+
+return_clk_unregister:
+ while (--i >= 0)
+ clk_unregister(cod->clks[i]);
+ kfree(cod);
+}
+
+CLK_OF_DECLARE(qoriq_sysclk_1, "fsl,qoriq-sysclk-1.0", sysclk_init);
+CLK_OF_DECLARE(qoriq_sysclk_2, "fsl,qoriq-sysclk-2.0", sysclk_init);
+CLK_OF_DECLARE(qoriq_core_pll_1, "fsl,qoriq-core-pll-1.0", core_pll_init);
+CLK_OF_DECLARE(qoriq_core_pll_2, "fsl,qoriq-core-pll-2.0", core_pll_init);
+CLK_OF_DECLARE(qoriq_core_mux_1, "fsl,qoriq-core-mux-1.0", core_mux_init);
+CLK_OF_DECLARE(qoriq_core_mux_2, "fsl,qoriq-core-mux-2.0", core_mux_init);
+CLK_OF_DECLARE(qoriq_pltfrm_pll_1, "fsl,qoriq-platform-pll-1.0", pltfrm_pll_init);
+CLK_OF_DECLARE(qoriq_pltfrm_pll_2, "fsl,qoriq-platform-pll-2.0", pltfrm_pll_init);
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 642cf37..eb01529 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -9,7 +9,7 @@
* Standard functionality for the common clock API. See Documentation/clk.txt
*/
-#include <linux/clk-private.h>
+#include <linux/clk-provider.h>
#include <linux/clk/clk-conf.h>
#include <linux/module.h>
#include <linux/mutex.h>
@@ -37,6 +37,55 @@
static HLIST_HEAD(clk_orphan_list);
static LIST_HEAD(clk_notifier_list);
+static long clk_core_get_accuracy(struct clk_core *clk);
+static unsigned long clk_core_get_rate(struct clk_core *clk);
+static int clk_core_get_phase(struct clk_core *clk);
+static bool clk_core_is_prepared(struct clk_core *clk);
+static bool clk_core_is_enabled(struct clk_core *clk);
+static struct clk_core *clk_core_lookup(const char *name);
+
+/*** private data structures ***/
+
+struct clk_core {
+ const char *name;
+ const struct clk_ops *ops;
+ struct clk_hw *hw;
+ struct module *owner;
+ struct clk_core *parent;
+ const char **parent_names;
+ struct clk_core **parents;
+ u8 num_parents;
+ u8 new_parent_index;
+ unsigned long rate;
+ unsigned long req_rate;
+ unsigned long new_rate;
+ struct clk_core *new_parent;
+ struct clk_core *new_child;
+ unsigned long flags;
+ unsigned int enable_count;
+ unsigned int prepare_count;
+ unsigned long accuracy;
+ int phase;
+ struct hlist_head children;
+ struct hlist_node child_node;
+ struct hlist_node debug_node;
+ struct hlist_head clks;
+ unsigned int notifier_count;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *dentry;
+#endif
+ struct kref ref;
+};
+
+struct clk {
+ struct clk_core *core;
+ const char *dev_id;
+ const char *con_id;
+ unsigned long min_rate;
+ unsigned long max_rate;
+ struct hlist_node child_node;
+};
+
/*** locking ***/
static void clk_prepare_lock(void)
{
@@ -114,7 +163,8 @@
NULL,
};
-static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level)
+static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
+ int level)
{
if (!c)
return;
@@ -122,14 +172,14 @@
seq_printf(s, "%*s%-*s %11d %12d %11lu %10lu %-3d\n",
level * 3 + 1, "",
30 - level * 3, c->name,
- c->enable_count, c->prepare_count, clk_get_rate(c),
- clk_get_accuracy(c), clk_get_phase(c));
+ c->enable_count, c->prepare_count, clk_core_get_rate(c),
+ clk_core_get_accuracy(c), clk_core_get_phase(c));
}
-static void clk_summary_show_subtree(struct seq_file *s, struct clk *c,
+static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
int level)
{
- struct clk *child;
+ struct clk_core *child;
if (!c)
return;
@@ -142,7 +192,7 @@
static int clk_summary_show(struct seq_file *s, void *data)
{
- struct clk *c;
+ struct clk_core *c;
struct hlist_head **lists = (struct hlist_head **)s->private;
seq_puts(s, " clock enable_cnt prepare_cnt rate accuracy phase\n");
@@ -172,7 +222,7 @@
.release = single_release,
};
-static void clk_dump_one(struct seq_file *s, struct clk *c, int level)
+static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level)
{
if (!c)
return;
@@ -180,14 +230,14 @@
seq_printf(s, "\"%s\": { ", c->name);
seq_printf(s, "\"enable_count\": %d,", c->enable_count);
seq_printf(s, "\"prepare_count\": %d,", c->prepare_count);
- seq_printf(s, "\"rate\": %lu", clk_get_rate(c));
- seq_printf(s, "\"accuracy\": %lu", clk_get_accuracy(c));
- seq_printf(s, "\"phase\": %d", clk_get_phase(c));
+ seq_printf(s, "\"rate\": %lu", clk_core_get_rate(c));
+ seq_printf(s, "\"accuracy\": %lu", clk_core_get_accuracy(c));
+ seq_printf(s, "\"phase\": %d", clk_core_get_phase(c));
}
-static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level)
+static void clk_dump_subtree(struct seq_file *s, struct clk_core *c, int level)
{
- struct clk *child;
+ struct clk_core *child;
if (!c)
return;
@@ -204,7 +254,7 @@
static int clk_dump(struct seq_file *s, void *data)
{
- struct clk *c;
+ struct clk_core *c;
bool first_node = true;
struct hlist_head **lists = (struct hlist_head **)s->private;
@@ -240,7 +290,7 @@
.release = single_release,
};
-static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry)
+static int clk_debug_create_one(struct clk_core *clk, struct dentry *pdentry)
{
struct dentry *d;
int ret = -ENOMEM;
@@ -315,7 +365,7 @@
* initialized. Otherwise it bails out early since the debugfs clk tree
* will be created lazily by clk_debug_init as part of a late_initcall.
*/
-static int clk_debug_register(struct clk *clk)
+static int clk_debug_register(struct clk_core *clk)
{
int ret = 0;
@@ -340,16 +390,12 @@
* debugfs clk tree if clk->dentry points to debugfs created by
* clk_debug_register in __clk_init.
*/
-static void clk_debug_unregister(struct clk *clk)
+static void clk_debug_unregister(struct clk_core *clk)
{
mutex_lock(&clk_debug_lock);
- if (!clk->dentry)
- goto out;
-
hlist_del_init(&clk->debug_node);
debugfs_remove_recursive(clk->dentry);
clk->dentry = NULL;
-out:
mutex_unlock(&clk_debug_lock);
}
@@ -358,8 +404,9 @@
{
struct dentry *d = NULL;
- if (hw->clk->dentry)
- d = debugfs_create_file(name, mode, hw->clk->dentry, data, fops);
+ if (hw->core->dentry)
+ d = debugfs_create_file(name, mode, hw->core->dentry, data,
+ fops);
return d;
}
@@ -379,7 +426,7 @@
*/
static int __init clk_debug_init(void)
{
- struct clk *clk;
+ struct clk_core *clk;
struct dentry *d;
rootdir = debugfs_create_dir("clk", NULL);
@@ -418,22 +465,20 @@
}
late_initcall(clk_debug_init);
#else
-static inline int clk_debug_register(struct clk *clk) { return 0; }
-static inline void clk_debug_reparent(struct clk *clk, struct clk *new_parent)
+static inline int clk_debug_register(struct clk_core *clk) { return 0; }
+static inline void clk_debug_reparent(struct clk_core *clk,
+ struct clk_core *new_parent)
{
}
-static inline void clk_debug_unregister(struct clk *clk)
+static inline void clk_debug_unregister(struct clk_core *clk)
{
}
#endif
/* caller must hold prepare_lock */
-static void clk_unprepare_unused_subtree(struct clk *clk)
+static void clk_unprepare_unused_subtree(struct clk_core *clk)
{
- struct clk *child;
-
- if (!clk)
- return;
+ struct clk_core *child;
hlist_for_each_entry(child, &clk->children, child_node)
clk_unprepare_unused_subtree(child);
@@ -444,7 +489,7 @@
if (clk->flags & CLK_IGNORE_UNUSED)
return;
- if (__clk_is_prepared(clk)) {
+ if (clk_core_is_prepared(clk)) {
if (clk->ops->unprepare_unused)
clk->ops->unprepare_unused(clk->hw);
else if (clk->ops->unprepare)
@@ -453,14 +498,11 @@
}
/* caller must hold prepare_lock */
-static void clk_disable_unused_subtree(struct clk *clk)
+static void clk_disable_unused_subtree(struct clk_core *clk)
{
- struct clk *child;
+ struct clk_core *child;
unsigned long flags;
- if (!clk)
- goto out;
-
hlist_for_each_entry(child, &clk->children, child_node)
clk_disable_unused_subtree(child);
@@ -477,7 +519,7 @@
* sequence. call .disable_unused if available, otherwise fall
* back to .disable
*/
- if (__clk_is_enabled(clk)) {
+ if (clk_core_is_enabled(clk)) {
if (clk->ops->disable_unused)
clk->ops->disable_unused(clk->hw);
else if (clk->ops->disable)
@@ -486,9 +528,6 @@
unlock_out:
clk_enable_unlock(flags);
-
-out:
- return;
}
static bool clk_ignore_unused;
@@ -501,7 +540,7 @@
static int clk_disable_unused(void)
{
- struct clk *clk;
+ struct clk_core *clk;
if (clk_ignore_unused) {
pr_warn("clk: Not disabling unused clocks\n");
@@ -532,48 +571,65 @@
const char *__clk_get_name(struct clk *clk)
{
- return !clk ? NULL : clk->name;
+ return !clk ? NULL : clk->core->name;
}
EXPORT_SYMBOL_GPL(__clk_get_name);
struct clk_hw *__clk_get_hw(struct clk *clk)
{
- return !clk ? NULL : clk->hw;
+ return !clk ? NULL : clk->core->hw;
}
EXPORT_SYMBOL_GPL(__clk_get_hw);
u8 __clk_get_num_parents(struct clk *clk)
{
- return !clk ? 0 : clk->num_parents;
+ return !clk ? 0 : clk->core->num_parents;
}
EXPORT_SYMBOL_GPL(__clk_get_num_parents);
struct clk *__clk_get_parent(struct clk *clk)
{
- return !clk ? NULL : clk->parent;
+ if (!clk)
+ return NULL;
+
+ /* TODO: Create a per-user clk and change callers to call clk_put */
+ return !clk->core->parent ? NULL : clk->core->parent->hw->clk;
}
EXPORT_SYMBOL_GPL(__clk_get_parent);
-struct clk *clk_get_parent_by_index(struct clk *clk, u8 index)
+static struct clk_core *clk_core_get_parent_by_index(struct clk_core *clk,
+ u8 index)
{
if (!clk || index >= clk->num_parents)
return NULL;
else if (!clk->parents)
- return __clk_lookup(clk->parent_names[index]);
+ return clk_core_lookup(clk->parent_names[index]);
else if (!clk->parents[index])
return clk->parents[index] =
- __clk_lookup(clk->parent_names[index]);
+ clk_core_lookup(clk->parent_names[index]);
else
return clk->parents[index];
}
+
+struct clk *clk_get_parent_by_index(struct clk *clk, u8 index)
+{
+ struct clk_core *parent;
+
+ if (!clk)
+ return NULL;
+
+ parent = clk_core_get_parent_by_index(clk->core, index);
+
+ return !parent ? NULL : parent->hw->clk;
+}
EXPORT_SYMBOL_GPL(clk_get_parent_by_index);
unsigned int __clk_get_enable_count(struct clk *clk)
{
- return !clk ? 0 : clk->enable_count;
+ return !clk ? 0 : clk->core->enable_count;
}
-unsigned long __clk_get_rate(struct clk *clk)
+static unsigned long clk_core_get_rate_nolock(struct clk_core *clk)
{
unsigned long ret;
@@ -593,9 +649,17 @@
out:
return ret;
}
+
+unsigned long __clk_get_rate(struct clk *clk)
+{
+ if (!clk)
+ return 0;
+
+ return clk_core_get_rate_nolock(clk->core);
+}
EXPORT_SYMBOL_GPL(__clk_get_rate);
-static unsigned long __clk_get_accuracy(struct clk *clk)
+static unsigned long __clk_get_accuracy(struct clk_core *clk)
{
if (!clk)
return 0;
@@ -605,11 +669,11 @@
unsigned long __clk_get_flags(struct clk *clk)
{
- return !clk ? 0 : clk->flags;
+ return !clk ? 0 : clk->core->flags;
}
EXPORT_SYMBOL_GPL(__clk_get_flags);
-bool __clk_is_prepared(struct clk *clk)
+static bool clk_core_is_prepared(struct clk_core *clk)
{
int ret;
@@ -630,7 +694,15 @@
return !!ret;
}
-bool __clk_is_enabled(struct clk *clk)
+bool __clk_is_prepared(struct clk *clk)
+{
+ if (!clk)
+ return false;
+
+ return clk_core_is_prepared(clk->core);
+}
+
+static bool clk_core_is_enabled(struct clk_core *clk)
{
int ret;
@@ -650,12 +722,21 @@
out:
return !!ret;
}
+
+bool __clk_is_enabled(struct clk *clk)
+{
+ if (!clk)
+ return false;
+
+ return clk_core_is_enabled(clk->core);
+}
EXPORT_SYMBOL_GPL(__clk_is_enabled);
-static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk)
+static struct clk_core *__clk_lookup_subtree(const char *name,
+ struct clk_core *clk)
{
- struct clk *child;
- struct clk *ret;
+ struct clk_core *child;
+ struct clk_core *ret;
if (!strcmp(clk->name, name))
return clk;
@@ -669,10 +750,10 @@
return NULL;
}
-struct clk *__clk_lookup(const char *name)
+static struct clk_core *clk_core_lookup(const char *name)
{
- struct clk *root_clk;
- struct clk *ret;
+ struct clk_core *root_clk;
+ struct clk_core *ret;
if (!name)
return NULL;
@@ -694,42 +775,53 @@
return NULL;
}
-/*
- * Helper for finding best parent to provide a given frequency. This can be used
- * directly as a determine_rate callback (e.g. for a mux), or from a more
- * complex clock that may combine a mux with other operations.
- */
-long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *best_parent_rate,
- struct clk_hw **best_parent_p)
+static bool mux_is_better_rate(unsigned long rate, unsigned long now,
+ unsigned long best, unsigned long flags)
{
- struct clk *clk = hw->clk, *parent, *best_parent = NULL;
+ if (flags & CLK_MUX_ROUND_CLOSEST)
+ return abs(now - rate) < abs(best - rate);
+
+ return now <= rate && now > best;
+}
+
+static long
+clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
+ unsigned long *best_parent_rate,
+ struct clk_hw **best_parent_p,
+ unsigned long flags)
+{
+ struct clk_core *core = hw->core, *parent, *best_parent = NULL;
int i, num_parents;
unsigned long parent_rate, best = 0;
/* if NO_REPARENT flag set, pass through to current parent */
- if (clk->flags & CLK_SET_RATE_NO_REPARENT) {
- parent = clk->parent;
- if (clk->flags & CLK_SET_RATE_PARENT)
- best = __clk_round_rate(parent, rate);
+ if (core->flags & CLK_SET_RATE_NO_REPARENT) {
+ parent = core->parent;
+ if (core->flags & CLK_SET_RATE_PARENT)
+ best = __clk_determine_rate(parent ? parent->hw : NULL,
+ rate, min_rate, max_rate);
else if (parent)
- best = __clk_get_rate(parent);
+ best = clk_core_get_rate_nolock(parent);
else
- best = __clk_get_rate(clk);
+ best = clk_core_get_rate_nolock(core);
goto out;
}
/* find the parent that can provide the fastest rate <= rate */
- num_parents = clk->num_parents;
+ num_parents = core->num_parents;
for (i = 0; i < num_parents; i++) {
- parent = clk_get_parent_by_index(clk, i);
+ parent = clk_core_get_parent_by_index(core, i);
if (!parent)
continue;
- if (clk->flags & CLK_SET_RATE_PARENT)
- parent_rate = __clk_round_rate(parent, rate);
+ if (core->flags & CLK_SET_RATE_PARENT)
+ parent_rate = __clk_determine_rate(parent->hw, rate,
+ min_rate,
+ max_rate);
else
- parent_rate = __clk_get_rate(parent);
- if (parent_rate <= rate && parent_rate > best) {
+ parent_rate = clk_core_get_rate_nolock(parent);
+ if (mux_is_better_rate(rate, parent_rate, best, flags)) {
best_parent = parent;
best = parent_rate;
}
@@ -742,11 +834,63 @@
return best;
}
+
+struct clk *__clk_lookup(const char *name)
+{
+ struct clk_core *core = clk_core_lookup(name);
+
+ return !core ? NULL : core->hw->clk;
+}
+
+static void clk_core_get_boundaries(struct clk_core *clk,
+ unsigned long *min_rate,
+ unsigned long *max_rate)
+{
+ struct clk *clk_user;
+
+ *min_rate = 0;
+ *max_rate = ULONG_MAX;
+
+ hlist_for_each_entry(clk_user, &clk->clks, child_node)
+ *min_rate = max(*min_rate, clk_user->min_rate);
+
+ hlist_for_each_entry(clk_user, &clk->clks, child_node)
+ *max_rate = min(*max_rate, clk_user->max_rate);
+}
+
+/*
+ * Helper for finding best parent to provide a given frequency. This can be used
+ * directly as a determine_rate callback (e.g. for a mux), or from a more
+ * complex clock that may combine a mux with other operations.
+ */
+long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
+ unsigned long *best_parent_rate,
+ struct clk_hw **best_parent_p)
+{
+ return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate,
+ best_parent_rate,
+ best_parent_p, 0);
+}
EXPORT_SYMBOL_GPL(__clk_mux_determine_rate);
+long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
+ unsigned long *best_parent_rate,
+ struct clk_hw **best_parent_p)
+{
+ return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate,
+ best_parent_rate,
+ best_parent_p,
+ CLK_MUX_ROUND_CLOSEST);
+}
+EXPORT_SYMBOL_GPL(__clk_mux_determine_rate_closest);
+
/*** clk api ***/
-void __clk_unprepare(struct clk *clk)
+static void clk_core_unprepare(struct clk_core *clk)
{
if (!clk)
return;
@@ -762,7 +906,7 @@
if (clk->ops->unprepare)
clk->ops->unprepare(clk->hw);
- __clk_unprepare(clk->parent);
+ clk_core_unprepare(clk->parent);
}
/**
@@ -782,12 +926,12 @@
return;
clk_prepare_lock();
- __clk_unprepare(clk);
+ clk_core_unprepare(clk->core);
clk_prepare_unlock();
}
EXPORT_SYMBOL_GPL(clk_unprepare);
-int __clk_prepare(struct clk *clk)
+static int clk_core_prepare(struct clk_core *clk)
{
int ret = 0;
@@ -795,14 +939,14 @@
return 0;
if (clk->prepare_count == 0) {
- ret = __clk_prepare(clk->parent);
+ ret = clk_core_prepare(clk->parent);
if (ret)
return ret;
if (clk->ops->prepare) {
ret = clk->ops->prepare(clk->hw);
if (ret) {
- __clk_unprepare(clk->parent);
+ clk_core_unprepare(clk->parent);
return ret;
}
}
@@ -829,15 +973,18 @@
{
int ret;
+ if (!clk)
+ return 0;
+
clk_prepare_lock();
- ret = __clk_prepare(clk);
+ ret = clk_core_prepare(clk->core);
clk_prepare_unlock();
return ret;
}
EXPORT_SYMBOL_GPL(clk_prepare);
-static void __clk_disable(struct clk *clk)
+static void clk_core_disable(struct clk_core *clk)
{
if (!clk)
return;
@@ -851,7 +998,15 @@
if (clk->ops->disable)
clk->ops->disable(clk->hw);
- __clk_disable(clk->parent);
+ clk_core_disable(clk->parent);
+}
+
+static void __clk_disable(struct clk *clk)
+{
+ if (!clk)
+ return;
+
+ clk_core_disable(clk->core);
}
/**
@@ -879,7 +1034,7 @@
}
EXPORT_SYMBOL_GPL(clk_disable);
-static int __clk_enable(struct clk *clk)
+static int clk_core_enable(struct clk_core *clk)
{
int ret = 0;
@@ -890,7 +1045,7 @@
return -ESHUTDOWN;
if (clk->enable_count == 0) {
- ret = __clk_enable(clk->parent);
+ ret = clk_core_enable(clk->parent);
if (ret)
return ret;
@@ -898,7 +1053,7 @@
if (clk->ops->enable) {
ret = clk->ops->enable(clk->hw);
if (ret) {
- __clk_disable(clk->parent);
+ clk_core_disable(clk->parent);
return ret;
}
}
@@ -908,6 +1063,14 @@
return 0;
}
+static int __clk_enable(struct clk *clk)
+{
+ if (!clk)
+ return 0;
+
+ return clk_core_enable(clk->core);
+}
+
/**
* clk_enable - ungate a clock
* @clk: the clk being ungated
@@ -934,17 +1097,13 @@
}
EXPORT_SYMBOL_GPL(clk_enable);
-/**
- * __clk_round_rate - round the given rate for a clk
- * @clk: round the rate of this clock
- * @rate: the rate which is to be rounded
- *
- * Caller must hold prepare_lock. Useful for clk_ops such as .set_rate
- */
-unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
+static unsigned long clk_core_round_rate_nolock(struct clk_core *clk,
+ unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate)
{
unsigned long parent_rate = 0;
- struct clk *parent;
+ struct clk_core *parent;
struct clk_hw *parent_hw;
if (!clk)
@@ -956,15 +1115,59 @@
if (clk->ops->determine_rate) {
parent_hw = parent ? parent->hw : NULL;
- return clk->ops->determine_rate(clk->hw, rate, &parent_rate,
- &parent_hw);
+ return clk->ops->determine_rate(clk->hw, rate,
+ min_rate, max_rate,
+ &parent_rate, &parent_hw);
} else if (clk->ops->round_rate)
return clk->ops->round_rate(clk->hw, rate, &parent_rate);
else if (clk->flags & CLK_SET_RATE_PARENT)
- return __clk_round_rate(clk->parent, rate);
+ return clk_core_round_rate_nolock(clk->parent, rate, min_rate,
+ max_rate);
else
return clk->rate;
}
+
+/**
+ * __clk_determine_rate - get the closest rate actually supported by a clock
+ * @hw: determine the rate of this clock
+ * @rate: target rate
+ * @min_rate: returned rate must be greater than this rate
+ * @max_rate: returned rate must be less than this rate
+ *
+ * Caller must hold prepare_lock. Useful for clk_ops such as .set_rate and
+ * .determine_rate.
+ */
+unsigned long __clk_determine_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate)
+{
+ if (!hw)
+ return 0;
+
+ return clk_core_round_rate_nolock(hw->core, rate, min_rate, max_rate);
+}
+EXPORT_SYMBOL_GPL(__clk_determine_rate);
+
+/**
+ * __clk_round_rate - round the given rate for a clk
+ * @clk: round the rate of this clock
+ * @rate: the rate which is to be rounded
+ *
+ * Caller must hold prepare_lock. Useful for clk_ops such as .set_rate
+ */
+unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned long min_rate;
+ unsigned long max_rate;
+
+ if (!clk)
+ return 0;
+
+ clk_core_get_boundaries(clk->core, &min_rate, &max_rate);
+
+ return clk_core_round_rate_nolock(clk->core, rate, min_rate, max_rate);
+}
EXPORT_SYMBOL_GPL(__clk_round_rate);
/**
@@ -980,6 +1183,9 @@
{
unsigned long ret;
+ if (!clk)
+ return 0;
+
clk_prepare_lock();
ret = __clk_round_rate(clk, rate);
clk_prepare_unlock();
@@ -1002,22 +1208,21 @@
* called if all went well, or NOTIFY_STOP or NOTIFY_BAD immediately if
* a driver returns that.
*/
-static int __clk_notify(struct clk *clk, unsigned long msg,
+static int __clk_notify(struct clk_core *clk, unsigned long msg,
unsigned long old_rate, unsigned long new_rate)
{
struct clk_notifier *cn;
struct clk_notifier_data cnd;
int ret = NOTIFY_DONE;
- cnd.clk = clk;
cnd.old_rate = old_rate;
cnd.new_rate = new_rate;
list_for_each_entry(cn, &clk_notifier_list, node) {
- if (cn->clk == clk) {
+ if (cn->clk->core == clk) {
+ cnd.clk = cn->clk;
ret = srcu_notifier_call_chain(&cn->notifier_head, msg,
&cnd);
- break;
}
}
@@ -1035,10 +1240,10 @@
*
* Caller must hold prepare_lock.
*/
-static void __clk_recalc_accuracies(struct clk *clk)
+static void __clk_recalc_accuracies(struct clk_core *clk)
{
unsigned long parent_accuracy = 0;
- struct clk *child;
+ struct clk_core *child;
if (clk->parent)
parent_accuracy = clk->parent->accuracy;
@@ -1053,16 +1258,7 @@
__clk_recalc_accuracies(child);
}
-/**
- * clk_get_accuracy - return the accuracy of clk
- * @clk: the clk whose accuracy is being returned
- *
- * Simply returns the cached accuracy of the clk, unless
- * CLK_GET_ACCURACY_NOCACHE flag is set, which means a recalc_rate will be
- * issued.
- * If clk is NULL then returns 0.
- */
-long clk_get_accuracy(struct clk *clk)
+static long clk_core_get_accuracy(struct clk_core *clk)
{
unsigned long accuracy;
@@ -1075,9 +1271,27 @@
return accuracy;
}
+
+/**
+ * clk_get_accuracy - return the accuracy of clk
+ * @clk: the clk whose accuracy is being returned
+ *
+ * Simply returns the cached accuracy of the clk, unless
+ * CLK_GET_ACCURACY_NOCACHE flag is set, which means a recalc_rate will be
+ * issued.
+ * If clk is NULL then returns 0.
+ */
+long clk_get_accuracy(struct clk *clk)
+{
+ if (!clk)
+ return 0;
+
+ return clk_core_get_accuracy(clk->core);
+}
EXPORT_SYMBOL_GPL(clk_get_accuracy);
-static unsigned long clk_recalc(struct clk *clk, unsigned long parent_rate)
+static unsigned long clk_recalc(struct clk_core *clk,
+ unsigned long parent_rate)
{
if (clk->ops->recalc_rate)
return clk->ops->recalc_rate(clk->hw, parent_rate);
@@ -1098,11 +1312,11 @@
*
* Caller must hold prepare_lock.
*/
-static void __clk_recalc_rates(struct clk *clk, unsigned long msg)
+static void __clk_recalc_rates(struct clk_core *clk, unsigned long msg)
{
unsigned long old_rate;
unsigned long parent_rate = 0;
- struct clk *child;
+ struct clk_core *child;
old_rate = clk->rate;
@@ -1122,6 +1336,22 @@
__clk_recalc_rates(child, msg);
}
+static unsigned long clk_core_get_rate(struct clk_core *clk)
+{
+ unsigned long rate;
+
+ clk_prepare_lock();
+
+ if (clk && (clk->flags & CLK_GET_RATE_NOCACHE))
+ __clk_recalc_rates(clk, 0);
+
+ rate = clk_core_get_rate_nolock(clk);
+ clk_prepare_unlock();
+
+ return rate;
+}
+EXPORT_SYMBOL_GPL(clk_core_get_rate);
+
/**
* clk_get_rate - return the rate of clk
* @clk: the clk whose rate is being returned
@@ -1132,21 +1362,15 @@
*/
unsigned long clk_get_rate(struct clk *clk)
{
- unsigned long rate;
+ if (!clk)
+ return 0;
- clk_prepare_lock();
-
- if (clk && (clk->flags & CLK_GET_RATE_NOCACHE))
- __clk_recalc_rates(clk, 0);
-
- rate = __clk_get_rate(clk);
- clk_prepare_unlock();
-
- return rate;
+ return clk_core_get_rate(clk->core);
}
EXPORT_SYMBOL_GPL(clk_get_rate);
-static int clk_fetch_parent_index(struct clk *clk, struct clk *parent)
+static int clk_fetch_parent_index(struct clk_core *clk,
+ struct clk_core *parent)
{
int i;
@@ -1160,7 +1384,7 @@
/*
* find index of new parent clock using cached parent ptrs,
* or if not yet cached, use string name comparison and cache
- * them now to avoid future calls to __clk_lookup.
+ * them now to avoid future calls to clk_core_lookup.
*/
for (i = 0; i < clk->num_parents; i++) {
if (clk->parents[i] == parent)
@@ -1170,7 +1394,7 @@
continue;
if (!strcmp(clk->parent_names[i], parent->name)) {
- clk->parents[i] = __clk_lookup(parent->name);
+ clk->parents[i] = clk_core_lookup(parent->name);
return i;
}
}
@@ -1178,7 +1402,7 @@
return -EINVAL;
}
-static void clk_reparent(struct clk *clk, struct clk *new_parent)
+static void clk_reparent(struct clk_core *clk, struct clk_core *new_parent)
{
hlist_del(&clk->child_node);
@@ -1195,10 +1419,11 @@
clk->parent = new_parent;
}
-static struct clk *__clk_set_parent_before(struct clk *clk, struct clk *parent)
+static struct clk_core *__clk_set_parent_before(struct clk_core *clk,
+ struct clk_core *parent)
{
unsigned long flags;
- struct clk *old_parent = clk->parent;
+ struct clk_core *old_parent = clk->parent;
/*
* Migrate prepare state between parents and prevent race with
@@ -1218,9 +1443,9 @@
* See also: Comment for clk_set_parent() below.
*/
if (clk->prepare_count) {
- __clk_prepare(parent);
- clk_enable(parent);
- clk_enable(clk);
+ clk_core_prepare(parent);
+ clk_core_enable(parent);
+ clk_core_enable(clk);
}
/* update the clk tree topology */
@@ -1231,25 +1456,27 @@
return old_parent;
}
-static void __clk_set_parent_after(struct clk *clk, struct clk *parent,
- struct clk *old_parent)
+static void __clk_set_parent_after(struct clk_core *core,
+ struct clk_core *parent,
+ struct clk_core *old_parent)
{
/*
* Finish the migration of prepare state and undo the changes done
* for preventing a race with clk_enable().
*/
- if (clk->prepare_count) {
- clk_disable(clk);
- clk_disable(old_parent);
- __clk_unprepare(old_parent);
+ if (core->prepare_count) {
+ clk_core_disable(core);
+ clk_core_disable(old_parent);
+ clk_core_unprepare(old_parent);
}
}
-static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
+static int __clk_set_parent(struct clk_core *clk, struct clk_core *parent,
+ u8 p_index)
{
unsigned long flags;
int ret = 0;
- struct clk *old_parent;
+ struct clk_core *old_parent;
old_parent = __clk_set_parent_before(clk, parent);
@@ -1263,9 +1490,9 @@
clk_enable_unlock(flags);
if (clk->prepare_count) {
- clk_disable(clk);
- clk_disable(parent);
- __clk_unprepare(parent);
+ clk_core_disable(clk);
+ clk_core_disable(parent);
+ clk_core_unprepare(parent);
}
return ret;
}
@@ -1291,9 +1518,10 @@
*
* Caller must hold prepare_lock.
*/
-static int __clk_speculate_rates(struct clk *clk, unsigned long parent_rate)
+static int __clk_speculate_rates(struct clk_core *clk,
+ unsigned long parent_rate)
{
- struct clk *child;
+ struct clk_core *child;
unsigned long new_rate;
int ret = NOTIFY_DONE;
@@ -1319,10 +1547,10 @@
return ret;
}
-static void clk_calc_subtree(struct clk *clk, unsigned long new_rate,
- struct clk *new_parent, u8 p_index)
+static void clk_calc_subtree(struct clk_core *clk, unsigned long new_rate,
+ struct clk_core *new_parent, u8 p_index)
{
- struct clk *child;
+ struct clk_core *child;
clk->new_rate = new_rate;
clk->new_parent = new_parent;
@@ -1342,13 +1570,16 @@
* calculate the new rates returning the topmost clock that has to be
* changed.
*/
-static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
+static struct clk_core *clk_calc_new_rates(struct clk_core *clk,
+ unsigned long rate)
{
- struct clk *top = clk;
- struct clk *old_parent, *parent;
+ struct clk_core *top = clk;
+ struct clk_core *old_parent, *parent;
struct clk_hw *parent_hw;
unsigned long best_parent_rate = 0;
unsigned long new_rate;
+ unsigned long min_rate;
+ unsigned long max_rate;
int p_index = 0;
/* sanity */
@@ -1360,16 +1591,22 @@
if (parent)
best_parent_rate = parent->rate;
+ clk_core_get_boundaries(clk, &min_rate, &max_rate);
+
/* find the closest rate and parent clk/rate */
if (clk->ops->determine_rate) {
parent_hw = parent ? parent->hw : NULL;
new_rate = clk->ops->determine_rate(clk->hw, rate,
+ min_rate,
+ max_rate,
&best_parent_rate,
&parent_hw);
- parent = parent_hw ? parent_hw->clk : NULL;
+ parent = parent_hw ? parent_hw->core : NULL;
} else if (clk->ops->round_rate) {
new_rate = clk->ops->round_rate(clk->hw, rate,
&best_parent_rate);
+ if (new_rate < min_rate || new_rate > max_rate)
+ return NULL;
} else if (!parent || !(clk->flags & CLK_SET_RATE_PARENT)) {
/* pass-through clock without adjustable parent */
clk->new_rate = clk->rate;
@@ -1390,7 +1627,7 @@
}
/* try finding the new parent index */
- if (parent) {
+ if (parent && clk->num_parents > 1) {
p_index = clk_fetch_parent_index(clk, parent);
if (p_index < 0) {
pr_debug("%s: clk %s can not be parent of clk %s\n",
@@ -1414,9 +1651,10 @@
* so that in case of an error we can walk down the whole tree again and
* abort the change.
*/
-static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long event)
+static struct clk_core *clk_propagate_rate_change(struct clk_core *clk,
+ unsigned long event)
{
- struct clk *child, *tmp_clk, *fail_clk = NULL;
+ struct clk_core *child, *tmp_clk, *fail_clk = NULL;
int ret = NOTIFY_DONE;
if (clk->rate == clk->new_rate)
@@ -1451,14 +1689,14 @@
* walk down a subtree and set the new rates notifying the rate
* change on the way
*/
-static void clk_change_rate(struct clk *clk)
+static void clk_change_rate(struct clk_core *clk)
{
- struct clk *child;
+ struct clk_core *child;
struct hlist_node *tmp;
unsigned long old_rate;
unsigned long best_parent_rate = 0;
bool skip_set_rate = false;
- struct clk *old_parent;
+ struct clk_core *old_parent;
old_rate = clk->rate;
@@ -1506,6 +1744,45 @@
clk_change_rate(clk->new_child);
}
+static int clk_core_set_rate_nolock(struct clk_core *clk,
+ unsigned long req_rate)
+{
+ struct clk_core *top, *fail_clk;
+ unsigned long rate = req_rate;
+ int ret = 0;
+
+ if (!clk)
+ return 0;
+
+ /* bail early if nothing to do */
+ if (rate == clk_core_get_rate_nolock(clk))
+ return 0;
+
+ if ((clk->flags & CLK_SET_RATE_GATE) && clk->prepare_count)
+ return -EBUSY;
+
+ /* calculate new rates and get the topmost changed clock */
+ top = clk_calc_new_rates(clk, rate);
+ if (!top)
+ return -EINVAL;
+
+ /* notify that we are about to change rates */
+ fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
+ if (fail_clk) {
+ pr_debug("%s: failed to set %s rate\n", __func__,
+ fail_clk->name);
+ clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
+ return -EBUSY;
+ }
+
+ /* change the rates */
+ clk_change_rate(top);
+
+ clk->req_rate = req_rate;
+
+ return ret;
+}
+
/**
* clk_set_rate - specify a new rate for clk
* @clk: the clk whose rate is being changed
@@ -1529,8 +1806,7 @@
*/
int clk_set_rate(struct clk *clk, unsigned long rate)
{
- struct clk *top, *fail_clk;
- int ret = 0;
+ int ret;
if (!clk)
return 0;
@@ -1538,36 +1814,8 @@
/* prevent racing with updates to the clock topology */
clk_prepare_lock();
- /* bail early if nothing to do */
- if (rate == clk_get_rate(clk))
- goto out;
+ ret = clk_core_set_rate_nolock(clk->core, rate);
- if ((clk->flags & CLK_SET_RATE_GATE) && clk->prepare_count) {
- ret = -EBUSY;
- goto out;
- }
-
- /* calculate new rates and get the topmost changed clock */
- top = clk_calc_new_rates(clk, rate);
- if (!top) {
- ret = -EINVAL;
- goto out;
- }
-
- /* notify that we are about to change rates */
- fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
- if (fail_clk) {
- pr_debug("%s: failed to set %s rate\n", __func__,
- fail_clk->name);
- clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
- ret = -EBUSY;
- goto out;
- }
-
- /* change the rates */
- clk_change_rate(top);
-
-out:
clk_prepare_unlock();
return ret;
@@ -1575,6 +1823,74 @@
EXPORT_SYMBOL_GPL(clk_set_rate);
/**
+ * clk_set_rate_range - set a rate range for a clock source
+ * @clk: clock source
+ * @min: desired minimum clock rate in Hz, inclusive
+ * @max: desired maximum clock rate in Hz, inclusive
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max)
+{
+ int ret = 0;
+
+ if (!clk)
+ return 0;
+
+ if (min > max) {
+ pr_err("%s: clk %s dev %s con %s: invalid range [%lu, %lu]\n",
+ __func__, clk->core->name, clk->dev_id, clk->con_id,
+ min, max);
+ return -EINVAL;
+ }
+
+ clk_prepare_lock();
+
+ if (min != clk->min_rate || max != clk->max_rate) {
+ clk->min_rate = min;
+ clk->max_rate = max;
+ ret = clk_core_set_rate_nolock(clk->core, clk->core->req_rate);
+ }
+
+ clk_prepare_unlock();
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate_range);
+
+/**
+ * clk_set_min_rate - set a minimum clock rate for a clock source
+ * @clk: clock source
+ * @rate: desired minimum clock rate in Hz, inclusive
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_set_min_rate(struct clk *clk, unsigned long rate)
+{
+ if (!clk)
+ return 0;
+
+ return clk_set_rate_range(clk, rate, clk->max_rate);
+}
+EXPORT_SYMBOL_GPL(clk_set_min_rate);
+
+/**
+ * clk_set_max_rate - set a maximum clock rate for a clock source
+ * @clk: clock source
+ * @rate: desired maximum clock rate in Hz, inclusive
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_set_max_rate(struct clk *clk, unsigned long rate)
+{
+ if (!clk)
+ return 0;
+
+ return clk_set_rate_range(clk, clk->min_rate, rate);
+}
+EXPORT_SYMBOL_GPL(clk_set_max_rate);
+
+/**
* clk_get_parent - return the parent of a clk
* @clk: the clk whose parent gets returned
*
@@ -1599,11 +1915,11 @@
*
* For single-parent clocks without .get_parent, first check to see if the
* .parents array exists, and if so use it to avoid an expensive tree
- * traversal. If .parents does not exist then walk the tree with __clk_lookup.
+ * traversal. If .parents does not exist then walk the tree.
*/
-static struct clk *__clk_init_parent(struct clk *clk)
+static struct clk_core *__clk_init_parent(struct clk_core *clk)
{
- struct clk *ret = NULL;
+ struct clk_core *ret = NULL;
u8 index;
/* handle the trivial cases */
@@ -1613,7 +1929,7 @@
if (clk->num_parents == 1) {
if (IS_ERR_OR_NULL(clk->parent))
- clk->parent = __clk_lookup(clk->parent_names[0]);
+ clk->parent = clk_core_lookup(clk->parent_names[0]);
ret = clk->parent;
goto out;
}
@@ -1627,8 +1943,8 @@
/*
* Do our best to cache parent clocks in clk->parents. This prevents
- * unnecessary and expensive calls to __clk_lookup. We don't set
- * clk->parent here; that is done by the calling function
+ * unnecessary and expensive lookups. We don't set clk->parent here;
+ * that is done by the calling function.
*/
index = clk->ops->get_parent(clk->hw);
@@ -1638,13 +1954,14 @@
kcalloc(clk->num_parents, sizeof(struct clk *),
GFP_KERNEL);
- ret = clk_get_parent_by_index(clk, index);
+ ret = clk_core_get_parent_by_index(clk, index);
out:
return ret;
}
-void __clk_reparent(struct clk *clk, struct clk *new_parent)
+static void clk_core_reparent(struct clk_core *clk,
+ struct clk_core *new_parent)
{
clk_reparent(clk, new_parent);
__clk_recalc_accuracies(clk);
@@ -1652,23 +1969,40 @@
}
/**
- * clk_set_parent - switch the parent of a mux clk
- * @clk: the mux clk whose input we are switching
- * @parent: the new input to clk
+ * clk_has_parent - check if a clock is a possible parent for another
+ * @clk: clock source
+ * @parent: parent clock source
*
- * Re-parent clk to use parent as its new input source. If clk is in
- * prepared state, the clk will get enabled for the duration of this call. If
- * that's not acceptable for a specific clk (Eg: the consumer can't handle
- * that, the reparenting is glitchy in hardware, etc), use the
- * CLK_SET_PARENT_GATE flag to allow reparenting only when clk is unprepared.
+ * This function can be used in drivers that need to check that a clock can be
+ * the parent of another without actually changing the parent.
*
- * After successfully changing clk's parent clk_set_parent will update the
- * clk topology, sysfs topology and propagate rate recalculation via
- * __clk_recalc_rates.
- *
- * Returns 0 on success, -EERROR otherwise.
+ * Returns true if @parent is a possible parent for @clk, false otherwise.
*/
-int clk_set_parent(struct clk *clk, struct clk *parent)
+bool clk_has_parent(struct clk *clk, struct clk *parent)
+{
+ struct clk_core *core, *parent_core;
+ unsigned int i;
+
+ /* NULL clocks should be nops, so return success if either is NULL. */
+ if (!clk || !parent)
+ return true;
+
+ core = clk->core;
+ parent_core = parent->core;
+
+ /* Optimize for the case where the parent is already the parent. */
+ if (core->parent == parent_core)
+ return true;
+
+ for (i = 0; i < core->num_parents; i++)
+ if (strcmp(core->parent_names[i], parent_core->name) == 0)
+ return true;
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(clk_has_parent);
+
+static int clk_core_set_parent(struct clk_core *clk, struct clk_core *parent)
{
int ret = 0;
int p_index = 0;
@@ -1728,6 +2062,31 @@
return ret;
}
+
+/**
+ * clk_set_parent - switch the parent of a mux clk
+ * @clk: the mux clk whose input we are switching
+ * @parent: the new input to clk
+ *
+ * Re-parent clk to use parent as its new input source. If clk is in
+ * prepared state, the clk will get enabled for the duration of this call. If
+ * that's not acceptable for a specific clk (Eg: the consumer can't handle
+ * that, the reparenting is glitchy in hardware, etc), use the
+ * CLK_SET_PARENT_GATE flag to allow reparenting only when clk is unprepared.
+ *
+ * After successfully changing clk's parent clk_set_parent will update the
+ * clk topology, sysfs topology and propagate rate recalculation via
+ * __clk_recalc_rates.
+ *
+ * Returns 0 on success, -EERROR otherwise.
+ */
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ if (!clk)
+ return 0;
+
+ return clk_core_set_parent(clk->core, parent ? parent->core : NULL);
+}
EXPORT_SYMBOL_GPL(clk_set_parent);
/**
@@ -1764,13 +2123,13 @@
clk_prepare_lock();
- if (!clk->ops->set_phase)
+ if (!clk->core->ops->set_phase)
goto out_unlock;
- ret = clk->ops->set_phase(clk->hw, degrees);
+ ret = clk->core->ops->set_phase(clk->core->hw, degrees);
if (!ret)
- clk->phase = degrees;
+ clk->core->phase = degrees;
out_unlock:
clk_prepare_unlock();
@@ -1778,15 +2137,9 @@
out:
return ret;
}
+EXPORT_SYMBOL_GPL(clk_set_phase);
-/**
- * clk_get_phase - return the phase shift of a clock signal
- * @clk: clock signal source
- *
- * Returns the phase shift of a clock node in degrees, otherwise returns
- * -EERROR.
- */
-int clk_get_phase(struct clk *clk)
+static int clk_core_get_phase(struct clk_core *clk)
{
int ret = 0;
@@ -1800,28 +2153,48 @@
out:
return ret;
}
+EXPORT_SYMBOL_GPL(clk_get_phase);
+
+/**
+ * clk_get_phase - return the phase shift of a clock signal
+ * @clk: clock signal source
+ *
+ * Returns the phase shift of a clock node in degrees, otherwise returns
+ * -EERROR.
+ */
+int clk_get_phase(struct clk *clk)
+{
+ if (!clk)
+ return 0;
+
+ return clk_core_get_phase(clk->core);
+}
/**
* __clk_init - initialize the data structures in a struct clk
* @dev: device initializing this clk, placeholder for now
* @clk: clk being initialized
*
- * Initializes the lists in struct clk, queries the hardware for the
+ * Initializes the lists in struct clk_core, queries the hardware for the
* parent and rate and sets them both.
*/
-int __clk_init(struct device *dev, struct clk *clk)
+static int __clk_init(struct device *dev, struct clk *clk_user)
{
int i, ret = 0;
- struct clk *orphan;
+ struct clk_core *orphan;
struct hlist_node *tmp2;
+ struct clk_core *clk;
+ unsigned long rate;
- if (!clk)
+ if (!clk_user)
return -EINVAL;
+ clk = clk_user->core;
+
clk_prepare_lock();
/* check to see if a clock with this name is already registered */
- if (__clk_lookup(clk->name)) {
+ if (clk_core_lookup(clk->name)) {
pr_debug("%s: clk %s already initialized\n",
__func__, clk->name);
ret = -EEXIST;
@@ -1873,7 +2246,7 @@
clk->parents = kcalloc(clk->num_parents, sizeof(struct clk *),
GFP_KERNEL);
/*
- * __clk_lookup returns NULL for parents that have not been
+ * clk_core_lookup returns NULL for parents that have not been
* clk_init'd; thus any access to clk->parents[] must check
* for a NULL pointer. We can always perform lazy lookups for
* missing parents later on.
@@ -1881,7 +2254,7 @@
if (clk->parents)
for (i = 0; i < clk->num_parents; i++)
clk->parents[i] =
- __clk_lookup(clk->parent_names[i]);
+ clk_core_lookup(clk->parent_names[i]);
}
clk->parent = __clk_init_parent(clk);
@@ -1936,12 +2309,13 @@
* then rate is set to zero.
*/
if (clk->ops->recalc_rate)
- clk->rate = clk->ops->recalc_rate(clk->hw,
- __clk_get_rate(clk->parent));
+ rate = clk->ops->recalc_rate(clk->hw,
+ clk_core_get_rate_nolock(clk->parent));
else if (clk->parent)
- clk->rate = clk->parent->rate;
+ rate = clk->parent->rate;
else
- clk->rate = 0;
+ rate = 0;
+ clk->rate = clk->req_rate = rate;
/*
* walk the list of orphan clocks and reparent any that are children of
@@ -1951,13 +2325,13 @@
if (orphan->num_parents && orphan->ops->get_parent) {
i = orphan->ops->get_parent(orphan->hw);
if (!strcmp(clk->name, orphan->parent_names[i]))
- __clk_reparent(orphan, clk);
+ clk_core_reparent(orphan, clk);
continue;
}
for (i = 0; i < orphan->num_parents; i++)
if (!strcmp(clk->name, orphan->parent_names[i])) {
- __clk_reparent(orphan, clk);
+ clk_core_reparent(orphan, clk);
break;
}
}
@@ -1983,47 +2357,39 @@
return ret;
}
-/**
- * __clk_register - register a clock and return a cookie.
- *
- * Same as clk_register, except that the .clk field inside hw shall point to a
- * preallocated (generally statically allocated) struct clk. None of the fields
- * of the struct clk need to be initialized.
- *
- * The data pointed to by .init and .clk field shall NOT be marked as init
- * data.
- *
- * __clk_register is only exposed via clk-private.h and is intended for use with
- * very large numbers of clocks that need to be statically initialized. It is
- * a layering violation to include clk-private.h from any code which implements
- * a clock's .ops; as such any statically initialized clock data MUST be in a
- * separate C file from the logic that implements its operations. Returns 0
- * on success, otherwise an error code.
- */
-struct clk *__clk_register(struct device *dev, struct clk_hw *hw)
+struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
+ const char *con_id)
{
- int ret;
struct clk *clk;
- clk = hw->clk;
- clk->name = hw->init->name;
- clk->ops = hw->init->ops;
- clk->hw = hw;
- clk->flags = hw->init->flags;
- clk->parent_names = hw->init->parent_names;
- clk->num_parents = hw->init->num_parents;
- if (dev && dev->driver)
- clk->owner = dev->driver->owner;
- else
- clk->owner = NULL;
+ /* This is to allow this function to be chained to others */
+ if (!hw || IS_ERR(hw))
+ return (struct clk *) hw;
- ret = __clk_init(dev, clk);
- if (ret)
- return ERR_PTR(ret);
+ clk = kzalloc(sizeof(*clk), GFP_KERNEL);
+ if (!clk)
+ return ERR_PTR(-ENOMEM);
+
+ clk->core = hw->core;
+ clk->dev_id = dev_id;
+ clk->con_id = con_id;
+ clk->max_rate = ULONG_MAX;
+
+ clk_prepare_lock();
+ hlist_add_head(&clk->child_node, &hw->core->clks);
+ clk_prepare_unlock();
return clk;
}
-EXPORT_SYMBOL_GPL(__clk_register);
+
+void __clk_free_clk(struct clk *clk)
+{
+ clk_prepare_lock();
+ hlist_del(&clk->child_node);
+ clk_prepare_unlock();
+
+ kfree(clk);
+}
/**
* clk_register - allocate a new clock, register it and return an opaque cookie
@@ -2039,7 +2405,7 @@
struct clk *clk_register(struct device *dev, struct clk_hw *hw)
{
int i, ret;
- struct clk *clk;
+ struct clk_core *clk;
clk = kzalloc(sizeof(*clk), GFP_KERNEL);
if (!clk) {
@@ -2060,7 +2426,7 @@
clk->hw = hw;
clk->flags = hw->init->flags;
clk->num_parents = hw->init->num_parents;
- hw->clk = clk;
+ hw->core = clk;
/* allocate local copy in case parent_names is __initdata */
clk->parent_names = kcalloc(clk->num_parents, sizeof(char *),
@@ -2084,9 +2450,21 @@
}
}
- ret = __clk_init(dev, clk);
+ INIT_HLIST_HEAD(&clk->clks);
+
+ hw->clk = __clk_create_clk(hw, NULL, NULL);
+ if (IS_ERR(hw->clk)) {
+ pr_err("%s: could not allocate per-user clk\n", __func__);
+ ret = PTR_ERR(hw->clk);
+ goto fail_parent_names_copy;
+ }
+
+ ret = __clk_init(dev, hw->clk);
if (!ret)
- return clk;
+ return hw->clk;
+
+ __clk_free_clk(hw->clk);
+ hw->clk = NULL;
fail_parent_names_copy:
while (--i >= 0)
@@ -2107,7 +2485,7 @@
*/
static void __clk_release(struct kref *ref)
{
- struct clk *clk = container_of(ref, struct clk, ref);
+ struct clk_core *clk = container_of(ref, struct clk_core, ref);
int i = clk->num_parents;
kfree(clk->parents);
@@ -2165,12 +2543,13 @@
if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
return;
- clk_debug_unregister(clk);
+ clk_debug_unregister(clk->core);
clk_prepare_lock();
- if (clk->ops == &clk_nodrv_ops) {
- pr_err("%s: unregistered clock: %s\n", __func__, clk->name);
+ if (clk->core->ops == &clk_nodrv_ops) {
+ pr_err("%s: unregistered clock: %s\n", __func__,
+ clk->core->name);
return;
}
/*
@@ -2178,24 +2557,25 @@
* a reference to this clock.
*/
flags = clk_enable_lock();
- clk->ops = &clk_nodrv_ops;
+ clk->core->ops = &clk_nodrv_ops;
clk_enable_unlock(flags);
- if (!hlist_empty(&clk->children)) {
- struct clk *child;
+ if (!hlist_empty(&clk->core->children)) {
+ struct clk_core *child;
struct hlist_node *t;
/* Reparent all children to the orphan list. */
- hlist_for_each_entry_safe(child, t, &clk->children, child_node)
- clk_set_parent(child, NULL);
+ hlist_for_each_entry_safe(child, t, &clk->core->children,
+ child_node)
+ clk_core_set_parent(child, NULL);
}
- hlist_del_init(&clk->child_node);
+ hlist_del_init(&clk->core->child_node);
- if (clk->prepare_count)
+ if (clk->core->prepare_count)
pr_warn("%s: unregistering prepared clock: %s\n",
- __func__, clk->name);
- kref_put(&clk->ref, __clk_release);
+ __func__, clk->core->name);
+ kref_put(&clk->core->ref, __clk_release);
clk_prepare_unlock();
}
@@ -2263,11 +2643,13 @@
*/
int __clk_get(struct clk *clk)
{
- if (clk) {
- if (!try_module_get(clk->owner))
+ struct clk_core *core = !clk ? NULL : clk->core;
+
+ if (core) {
+ if (!try_module_get(core->owner))
return 0;
- kref_get(&clk->ref);
+ kref_get(&core->ref);
}
return 1;
}
@@ -2280,11 +2662,20 @@
return;
clk_prepare_lock();
- owner = clk->owner;
- kref_put(&clk->ref, __clk_release);
+
+ hlist_del(&clk->child_node);
+ if (clk->min_rate > clk->core->req_rate ||
+ clk->max_rate < clk->core->req_rate)
+ clk_core_set_rate_nolock(clk->core, clk->core->req_rate);
+
+ owner = clk->core->owner;
+ kref_put(&clk->core->ref, __clk_release);
+
clk_prepare_unlock();
module_put(owner);
+
+ kfree(clk);
}
/*** clk rate change notifiers ***/
@@ -2339,7 +2730,7 @@
ret = srcu_notifier_chain_register(&cn->notifier_head, nb);
- clk->notifier_count++;
+ clk->core->notifier_count++;
out:
clk_prepare_unlock();
@@ -2376,7 +2767,7 @@
if (cn->clk == clk) {
ret = srcu_notifier_chain_unregister(&cn->notifier_head, nb);
- clk->notifier_count--;
+ clk->core->notifier_count--;
/* XXX the notifier code should handle this better */
if (!cn->notifier_head.head) {
@@ -2506,7 +2897,8 @@
}
EXPORT_SYMBOL_GPL(of_clk_del_provider);
-struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec)
+struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
+ const char *dev_id, const char *con_id)
{
struct of_clk_provider *provider;
struct clk *clk = ERR_PTR(-EPROBE_DEFER);
@@ -2515,8 +2907,17 @@
list_for_each_entry(provider, &of_clk_providers, link) {
if (provider->node == clkspec->np)
clk = provider->get(clkspec, provider->data);
- if (!IS_ERR(clk))
+ if (!IS_ERR(clk)) {
+ clk = __clk_create_clk(__clk_get_hw(clk), dev_id,
+ con_id);
+
+ if (!IS_ERR(clk) && !__clk_get(clk)) {
+ __clk_free_clk(clk);
+ clk = ERR_PTR(-ENOENT);
+ }
+
break;
+ }
}
return clk;
@@ -2527,7 +2928,7 @@
struct clk *clk;
mutex_lock(&of_clk_mutex);
- clk = __of_clk_get_from_provider(clkspec);
+ clk = __of_clk_get_from_provider(clkspec, NULL, __func__);
mutex_unlock(&of_clk_mutex);
return clk;
diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h
index c798138..ba84540 100644
--- a/drivers/clk/clk.h
+++ b/drivers/clk/clk.h
@@ -9,9 +9,31 @@
* published by the Free Software Foundation.
*/
+struct clk_hw;
+
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
struct clk *of_clk_get_by_clkspec(struct of_phandle_args *clkspec);
-struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec);
+struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
+ const char *dev_id, const char *con_id);
void of_clk_lock(void);
void of_clk_unlock(void);
#endif
+
+#ifdef CONFIG_COMMON_CLK
+struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
+ const char *con_id);
+void __clk_free_clk(struct clk *clk);
+#else
+/* All these casts to avoid ifdefs in clkdev... */
+static inline struct clk *
+__clk_create_clk(struct clk_hw *hw, const char *dev_id, const char *con_id)
+{
+ return (struct clk *)hw;
+}
+static inline void __clk_free_clk(struct clk *clk) { }
+static struct clk_hw *__clk_get_hw(struct clk *clk)
+{
+ return (struct clk_hw *)clk;
+}
+
+#endif
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index da4bda8..043fd36 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -19,6 +19,7 @@
#include <linux/mutex.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
#include <linux/of.h>
#include "clk.h"
@@ -28,6 +29,20 @@
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
+static struct clk *__of_clk_get_by_clkspec(struct of_phandle_args *clkspec,
+ const char *dev_id, const char *con_id)
+{
+ struct clk *clk;
+
+ if (!clkspec)
+ return ERR_PTR(-EINVAL);
+
+ of_clk_lock();
+ clk = __of_clk_get_from_provider(clkspec, dev_id, con_id);
+ of_clk_unlock();
+ return clk;
+}
+
/**
* of_clk_get_by_clkspec() - Lookup a clock form a clock provider
* @clkspec: pointer to a clock specifier data structure
@@ -38,22 +53,11 @@
*/
struct clk *of_clk_get_by_clkspec(struct of_phandle_args *clkspec)
{
- struct clk *clk;
-
- if (!clkspec)
- return ERR_PTR(-EINVAL);
-
- of_clk_lock();
- clk = __of_clk_get_from_provider(clkspec);
-
- if (!IS_ERR(clk) && !__clk_get(clk))
- clk = ERR_PTR(-ENOENT);
-
- of_clk_unlock();
- return clk;
+ return __of_clk_get_by_clkspec(clkspec, NULL, __func__);
}
-struct clk *of_clk_get(struct device_node *np, int index)
+static struct clk *__of_clk_get(struct device_node *np, int index,
+ const char *dev_id, const char *con_id)
{
struct of_phandle_args clkspec;
struct clk *clk;
@@ -67,22 +71,21 @@
if (rc)
return ERR_PTR(rc);
- clk = of_clk_get_by_clkspec(&clkspec);
+ clk = __of_clk_get_by_clkspec(&clkspec, dev_id, con_id);
of_node_put(clkspec.np);
+
return clk;
}
+
+struct clk *of_clk_get(struct device_node *np, int index)
+{
+ return __of_clk_get(np, index, np->full_name, NULL);
+}
EXPORT_SYMBOL(of_clk_get);
-/**
- * of_clk_get_by_name() - Parse and lookup a clock referenced by a device node
- * @np: pointer to clock consumer node
- * @name: name of consumer's clock input, or NULL for the first clock reference
- *
- * This function parses the clocks and clock-names properties,
- * and uses them to look up the struct clk from the registered list of clock
- * providers.
- */
-struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
+static struct clk *__of_clk_get_by_name(struct device_node *np,
+ const char *dev_id,
+ const char *name)
{
struct clk *clk = ERR_PTR(-ENOENT);
@@ -97,10 +100,10 @@
*/
if (name)
index = of_property_match_string(np, "clock-names", name);
- clk = of_clk_get(np, index);
- if (!IS_ERR(clk))
+ clk = __of_clk_get(np, index, dev_id, name);
+ if (!IS_ERR(clk)) {
break;
- else if (name && index >= 0) {
+ } else if (name && index >= 0) {
if (PTR_ERR(clk) != -EPROBE_DEFER)
pr_err("ERROR: could not get clock %s:%s(%i)\n",
np->full_name, name ? name : "", index);
@@ -119,7 +122,33 @@
return clk;
}
+
+/**
+ * of_clk_get_by_name() - Parse and lookup a clock referenced by a device node
+ * @np: pointer to clock consumer node
+ * @name: name of consumer's clock input, or NULL for the first clock reference
+ *
+ * This function parses the clocks and clock-names properties,
+ * and uses them to look up the struct clk from the registered list of clock
+ * providers.
+ */
+struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
+{
+ if (!np)
+ return ERR_PTR(-ENOENT);
+
+ return __of_clk_get_by_name(np, np->full_name, name);
+}
EXPORT_SYMBOL(of_clk_get_by_name);
+
+#else /* defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) */
+
+static struct clk *__of_clk_get_by_name(struct device_node *np,
+ const char *dev_id,
+ const char *name)
+{
+ return ERR_PTR(-ENOENT);
+}
#endif
/*
@@ -168,14 +197,28 @@
struct clk *clk_get_sys(const char *dev_id, const char *con_id)
{
struct clk_lookup *cl;
+ struct clk *clk = NULL;
mutex_lock(&clocks_mutex);
+
cl = clk_find(dev_id, con_id);
- if (cl && !__clk_get(cl->clk))
+ if (!cl)
+ goto out;
+
+ clk = __clk_create_clk(__clk_get_hw(cl->clk), dev_id, con_id);
+ if (IS_ERR(clk))
+ goto out;
+
+ if (!__clk_get(clk)) {
+ __clk_free_clk(clk);
cl = NULL;
+ goto out;
+ }
+
+out:
mutex_unlock(&clocks_mutex);
- return cl ? cl->clk : ERR_PTR(-ENOENT);
+ return cl ? clk : ERR_PTR(-ENOENT);
}
EXPORT_SYMBOL(clk_get_sys);
@@ -185,10 +228,8 @@
struct clk *clk;
if (dev) {
- clk = of_clk_get_by_name(dev->of_node, con_id);
- if (!IS_ERR(clk))
- return clk;
- if (PTR_ERR(clk) == -EPROBE_DEFER)
+ clk = __of_clk_get_by_name(dev->of_node, dev_id, con_id);
+ if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER)
return clk;
}
@@ -331,6 +372,7 @@
return 0;
}
+EXPORT_SYMBOL(clk_register_clkdev);
/**
* clk_register_clkdevs - register a set of clk_lookup for a struct clk
diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c
index 007144f..2e4f6d4 100644
--- a/drivers/clk/hisilicon/clk-hi3620.c
+++ b/drivers/clk/hisilicon/clk-hi3620.c
@@ -295,6 +295,8 @@
}
static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_p)
{
diff --git a/drivers/clk/mmp/clk-mix.c b/drivers/clk/mmp/clk-mix.c
index 48fa53c..de6a873 100644
--- a/drivers/clk/mmp/clk-mix.c
+++ b/drivers/clk/mmp/clk-mix.c
@@ -202,6 +202,8 @@
}
static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk)
{
diff --git a/drivers/clk/pxa/Makefile b/drivers/clk/pxa/Makefile
index 38e9153..38e37bf 100644
--- a/drivers/clk/pxa/Makefile
+++ b/drivers/clk/pxa/Makefile
@@ -1,3 +1,4 @@
obj-y += clk-pxa.o
obj-$(CONFIG_PXA25x) += clk-pxa25x.o
obj-$(CONFIG_PXA27x) += clk-pxa27x.o
+obj-$(CONFIG_PXA3xx) += clk-pxa3xx.o
diff --git a/drivers/clk/pxa/clk-pxa.c b/drivers/clk/pxa/clk-pxa.c
index 4e83475..29cee9e 100644
--- a/drivers/clk/pxa/clk-pxa.c
+++ b/drivers/clk/pxa/clk-pxa.c
@@ -46,7 +46,7 @@
fix = &pclk->lp;
else
fix = &pclk->hp;
- fix->hw.clk = hw->clk;
+ __clk_hw_set_clk(&fix->hw, hw);
return clk_fixed_factor_ops.recalc_rate(&fix->hw, parent_rate);
}
diff --git a/drivers/clk/pxa/clk-pxa3xx.c b/drivers/clk/pxa/clk-pxa3xx.c
new file mode 100644
index 0000000..39f891b
--- /dev/null
+++ b/drivers/clk/pxa/clk-pxa3xx.c
@@ -0,0 +1,364 @@
+/*
+ * Marvell PXA3xxx family clocks
+ *
+ * Copyright (C) 2014 Robert Jarzmik
+ *
+ * Heavily inspired from former arch/arm/mach-pxa/pxa3xx.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * For non-devicetree platforms. Once pxa is fully converted to devicetree, this
+ * should go away.
+ */
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <mach/smemc.h>
+#include <mach/pxa3xx-regs.h>
+
+#include <dt-bindings/clock/pxa-clock.h>
+#include "clk-pxa.h"
+
+#define KHz 1000
+#define MHz (1000 * 1000)
+
+enum {
+ PXA_CORE_60Mhz = 0,
+ PXA_CORE_RUN,
+ PXA_CORE_TURBO,
+};
+
+enum {
+ PXA_BUS_60Mhz = 0,
+ PXA_BUS_HSS,
+};
+
+/* crystal frequency to HSIO bus frequency multiplier (HSS) */
+static unsigned char hss_mult[4] = { 8, 12, 16, 24 };
+
+/* crystal frequency to static memory controller multiplier (SMCFS) */
+static unsigned int smcfs_mult[8] = { 6, 0, 8, 0, 0, 16, };
+static unsigned int df_clkdiv[4] = { 1, 2, 4, 1 };
+
+static const char * const get_freq_khz[] = {
+ "core", "ring_osc_60mhz", "run", "cpll", "system_bus"
+};
+
+/*
+ * Get the clock frequency as reflected by ACSR and the turbo flag.
+ * We assume these values have been applied via a fcs.
+ * If info is not 0 we also display the current settings.
+ */
+unsigned int pxa3xx_get_clk_frequency_khz(int info)
+{
+ struct clk *clk;
+ unsigned long clks[5];
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ clk = clk_get(NULL, get_freq_khz[i]);
+ if (IS_ERR(clk)) {
+ clks[i] = 0;
+ } else {
+ clks[i] = clk_get_rate(clk);
+ clk_put(clk);
+ }
+ }
+ if (info) {
+ pr_info("RO Mode clock: %ld.%02ldMHz\n",
+ clks[1] / 1000000, (clks[0] % 1000000) / 10000);
+ pr_info("Run Mode clock: %ld.%02ldMHz\n",
+ clks[2] / 1000000, (clks[1] % 1000000) / 10000);
+ pr_info("Turbo Mode clock: %ld.%02ldMHz\n",
+ clks[3] / 1000000, (clks[2] % 1000000) / 10000);
+ pr_info("System bus clock: %ld.%02ldMHz\n",
+ clks[4] / 1000000, (clks[4] % 1000000) / 10000);
+ }
+ return (unsigned int)clks[0];
+}
+
+static unsigned long clk_pxa3xx_ac97_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ unsigned long ac97_div, rate;
+
+ ac97_div = AC97_DIV;
+
+ /* This may loose precision for some rates but won't for the
+ * standard 24.576MHz.
+ */
+ rate = parent_rate / 2;
+ rate /= ((ac97_div >> 12) & 0x7fff);
+ rate *= (ac97_div & 0xfff);
+
+ return rate;
+}
+PARENTS(clk_pxa3xx_ac97) = { "spll_624mhz" };
+RATE_RO_OPS(clk_pxa3xx_ac97, "ac97");
+
+static unsigned long clk_pxa3xx_smemc_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ unsigned long acsr = ACSR;
+ unsigned long memclkcfg = __raw_readl(MEMCLKCFG);
+
+ return (parent_rate / 48) * smcfs_mult[(acsr >> 23) & 0x7] /
+ df_clkdiv[(memclkcfg >> 16) & 0x3];
+}
+PARENTS(clk_pxa3xx_smemc) = { "spll_624mhz" };
+RATE_RO_OPS(clk_pxa3xx_smemc, "smemc");
+
+static bool pxa3xx_is_ring_osc_forced(void)
+{
+ unsigned long acsr = ACSR;
+
+ return acsr & ACCR_D0CS;
+}
+
+PARENTS(pxa3xx_pbus) = { "ring_osc_60mhz", "spll_624mhz" };
+PARENTS(pxa3xx_32Khz_bus) = { "osc_32_768khz", "osc_32_768khz" };
+PARENTS(pxa3xx_13MHz_bus) = { "osc_13mhz", "osc_13mhz" };
+PARENTS(pxa3xx_ac97_bus) = { "ring_osc_60mhz", "ac97" };
+PARENTS(pxa3xx_sbus) = { "ring_osc_60mhz", "system_bus" };
+PARENTS(pxa3xx_smemcbus) = { "ring_osc_60mhz", "smemc" };
+
+#define CKEN_AB(bit) ((CKEN_ ## bit > 31) ? &CKENA : &CKENB)
+#define PXA3XX_CKEN(dev_id, con_id, parents, mult_lp, div_lp, mult_hp, \
+ div_hp, bit, is_lp, flags) \
+ PXA_CKEN(dev_id, con_id, bit, parents, mult_lp, div_lp, \
+ mult_hp, div_hp, is_lp, CKEN_AB(bit), \
+ (CKEN_ ## bit % 32), flags)
+#define PXA3XX_PBUS_CKEN(dev_id, con_id, bit, mult_lp, div_lp, \
+ mult_hp, div_hp, delay) \
+ PXA3XX_CKEN(dev_id, con_id, pxa3xx_pbus_parents, mult_lp, \
+ div_lp, mult_hp, div_hp, bit, pxa3xx_is_ring_osc_forced, 0)
+#define PXA3XX_CKEN_1RATE(dev_id, con_id, bit, parents) \
+ PXA_CKEN_1RATE(dev_id, con_id, bit, parents, \
+ CKEN_AB(bit), (CKEN_ ## bit % 32), 0)
+
+static struct desc_clk_cken pxa3xx_clocks[] __initdata = {
+ PXA3XX_PBUS_CKEN("pxa2xx-uart.0", NULL, FFUART, 1, 4, 1, 42, 1),
+ PXA3XX_PBUS_CKEN("pxa2xx-uart.1", NULL, BTUART, 1, 4, 1, 42, 1),
+ PXA3XX_PBUS_CKEN("pxa2xx-uart.2", NULL, STUART, 1, 4, 1, 42, 1),
+ PXA3XX_PBUS_CKEN("pxa2xx-i2c.0", NULL, I2C, 2, 5, 1, 19, 0),
+ PXA3XX_PBUS_CKEN("pxa27x-udc", NULL, UDC, 1, 4, 1, 13, 5),
+ PXA3XX_PBUS_CKEN("pxa27x-ohci", NULL, USBH, 1, 4, 1, 13, 0),
+ PXA3XX_PBUS_CKEN("pxa3xx-u2d", NULL, USB2, 1, 4, 1, 13, 0),
+ PXA3XX_PBUS_CKEN("pxa27x-pwm.0", NULL, PWM0, 1, 6, 1, 48, 0),
+ PXA3XX_PBUS_CKEN("pxa27x-pwm.1", NULL, PWM1, 1, 6, 1, 48, 0),
+ PXA3XX_PBUS_CKEN("pxa2xx-mci.0", NULL, MMC1, 1, 4, 1, 24, 0),
+ PXA3XX_PBUS_CKEN("pxa2xx-mci.1", NULL, MMC2, 1, 4, 1, 24, 0),
+ PXA3XX_PBUS_CKEN("pxa2xx-mci.2", NULL, MMC3, 1, 4, 1, 24, 0),
+
+ PXA3XX_CKEN_1RATE("pxa27x-keypad", NULL, KEYPAD,
+ pxa3xx_32Khz_bus_parents),
+ PXA3XX_CKEN_1RATE("pxa3xx-ssp.0", NULL, SSP1, pxa3xx_13MHz_bus_parents),
+ PXA3XX_CKEN_1RATE("pxa3xx-ssp.1", NULL, SSP2, pxa3xx_13MHz_bus_parents),
+ PXA3XX_CKEN_1RATE("pxa3xx-ssp.2", NULL, SSP3, pxa3xx_13MHz_bus_parents),
+ PXA3XX_CKEN_1RATE("pxa3xx-ssp.3", NULL, SSP4, pxa3xx_13MHz_bus_parents),
+
+ PXA3XX_CKEN(NULL, "AC97CLK", pxa3xx_ac97_bus_parents, 1, 4, 1, 1, AC97,
+ pxa3xx_is_ring_osc_forced, 0),
+ PXA3XX_CKEN(NULL, "CAMCLK", pxa3xx_sbus_parents, 1, 2, 1, 1, CAMERA,
+ pxa3xx_is_ring_osc_forced, 0),
+ PXA3XX_CKEN("pxa2xx-fb", NULL, pxa3xx_sbus_parents, 1, 1, 1, 1, LCD,
+ pxa3xx_is_ring_osc_forced, 0),
+ PXA3XX_CKEN("pxa2xx-pcmcia", NULL, pxa3xx_smemcbus_parents, 1, 4,
+ 1, 1, SMC, pxa3xx_is_ring_osc_forced, CLK_IGNORE_UNUSED),
+};
+
+static struct desc_clk_cken pxa300_310_clocks[] __initdata = {
+
+ PXA3XX_PBUS_CKEN("pxa3xx-gcu", NULL, PXA300_GCU, 1, 1, 1, 1, 0),
+ PXA3XX_PBUS_CKEN("pxa3xx-nand", NULL, NAND, 1, 2, 1, 4, 0),
+ PXA3XX_CKEN_1RATE("pxa3xx-gpio", NULL, GPIO, pxa3xx_13MHz_bus_parents),
+};
+
+static struct desc_clk_cken pxa320_clocks[] __initdata = {
+ PXA3XX_PBUS_CKEN("pxa3xx-nand", NULL, NAND, 1, 2, 1, 6, 0),
+ PXA3XX_PBUS_CKEN("pxa3xx-gcu", NULL, PXA320_GCU, 1, 1, 1, 1, 0),
+ PXA3XX_CKEN_1RATE("pxa3xx-gpio", NULL, GPIO, pxa3xx_13MHz_bus_parents),
+};
+
+static struct desc_clk_cken pxa93x_clocks[] __initdata = {
+
+ PXA3XX_PBUS_CKEN("pxa3xx-gcu", NULL, PXA300_GCU, 1, 1, 1, 1, 0),
+ PXA3XX_PBUS_CKEN("pxa3xx-nand", NULL, NAND, 1, 2, 1, 4, 0),
+ PXA3XX_CKEN_1RATE("pxa93x-gpio", NULL, GPIO, pxa3xx_13MHz_bus_parents),
+};
+
+static unsigned long clk_pxa3xx_system_bus_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ unsigned long acsr = ACSR;
+ unsigned int hss = (acsr >> 14) & 0x3;
+
+ if (pxa3xx_is_ring_osc_forced())
+ return parent_rate;
+ return parent_rate / 48 * hss_mult[hss];
+}
+
+static u8 clk_pxa3xx_system_bus_get_parent(struct clk_hw *hw)
+{
+ if (pxa3xx_is_ring_osc_forced())
+ return PXA_BUS_60Mhz;
+ else
+ return PXA_BUS_HSS;
+}
+
+PARENTS(clk_pxa3xx_system_bus) = { "ring_osc_60mhz", "spll_624mhz" };
+MUX_RO_RATE_RO_OPS(clk_pxa3xx_system_bus, "system_bus");
+
+static unsigned long clk_pxa3xx_core_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return parent_rate;
+}
+
+static u8 clk_pxa3xx_core_get_parent(struct clk_hw *hw)
+{
+ unsigned long xclkcfg;
+ unsigned int t;
+
+ if (pxa3xx_is_ring_osc_forced())
+ return PXA_CORE_60Mhz;
+
+ /* Read XCLKCFG register turbo bit */
+ __asm__ __volatile__("mrc\tp14, 0, %0, c6, c0, 0" : "=r"(xclkcfg));
+ t = xclkcfg & 0x1;
+
+ if (t)
+ return PXA_CORE_TURBO;
+ return PXA_CORE_RUN;
+}
+PARENTS(clk_pxa3xx_core) = { "ring_osc_60mhz", "run", "cpll" };
+MUX_RO_RATE_RO_OPS(clk_pxa3xx_core, "core");
+
+static unsigned long clk_pxa3xx_run_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ unsigned long acsr = ACSR;
+ unsigned int xn = (acsr & ACCR_XN_MASK) >> 8;
+ unsigned int t, xclkcfg;
+
+ /* Read XCLKCFG register turbo bit */
+ __asm__ __volatile__("mrc\tp14, 0, %0, c6, c0, 0" : "=r"(xclkcfg));
+ t = xclkcfg & 0x1;
+
+ return t ? (parent_rate / xn) * 2 : parent_rate;
+}
+PARENTS(clk_pxa3xx_run) = { "cpll" };
+RATE_RO_OPS(clk_pxa3xx_run, "run");
+
+static unsigned long clk_pxa3xx_cpll_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ unsigned long acsr = ACSR;
+ unsigned int xn = (acsr & ACCR_XN_MASK) >> 8;
+ unsigned int xl = acsr & ACCR_XL_MASK;
+ unsigned int t, xclkcfg;
+
+ /* Read XCLKCFG register turbo bit */
+ __asm__ __volatile__("mrc\tp14, 0, %0, c6, c0, 0" : "=r"(xclkcfg));
+ t = xclkcfg & 0x1;
+
+ pr_info("RJK: parent_rate=%lu, xl=%u, xn=%u\n", parent_rate, xl, xn);
+ return t ? parent_rate * xl * xn : parent_rate * xl;
+}
+PARENTS(clk_pxa3xx_cpll) = { "osc_13mhz" };
+RATE_RO_OPS(clk_pxa3xx_cpll, "cpll");
+
+static void __init pxa3xx_register_core(void)
+{
+ clk_register_clk_pxa3xx_cpll();
+ clk_register_clk_pxa3xx_run();
+
+ clkdev_pxa_register(CLK_CORE, "core", NULL,
+ clk_register_clk_pxa3xx_core());
+}
+
+static void __init pxa3xx_register_plls(void)
+{
+ clk_register_fixed_rate(NULL, "osc_13mhz", NULL,
+ CLK_GET_RATE_NOCACHE | CLK_IS_ROOT,
+ 13 * MHz);
+ clk_register_fixed_rate(NULL, "osc_32_768khz", NULL,
+ CLK_GET_RATE_NOCACHE | CLK_IS_ROOT,
+ 32768);
+ clk_register_fixed_rate(NULL, "ring_osc_120mhz", NULL,
+ CLK_GET_RATE_NOCACHE | CLK_IS_ROOT,
+ 120 * MHz);
+ clk_register_fixed_rate(NULL, "clk_dummy", NULL, CLK_IS_ROOT, 0);
+ clk_register_fixed_factor(NULL, "spll_624mhz", "osc_13mhz", 0, 48, 1);
+ clk_register_fixed_factor(NULL, "ring_osc_60mhz", "ring_osc_120mhz",
+ 0, 1, 2);
+}
+
+#define DUMMY_CLK(_con_id, _dev_id, _parent) \
+ { .con_id = _con_id, .dev_id = _dev_id, .parent = _parent }
+struct dummy_clk {
+ const char *con_id;
+ const char *dev_id;
+ const char *parent;
+};
+static struct dummy_clk dummy_clks[] __initdata = {
+ DUMMY_CLK(NULL, "pxa93x-gpio", "osc_13mhz"),
+ DUMMY_CLK(NULL, "sa1100-rtc", "osc_32_768khz"),
+ DUMMY_CLK("UARTCLK", "pxa2xx-ir", "STUART"),
+ DUMMY_CLK(NULL, "pxa3xx-pwri2c.1", "osc_13mhz"),
+};
+
+static void __init pxa3xx_dummy_clocks_init(void)
+{
+ struct clk *clk;
+ struct dummy_clk *d;
+ const char *name;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dummy_clks); i++) {
+ d = &dummy_clks[i];
+ name = d->dev_id ? d->dev_id : d->con_id;
+ clk = clk_register_fixed_factor(NULL, name, d->parent, 0, 1, 1);
+ clk_register_clkdev(clk, d->con_id, d->dev_id);
+ }
+}
+
+static void __init pxa3xx_base_clocks_init(void)
+{
+ pxa3xx_register_plls();
+ pxa3xx_register_core();
+ clk_register_clk_pxa3xx_system_bus();
+ clk_register_clk_pxa3xx_ac97();
+ clk_register_clk_pxa3xx_smemc();
+ clk_register_gate(NULL, "CLK_POUT", "osc_13mhz", 0,
+ (void __iomem *)&OSCC, 11, 0, NULL);
+}
+
+int __init pxa3xx_clocks_init(void)
+{
+ int ret;
+
+ pxa3xx_base_clocks_init();
+ pxa3xx_dummy_clocks_init();
+ ret = clk_pxa_cken_init(pxa3xx_clocks, ARRAY_SIZE(pxa3xx_clocks));
+ if (ret)
+ return ret;
+ if (cpu_is_pxa320())
+ return clk_pxa_cken_init(pxa320_clocks,
+ ARRAY_SIZE(pxa320_clocks));
+ if (cpu_is_pxa300() || cpu_is_pxa310())
+ return clk_pxa_cken_init(pxa300_310_clocks,
+ ARRAY_SIZE(pxa300_310_clocks));
+ return clk_pxa_cken_init(pxa93x_clocks, ARRAY_SIZE(pxa93x_clocks));
+}
+
+static void __init pxa3xx_dt_clocks_init(struct device_node *np)
+{
+ pxa3xx_clocks_init();
+ clk_pxa_dt_common_init(np);
+}
+CLK_OF_DECLARE(pxa_clks, "marvell,pxa300-clocks", pxa3xx_dt_clocks_init);
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 1107351..0d7ab52 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -29,6 +29,15 @@
Say Y if you want to use peripheral devices such as UART, SPI,
i2c, USB, SD/eMMC, etc.
+config IPQ_LCC_806X
+ tristate "IPQ806x LPASS Clock Controller"
+ select IPQ_GCC_806X
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the LPASS clock controller on ipq806x devices.
+ Say Y if you want to use audio devices such as i2s, pcm,
+ S/PDIF, etc.
+
config MSM_GCC_8660
tristate "MSM8660 Global Clock Controller"
depends on COMMON_CLK_QCOM
@@ -45,6 +54,15 @@
Say Y if you want to use peripheral devices such as UART, SPI,
i2c, USB, SD/eMMC, SATA, PCIe, etc.
+config MSM_LCC_8960
+ tristate "APQ8064/MSM8960 LPASS Clock Controller"
+ select MSM_GCC_8960
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the LPASS clock controller on apq8064/msm8960 devices.
+ Say Y if you want to use audio devices such as i2s, pcm,
+ SLIMBus, etc.
+
config MSM_MMCC_8960
tristate "MSM8960 Multimedia Clock Controller"
select MSM_GCC_8960
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 783cfb2..6178264 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -6,13 +6,17 @@
clk-qcom-y += clk-rcg.o
clk-qcom-y += clk-rcg2.o
clk-qcom-y += clk-branch.o
+clk-qcom-y += clk-regmap-divider.o
+clk-qcom-y += clk-regmap-mux.o
clk-qcom-y += reset.o
obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o
obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o
+obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o
obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o
obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o
+obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o
obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o
obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
diff --git a/drivers/clk/qcom/clk-pll.c b/drivers/clk/qcom/clk-pll.c
index 60873a7..b4325f6 100644
--- a/drivers/clk/qcom/clk-pll.c
+++ b/drivers/clk/qcom/clk-pll.c
@@ -141,6 +141,7 @@
static long
clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p)
{
struct clk_pll *pll = to_clk_pll(hw);
diff --git a/drivers/clk/qcom/clk-rcg.c b/drivers/clk/qcom/clk-rcg.c
index 0b93972..0039bd7 100644
--- a/drivers/clk/qcom/clk-rcg.c
+++ b/drivers/clk/qcom/clk-rcg.c
@@ -368,6 +368,7 @@
static long _freq_tbl_determine_rate(struct clk_hw *hw,
const struct freq_tbl *f, unsigned long rate,
+ unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p_hw)
{
unsigned long clk_flags;
@@ -397,22 +398,27 @@
}
static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p)
{
struct clk_rcg *rcg = to_clk_rcg(hw);
- return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p);
+ return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate,
+ max_rate, p_rate, p);
}
static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p)
{
struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
- return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p);
+ return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate,
+ max_rate, p_rate, p);
}
static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p_hw)
{
struct clk_rcg *rcg = to_clk_rcg(hw);
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 08b8b37..742acfa 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -208,6 +208,7 @@
}
static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
@@ -361,6 +362,8 @@
}
static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
@@ -412,6 +415,7 @@
EXPORT_SYMBOL_GPL(clk_edp_pixel_ops);
static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p_hw)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
@@ -476,6 +480,8 @@
};
static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
diff --git a/drivers/clk/qcom/clk-regmap-divider.c b/drivers/clk/qcom/clk-regmap-divider.c
new file mode 100644
index 0000000..5348491
--- /dev/null
+++ b/drivers/clk/qcom/clk-regmap-divider.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <linux/export.h>
+
+#include "clk-regmap-divider.h"
+
+static inline struct clk_regmap_div *to_clk_regmap_div(struct clk_hw *hw)
+{
+ return container_of(to_clk_regmap(hw), struct clk_regmap_div, clkr);
+}
+
+static long div_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_regmap_div *divider = to_clk_regmap_div(hw);
+
+ return divider_round_rate(hw, rate, prate, NULL, divider->width,
+ CLK_DIVIDER_ROUND_CLOSEST);
+}
+
+static int div_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_regmap_div *divider = to_clk_regmap_div(hw);
+ struct clk_regmap *clkr = ÷r->clkr;
+ u32 div;
+
+ div = divider_get_val(rate, parent_rate, NULL, divider->width,
+ CLK_DIVIDER_ROUND_CLOSEST);
+
+ return regmap_update_bits(clkr->regmap, divider->reg,
+ (BIT(divider->width) - 1) << divider->shift,
+ div << divider->shift);
+}
+
+static unsigned long div_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_regmap_div *divider = to_clk_regmap_div(hw);
+ struct clk_regmap *clkr = ÷r->clkr;
+ u32 div;
+
+ regmap_read(clkr->regmap, divider->reg, &div);
+ div >>= divider->shift;
+ div &= BIT(divider->width) - 1;
+
+ return divider_recalc_rate(hw, parent_rate, div, NULL,
+ CLK_DIVIDER_ROUND_CLOSEST);
+}
+
+const struct clk_ops clk_regmap_div_ops = {
+ .round_rate = div_round_rate,
+ .set_rate = div_set_rate,
+ .recalc_rate = div_recalc_rate,
+};
+EXPORT_SYMBOL_GPL(clk_regmap_div_ops);
diff --git a/drivers/clk/qcom/clk-regmap-divider.h b/drivers/clk/qcom/clk-regmap-divider.h
new file mode 100644
index 0000000..fc4492e
--- /dev/null
+++ b/drivers/clk/qcom/clk-regmap-divider.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QCOM_CLK_REGMAP_DIVIDER_H__
+#define __QCOM_CLK_REGMAP_DIVIDER_H__
+
+#include <linux/clk-provider.h>
+#include "clk-regmap.h"
+
+struct clk_regmap_div {
+ u32 reg;
+ u32 shift;
+ u32 width;
+ struct clk_regmap clkr;
+};
+
+extern const struct clk_ops clk_regmap_div_ops;
+
+#endif
diff --git a/drivers/clk/qcom/clk-regmap-mux.c b/drivers/clk/qcom/clk-regmap-mux.c
new file mode 100644
index 0000000..cae3071
--- /dev/null
+++ b/drivers/clk/qcom/clk-regmap-mux.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <linux/export.h>
+
+#include "clk-regmap-mux.h"
+
+static inline struct clk_regmap_mux *to_clk_regmap_mux(struct clk_hw *hw)
+{
+ return container_of(to_clk_regmap(hw), struct clk_regmap_mux, clkr);
+}
+
+static u8 mux_get_parent(struct clk_hw *hw)
+{
+ struct clk_regmap_mux *mux = to_clk_regmap_mux(hw);
+ struct clk_regmap *clkr = to_clk_regmap(hw);
+ unsigned int mask = GENMASK(mux->width - 1, 0);
+ unsigned int val;
+
+ regmap_read(clkr->regmap, mux->reg, &val);
+
+ val >>= mux->shift;
+ val &= mask;
+
+ return val;
+}
+
+static int mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_regmap_mux *mux = to_clk_regmap_mux(hw);
+ struct clk_regmap *clkr = to_clk_regmap(hw);
+ unsigned int mask = GENMASK(mux->width + mux->shift - 1, mux->shift);
+ unsigned int val;
+
+ val = index;
+ val <<= mux->shift;
+
+ return regmap_update_bits(clkr->regmap, mux->reg, mask, val);
+}
+
+const struct clk_ops clk_regmap_mux_closest_ops = {
+ .get_parent = mux_get_parent,
+ .set_parent = mux_set_parent,
+ .determine_rate = __clk_mux_determine_rate_closest,
+};
+EXPORT_SYMBOL_GPL(clk_regmap_mux_closest_ops);
diff --git a/drivers/clk/qcom/clk-regmap-mux.h b/drivers/clk/qcom/clk-regmap-mux.h
new file mode 100644
index 0000000..5cec761
--- /dev/null
+++ b/drivers/clk/qcom/clk-regmap-mux.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QCOM_CLK_REGMAP_MUX_H__
+#define __QCOM_CLK_REGMAP_MUX_H__
+
+#include <linux/clk-provider.h>
+#include "clk-regmap.h"
+
+struct clk_regmap_mux {
+ u32 reg;
+ u32 shift;
+ u32 width;
+ struct clk_regmap clkr;
+};
+
+extern const struct clk_ops clk_regmap_mux_closest_ops;
+
+#endif
diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c
index afed5eb..cbdc31d 100644
--- a/drivers/clk/qcom/gcc-ipq806x.c
+++ b/drivers/clk/qcom/gcc-ipq806x.c
@@ -75,6 +75,17 @@
},
};
+static struct clk_regmap pll4_vote = {
+ .enable_reg = 0x34c0,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "pll4_vote",
+ .parent_names = (const char *[]){ "pll4" },
+ .num_parents = 1,
+ .ops = &clk_pll_vote_ops,
+ },
+};
+
static struct clk_pll pll8 = {
.l_reg = 0x3144,
.m_reg = 0x3148,
@@ -2163,6 +2174,7 @@
[PLL0] = &pll0.clkr,
[PLL0_VOTE] = &pll0_vote,
[PLL3] = &pll3.clkr,
+ [PLL4_VOTE] = &pll4_vote,
[PLL8] = &pll8.clkr,
[PLL8_VOTE] = &pll8_vote,
[PLL14] = &pll14.clkr,
diff --git a/drivers/clk/qcom/lcc-ipq806x.c b/drivers/clk/qcom/lcc-ipq806x.c
new file mode 100644
index 0000000..121ffde
--- /dev/null
+++ b/drivers/clk/qcom/lcc-ipq806x.c
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,lcc-ipq806x.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+
+static struct clk_pll pll4 = {
+ .l_reg = 0x4,
+ .m_reg = 0x8,
+ .n_reg = 0xc,
+ .config_reg = 0x14,
+ .mode_reg = 0x0,
+ .status_reg = 0x18,
+ .status_bit = 16,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pll4",
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .ops = &clk_pll_ops,
+ },
+};
+
+static const struct pll_config pll4_config = {
+ .l = 0xf,
+ .m = 0x91,
+ .n = 0xc7,
+ .vco_val = 0x0,
+ .vco_mask = BIT(17) | BIT(16),
+ .pre_div_val = 0x0,
+ .pre_div_mask = BIT(19),
+ .post_div_val = 0x0,
+ .post_div_mask = BIT(21) | BIT(20),
+ .mn_ena_mask = BIT(22),
+ .main_output_mask = BIT(23),
+};
+
+#define P_PXO 0
+#define P_PLL4 1
+
+static const u8 lcc_pxo_pll4_map[] = {
+ [P_PXO] = 0,
+ [P_PLL4] = 2,
+};
+
+static const char *lcc_pxo_pll4[] = {
+ "pxo",
+ "pll4_vote",
+};
+
+static struct freq_tbl clk_tbl_aif_mi2s[] = {
+ { 1024000, P_PLL4, 4, 1, 96 },
+ { 1411200, P_PLL4, 4, 2, 139 },
+ { 1536000, P_PLL4, 4, 1, 64 },
+ { 2048000, P_PLL4, 4, 1, 48 },
+ { 2116800, P_PLL4, 4, 2, 93 },
+ { 2304000, P_PLL4, 4, 2, 85 },
+ { 2822400, P_PLL4, 4, 6, 209 },
+ { 3072000, P_PLL4, 4, 1, 32 },
+ { 3175200, P_PLL4, 4, 1, 31 },
+ { 4096000, P_PLL4, 4, 1, 24 },
+ { 4233600, P_PLL4, 4, 9, 209 },
+ { 4608000, P_PLL4, 4, 3, 64 },
+ { 5644800, P_PLL4, 4, 12, 209 },
+ { 6144000, P_PLL4, 4, 1, 16 },
+ { 6350400, P_PLL4, 4, 2, 31 },
+ { 8192000, P_PLL4, 4, 1, 12 },
+ { 8467200, P_PLL4, 4, 18, 209 },
+ { 9216000, P_PLL4, 4, 3, 32 },
+ { 11289600, P_PLL4, 4, 24, 209 },
+ { 12288000, P_PLL4, 4, 1, 8 },
+ { 12700800, P_PLL4, 4, 27, 209 },
+ { 13824000, P_PLL4, 4, 9, 64 },
+ { 16384000, P_PLL4, 4, 1, 6 },
+ { 16934400, P_PLL4, 4, 41, 238 },
+ { 18432000, P_PLL4, 4, 3, 16 },
+ { 22579200, P_PLL4, 2, 24, 209 },
+ { 24576000, P_PLL4, 4, 1, 4 },
+ { 27648000, P_PLL4, 4, 9, 32 },
+ { 33868800, P_PLL4, 4, 41, 119 },
+ { 36864000, P_PLL4, 4, 3, 8 },
+ { 45158400, P_PLL4, 1, 24, 209 },
+ { 49152000, P_PLL4, 4, 1, 2 },
+ { 50803200, P_PLL4, 1, 27, 209 },
+ { }
+};
+
+static struct clk_rcg mi2s_osr_src = {
+ .ns_reg = 0x48,
+ .md_reg = 0x4c,
+ .mn = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 24,
+ .m_val_shift = 8,
+ .width = 8,
+ },
+ .p = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .s = {
+ .src_sel_shift = 0,
+ .parent_map = lcc_pxo_pll4_map,
+ },
+ .freq_tbl = clk_tbl_aif_mi2s,
+ .clkr = {
+ .enable_reg = 0x48,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_osr_src",
+ .parent_names = lcc_pxo_pll4,
+ .num_parents = 2,
+ .ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
+ },
+ },
+};
+
+static const char *lcc_mi2s_parents[] = {
+ "mi2s_osr_src",
+};
+
+static struct clk_branch mi2s_osr_clk = {
+ .halt_reg = 0x50,
+ .halt_bit = 1,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0x48,
+ .enable_mask = BIT(17),
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_osr_clk",
+ .parent_names = lcc_mi2s_parents,
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_regmap_div mi2s_div_clk = {
+ .reg = 0x48,
+ .shift = 10,
+ .width = 4,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_div_clk",
+ .parent_names = lcc_mi2s_parents,
+ .num_parents = 1,
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
+static struct clk_branch mi2s_bit_div_clk = {
+ .halt_reg = 0x50,
+ .halt_bit = 0,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0x48,
+ .enable_mask = BIT(15),
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_bit_div_clk",
+ .parent_names = (const char *[]){ "mi2s_div_clk" },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+
+static struct clk_regmap_mux mi2s_bit_clk = {
+ .reg = 0x48,
+ .shift = 14,
+ .width = 1,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_bit_clk",
+ .parent_names = (const char *[]){
+ "mi2s_bit_div_clk",
+ "mi2s_codec_clk",
+ },
+ .num_parents = 2,
+ .ops = &clk_regmap_mux_closest_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct freq_tbl clk_tbl_pcm[] = {
+ { 64000, P_PLL4, 4, 1, 1536 },
+ { 128000, P_PLL4, 4, 1, 768 },
+ { 256000, P_PLL4, 4, 1, 384 },
+ { 512000, P_PLL4, 4, 1, 192 },
+ { 1024000, P_PLL4, 4, 1, 96 },
+ { 2048000, P_PLL4, 4, 1, 48 },
+ { },
+};
+
+static struct clk_rcg pcm_src = {
+ .ns_reg = 0x54,
+ .md_reg = 0x58,
+ .mn = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 16,
+ },
+ .p = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .s = {
+ .src_sel_shift = 0,
+ .parent_map = lcc_pxo_pll4_map,
+ },
+ .freq_tbl = clk_tbl_pcm,
+ .clkr = {
+ .enable_reg = 0x54,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "pcm_src",
+ .parent_names = lcc_pxo_pll4,
+ .num_parents = 2,
+ .ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
+ },
+ },
+};
+
+static struct clk_branch pcm_clk_out = {
+ .halt_reg = 0x5c,
+ .halt_bit = 0,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0x54,
+ .enable_mask = BIT(11),
+ .hw.init = &(struct clk_init_data){
+ .name = "pcm_clk_out",
+ .parent_names = (const char *[]){ "pcm_src" },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_regmap_mux pcm_clk = {
+ .reg = 0x54,
+ .shift = 10,
+ .width = 1,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "pcm_clk",
+ .parent_names = (const char *[]){
+ "pcm_clk_out",
+ "pcm_codec_clk",
+ },
+ .num_parents = 2,
+ .ops = &clk_regmap_mux_closest_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct freq_tbl clk_tbl_aif_osr[] = {
+ { 22050, P_PLL4, 1, 147, 20480 },
+ { 32000, P_PLL4, 1, 1, 96 },
+ { 44100, P_PLL4, 1, 147, 10240 },
+ { 48000, P_PLL4, 1, 1, 64 },
+ { 88200, P_PLL4, 1, 147, 5120 },
+ { 96000, P_PLL4, 1, 1, 32 },
+ { 176400, P_PLL4, 1, 147, 2560 },
+ { 192000, P_PLL4, 1, 1, 16 },
+ { },
+};
+
+static struct clk_rcg spdif_src = {
+ .ns_reg = 0xcc,
+ .md_reg = 0xd0,
+ .mn = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .p = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .s = {
+ .src_sel_shift = 0,
+ .parent_map = lcc_pxo_pll4_map,
+ },
+ .freq_tbl = clk_tbl_aif_osr,
+ .clkr = {
+ .enable_reg = 0xcc,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "spdif_src",
+ .parent_names = lcc_pxo_pll4,
+ .num_parents = 2,
+ .ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
+ },
+ },
+};
+
+static const char *lcc_spdif_parents[] = {
+ "spdif_src",
+};
+
+static struct clk_branch spdif_clk = {
+ .halt_reg = 0xd4,
+ .halt_bit = 1,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0xcc,
+ .enable_mask = BIT(12),
+ .hw.init = &(struct clk_init_data){
+ .name = "spdif_clk",
+ .parent_names = lcc_spdif_parents,
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct freq_tbl clk_tbl_ahbix[] = {
+ { 131072, P_PLL4, 1, 1, 3 },
+ { },
+};
+
+static struct clk_rcg ahbix_clk = {
+ .ns_reg = 0x38,
+ .md_reg = 0x3c,
+ .mn = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 24,
+ .m_val_shift = 8,
+ .width = 8,
+ },
+ .p = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .s = {
+ .src_sel_shift = 0,
+ .parent_map = lcc_pxo_pll4_map,
+ },
+ .freq_tbl = clk_tbl_ahbix,
+ .clkr = {
+ .enable_reg = 0x38,
+ .enable_mask = BIT(10), /* toggle the gfmux to select mn/pxo */
+ .hw.init = &(struct clk_init_data){
+ .name = "ahbix",
+ .parent_names = lcc_pxo_pll4,
+ .num_parents = 2,
+ .ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
+ },
+ },
+};
+
+static struct clk_regmap *lcc_ipq806x_clks[] = {
+ [PLL4] = &pll4.clkr,
+ [MI2S_OSR_SRC] = &mi2s_osr_src.clkr,
+ [MI2S_OSR_CLK] = &mi2s_osr_clk.clkr,
+ [MI2S_DIV_CLK] = &mi2s_div_clk.clkr,
+ [MI2S_BIT_DIV_CLK] = &mi2s_bit_div_clk.clkr,
+ [MI2S_BIT_CLK] = &mi2s_bit_clk.clkr,
+ [PCM_SRC] = &pcm_src.clkr,
+ [PCM_CLK_OUT] = &pcm_clk_out.clkr,
+ [PCM_CLK] = &pcm_clk.clkr,
+ [SPDIF_SRC] = &spdif_src.clkr,
+ [SPDIF_CLK] = &spdif_clk.clkr,
+ [AHBIX_CLK] = &ahbix_clk.clkr,
+};
+
+static const struct regmap_config lcc_ipq806x_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0xfc,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc lcc_ipq806x_desc = {
+ .config = &lcc_ipq806x_regmap_config,
+ .clks = lcc_ipq806x_clks,
+ .num_clks = ARRAY_SIZE(lcc_ipq806x_clks),
+};
+
+static const struct of_device_id lcc_ipq806x_match_table[] = {
+ { .compatible = "qcom,lcc-ipq8064" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lcc_ipq806x_match_table);
+
+static int lcc_ipq806x_probe(struct platform_device *pdev)
+{
+ u32 val;
+ struct regmap *regmap;
+
+ regmap = qcom_cc_map(pdev, &lcc_ipq806x_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* Configure the rate of PLL4 if the bootloader hasn't already */
+ val = regmap_read(regmap, 0x0, &val);
+ if (!val)
+ clk_pll_configure_sr(&pll4, regmap, &pll4_config, true);
+ /* Enable PLL4 source on the LPASS Primary PLL Mux */
+ regmap_write(regmap, 0xc4, 0x1);
+
+ return qcom_cc_really_probe(pdev, &lcc_ipq806x_desc, regmap);
+}
+
+static int lcc_ipq806x_remove(struct platform_device *pdev)
+{
+ qcom_cc_remove(pdev);
+ return 0;
+}
+
+static struct platform_driver lcc_ipq806x_driver = {
+ .probe = lcc_ipq806x_probe,
+ .remove = lcc_ipq806x_remove,
+ .driver = {
+ .name = "lcc-ipq806x",
+ .owner = THIS_MODULE,
+ .of_match_table = lcc_ipq806x_match_table,
+ },
+};
+module_platform_driver(lcc_ipq806x_driver);
+
+MODULE_DESCRIPTION("QCOM LCC IPQ806x Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:lcc-ipq806x");
diff --git a/drivers/clk/qcom/lcc-msm8960.c b/drivers/clk/qcom/lcc-msm8960.c
new file mode 100644
index 0000000..a75a408
--- /dev/null
+++ b/drivers/clk/qcom/lcc-msm8960.c
@@ -0,0 +1,585 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,lcc-msm8960.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+
+static struct clk_pll pll4 = {
+ .l_reg = 0x4,
+ .m_reg = 0x8,
+ .n_reg = 0xc,
+ .config_reg = 0x14,
+ .mode_reg = 0x0,
+ .status_reg = 0x18,
+ .status_bit = 16,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pll4",
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .ops = &clk_pll_ops,
+ },
+};
+
+#define P_PXO 0
+#define P_PLL4 1
+
+static const u8 lcc_pxo_pll4_map[] = {
+ [P_PXO] = 0,
+ [P_PLL4] = 2,
+};
+
+static const char *lcc_pxo_pll4[] = {
+ "pxo",
+ "pll4_vote",
+};
+
+static struct freq_tbl clk_tbl_aif_osr_492[] = {
+ { 512000, P_PLL4, 4, 1, 240 },
+ { 768000, P_PLL4, 4, 1, 160 },
+ { 1024000, P_PLL4, 4, 1, 120 },
+ { 1536000, P_PLL4, 4, 1, 80 },
+ { 2048000, P_PLL4, 4, 1, 60 },
+ { 3072000, P_PLL4, 4, 1, 40 },
+ { 4096000, P_PLL4, 4, 1, 30 },
+ { 6144000, P_PLL4, 4, 1, 20 },
+ { 8192000, P_PLL4, 4, 1, 15 },
+ { 12288000, P_PLL4, 4, 1, 10 },
+ { 24576000, P_PLL4, 4, 1, 5 },
+ { 27000000, P_PXO, 1, 0, 0 },
+ { }
+};
+
+static struct freq_tbl clk_tbl_aif_osr_393[] = {
+ { 512000, P_PLL4, 4, 1, 192 },
+ { 768000, P_PLL4, 4, 1, 128 },
+ { 1024000, P_PLL4, 4, 1, 96 },
+ { 1536000, P_PLL4, 4, 1, 64 },
+ { 2048000, P_PLL4, 4, 1, 48 },
+ { 3072000, P_PLL4, 4, 1, 32 },
+ { 4096000, P_PLL4, 4, 1, 24 },
+ { 6144000, P_PLL4, 4, 1, 16 },
+ { 8192000, P_PLL4, 4, 1, 12 },
+ { 12288000, P_PLL4, 4, 1, 8 },
+ { 24576000, P_PLL4, 4, 1, 4 },
+ { 27000000, P_PXO, 1, 0, 0 },
+ { }
+};
+
+static struct clk_rcg mi2s_osr_src = {
+ .ns_reg = 0x48,
+ .md_reg = 0x4c,
+ .mn = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 24,
+ .m_val_shift = 8,
+ .width = 8,
+ },
+ .p = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .s = {
+ .src_sel_shift = 0,
+ .parent_map = lcc_pxo_pll4_map,
+ },
+ .freq_tbl = clk_tbl_aif_osr_393,
+ .clkr = {
+ .enable_reg = 0x48,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_osr_src",
+ .parent_names = lcc_pxo_pll4,
+ .num_parents = 2,
+ .ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
+ },
+ },
+};
+
+static const char *lcc_mi2s_parents[] = {
+ "mi2s_osr_src",
+};
+
+static struct clk_branch mi2s_osr_clk = {
+ .halt_reg = 0x50,
+ .halt_bit = 1,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0x48,
+ .enable_mask = BIT(17),
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_osr_clk",
+ .parent_names = lcc_mi2s_parents,
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_regmap_div mi2s_div_clk = {
+ .reg = 0x48,
+ .shift = 10,
+ .width = 4,
+ .clkr = {
+ .enable_reg = 0x48,
+ .enable_mask = BIT(15),
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_div_clk",
+ .parent_names = lcc_mi2s_parents,
+ .num_parents = 1,
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
+static struct clk_branch mi2s_bit_div_clk = {
+ .halt_reg = 0x50,
+ .halt_bit = 0,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0x48,
+ .enable_mask = BIT(15),
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_bit_div_clk",
+ .parent_names = (const char *[]){ "mi2s_div_clk" },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_regmap_mux mi2s_bit_clk = {
+ .reg = 0x48,
+ .shift = 14,
+ .width = 1,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_bit_clk",
+ .parent_names = (const char *[]){
+ "mi2s_bit_div_clk",
+ "mi2s_codec_clk",
+ },
+ .num_parents = 2,
+ .ops = &clk_regmap_mux_closest_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+#define CLK_AIF_OSR_DIV(prefix, _ns, _md, hr) \
+static struct clk_rcg prefix##_osr_src = { \
+ .ns_reg = _ns, \
+ .md_reg = _md, \
+ .mn = { \
+ .mnctr_en_bit = 8, \
+ .mnctr_reset_bit = 7, \
+ .mnctr_mode_shift = 5, \
+ .n_val_shift = 24, \
+ .m_val_shift = 8, \
+ .width = 8, \
+ }, \
+ .p = { \
+ .pre_div_shift = 3, \
+ .pre_div_width = 2, \
+ }, \
+ .s = { \
+ .src_sel_shift = 0, \
+ .parent_map = lcc_pxo_pll4_map, \
+ }, \
+ .freq_tbl = clk_tbl_aif_osr_393, \
+ .clkr = { \
+ .enable_reg = _ns, \
+ .enable_mask = BIT(9), \
+ .hw.init = &(struct clk_init_data){ \
+ .name = #prefix "_osr_src", \
+ .parent_names = lcc_pxo_pll4, \
+ .num_parents = 2, \
+ .ops = &clk_rcg_ops, \
+ .flags = CLK_SET_RATE_GATE, \
+ }, \
+ }, \
+}; \
+ \
+static const char *lcc_##prefix##_parents[] = { \
+ #prefix "_osr_src", \
+}; \
+ \
+static struct clk_branch prefix##_osr_clk = { \
+ .halt_reg = hr, \
+ .halt_bit = 1, \
+ .halt_check = BRANCH_HALT_ENABLE, \
+ .clkr = { \
+ .enable_reg = _ns, \
+ .enable_mask = BIT(21), \
+ .hw.init = &(struct clk_init_data){ \
+ .name = #prefix "_osr_clk", \
+ .parent_names = lcc_##prefix##_parents, \
+ .num_parents = 1, \
+ .ops = &clk_branch_ops, \
+ .flags = CLK_SET_RATE_PARENT, \
+ }, \
+ }, \
+}; \
+ \
+static struct clk_regmap_div prefix##_div_clk = { \
+ .reg = _ns, \
+ .shift = 10, \
+ .width = 8, \
+ .clkr = { \
+ .hw.init = &(struct clk_init_data){ \
+ .name = #prefix "_div_clk", \
+ .parent_names = lcc_##prefix##_parents, \
+ .num_parents = 1, \
+ .ops = &clk_regmap_div_ops, \
+ }, \
+ }, \
+}; \
+ \
+static struct clk_branch prefix##_bit_div_clk = { \
+ .halt_reg = hr, \
+ .halt_bit = 0, \
+ .halt_check = BRANCH_HALT_ENABLE, \
+ .clkr = { \
+ .enable_reg = _ns, \
+ .enable_mask = BIT(19), \
+ .hw.init = &(struct clk_init_data){ \
+ .name = #prefix "_bit_div_clk", \
+ .parent_names = (const char *[]){ \
+ #prefix "_div_clk" \
+ }, \
+ .num_parents = 1, \
+ .ops = &clk_branch_ops, \
+ .flags = CLK_SET_RATE_PARENT, \
+ }, \
+ }, \
+}; \
+ \
+static struct clk_regmap_mux prefix##_bit_clk = { \
+ .reg = _ns, \
+ .shift = 18, \
+ .width = 1, \
+ .clkr = { \
+ .hw.init = &(struct clk_init_data){ \
+ .name = #prefix "_bit_clk", \
+ .parent_names = (const char *[]){ \
+ #prefix "_bit_div_clk", \
+ #prefix "_codec_clk", \
+ }, \
+ .num_parents = 2, \
+ .ops = &clk_regmap_mux_closest_ops, \
+ .flags = CLK_SET_RATE_PARENT, \
+ }, \
+ }, \
+}
+
+CLK_AIF_OSR_DIV(codec_i2s_mic, 0x60, 0x64, 0x68);
+CLK_AIF_OSR_DIV(spare_i2s_mic, 0x78, 0x7c, 0x80);
+CLK_AIF_OSR_DIV(codec_i2s_spkr, 0x6c, 0x70, 0x74);
+CLK_AIF_OSR_DIV(spare_i2s_spkr, 0x84, 0x88, 0x8c);
+
+static struct freq_tbl clk_tbl_pcm_492[] = {
+ { 256000, P_PLL4, 4, 1, 480 },
+ { 512000, P_PLL4, 4, 1, 240 },
+ { 768000, P_PLL4, 4, 1, 160 },
+ { 1024000, P_PLL4, 4, 1, 120 },
+ { 1536000, P_PLL4, 4, 1, 80 },
+ { 2048000, P_PLL4, 4, 1, 60 },
+ { 3072000, P_PLL4, 4, 1, 40 },
+ { 4096000, P_PLL4, 4, 1, 30 },
+ { 6144000, P_PLL4, 4, 1, 20 },
+ { 8192000, P_PLL4, 4, 1, 15 },
+ { 12288000, P_PLL4, 4, 1, 10 },
+ { 24576000, P_PLL4, 4, 1, 5 },
+ { 27000000, P_PXO, 1, 0, 0 },
+ { }
+};
+
+static struct freq_tbl clk_tbl_pcm_393[] = {
+ { 256000, P_PLL4, 4, 1, 384 },
+ { 512000, P_PLL4, 4, 1, 192 },
+ { 768000, P_PLL4, 4, 1, 128 },
+ { 1024000, P_PLL4, 4, 1, 96 },
+ { 1536000, P_PLL4, 4, 1, 64 },
+ { 2048000, P_PLL4, 4, 1, 48 },
+ { 3072000, P_PLL4, 4, 1, 32 },
+ { 4096000, P_PLL4, 4, 1, 24 },
+ { 6144000, P_PLL4, 4, 1, 16 },
+ { 8192000, P_PLL4, 4, 1, 12 },
+ { 12288000, P_PLL4, 4, 1, 8 },
+ { 24576000, P_PLL4, 4, 1, 4 },
+ { 27000000, P_PXO, 1, 0, 0 },
+ { }
+};
+
+static struct clk_rcg pcm_src = {
+ .ns_reg = 0x54,
+ .md_reg = 0x58,
+ .mn = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 16,
+ },
+ .p = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .s = {
+ .src_sel_shift = 0,
+ .parent_map = lcc_pxo_pll4_map,
+ },
+ .freq_tbl = clk_tbl_pcm_393,
+ .clkr = {
+ .enable_reg = 0x54,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "pcm_src",
+ .parent_names = lcc_pxo_pll4,
+ .num_parents = 2,
+ .ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
+ },
+ },
+};
+
+static struct clk_branch pcm_clk_out = {
+ .halt_reg = 0x5c,
+ .halt_bit = 0,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0x54,
+ .enable_mask = BIT(11),
+ .hw.init = &(struct clk_init_data){
+ .name = "pcm_clk_out",
+ .parent_names = (const char *[]){ "pcm_src" },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_regmap_mux pcm_clk = {
+ .reg = 0x54,
+ .shift = 10,
+ .width = 1,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "pcm_clk",
+ .parent_names = (const char *[]){
+ "pcm_clk_out",
+ "pcm_codec_clk",
+ },
+ .num_parents = 2,
+ .ops = &clk_regmap_mux_closest_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_rcg slimbus_src = {
+ .ns_reg = 0xcc,
+ .md_reg = 0xd0,
+ .mn = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .p = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .s = {
+ .src_sel_shift = 0,
+ .parent_map = lcc_pxo_pll4_map,
+ },
+ .freq_tbl = clk_tbl_aif_osr_393,
+ .clkr = {
+ .enable_reg = 0xcc,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "slimbus_src",
+ .parent_names = lcc_pxo_pll4,
+ .num_parents = 2,
+ .ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
+ },
+ },
+};
+
+static const char *lcc_slimbus_parents[] = {
+ "slimbus_src",
+};
+
+static struct clk_branch audio_slimbus_clk = {
+ .halt_reg = 0xd4,
+ .halt_bit = 0,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0xcc,
+ .enable_mask = BIT(10),
+ .hw.init = &(struct clk_init_data){
+ .name = "audio_slimbus_clk",
+ .parent_names = lcc_slimbus_parents,
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_branch sps_slimbus_clk = {
+ .halt_reg = 0xd4,
+ .halt_bit = 1,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0xcc,
+ .enable_mask = BIT(12),
+ .hw.init = &(struct clk_init_data){
+ .name = "sps_slimbus_clk",
+ .parent_names = lcc_slimbus_parents,
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_regmap *lcc_msm8960_clks[] = {
+ [PLL4] = &pll4.clkr,
+ [MI2S_OSR_SRC] = &mi2s_osr_src.clkr,
+ [MI2S_OSR_CLK] = &mi2s_osr_clk.clkr,
+ [MI2S_DIV_CLK] = &mi2s_div_clk.clkr,
+ [MI2S_BIT_DIV_CLK] = &mi2s_bit_div_clk.clkr,
+ [MI2S_BIT_CLK] = &mi2s_bit_clk.clkr,
+ [PCM_SRC] = &pcm_src.clkr,
+ [PCM_CLK_OUT] = &pcm_clk_out.clkr,
+ [PCM_CLK] = &pcm_clk.clkr,
+ [SLIMBUS_SRC] = &slimbus_src.clkr,
+ [AUDIO_SLIMBUS_CLK] = &audio_slimbus_clk.clkr,
+ [SPS_SLIMBUS_CLK] = &sps_slimbus_clk.clkr,
+ [CODEC_I2S_MIC_OSR_SRC] = &codec_i2s_mic_osr_src.clkr,
+ [CODEC_I2S_MIC_OSR_CLK] = &codec_i2s_mic_osr_clk.clkr,
+ [CODEC_I2S_MIC_DIV_CLK] = &codec_i2s_mic_div_clk.clkr,
+ [CODEC_I2S_MIC_BIT_DIV_CLK] = &codec_i2s_mic_bit_div_clk.clkr,
+ [CODEC_I2S_MIC_BIT_CLK] = &codec_i2s_mic_bit_clk.clkr,
+ [SPARE_I2S_MIC_OSR_SRC] = &spare_i2s_mic_osr_src.clkr,
+ [SPARE_I2S_MIC_OSR_CLK] = &spare_i2s_mic_osr_clk.clkr,
+ [SPARE_I2S_MIC_DIV_CLK] = &spare_i2s_mic_div_clk.clkr,
+ [SPARE_I2S_MIC_BIT_DIV_CLK] = &spare_i2s_mic_bit_div_clk.clkr,
+ [SPARE_I2S_MIC_BIT_CLK] = &spare_i2s_mic_bit_clk.clkr,
+ [CODEC_I2S_SPKR_OSR_SRC] = &codec_i2s_spkr_osr_src.clkr,
+ [CODEC_I2S_SPKR_OSR_CLK] = &codec_i2s_spkr_osr_clk.clkr,
+ [CODEC_I2S_SPKR_DIV_CLK] = &codec_i2s_spkr_div_clk.clkr,
+ [CODEC_I2S_SPKR_BIT_DIV_CLK] = &codec_i2s_spkr_bit_div_clk.clkr,
+ [CODEC_I2S_SPKR_BIT_CLK] = &codec_i2s_spkr_bit_clk.clkr,
+ [SPARE_I2S_SPKR_OSR_SRC] = &spare_i2s_spkr_osr_src.clkr,
+ [SPARE_I2S_SPKR_OSR_CLK] = &spare_i2s_spkr_osr_clk.clkr,
+ [SPARE_I2S_SPKR_DIV_CLK] = &spare_i2s_spkr_div_clk.clkr,
+ [SPARE_I2S_SPKR_BIT_DIV_CLK] = &spare_i2s_spkr_bit_div_clk.clkr,
+ [SPARE_I2S_SPKR_BIT_CLK] = &spare_i2s_spkr_bit_clk.clkr,
+};
+
+static const struct regmap_config lcc_msm8960_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0xfc,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc lcc_msm8960_desc = {
+ .config = &lcc_msm8960_regmap_config,
+ .clks = lcc_msm8960_clks,
+ .num_clks = ARRAY_SIZE(lcc_msm8960_clks),
+};
+
+static const struct of_device_id lcc_msm8960_match_table[] = {
+ { .compatible = "qcom,lcc-msm8960" },
+ { .compatible = "qcom,lcc-apq8064" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lcc_msm8960_match_table);
+
+static int lcc_msm8960_probe(struct platform_device *pdev)
+{
+ u32 val;
+ struct regmap *regmap;
+
+ regmap = qcom_cc_map(pdev, &lcc_msm8960_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* Use the correct frequency plan depending on speed of PLL4 */
+ val = regmap_read(regmap, 0x4, &val);
+ if (val == 0x12) {
+ slimbus_src.freq_tbl = clk_tbl_aif_osr_492;
+ mi2s_osr_src.freq_tbl = clk_tbl_aif_osr_492;
+ codec_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492;
+ spare_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492;
+ codec_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492;
+ spare_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492;
+ pcm_src.freq_tbl = clk_tbl_pcm_492;
+ }
+ /* Enable PLL4 source on the LPASS Primary PLL Mux */
+ regmap_write(regmap, 0xc4, 0x1);
+
+ return qcom_cc_really_probe(pdev, &lcc_msm8960_desc, regmap);
+}
+
+static int lcc_msm8960_remove(struct platform_device *pdev)
+{
+ qcom_cc_remove(pdev);
+ return 0;
+}
+
+static struct platform_driver lcc_msm8960_driver = {
+ .probe = lcc_msm8960_probe,
+ .remove = lcc_msm8960_remove,
+ .driver = {
+ .name = "lcc-msm8960",
+ .owner = THIS_MODULE,
+ .of_match_table = lcc_msm8960_match_table,
+ },
+};
+module_platform_driver(lcc_msm8960_driver);
+
+MODULE_DESCRIPTION("QCOM LCC MSM8960 Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:lcc-msm8960");
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index cbcddcc..05d7a0b 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -535,44 +535,44 @@
COMPOSITE(0, "uart0_src", mux_pll_src_cpll_gll_usb_npll_p, 0,
RK3288_CLKSEL_CON(13), 13, 2, MFLAGS, 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 8, GFLAGS),
- COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", 0,
+ COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(17), 0,
RK3288_CLKGATE_CON(1), 9, GFLAGS),
- MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, 0,
+ MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(13), 8, 2, MFLAGS),
MUX(0, "uart_src", mux_pll_src_cpll_gpll_p, 0,
RK3288_CLKSEL_CON(13), 15, 1, MFLAGS),
COMPOSITE_NOMUX(0, "uart1_src", "uart_src", 0,
RK3288_CLKSEL_CON(14), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 10, GFLAGS),
- COMPOSITE_FRAC(0, "uart1_frac", "uart1_src", 0,
+ COMPOSITE_FRAC(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(18), 0,
RK3288_CLKGATE_CON(1), 11, GFLAGS),
- MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, 0,
+ MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(14), 8, 2, MFLAGS),
COMPOSITE_NOMUX(0, "uart2_src", "uart_src", 0,
RK3288_CLKSEL_CON(15), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 12, GFLAGS),
- COMPOSITE_FRAC(0, "uart2_frac", "uart2_src", 0,
+ COMPOSITE_FRAC(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(19), 0,
RK3288_CLKGATE_CON(1), 13, GFLAGS),
- MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, 0,
+ MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(15), 8, 2, MFLAGS),
COMPOSITE_NOMUX(0, "uart3_src", "uart_src", 0,
RK3288_CLKSEL_CON(16), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 14, GFLAGS),
- COMPOSITE_FRAC(0, "uart3_frac", "uart3_src", 0,
+ COMPOSITE_FRAC(0, "uart3_frac", "uart3_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(20), 0,
RK3288_CLKGATE_CON(1), 15, GFLAGS),
- MUX(SCLK_UART3, "sclk_uart3", mux_uart3_p, 0,
+ MUX(SCLK_UART3, "sclk_uart3", mux_uart3_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(16), 8, 2, MFLAGS),
COMPOSITE_NOMUX(0, "uart4_src", "uart_src", 0,
RK3288_CLKSEL_CON(3), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(2), 12, GFLAGS),
- COMPOSITE_FRAC(0, "uart4_frac", "uart4_src", 0,
+ COMPOSITE_FRAC(0, "uart4_frac", "uart4_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(7), 0,
RK3288_CLKGATE_CON(2), 13, GFLAGS),
- MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, 0,
+ MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(3), 8, 2, MFLAGS),
COMPOSITE(0, "mac_pll_src", mux_pll_src_npll_cpll_gpll_p, 0,
@@ -598,7 +598,7 @@
GATE(0, "jtag", "ext_jtag", 0,
RK3288_CLKGATE_CON(4), 14, GFLAGS),
- COMPOSITE_NODIV(0, "usbphy480m_src", mux_usbphy480m_p, 0,
+ COMPOSITE_NODIV(SCLK_USBPHY480M_SRC, "usbphy480m_src", mux_usbphy480m_p, 0,
RK3288_CLKSEL_CON(13), 11, 2, MFLAGS,
RK3288_CLKGATE_CON(5), 14, GFLAGS),
COMPOSITE_NODIV(SCLK_HSICPHY480M, "sclk_hsicphy480m", mux_hsicphy480m_p, 0,
@@ -704,8 +704,8 @@
GATE(SCLK_LCDC_PWM0, "sclk_lcdc_pwm0", "xin24m", 0, RK3288_CLKGATE_CON(13), 10, GFLAGS),
GATE(SCLK_LCDC_PWM1, "sclk_lcdc_pwm1", "xin24m", 0, RK3288_CLKGATE_CON(13), 11, GFLAGS),
- GATE(0, "sclk_pvtm_core", "xin24m", 0, RK3288_CLKGATE_CON(5), 9, GFLAGS),
- GATE(0, "sclk_pvtm_gpu", "xin24m", 0, RK3288_CLKGATE_CON(5), 10, GFLAGS),
+ GATE(SCLK_PVTM_CORE, "sclk_pvtm_core", "xin24m", 0, RK3288_CLKGATE_CON(5), 9, GFLAGS),
+ GATE(SCLK_PVTM_GPU, "sclk_pvtm_gpu", "xin24m", 0, RK3288_CLKGATE_CON(5), 10, GFLAGS),
GATE(0, "sclk_mipidsi_24m", "xin24m", 0, RK3288_CLKGATE_CON(5), 15, GFLAGS),
/* sclk_gpu gates */
@@ -805,6 +805,20 @@
rk3288_saved_cru_regs[i] =
readl_relaxed(rk3288_cru_base + reg_id);
}
+
+ /*
+ * Switch PLLs other than DPLL (for SDRAM) to slow mode to
+ * avoid crashes on resume. The Mask ROM on the system will
+ * put APLL, CPLL, and GPLL into slow mode at resume time
+ * anyway (which is why we restore them), but we might not
+ * even make it to the Mask ROM if this isn't done at suspend
+ * time.
+ *
+ * NOTE: only APLL truly matters here, but we'll do them all.
+ */
+
+ writel_relaxed(0xf3030000, rk3288_cru_base + RK3288_MODE_CON);
+
return 0;
}
@@ -866,6 +880,14 @@
pr_warn("%s: could not register clock hclk_vcodec_pre: %ld\n",
__func__, PTR_ERR(clk));
+ /* Watchdog pclk is controlled by RK3288_SGRF_SOC_CON0[1]. */
+ clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_pd_alive", 0, 1, 1);
+ if (IS_ERR(clk))
+ pr_warn("%s: could not register clock pclk_wdt: %ld\n",
+ __func__, PTR_ERR(clk));
+ else
+ rockchip_clk_add_lookup(clk, PCLK_WDT);
+
rockchip_clk_register_plls(rk3288_pll_clks,
ARRAY_SIZE(rk3288_pll_clks),
RK3288_GRF_SOC_STATUS1);
diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c
index f2c2ccc..454b02a 100644
--- a/drivers/clk/samsung/clk-exynos-audss.c
+++ b/drivers/clk/samsung/clk-exynos-audss.c
@@ -82,6 +82,26 @@
{},
};
+static void exynos_audss_clk_teardown(void)
+{
+ int i;
+
+ for (i = EXYNOS_MOUT_AUDSS; i < EXYNOS_DOUT_SRP; i++) {
+ if (!IS_ERR(clk_table[i]))
+ clk_unregister_mux(clk_table[i]);
+ }
+
+ for (; i < EXYNOS_SRP_CLK; i++) {
+ if (!IS_ERR(clk_table[i]))
+ clk_unregister_divider(clk_table[i]);
+ }
+
+ for (; i < clk_data.clk_num; i++) {
+ if (!IS_ERR(clk_table[i]))
+ clk_unregister_gate(clk_table[i]);
+ }
+}
+
/* register exynos_audss clocks */
static int exynos_audss_clk_probe(struct platform_device *pdev)
{
@@ -219,10 +239,7 @@
return 0;
unregister:
- for (i = 0; i < clk_data.clk_num; i++) {
- if (!IS_ERR(clk_table[i]))
- clk_unregister(clk_table[i]);
- }
+ exynos_audss_clk_teardown();
if (!IS_ERR(epll))
clk_disable_unprepare(epll);
@@ -232,18 +249,13 @@
static int exynos_audss_clk_remove(struct platform_device *pdev)
{
- int i;
-
#ifdef CONFIG_PM_SLEEP
unregister_syscore_ops(&exynos_audss_clk_syscore_ops);
#endif
of_clk_del_provider(pdev->dev.of_node);
- for (i = 0; i < clk_data.clk_num; i++) {
- if (!IS_ERR(clk_table[i]))
- clk_unregister(clk_table[i]);
- }
+ exynos_audss_clk_teardown();
if (!IS_ERR(epll))
clk_disable_unprepare(epll);
diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c
index 6e6cca3..cc4c348 100644
--- a/drivers/clk/samsung/clk-exynos3250.c
+++ b/drivers/clk/samsung/clk-exynos3250.c
@@ -104,27 +104,6 @@
#define PWR_CTRL1_USE_CORE1_WFI (1 << 1)
#define PWR_CTRL1_USE_CORE0_WFI (1 << 0)
-/* list of PLLs to be registered */
-enum exynos3250_plls {
- apll, mpll, vpll, upll,
- nr_plls
-};
-
-/* list of PLLs in DMC block to be registered */
-enum exynos3250_dmc_plls {
- bpll, epll,
- nr_dmc_plls
-};
-
-static void __iomem *reg_base;
-static void __iomem *dmc_reg_base;
-
-/*
- * Support for CMU save/restore across system suspends
- */
-#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *exynos3250_clk_regs;
-
static unsigned long exynos3250_cmu_clk_regs[] __initdata = {
SRC_LEFTBUS,
DIV_LEFTBUS,
@@ -195,43 +174,6 @@
PWR_CTRL2,
};
-static int exynos3250_clk_suspend(void)
-{
- samsung_clk_save(reg_base, exynos3250_clk_regs,
- ARRAY_SIZE(exynos3250_cmu_clk_regs));
- return 0;
-}
-
-static void exynos3250_clk_resume(void)
-{
- samsung_clk_restore(reg_base, exynos3250_clk_regs,
- ARRAY_SIZE(exynos3250_cmu_clk_regs));
-}
-
-static struct syscore_ops exynos3250_clk_syscore_ops = {
- .suspend = exynos3250_clk_suspend,
- .resume = exynos3250_clk_resume,
-};
-
-static void exynos3250_clk_sleep_init(void)
-{
- exynos3250_clk_regs =
- samsung_clk_alloc_reg_dump(exynos3250_cmu_clk_regs,
- ARRAY_SIZE(exynos3250_cmu_clk_regs));
- if (!exynos3250_clk_regs) {
- pr_warn("%s: Failed to allocate sleep save data\n", __func__);
- goto err;
- }
-
- register_syscore_ops(&exynos3250_clk_syscore_ops);
- return;
-err:
- kfree(exynos3250_clk_regs);
-}
-#else
-static inline void exynos3250_clk_sleep_init(void) { }
-#endif
-
/* list of all parent clock list */
PNAME(mout_vpllsrc_p) = { "fin_pll", };
@@ -782,18 +724,18 @@
{ /* sentinel */ }
};
-static struct samsung_pll_clock exynos3250_plls[nr_plls] __initdata = {
- [apll] = PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll",
- APLL_LOCK, APLL_CON0, NULL),
- [mpll] = PLL(pll_35xx, CLK_FOUT_MPLL, "fout_mpll", "fin_pll",
- MPLL_LOCK, MPLL_CON0, NULL),
- [vpll] = PLL(pll_36xx, CLK_FOUT_VPLL, "fout_vpll", "fin_pll",
- VPLL_LOCK, VPLL_CON0, NULL),
- [upll] = PLL(pll_35xx, CLK_FOUT_UPLL, "fout_upll", "fin_pll",
- UPLL_LOCK, UPLL_CON0, NULL),
+static struct samsung_pll_clock exynos3250_plls[] __initdata = {
+ PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll",
+ APLL_LOCK, APLL_CON0, exynos3250_pll_rates),
+ PLL(pll_35xx, CLK_FOUT_MPLL, "fout_mpll", "fin_pll",
+ MPLL_LOCK, MPLL_CON0, exynos3250_pll_rates),
+ PLL(pll_36xx, CLK_FOUT_VPLL, "fout_vpll", "fin_pll",
+ VPLL_LOCK, VPLL_CON0, exynos3250_vpll_rates),
+ PLL(pll_35xx, CLK_FOUT_UPLL, "fout_upll", "fin_pll",
+ UPLL_LOCK, UPLL_CON0, exynos3250_pll_rates),
};
-static void __init exynos3_core_down_clock(void)
+static void __init exynos3_core_down_clock(void __iomem *reg_base)
{
unsigned int tmp;
@@ -814,38 +756,31 @@
__raw_writel(0x0, reg_base + PWR_CTRL2);
}
+static struct samsung_cmu_info cmu_info __initdata = {
+ .pll_clks = exynos3250_plls,
+ .nr_pll_clks = ARRAY_SIZE(exynos3250_plls),
+ .mux_clks = mux_clks,
+ .nr_mux_clks = ARRAY_SIZE(mux_clks),
+ .div_clks = div_clks,
+ .nr_div_clks = ARRAY_SIZE(div_clks),
+ .gate_clks = gate_clks,
+ .nr_gate_clks = ARRAY_SIZE(gate_clks),
+ .fixed_factor_clks = fixed_factor_clks,
+ .nr_fixed_factor_clks = ARRAY_SIZE(fixed_factor_clks),
+ .nr_clk_ids = CLK_NR_CLKS,
+ .clk_regs = exynos3250_cmu_clk_regs,
+ .nr_clk_regs = ARRAY_SIZE(exynos3250_cmu_clk_regs),
+};
+
static void __init exynos3250_cmu_init(struct device_node *np)
{
struct samsung_clk_provider *ctx;
- reg_base = of_iomap(np, 0);
- if (!reg_base)
- panic("%s: failed to map registers\n", __func__);
-
- ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS);
+ ctx = samsung_cmu_register_one(np, &cmu_info);
if (!ctx)
- panic("%s: unable to allocate context.\n", __func__);
+ return;
- samsung_clk_register_fixed_factor(ctx, fixed_factor_clks,
- ARRAY_SIZE(fixed_factor_clks));
-
- exynos3250_plls[apll].rate_table = exynos3250_pll_rates;
- exynos3250_plls[mpll].rate_table = exynos3250_pll_rates;
- exynos3250_plls[vpll].rate_table = exynos3250_vpll_rates;
- exynos3250_plls[upll].rate_table = exynos3250_pll_rates;
-
- samsung_clk_register_pll(ctx, exynos3250_plls,
- ARRAY_SIZE(exynos3250_plls), reg_base);
-
- samsung_clk_register_mux(ctx, mux_clks, ARRAY_SIZE(mux_clks));
- samsung_clk_register_div(ctx, div_clks, ARRAY_SIZE(div_clks));
- samsung_clk_register_gate(ctx, gate_clks, ARRAY_SIZE(gate_clks));
-
- exynos3_core_down_clock();
-
- exynos3250_clk_sleep_init();
-
- samsung_clk_of_add_provider(np, ctx);
+ exynos3_core_down_clock(ctx->reg_base);
}
CLK_OF_DECLARE(exynos3250_cmu, "samsung,exynos3250-cmu", exynos3250_cmu_init);
@@ -872,12 +807,6 @@
#define EPLL_CON2 0x111c
#define SRC_EPLL 0x1120
-/*
- * Support for CMU save/restore across system suspends
- */
-#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *exynos3250_dmc_clk_regs;
-
static unsigned long exynos3250_cmu_dmc_clk_regs[] __initdata = {
BPLL_LOCK,
BPLL_CON0,
@@ -899,43 +828,6 @@
SRC_EPLL,
};
-static int exynos3250_dmc_clk_suspend(void)
-{
- samsung_clk_save(dmc_reg_base, exynos3250_dmc_clk_regs,
- ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs));
- return 0;
-}
-
-static void exynos3250_dmc_clk_resume(void)
-{
- samsung_clk_restore(dmc_reg_base, exynos3250_dmc_clk_regs,
- ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs));
-}
-
-static struct syscore_ops exynos3250_dmc_clk_syscore_ops = {
- .suspend = exynos3250_dmc_clk_suspend,
- .resume = exynos3250_dmc_clk_resume,
-};
-
-static void exynos3250_dmc_clk_sleep_init(void)
-{
- exynos3250_dmc_clk_regs =
- samsung_clk_alloc_reg_dump(exynos3250_cmu_dmc_clk_regs,
- ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs));
- if (!exynos3250_dmc_clk_regs) {
- pr_warn("%s: Failed to allocate sleep save data\n", __func__);
- goto err;
- }
-
- register_syscore_ops(&exynos3250_dmc_clk_syscore_ops);
- return;
-err:
- kfree(exynos3250_dmc_clk_regs);
-}
-#else
-static inline void exynos3250_dmc_clk_sleep_init(void) { }
-#endif
-
PNAME(mout_epll_p) = { "fin_pll", "fout_epll", };
PNAME(mout_bpll_p) = { "fin_pll", "fout_bpll", };
PNAME(mout_mpll_mif_p) = { "fin_pll", "sclk_mpll_mif", };
@@ -977,43 +869,28 @@
DIV(CLK_DIV_DMCD, "div_dmcd", "div_dmc", DIV_DMC1, 11, 3),
};
-static struct samsung_pll_clock exynos3250_dmc_plls[nr_dmc_plls] __initdata = {
- [bpll] = PLL(pll_35xx, CLK_FOUT_BPLL, "fout_bpll", "fin_pll",
- BPLL_LOCK, BPLL_CON0, NULL),
- [epll] = PLL(pll_36xx, CLK_FOUT_EPLL, "fout_epll", "fin_pll",
- EPLL_LOCK, EPLL_CON0, NULL),
+static struct samsung_pll_clock exynos3250_dmc_plls[] __initdata = {
+ PLL(pll_35xx, CLK_FOUT_BPLL, "fout_bpll", "fin_pll",
+ BPLL_LOCK, BPLL_CON0, exynos3250_pll_rates),
+ PLL(pll_36xx, CLK_FOUT_EPLL, "fout_epll", "fin_pll",
+ EPLL_LOCK, EPLL_CON0, exynos3250_epll_rates),
+};
+
+static struct samsung_cmu_info dmc_cmu_info __initdata = {
+ .pll_clks = exynos3250_dmc_plls,
+ .nr_pll_clks = ARRAY_SIZE(exynos3250_dmc_plls),
+ .mux_clks = dmc_mux_clks,
+ .nr_mux_clks = ARRAY_SIZE(dmc_mux_clks),
+ .div_clks = dmc_div_clks,
+ .nr_div_clks = ARRAY_SIZE(dmc_div_clks),
+ .nr_clk_ids = NR_CLKS_DMC,
+ .clk_regs = exynos3250_cmu_dmc_clk_regs,
+ .nr_clk_regs = ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs),
};
static void __init exynos3250_cmu_dmc_init(struct device_node *np)
{
- struct samsung_clk_provider *ctx;
-
- dmc_reg_base = of_iomap(np, 0);
- if (!dmc_reg_base)
- panic("%s: failed to map registers\n", __func__);
-
- ctx = samsung_clk_init(np, dmc_reg_base, NR_CLKS_DMC);
- if (!ctx)
- panic("%s: unable to allocate context.\n", __func__);
-
- exynos3250_dmc_plls[bpll].rate_table = exynos3250_pll_rates;
- exynos3250_dmc_plls[epll].rate_table = exynos3250_epll_rates;
-
- pr_err("CLK registering epll bpll: %d, %d, %d, %d\n",
- exynos3250_dmc_plls[bpll].rate_table[0].rate,
- exynos3250_dmc_plls[bpll].rate_table[0].mdiv,
- exynos3250_dmc_plls[bpll].rate_table[0].pdiv,
- exynos3250_dmc_plls[bpll].rate_table[0].sdiv
- );
- samsung_clk_register_pll(ctx, exynos3250_dmc_plls,
- ARRAY_SIZE(exynos3250_dmc_plls), dmc_reg_base);
-
- samsung_clk_register_mux(ctx, dmc_mux_clks, ARRAY_SIZE(dmc_mux_clks));
- samsung_clk_register_div(ctx, dmc_div_clks, ARRAY_SIZE(dmc_div_clks));
-
- exynos3250_dmc_clk_sleep_init();
-
- samsung_clk_of_add_provider(np, ctx);
+ samsung_cmu_register_one(np, &dmc_cmu_info);
}
CLK_OF_DECLARE(exynos3250_cmu_dmc, "samsung,exynos3250-cmu-dmc",
exynos3250_cmu_dmc_init);
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
index 88e8c6b..51462e8 100644
--- a/drivers/clk/samsung/clk-exynos4.c
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -703,12 +703,12 @@
/* list of divider clocks supported in all exynos4 soc's */
static struct samsung_div_clock exynos4_div_clks[] __initdata = {
- DIV(0, "div_gdl", "mout_gdl", DIV_LEFTBUS, 0, 3),
+ DIV(CLK_DIV_GDL, "div_gdl", "mout_gdl", DIV_LEFTBUS, 0, 3),
DIV(0, "div_gpl", "div_gdl", DIV_LEFTBUS, 4, 3),
DIV(0, "div_clkout_leftbus", "mout_clkout_leftbus",
CLKOUT_CMU_LEFTBUS, 8, 6),
- DIV(0, "div_gdr", "mout_gdr", DIV_RIGHTBUS, 0, 3),
+ DIV(CLK_DIV_GDR, "div_gdr", "mout_gdr", DIV_RIGHTBUS, 0, 3),
DIV(0, "div_gpr", "div_gdr", DIV_RIGHTBUS, 4, 3),
DIV(0, "div_clkout_rightbus", "mout_clkout_rightbus",
CLKOUT_CMU_RIGHTBUS, 8, 6),
@@ -781,10 +781,10 @@
CLK_SET_RATE_PARENT, 0),
DIV(0, "div_clkout_top", "mout_clkout_top", CLKOUT_CMU_TOP, 8, 6),
- DIV(0, "div_acp", "mout_dmc_bus", DIV_DMC0, 0, 3),
+ DIV(CLK_DIV_ACP, "div_acp", "mout_dmc_bus", DIV_DMC0, 0, 3),
DIV(0, "div_acp_pclk", "div_acp", DIV_DMC0, 4, 3),
DIV(0, "div_dphy", "mout_dphy", DIV_DMC0, 8, 3),
- DIV(0, "div_dmc", "mout_dmc_bus", DIV_DMC0, 12, 3),
+ DIV(CLK_DIV_DMC, "div_dmc", "mout_dmc_bus", DIV_DMC0, 12, 3),
DIV(0, "div_dmcd", "div_dmc", DIV_DMC0, 16, 3),
DIV(0, "div_dmcp", "div_dmcd", DIV_DMC0, 20, 3),
DIV(0, "div_pwi", "mout_pwi", DIV_DMC1, 8, 4),
@@ -829,7 +829,7 @@
DIV_F(CLK_DIV_MCUISP1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1,
8, 3, CLK_GET_RATE_NOCACHE, 0),
DIV(CLK_SCLK_FIMG2D, "sclk_fimg2d", "mout_g2d", DIV_DMC1, 0, 4),
- DIV(0, "div_c2c", "mout_c2c", DIV_DMC1, 4, 3),
+ DIV(CLK_DIV_C2C, "div_c2c", "mout_c2c", DIV_DMC1, 4, 3),
DIV(0, "div_c2c_aclk", "div_c2c", DIV_DMC1, 12, 3),
};
diff --git a/drivers/clk/samsung/clk-exynos4415.c b/drivers/clk/samsung/clk-exynos4415.c
index 2123fc2..6c78b09 100644
--- a/drivers/clk/samsung/clk-exynos4415.c
+++ b/drivers/clk/samsung/clk-exynos4415.c
@@ -113,19 +113,6 @@
#define DIV_CPU0 0x14500
#define DIV_CPU1 0x14504
-enum exynos4415_plls {
- apll, epll, g3d_pll, isp_pll, disp_pll,
- nr_plls,
-};
-
-static struct samsung_clk_provider *exynos4415_ctx;
-
-/*
- * Support for CMU save/restore across system suspends
- */
-#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *exynos4415_clk_regs;
-
static unsigned long exynos4415_cmu_clk_regs[] __initdata = {
SRC_LEFTBUS,
DIV_LEFTBUS,
@@ -219,41 +206,6 @@
DIV_CPU1,
};
-static int exynos4415_clk_suspend(void)
-{
- samsung_clk_save(exynos4415_ctx->reg_base, exynos4415_clk_regs,
- ARRAY_SIZE(exynos4415_cmu_clk_regs));
-
- return 0;
-}
-
-static void exynos4415_clk_resume(void)
-{
- samsung_clk_restore(exynos4415_ctx->reg_base, exynos4415_clk_regs,
- ARRAY_SIZE(exynos4415_cmu_clk_regs));
-}
-
-static struct syscore_ops exynos4415_clk_syscore_ops = {
- .suspend = exynos4415_clk_suspend,
- .resume = exynos4415_clk_resume,
-};
-
-static void exynos4415_clk_sleep_init(void)
-{
- exynos4415_clk_regs =
- samsung_clk_alloc_reg_dump(exynos4415_cmu_clk_regs,
- ARRAY_SIZE(exynos4415_cmu_clk_regs));
- if (!exynos4415_clk_regs) {
- pr_warn("%s: Failed to allocate sleep save data\n", __func__);
- return;
- }
-
- register_syscore_ops(&exynos4415_clk_syscore_ops);
-}
-#else
-static inline void exynos4415_clk_sleep_init(void) { }
-#endif
-
/* list of all parent clock list */
PNAME(mout_g3d_pllsrc_p) = { "fin_pll", };
@@ -959,56 +911,40 @@
{ /* sentinel */ }
};
-static struct samsung_pll_clock exynos4415_plls[nr_plls] __initdata = {
- [apll] = PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll",
- APLL_LOCK, APLL_CON0, NULL),
- [epll] = PLL(pll_36xx, CLK_FOUT_EPLL, "fout_epll", "fin_pll",
- EPLL_LOCK, EPLL_CON0, NULL),
- [g3d_pll] = PLL(pll_35xx, CLK_FOUT_G3D_PLL, "fout_g3d_pll",
- "mout_g3d_pllsrc", G3D_PLL_LOCK, G3D_PLL_CON0, NULL),
- [isp_pll] = PLL(pll_35xx, CLK_FOUT_ISP_PLL, "fout_isp_pll", "fin_pll",
- ISP_PLL_LOCK, ISP_PLL_CON0, NULL),
- [disp_pll] = PLL(pll_35xx, CLK_FOUT_DISP_PLL, "fout_disp_pll",
- "fin_pll", DISP_PLL_LOCK, DISP_PLL_CON0, NULL),
+static struct samsung_pll_clock exynos4415_plls[] __initdata = {
+ PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll",
+ APLL_LOCK, APLL_CON0, exynos4415_pll_rates),
+ PLL(pll_36xx, CLK_FOUT_EPLL, "fout_epll", "fin_pll",
+ EPLL_LOCK, EPLL_CON0, exynos4415_epll_rates),
+ PLL(pll_35xx, CLK_FOUT_G3D_PLL, "fout_g3d_pll", "mout_g3d_pllsrc",
+ G3D_PLL_LOCK, G3D_PLL_CON0, exynos4415_pll_rates),
+ PLL(pll_35xx, CLK_FOUT_ISP_PLL, "fout_isp_pll", "fin_pll",
+ ISP_PLL_LOCK, ISP_PLL_CON0, exynos4415_pll_rates),
+ PLL(pll_35xx, CLK_FOUT_DISP_PLL, "fout_disp_pll",
+ "fin_pll", DISP_PLL_LOCK, DISP_PLL_CON0, exynos4415_pll_rates),
+};
+
+static struct samsung_cmu_info cmu_info __initdata = {
+ .pll_clks = exynos4415_plls,
+ .nr_pll_clks = ARRAY_SIZE(exynos4415_plls),
+ .mux_clks = exynos4415_mux_clks,
+ .nr_mux_clks = ARRAY_SIZE(exynos4415_mux_clks),
+ .div_clks = exynos4415_div_clks,
+ .nr_div_clks = ARRAY_SIZE(exynos4415_div_clks),
+ .gate_clks = exynos4415_gate_clks,
+ .nr_gate_clks = ARRAY_SIZE(exynos4415_gate_clks),
+ .fixed_clks = exynos4415_fixed_rate_clks,
+ .nr_fixed_clks = ARRAY_SIZE(exynos4415_fixed_rate_clks),
+ .fixed_factor_clks = exynos4415_fixed_factor_clks,
+ .nr_fixed_factor_clks = ARRAY_SIZE(exynos4415_fixed_factor_clks),
+ .nr_clk_ids = CLK_NR_CLKS,
+ .clk_regs = exynos4415_cmu_clk_regs,
+ .nr_clk_regs = ARRAY_SIZE(exynos4415_cmu_clk_regs),
};
static void __init exynos4415_cmu_init(struct device_node *np)
{
- void __iomem *reg_base;
-
- reg_base = of_iomap(np, 0);
- if (!reg_base)
- panic("%s: failed to map registers\n", __func__);
-
- exynos4415_ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS);
- if (!exynos4415_ctx)
- panic("%s: unable to allocate context.\n", __func__);
-
- exynos4415_plls[apll].rate_table = exynos4415_pll_rates;
- exynos4415_plls[epll].rate_table = exynos4415_epll_rates;
- exynos4415_plls[g3d_pll].rate_table = exynos4415_pll_rates;
- exynos4415_plls[isp_pll].rate_table = exynos4415_pll_rates;
- exynos4415_plls[disp_pll].rate_table = exynos4415_pll_rates;
-
- samsung_clk_register_fixed_factor(exynos4415_ctx,
- exynos4415_fixed_factor_clks,
- ARRAY_SIZE(exynos4415_fixed_factor_clks));
- samsung_clk_register_fixed_rate(exynos4415_ctx,
- exynos4415_fixed_rate_clks,
- ARRAY_SIZE(exynos4415_fixed_rate_clks));
-
- samsung_clk_register_pll(exynos4415_ctx, exynos4415_plls,
- ARRAY_SIZE(exynos4415_plls), reg_base);
- samsung_clk_register_mux(exynos4415_ctx, exynos4415_mux_clks,
- ARRAY_SIZE(exynos4415_mux_clks));
- samsung_clk_register_div(exynos4415_ctx, exynos4415_div_clks,
- ARRAY_SIZE(exynos4415_div_clks));
- samsung_clk_register_gate(exynos4415_ctx, exynos4415_gate_clks,
- ARRAY_SIZE(exynos4415_gate_clks));
-
- exynos4415_clk_sleep_init();
-
- samsung_clk_of_add_provider(np, exynos4415_ctx);
+ samsung_cmu_register_one(np, &cmu_info);
}
CLK_OF_DECLARE(exynos4415_cmu, "samsung,exynos4415-cmu", exynos4415_cmu_init);
@@ -1027,16 +963,6 @@
#define SRC_DMC 0x300
#define DIV_DMC1 0x504
-enum exynos4415_dmc_plls {
- mpll, bpll,
- nr_dmc_plls,
-};
-
-static struct samsung_clk_provider *exynos4415_dmc_ctx;
-
-#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *exynos4415_dmc_clk_regs;
-
static unsigned long exynos4415_cmu_dmc_clk_regs[] __initdata = {
MPLL_LOCK,
MPLL_CON0,
@@ -1050,42 +976,6 @@
DIV_DMC1,
};
-static int exynos4415_dmc_clk_suspend(void)
-{
- samsung_clk_save(exynos4415_dmc_ctx->reg_base,
- exynos4415_dmc_clk_regs,
- ARRAY_SIZE(exynos4415_cmu_dmc_clk_regs));
- return 0;
-}
-
-static void exynos4415_dmc_clk_resume(void)
-{
- samsung_clk_restore(exynos4415_dmc_ctx->reg_base,
- exynos4415_dmc_clk_regs,
- ARRAY_SIZE(exynos4415_cmu_dmc_clk_regs));
-}
-
-static struct syscore_ops exynos4415_dmc_clk_syscore_ops = {
- .suspend = exynos4415_dmc_clk_suspend,
- .resume = exynos4415_dmc_clk_resume,
-};
-
-static void exynos4415_dmc_clk_sleep_init(void)
-{
- exynos4415_dmc_clk_regs =
- samsung_clk_alloc_reg_dump(exynos4415_cmu_dmc_clk_regs,
- ARRAY_SIZE(exynos4415_cmu_dmc_clk_regs));
- if (!exynos4415_dmc_clk_regs) {
- pr_warn("%s: Failed to allocate sleep save data\n", __func__);
- return;
- }
-
- register_syscore_ops(&exynos4415_dmc_clk_syscore_ops);
-}
-#else
-static inline void exynos4415_dmc_clk_sleep_init(void) { }
-#endif /* CONFIG_PM_SLEEP */
-
PNAME(mout_mpll_p) = { "fin_pll", "fout_mpll", };
PNAME(mout_bpll_p) = { "fin_pll", "fout_bpll", };
PNAME(mbpll_p) = { "mout_mpll", "mout_bpll", };
@@ -1107,38 +997,28 @@
DIV(CLK_DMC_DIV_MPLL_PRE, "div_mpll_pre", "mout_mpll", DIV_DMC1, 8, 2),
};
-static struct samsung_pll_clock exynos4415_dmc_plls[nr_dmc_plls] __initdata = {
- [mpll] = PLL(pll_35xx, CLK_DMC_FOUT_MPLL, "fout_mpll", "fin_pll",
- MPLL_LOCK, MPLL_CON0, NULL),
- [bpll] = PLL(pll_35xx, CLK_DMC_FOUT_BPLL, "fout_bpll", "fin_pll",
- BPLL_LOCK, BPLL_CON0, NULL),
+static struct samsung_pll_clock exynos4415_dmc_plls[] __initdata = {
+ PLL(pll_35xx, CLK_DMC_FOUT_MPLL, "fout_mpll", "fin_pll",
+ MPLL_LOCK, MPLL_CON0, exynos4415_pll_rates),
+ PLL(pll_35xx, CLK_DMC_FOUT_BPLL, "fout_bpll", "fin_pll",
+ BPLL_LOCK, BPLL_CON0, exynos4415_pll_rates),
+};
+
+static struct samsung_cmu_info cmu_dmc_info __initdata = {
+ .pll_clks = exynos4415_dmc_plls,
+ .nr_pll_clks = ARRAY_SIZE(exynos4415_dmc_plls),
+ .mux_clks = exynos4415_dmc_mux_clks,
+ .nr_mux_clks = ARRAY_SIZE(exynos4415_dmc_mux_clks),
+ .div_clks = exynos4415_dmc_div_clks,
+ .nr_div_clks = ARRAY_SIZE(exynos4415_dmc_div_clks),
+ .nr_clk_ids = NR_CLKS_DMC,
+ .clk_regs = exynos4415_cmu_dmc_clk_regs,
+ .nr_clk_regs = ARRAY_SIZE(exynos4415_cmu_dmc_clk_regs),
};
static void __init exynos4415_cmu_dmc_init(struct device_node *np)
{
- void __iomem *reg_base;
-
- reg_base = of_iomap(np, 0);
- if (!reg_base)
- panic("%s: failed to map registers\n", __func__);
-
- exynos4415_dmc_ctx = samsung_clk_init(np, reg_base, NR_CLKS_DMC);
- if (!exynos4415_dmc_ctx)
- panic("%s: unable to allocate context.\n", __func__);
-
- exynos4415_dmc_plls[mpll].rate_table = exynos4415_pll_rates;
- exynos4415_dmc_plls[bpll].rate_table = exynos4415_pll_rates;
-
- samsung_clk_register_pll(exynos4415_dmc_ctx, exynos4415_dmc_plls,
- ARRAY_SIZE(exynos4415_dmc_plls), reg_base);
- samsung_clk_register_mux(exynos4415_dmc_ctx, exynos4415_dmc_mux_clks,
- ARRAY_SIZE(exynos4415_dmc_mux_clks));
- samsung_clk_register_div(exynos4415_dmc_ctx, exynos4415_dmc_div_clks,
- ARRAY_SIZE(exynos4415_dmc_div_clks));
-
- exynos4415_dmc_clk_sleep_init();
-
- samsung_clk_of_add_provider(np, exynos4415_dmc_ctx);
+ samsung_cmu_register_one(np, &cmu_dmc_info);
}
CLK_OF_DECLARE(exynos4415_cmu_dmc, "samsung,exynos4415-cmu-dmc",
exynos4415_cmu_dmc_init);
diff --git a/drivers/clk/samsung/clk-exynos7.c b/drivers/clk/samsung/clk-exynos7.c
index ea4483b..03d36e8 100644
--- a/drivers/clk/samsung/clk-exynos7.c
+++ b/drivers/clk/samsung/clk-exynos7.c
@@ -34,6 +34,7 @@
#define DIV_TOPC0 0x0600
#define DIV_TOPC1 0x0604
#define DIV_TOPC3 0x060C
+#define ENABLE_ACLK_TOPC1 0x0804
static struct samsung_fixed_factor_clock topc_fixed_factor_clks[] __initdata = {
FFACTOR(0, "ffac_topc_bus0_pll_div2", "mout_bus0_pll_ctrl", 1, 2, 0),
@@ -45,6 +46,7 @@
};
/* List of parent clocks for Muxes in CMU_TOPC */
+PNAME(mout_aud_pll_ctrl_p) = { "fin_pll", "fout_aud_pll" };
PNAME(mout_bus0_pll_ctrl_p) = { "fin_pll", "fout_bus0_pll" };
PNAME(mout_bus1_pll_ctrl_p) = { "fin_pll", "fout_bus1_pll" };
PNAME(mout_cc_pll_ctrl_p) = { "fin_pll", "fout_cc_pll" };
@@ -104,9 +106,11 @@
MUX(0, "mout_sclk_bus0_pll_out", mout_sclk_bus0_pll_out_p,
MUX_SEL_TOPC1, 16, 1),
+ MUX(0, "mout_aud_pll_ctrl", mout_aud_pll_ctrl_p, MUX_SEL_TOPC1, 0, 1),
MUX(0, "mout_aclk_ccore_133", mout_topc_group2, MUX_SEL_TOPC2, 4, 2),
+ MUX(0, "mout_aclk_mscl_532", mout_topc_group2, MUX_SEL_TOPC3, 20, 2),
MUX(0, "mout_aclk_peris_66", mout_topc_group2, MUX_SEL_TOPC3, 24, 2),
};
@@ -114,6 +118,8 @@
DIV(DOUT_ACLK_CCORE_133, "dout_aclk_ccore_133", "mout_aclk_ccore_133",
DIV_TOPC0, 4, 4),
+ DIV(DOUT_ACLK_MSCL_532, "dout_aclk_mscl_532", "mout_aclk_mscl_532",
+ DIV_TOPC1, 20, 4),
DIV(DOUT_ACLK_PERIS, "dout_aclk_peris_66", "mout_aclk_peris_66",
DIV_TOPC1, 24, 4),
@@ -125,6 +131,18 @@
DIV_TOPC3, 12, 3),
DIV(DOUT_SCLK_MFC_PLL, "dout_sclk_mfc_pll", "mout_mfc_pll_ctrl",
DIV_TOPC3, 16, 3),
+ DIV(DOUT_SCLK_AUD_PLL, "dout_sclk_aud_pll", "mout_aud_pll_ctrl",
+ DIV_TOPC3, 28, 3),
+};
+
+static struct samsung_pll_rate_table pll1460x_24mhz_tbl[] __initdata = {
+ PLL_36XX_RATE(491520000, 20, 1, 0, 31457),
+ {},
+};
+
+static struct samsung_gate_clock topc_gate_clks[] __initdata = {
+ GATE(ACLK_MSCL_532, "aclk_mscl_532", "dout_aclk_mscl_532",
+ ENABLE_ACLK_TOPC1, 20, 0, 0),
};
static struct samsung_pll_clock topc_pll_clks[] __initdata = {
@@ -136,8 +154,8 @@
BUS1_DPLL_CON0, NULL),
PLL(pll_1452x, 0, "fout_mfc_pll", "fin_pll", MFC_PLL_LOCK,
MFC_PLL_CON0, NULL),
- PLL(pll_1460x, 0, "fout_aud_pll", "fin_pll", AUD_PLL_LOCK,
- AUD_PLL_CON0, NULL),
+ PLL(pll_1460x, FOUT_AUD_PLL, "fout_aud_pll", "fin_pll", AUD_PLL_LOCK,
+ AUD_PLL_CON0, pll1460x_24mhz_tbl),
};
static struct samsung_cmu_info topc_cmu_info __initdata = {
@@ -147,6 +165,8 @@
.nr_mux_clks = ARRAY_SIZE(topc_mux_clks),
.div_clks = topc_div_clks,
.nr_div_clks = ARRAY_SIZE(topc_div_clks),
+ .gate_clks = topc_gate_clks,
+ .nr_gate_clks = ARRAY_SIZE(topc_gate_clks),
.fixed_factor_clks = topc_fixed_factor_clks,
.nr_fixed_factor_clks = ARRAY_SIZE(topc_fixed_factor_clks),
.nr_clk_ids = TOPC_NR_CLK,
@@ -166,9 +186,18 @@
#define MUX_SEL_TOP00 0x0200
#define MUX_SEL_TOP01 0x0204
#define MUX_SEL_TOP03 0x020C
+#define MUX_SEL_TOP0_PERIC0 0x0230
+#define MUX_SEL_TOP0_PERIC1 0x0234
+#define MUX_SEL_TOP0_PERIC2 0x0238
#define MUX_SEL_TOP0_PERIC3 0x023C
#define DIV_TOP03 0x060C
+#define DIV_TOP0_PERIC0 0x0630
+#define DIV_TOP0_PERIC1 0x0634
+#define DIV_TOP0_PERIC2 0x0638
#define DIV_TOP0_PERIC3 0x063C
+#define ENABLE_SCLK_TOP0_PERIC0 0x0A30
+#define ENABLE_SCLK_TOP0_PERIC1 0x0A34
+#define ENABLE_SCLK_TOP0_PERIC2 0x0A38
#define ENABLE_SCLK_TOP0_PERIC3 0x0A3C
/* List of parent clocks for Muxes in CMU_TOP0 */
@@ -176,6 +205,7 @@
PNAME(mout_bus1_pll_p) = { "fin_pll", "dout_sclk_bus1_pll" };
PNAME(mout_cc_pll_p) = { "fin_pll", "dout_sclk_cc_pll" };
PNAME(mout_mfc_pll_p) = { "fin_pll", "dout_sclk_mfc_pll" };
+PNAME(mout_aud_pll_p) = { "fin_pll", "dout_sclk_aud_pll" };
PNAME(mout_top0_half_bus0_pll_p) = {"mout_top0_bus0_pll",
"ffac_top0_bus0_pll_div2"};
@@ -189,18 +219,34 @@
PNAME(mout_top0_group1) = {"mout_top0_half_bus0_pll",
"mout_top0_half_bus1_pll", "mout_top0_half_cc_pll",
"mout_top0_half_mfc_pll"};
+PNAME(mout_top0_group3) = {"ioclk_audiocdclk0",
+ "ioclk_audiocdclk1", "ioclk_spdif_extclk",
+ "mout_top0_aud_pll", "mout_top0_half_bus0_pll",
+ "mout_top0_half_bus1_pll"};
+PNAME(mout_top0_group4) = {"ioclk_audiocdclk1", "mout_top0_aud_pll",
+ "mout_top0_half_bus0_pll", "mout_top0_half_bus1_pll"};
static unsigned long top0_clk_regs[] __initdata = {
MUX_SEL_TOP00,
MUX_SEL_TOP01,
MUX_SEL_TOP03,
+ MUX_SEL_TOP0_PERIC0,
+ MUX_SEL_TOP0_PERIC1,
+ MUX_SEL_TOP0_PERIC2,
MUX_SEL_TOP0_PERIC3,
DIV_TOP03,
+ DIV_TOP0_PERIC0,
+ DIV_TOP0_PERIC1,
+ DIV_TOP0_PERIC2,
DIV_TOP0_PERIC3,
+ ENABLE_SCLK_TOP0_PERIC0,
+ ENABLE_SCLK_TOP0_PERIC1,
+ ENABLE_SCLK_TOP0_PERIC2,
ENABLE_SCLK_TOP0_PERIC3,
};
static struct samsung_mux_clock top0_mux_clks[] __initdata = {
+ MUX(0, "mout_top0_aud_pll", mout_aud_pll_p, MUX_SEL_TOP00, 0, 1),
MUX(0, "mout_top0_mfc_pll", mout_mfc_pll_p, MUX_SEL_TOP00, 4, 1),
MUX(0, "mout_top0_cc_pll", mout_cc_pll_p, MUX_SEL_TOP00, 8, 1),
MUX(0, "mout_top0_bus1_pll", mout_bus1_pll_p, MUX_SEL_TOP00, 12, 1),
@@ -218,10 +264,20 @@
MUX(0, "mout_aclk_peric1_66", mout_top0_group1, MUX_SEL_TOP03, 12, 2),
MUX(0, "mout_aclk_peric0_66", mout_top0_group1, MUX_SEL_TOP03, 20, 2),
+ MUX(0, "mout_sclk_spdif", mout_top0_group3, MUX_SEL_TOP0_PERIC0, 4, 3),
+ MUX(0, "mout_sclk_pcm1", mout_top0_group4, MUX_SEL_TOP0_PERIC0, 8, 2),
+ MUX(0, "mout_sclk_i2s1", mout_top0_group4, MUX_SEL_TOP0_PERIC0, 20, 2),
+
+ MUX(0, "mout_sclk_spi1", mout_top0_group1, MUX_SEL_TOP0_PERIC1, 8, 2),
+ MUX(0, "mout_sclk_spi0", mout_top0_group1, MUX_SEL_TOP0_PERIC1, 20, 2),
+
+ MUX(0, "mout_sclk_spi3", mout_top0_group1, MUX_SEL_TOP0_PERIC2, 8, 2),
+ MUX(0, "mout_sclk_spi2", mout_top0_group1, MUX_SEL_TOP0_PERIC2, 20, 2),
MUX(0, "mout_sclk_uart3", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 4, 2),
MUX(0, "mout_sclk_uart2", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 8, 2),
MUX(0, "mout_sclk_uart1", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 12, 2),
MUX(0, "mout_sclk_uart0", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 16, 2),
+ MUX(0, "mout_sclk_spi4", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 20, 2),
};
static struct samsung_div_clock top0_div_clks[] __initdata = {
@@ -230,13 +286,40 @@
DIV(DOUT_ACLK_PERIC0, "dout_aclk_peric0_66", "mout_aclk_peric0_66",
DIV_TOP03, 20, 6),
+ DIV(0, "dout_sclk_spdif", "mout_sclk_spdif", DIV_TOP0_PERIC0, 4, 4),
+ DIV(0, "dout_sclk_pcm1", "mout_sclk_pcm1", DIV_TOP0_PERIC0, 8, 12),
+ DIV(0, "dout_sclk_i2s1", "mout_sclk_i2s1", DIV_TOP0_PERIC0, 20, 10),
+
+ DIV(0, "dout_sclk_spi1", "mout_sclk_spi1", DIV_TOP0_PERIC1, 8, 12),
+ DIV(0, "dout_sclk_spi0", "mout_sclk_spi0", DIV_TOP0_PERIC1, 20, 12),
+
+ DIV(0, "dout_sclk_spi3", "mout_sclk_spi3", DIV_TOP0_PERIC2, 8, 12),
+ DIV(0, "dout_sclk_spi2", "mout_sclk_spi2", DIV_TOP0_PERIC2, 20, 12),
+
DIV(0, "dout_sclk_uart3", "mout_sclk_uart3", DIV_TOP0_PERIC3, 4, 4),
DIV(0, "dout_sclk_uart2", "mout_sclk_uart2", DIV_TOP0_PERIC3, 8, 4),
DIV(0, "dout_sclk_uart1", "mout_sclk_uart1", DIV_TOP0_PERIC3, 12, 4),
DIV(0, "dout_sclk_uart0", "mout_sclk_uart0", DIV_TOP0_PERIC3, 16, 4),
+ DIV(0, "dout_sclk_spi4", "mout_sclk_spi4", DIV_TOP0_PERIC3, 20, 12),
};
static struct samsung_gate_clock top0_gate_clks[] __initdata = {
+ GATE(CLK_SCLK_SPDIF, "sclk_spdif", "dout_sclk_spdif",
+ ENABLE_SCLK_TOP0_PERIC0, 4, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_PCM1, "sclk_pcm1", "dout_sclk_pcm1",
+ ENABLE_SCLK_TOP0_PERIC0, 8, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_I2S1, "sclk_i2s1", "dout_sclk_i2s1",
+ ENABLE_SCLK_TOP0_PERIC0, 20, CLK_SET_RATE_PARENT, 0),
+
+ GATE(CLK_SCLK_SPI1, "sclk_spi1", "dout_sclk_spi1",
+ ENABLE_SCLK_TOP0_PERIC1, 8, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_SPI0, "sclk_spi0", "dout_sclk_spi0",
+ ENABLE_SCLK_TOP0_PERIC1, 20, CLK_SET_RATE_PARENT, 0),
+
+ GATE(CLK_SCLK_SPI3, "sclk_spi3", "dout_sclk_spi3",
+ ENABLE_SCLK_TOP0_PERIC2, 8, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_SPI2, "sclk_spi2", "dout_sclk_spi2",
+ ENABLE_SCLK_TOP0_PERIC2, 20, CLK_SET_RATE_PARENT, 0),
GATE(CLK_SCLK_UART3, "sclk_uart3", "dout_sclk_uart3",
ENABLE_SCLK_TOP0_PERIC3, 4, 0, 0),
GATE(CLK_SCLK_UART2, "sclk_uart2", "dout_sclk_uart2",
@@ -245,6 +328,8 @@
ENABLE_SCLK_TOP0_PERIC3, 12, 0, 0),
GATE(CLK_SCLK_UART0, "sclk_uart0", "dout_sclk_uart0",
ENABLE_SCLK_TOP0_PERIC3, 16, 0, 0),
+ GATE(CLK_SCLK_SPI4, "sclk_spi4", "dout_sclk_spi4",
+ ENABLE_SCLK_TOP0_PERIC3, 20, CLK_SET_RATE_PARENT, 0),
};
static struct samsung_fixed_factor_clock top0_fixed_factor_clks[] __initdata = {
@@ -343,6 +428,8 @@
MUX(0, "mout_aclk_fsys0_200", mout_top1_group1, MUX_SEL_TOP13, 28, 2),
MUX(0, "mout_sclk_mmc2", mout_top1_group1, MUX_SEL_TOP1_FSYS0, 24, 2),
+ MUX(0, "mout_sclk_usbdrd300", mout_top1_group1,
+ MUX_SEL_TOP1_FSYS0, 28, 2),
MUX(0, "mout_sclk_mmc1", mout_top1_group1, MUX_SEL_TOP1_FSYS1, 24, 2),
MUX(0, "mout_sclk_mmc0", mout_top1_group1, MUX_SEL_TOP1_FSYS1, 28, 2),
@@ -356,6 +443,8 @@
DIV(DOUT_SCLK_MMC2, "dout_sclk_mmc2", "mout_sclk_mmc2",
DIV_TOP1_FSYS0, 24, 4),
+ DIV(0, "dout_sclk_usbdrd300", "mout_sclk_usbdrd300",
+ DIV_TOP1_FSYS0, 28, 4),
DIV(DOUT_SCLK_MMC1, "dout_sclk_mmc1", "mout_sclk_mmc1",
DIV_TOP1_FSYS1, 24, 4),
@@ -366,6 +455,8 @@
static struct samsung_gate_clock top1_gate_clks[] __initdata = {
GATE(CLK_SCLK_MMC2, "sclk_mmc2", "dout_sclk_mmc2",
ENABLE_SCLK_TOP1_FSYS0, 24, CLK_SET_RATE_PARENT, 0),
+ GATE(0, "sclk_usbdrd300", "dout_sclk_usbdrd300",
+ ENABLE_SCLK_TOP1_FSYS0, 28, 0, 0),
GATE(CLK_SCLK_MMC1, "sclk_mmc1", "dout_sclk_mmc1",
ENABLE_SCLK_TOP1_FSYS1, 24, CLK_SET_RATE_PARENT, 0),
@@ -514,6 +605,7 @@
/* Register Offset definitions for CMU_PERIC1 (0x14C80000) */
#define MUX_SEL_PERIC10 0x0200
#define MUX_SEL_PERIC11 0x0204
+#define MUX_SEL_PERIC12 0x0208
#define ENABLE_PCLK_PERIC1 0x0900
#define ENABLE_SCLK_PERIC10 0x0A00
@@ -525,10 +617,16 @@
PNAME(mout_sclk_uart1_p) = { "fin_pll", "sclk_uart1" };
PNAME(mout_sclk_uart2_p) = { "fin_pll", "sclk_uart2" };
PNAME(mout_sclk_uart3_p) = { "fin_pll", "sclk_uart3" };
+PNAME(mout_sclk_spi0_p) = { "fin_pll", "sclk_spi0" };
+PNAME(mout_sclk_spi1_p) = { "fin_pll", "sclk_spi1" };
+PNAME(mout_sclk_spi2_p) = { "fin_pll", "sclk_spi2" };
+PNAME(mout_sclk_spi3_p) = { "fin_pll", "sclk_spi3" };
+PNAME(mout_sclk_spi4_p) = { "fin_pll", "sclk_spi4" };
static unsigned long peric1_clk_regs[] __initdata = {
MUX_SEL_PERIC10,
MUX_SEL_PERIC11,
+ MUX_SEL_PERIC12,
ENABLE_PCLK_PERIC1,
ENABLE_SCLK_PERIC10,
};
@@ -537,6 +635,16 @@
MUX(0, "mout_aclk_peric1_66_user", mout_aclk_peric1_66_p,
MUX_SEL_PERIC10, 0, 1),
+ MUX_F(0, "mout_sclk_spi0_user", mout_sclk_spi0_p,
+ MUX_SEL_PERIC11, 0, 1, CLK_SET_RATE_PARENT, 0),
+ MUX_F(0, "mout_sclk_spi1_user", mout_sclk_spi1_p,
+ MUX_SEL_PERIC11, 4, 1, CLK_SET_RATE_PARENT, 0),
+ MUX_F(0, "mout_sclk_spi2_user", mout_sclk_spi2_p,
+ MUX_SEL_PERIC11, 8, 1, CLK_SET_RATE_PARENT, 0),
+ MUX_F(0, "mout_sclk_spi3_user", mout_sclk_spi3_p,
+ MUX_SEL_PERIC11, 12, 1, CLK_SET_RATE_PARENT, 0),
+ MUX_F(0, "mout_sclk_spi4_user", mout_sclk_spi4_p,
+ MUX_SEL_PERIC11, 16, 1, CLK_SET_RATE_PARENT, 0),
MUX(0, "mout_sclk_uart1_user", mout_sclk_uart1_p,
MUX_SEL_PERIC11, 20, 1),
MUX(0, "mout_sclk_uart2_user", mout_sclk_uart2_p,
@@ -562,6 +670,22 @@
ENABLE_PCLK_PERIC1, 10, 0, 0),
GATE(PCLK_UART3, "pclk_uart3", "mout_aclk_peric1_66_user",
ENABLE_PCLK_PERIC1, 11, 0, 0),
+ GATE(PCLK_SPI0, "pclk_spi0", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 12, 0, 0),
+ GATE(PCLK_SPI1, "pclk_spi1", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 13, 0, 0),
+ GATE(PCLK_SPI2, "pclk_spi2", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 14, 0, 0),
+ GATE(PCLK_SPI3, "pclk_spi3", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 15, 0, 0),
+ GATE(PCLK_SPI4, "pclk_spi4", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 16, 0, 0),
+ GATE(PCLK_I2S1, "pclk_i2s1", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 17, CLK_SET_RATE_PARENT, 0),
+ GATE(PCLK_PCM1, "pclk_pcm1", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 18, 0, 0),
+ GATE(PCLK_SPDIF, "pclk_spdif", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 19, 0, 0),
GATE(SCLK_UART1, "sclk_uart1_user", "mout_sclk_uart1_user",
ENABLE_SCLK_PERIC10, 9, 0, 0),
@@ -569,6 +693,22 @@
ENABLE_SCLK_PERIC10, 10, 0, 0),
GATE(SCLK_UART3, "sclk_uart3_user", "mout_sclk_uart3_user",
ENABLE_SCLK_PERIC10, 11, 0, 0),
+ GATE(SCLK_SPI0, "sclk_spi0_user", "mout_sclk_spi0_user",
+ ENABLE_SCLK_PERIC10, 12, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_SPI1, "sclk_spi1_user", "mout_sclk_spi1_user",
+ ENABLE_SCLK_PERIC10, 13, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_SPI2, "sclk_spi2_user", "mout_sclk_spi2_user",
+ ENABLE_SCLK_PERIC10, 14, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_SPI3, "sclk_spi3_user", "mout_sclk_spi3_user",
+ ENABLE_SCLK_PERIC10, 15, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_SPI4, "sclk_spi4_user", "mout_sclk_spi4_user",
+ ENABLE_SCLK_PERIC10, 16, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_I2S1, "sclk_i2s1_user", "sclk_i2s1",
+ ENABLE_SCLK_PERIC10, 17, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_PCM1, "sclk_pcm1_user", "sclk_pcm1",
+ ENABLE_SCLK_PERIC10, 18, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_SPDIF, "sclk_spdif_user", "sclk_spdif",
+ ENABLE_SCLK_PERIC10, 19, CLK_SET_RATE_PARENT, 0),
};
static struct samsung_cmu_info peric1_cmu_info __initdata = {
@@ -647,7 +787,12 @@
/* Register Offset definitions for CMU_FSYS0 (0x10E90000) */
#define MUX_SEL_FSYS00 0x0200
#define MUX_SEL_FSYS01 0x0204
+#define MUX_SEL_FSYS02 0x0208
+#define ENABLE_ACLK_FSYS00 0x0800
#define ENABLE_ACLK_FSYS01 0x0804
+#define ENABLE_SCLK_FSYS01 0x0A04
+#define ENABLE_SCLK_FSYS02 0x0A08
+#define ENABLE_SCLK_FSYS04 0x0A10
/*
* List of parent clocks for Muxes in CMU_FSYS0
@@ -655,10 +800,29 @@
PNAME(mout_aclk_fsys0_200_p) = { "fin_pll", "dout_aclk_fsys0_200" };
PNAME(mout_sclk_mmc2_p) = { "fin_pll", "sclk_mmc2" };
+PNAME(mout_sclk_usbdrd300_p) = { "fin_pll", "sclk_usbdrd300" };
+PNAME(mout_phyclk_usbdrd300_udrd30_phyclk_p) = { "fin_pll",
+ "phyclk_usbdrd300_udrd30_phyclock" };
+PNAME(mout_phyclk_usbdrd300_udrd30_pipe_pclk_p) = { "fin_pll",
+ "phyclk_usbdrd300_udrd30_pipe_pclk" };
+
+/* fixed rate clocks used in the FSYS0 block */
+struct samsung_fixed_rate_clock fixed_rate_clks_fsys0[] __initdata = {
+ FRATE(0, "phyclk_usbdrd300_udrd30_phyclock", NULL,
+ CLK_IS_ROOT, 60000000),
+ FRATE(0, "phyclk_usbdrd300_udrd30_pipe_pclk", NULL,
+ CLK_IS_ROOT, 125000000),
+};
+
static unsigned long fsys0_clk_regs[] __initdata = {
MUX_SEL_FSYS00,
MUX_SEL_FSYS01,
+ MUX_SEL_FSYS02,
+ ENABLE_ACLK_FSYS00,
ENABLE_ACLK_FSYS01,
+ ENABLE_SCLK_FSYS01,
+ ENABLE_SCLK_FSYS02,
+ ENABLE_SCLK_FSYS04,
};
static struct samsung_mux_clock fsys0_mux_clks[] __initdata = {
@@ -666,11 +830,49 @@
MUX_SEL_FSYS00, 24, 1),
MUX(0, "mout_sclk_mmc2_user", mout_sclk_mmc2_p, MUX_SEL_FSYS01, 24, 1),
+ MUX(0, "mout_sclk_usbdrd300_user", mout_sclk_usbdrd300_p,
+ MUX_SEL_FSYS01, 28, 1),
+
+ MUX(0, "mout_phyclk_usbdrd300_udrd30_pipe_pclk_user",
+ mout_phyclk_usbdrd300_udrd30_pipe_pclk_p,
+ MUX_SEL_FSYS02, 24, 1),
+ MUX(0, "mout_phyclk_usbdrd300_udrd30_phyclk_user",
+ mout_phyclk_usbdrd300_udrd30_phyclk_p,
+ MUX_SEL_FSYS02, 28, 1),
};
static struct samsung_gate_clock fsys0_gate_clks[] __initdata = {
+ GATE(ACLK_AXIUS_USBDRD30X_FSYS0X, "aclk_axius_usbdrd30x_fsys0x",
+ "mout_aclk_fsys0_200_user",
+ ENABLE_ACLK_FSYS00, 19, 0, 0),
+ GATE(ACLK_PDMA1, "aclk_pdma1", "mout_aclk_fsys0_200_user",
+ ENABLE_ACLK_FSYS00, 3, 0, 0),
+ GATE(ACLK_PDMA0, "aclk_pdma0", "mout_aclk_fsys0_200_user",
+ ENABLE_ACLK_FSYS00, 4, 0, 0),
+
+ GATE(ACLK_USBDRD300, "aclk_usbdrd300", "mout_aclk_fsys0_200_user",
+ ENABLE_ACLK_FSYS01, 29, 0, 0),
GATE(ACLK_MMC2, "aclk_mmc2", "mout_aclk_fsys0_200_user",
ENABLE_ACLK_FSYS01, 31, 0, 0),
+
+ GATE(SCLK_USBDRD300_SUSPENDCLK, "sclk_usbdrd300_suspendclk",
+ "mout_sclk_usbdrd300_user",
+ ENABLE_SCLK_FSYS01, 4, 0, 0),
+ GATE(SCLK_USBDRD300_REFCLK, "sclk_usbdrd300_refclk", "fin_pll",
+ ENABLE_SCLK_FSYS01, 8, 0, 0),
+
+ GATE(PHYCLK_USBDRD300_UDRD30_PIPE_PCLK_USER,
+ "phyclk_usbdrd300_udrd30_pipe_pclk_user",
+ "mout_phyclk_usbdrd300_udrd30_pipe_pclk_user",
+ ENABLE_SCLK_FSYS02, 24, 0, 0),
+ GATE(PHYCLK_USBDRD300_UDRD30_PHYCLK_USER,
+ "phyclk_usbdrd300_udrd30_phyclk_user",
+ "mout_phyclk_usbdrd300_udrd30_phyclk_user",
+ ENABLE_SCLK_FSYS02, 28, 0, 0),
+
+ GATE(OSCCLK_PHY_CLKOUT_USB30_PHY, "oscclk_phy_clkout_usb30_phy",
+ "fin_pll",
+ ENABLE_SCLK_FSYS04, 28, 0, 0),
};
static struct samsung_cmu_info fsys0_cmu_info __initdata = {
@@ -741,3 +943,205 @@
CLK_OF_DECLARE(exynos7_clk_fsys1, "samsung,exynos7-clock-fsys1",
exynos7_clk_fsys1_init);
+
+#define MUX_SEL_MSCL 0x0200
+#define DIV_MSCL 0x0600
+#define ENABLE_ACLK_MSCL 0x0800
+#define ENABLE_PCLK_MSCL 0x0900
+
+/* List of parent clocks for Muxes in CMU_MSCL */
+PNAME(mout_aclk_mscl_532_user_p) = { "fin_pll", "aclk_mscl_532" };
+
+static unsigned long mscl_clk_regs[] __initdata = {
+ MUX_SEL_MSCL,
+ DIV_MSCL,
+ ENABLE_ACLK_MSCL,
+ ENABLE_PCLK_MSCL,
+};
+
+static struct samsung_mux_clock mscl_mux_clks[] __initdata = {
+ MUX(USERMUX_ACLK_MSCL_532, "usermux_aclk_mscl_532",
+ mout_aclk_mscl_532_user_p, MUX_SEL_MSCL, 0, 1),
+};
+static struct samsung_div_clock mscl_div_clks[] __initdata = {
+ DIV(DOUT_PCLK_MSCL, "dout_pclk_mscl", "usermux_aclk_mscl_532",
+ DIV_MSCL, 0, 3),
+};
+static struct samsung_gate_clock mscl_gate_clks[] __initdata = {
+
+ GATE(ACLK_MSCL_0, "aclk_mscl_0", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 31, 0, 0),
+ GATE(ACLK_MSCL_1, "aclk_mscl_1", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 30, 0, 0),
+ GATE(ACLK_JPEG, "aclk_jpeg", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 29, 0, 0),
+ GATE(ACLK_G2D, "aclk_g2d", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 28, 0, 0),
+ GATE(ACLK_LH_ASYNC_SI_MSCL_0, "aclk_lh_async_si_mscl_0",
+ "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 27, 0, 0),
+ GATE(ACLK_LH_ASYNC_SI_MSCL_1, "aclk_lh_async_si_mscl_1",
+ "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 26, 0, 0),
+ GATE(ACLK_XIU_MSCLX_0, "aclk_xiu_msclx_0", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 25, 0, 0),
+ GATE(ACLK_XIU_MSCLX_1, "aclk_xiu_msclx_1", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 24, 0, 0),
+ GATE(ACLK_AXI2ACEL_BRIDGE, "aclk_axi2acel_bridge",
+ "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 23, 0, 0),
+ GATE(ACLK_QE_MSCL_0, "aclk_qe_mscl_0", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 22, 0, 0),
+ GATE(ACLK_QE_MSCL_1, "aclk_qe_mscl_1", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 21, 0, 0),
+ GATE(ACLK_QE_JPEG, "aclk_qe_jpeg", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 20, 0, 0),
+ GATE(ACLK_QE_G2D, "aclk_qe_g2d", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 19, 0, 0),
+ GATE(ACLK_PPMU_MSCL_0, "aclk_ppmu_mscl_0", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 18, 0, 0),
+ GATE(ACLK_PPMU_MSCL_1, "aclk_ppmu_mscl_1", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 17, 0, 0),
+ GATE(ACLK_MSCLNP_133, "aclk_msclnp_133", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 16, 0, 0),
+ GATE(ACLK_AHB2APB_MSCL0P, "aclk_ahb2apb_mscl0p",
+ "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 15, 0, 0),
+ GATE(ACLK_AHB2APB_MSCL1P, "aclk_ahb2apb_mscl1p",
+ "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 14, 0, 0),
+
+ GATE(PCLK_MSCL_0, "pclk_mscl_0", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 31, 0, 0),
+ GATE(PCLK_MSCL_1, "pclk_mscl_1", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 30, 0, 0),
+ GATE(PCLK_JPEG, "pclk_jpeg", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 29, 0, 0),
+ GATE(PCLK_G2D, "pclk_g2d", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 28, 0, 0),
+ GATE(PCLK_QE_MSCL_0, "pclk_qe_mscl_0", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 27, 0, 0),
+ GATE(PCLK_QE_MSCL_1, "pclk_qe_mscl_1", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 26, 0, 0),
+ GATE(PCLK_QE_JPEG, "pclk_qe_jpeg", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 25, 0, 0),
+ GATE(PCLK_QE_G2D, "pclk_qe_g2d", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 24, 0, 0),
+ GATE(PCLK_PPMU_MSCL_0, "pclk_ppmu_mscl_0", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 23, 0, 0),
+ GATE(PCLK_PPMU_MSCL_1, "pclk_ppmu_mscl_1", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 22, 0, 0),
+ GATE(PCLK_AXI2ACEL_BRIDGE, "pclk_axi2acel_bridge", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 21, 0, 0),
+ GATE(PCLK_PMU_MSCL, "pclk_pmu_mscl", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 20, 0, 0),
+};
+
+static struct samsung_cmu_info mscl_cmu_info __initdata = {
+ .mux_clks = mscl_mux_clks,
+ .nr_mux_clks = ARRAY_SIZE(mscl_mux_clks),
+ .div_clks = mscl_div_clks,
+ .nr_div_clks = ARRAY_SIZE(mscl_div_clks),
+ .gate_clks = mscl_gate_clks,
+ .nr_gate_clks = ARRAY_SIZE(mscl_gate_clks),
+ .nr_clk_ids = MSCL_NR_CLK,
+ .clk_regs = mscl_clk_regs,
+ .nr_clk_regs = ARRAY_SIZE(mscl_clk_regs),
+};
+
+static void __init exynos7_clk_mscl_init(struct device_node *np)
+{
+ samsung_cmu_register_one(np, &mscl_cmu_info);
+}
+
+CLK_OF_DECLARE(exynos7_clk_mscl, "samsung,exynos7-clock-mscl",
+ exynos7_clk_mscl_init);
+
+/* Register Offset definitions for CMU_AUD (0x114C0000) */
+#define MUX_SEL_AUD 0x0200
+#define DIV_AUD0 0x0600
+#define DIV_AUD1 0x0604
+#define ENABLE_ACLK_AUD 0x0800
+#define ENABLE_PCLK_AUD 0x0900
+#define ENABLE_SCLK_AUD 0x0A00
+
+/*
+ * List of parent clocks for Muxes in CMU_AUD
+ */
+PNAME(mout_aud_pll_user_p) = { "fin_pll", "fout_aud_pll" };
+PNAME(mout_aud_group_p) = { "dout_aud_cdclk", "ioclk_audiocdclk0" };
+
+static unsigned long aud_clk_regs[] __initdata = {
+ MUX_SEL_AUD,
+ DIV_AUD0,
+ DIV_AUD1,
+ ENABLE_ACLK_AUD,
+ ENABLE_PCLK_AUD,
+ ENABLE_SCLK_AUD,
+};
+
+static struct samsung_mux_clock aud_mux_clks[] __initdata = {
+ MUX(0, "mout_sclk_i2s", mout_aud_group_p, MUX_SEL_AUD, 12, 1),
+ MUX(0, "mout_sclk_pcm", mout_aud_group_p, MUX_SEL_AUD, 16, 1),
+ MUX(0, "mout_aud_pll_user", mout_aud_pll_user_p, MUX_SEL_AUD, 20, 1),
+};
+
+static struct samsung_div_clock aud_div_clks[] __initdata = {
+ DIV(0, "dout_aud_ca5", "mout_aud_pll_user", DIV_AUD0, 0, 4),
+ DIV(0, "dout_aclk_aud", "dout_aud_ca5", DIV_AUD0, 4, 4),
+ DIV(0, "dout_aud_pclk_dbg", "dout_aud_ca5", DIV_AUD0, 8, 4),
+
+ DIV(0, "dout_sclk_i2s", "mout_sclk_i2s", DIV_AUD1, 0, 4),
+ DIV(0, "dout_sclk_pcm", "mout_sclk_pcm", DIV_AUD1, 4, 8),
+ DIV(0, "dout_sclk_uart", "dout_aud_cdclk", DIV_AUD1, 12, 4),
+ DIV(0, "dout_sclk_slimbus", "dout_aud_cdclk", DIV_AUD1, 16, 5),
+ DIV(0, "dout_aud_cdclk", "mout_aud_pll_user", DIV_AUD1, 24, 4),
+};
+
+static struct samsung_gate_clock aud_gate_clks[] __initdata = {
+ GATE(SCLK_PCM, "sclk_pcm", "dout_sclk_pcm",
+ ENABLE_SCLK_AUD, 27, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_I2S, "sclk_i2s", "dout_sclk_i2s",
+ ENABLE_SCLK_AUD, 28, CLK_SET_RATE_PARENT, 0),
+ GATE(0, "sclk_uart", "dout_sclk_uart", ENABLE_SCLK_AUD, 29, 0, 0),
+ GATE(0, "sclk_slimbus", "dout_sclk_slimbus",
+ ENABLE_SCLK_AUD, 30, 0, 0),
+
+ GATE(0, "pclk_dbg_aud", "dout_aud_pclk_dbg", ENABLE_PCLK_AUD, 19, 0, 0),
+ GATE(0, "pclk_gpio_aud", "dout_aclk_aud", ENABLE_PCLK_AUD, 20, 0, 0),
+ GATE(0, "pclk_wdt1", "dout_aclk_aud", ENABLE_PCLK_AUD, 22, 0, 0),
+ GATE(0, "pclk_wdt0", "dout_aclk_aud", ENABLE_PCLK_AUD, 23, 0, 0),
+ GATE(0, "pclk_slimbus", "dout_aclk_aud", ENABLE_PCLK_AUD, 24, 0, 0),
+ GATE(0, "pclk_uart", "dout_aclk_aud", ENABLE_PCLK_AUD, 25, 0, 0),
+ GATE(PCLK_PCM, "pclk_pcm", "dout_aclk_aud",
+ ENABLE_PCLK_AUD, 26, CLK_SET_RATE_PARENT, 0),
+ GATE(PCLK_I2S, "pclk_i2s", "dout_aclk_aud",
+ ENABLE_PCLK_AUD, 27, CLK_SET_RATE_PARENT, 0),
+ GATE(0, "pclk_timer", "dout_aclk_aud", ENABLE_PCLK_AUD, 28, 0, 0),
+ GATE(0, "pclk_smmu_aud", "dout_aclk_aud", ENABLE_PCLK_AUD, 31, 0, 0),
+
+ GATE(0, "aclk_smmu_aud", "dout_aclk_aud", ENABLE_ACLK_AUD, 27, 0, 0),
+ GATE(0, "aclk_acel_lh_async_si_top", "dout_aclk_aud",
+ ENABLE_ACLK_AUD, 28, 0, 0),
+ GATE(ACLK_ADMA, "aclk_dmac", "dout_aclk_aud", ENABLE_ACLK_AUD, 31, 0, 0),
+};
+
+static struct samsung_cmu_info aud_cmu_info __initdata = {
+ .mux_clks = aud_mux_clks,
+ .nr_mux_clks = ARRAY_SIZE(aud_mux_clks),
+ .div_clks = aud_div_clks,
+ .nr_div_clks = ARRAY_SIZE(aud_div_clks),
+ .gate_clks = aud_gate_clks,
+ .nr_gate_clks = ARRAY_SIZE(aud_gate_clks),
+ .nr_clk_ids = AUD_NR_CLK,
+ .clk_regs = aud_clk_regs,
+ .nr_clk_regs = ARRAY_SIZE(aud_clk_regs),
+};
+
+static void __init exynos7_clk_aud_init(struct device_node *np)
+{
+ samsung_cmu_register_one(np, &aud_cmu_info);
+}
+
+CLK_OF_DECLARE(exynos7_clk_aud, "samsung,exynos7-clock-aud",
+ exynos7_clk_aud_init);
diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
index 4bda540..9e1f88c 100644
--- a/drivers/clk/samsung/clk.c
+++ b/drivers/clk/samsung/clk.c
@@ -374,19 +374,24 @@
* Common function which registers plls, muxes, dividers and gates
* for each CMU. It also add CMU register list to register cache.
*/
-void __init samsung_cmu_register_one(struct device_node *np,
+struct samsung_clk_provider * __init samsung_cmu_register_one(
+ struct device_node *np,
struct samsung_cmu_info *cmu)
{
void __iomem *reg_base;
struct samsung_clk_provider *ctx;
reg_base = of_iomap(np, 0);
- if (!reg_base)
+ if (!reg_base) {
panic("%s: failed to map registers\n", __func__);
+ return NULL;
+ }
ctx = samsung_clk_init(np, reg_base, cmu->nr_clk_ids);
- if (!ctx)
+ if (!ctx) {
panic("%s: unable to alllocate ctx\n", __func__);
+ return ctx;
+ }
if (cmu->pll_clks)
samsung_clk_register_pll(ctx, cmu->pll_clks, cmu->nr_pll_clks,
@@ -410,4 +415,6 @@
cmu->nr_clk_regs);
samsung_clk_of_add_provider(np, ctx);
+
+ return ctx;
}
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index 8acabe1..e4c7538 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -392,7 +392,8 @@
struct samsung_pll_clock *pll_list,
unsigned int nr_clk, void __iomem *base);
-extern void __init samsung_cmu_register_one(struct device_node *,
+extern struct samsung_clk_provider __init *samsung_cmu_register_one(
+ struct device_node *,
struct samsung_cmu_info *);
extern unsigned long _get_rate(const char *clk_name);
diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile
index f83980f..0689d7f 100644
--- a/drivers/clk/shmobile/Makefile
+++ b/drivers/clk/shmobile/Makefile
@@ -1,9 +1,11 @@
obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o
obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o
+obj-$(CONFIG_ARCH_R8A73A4) += clk-r8a73a4.o
obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o
obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o
obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o
+obj-$(CONFIG_ARCH_R8A7793) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7794) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_SH73A0) += clk-sh73a0.o
obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o
diff --git a/drivers/clk/shmobile/clk-div6.c b/drivers/clk/shmobile/clk-div6.c
index 639241e..036a692 100644
--- a/drivers/clk/shmobile/clk-div6.c
+++ b/drivers/clk/shmobile/clk-div6.c
@@ -54,12 +54,19 @@
static void cpg_div6_clock_disable(struct clk_hw *hw)
{
struct div6_clock *clock = to_div6_clock(hw);
+ u32 val;
- /* DIV6 clocks require the divisor field to be non-zero when stopping
- * the clock.
+ val = clk_readl(clock->reg);
+ val |= CPG_DIV6_CKSTP;
+ /*
+ * DIV6 clocks require the divisor field to be non-zero when stopping
+ * the clock. However, some clocks (e.g. ZB on sh73a0) fail to be
+ * re-enabled later if the divisor field is changed when stopping the
+ * clock
*/
- clk_writel(clk_readl(clock->reg) | CPG_DIV6_CKSTP | CPG_DIV6_DIV_MASK,
- clock->reg);
+ if (!(val & CPG_DIV6_DIV_MASK))
+ val |= CPG_DIV6_DIV_MASK;
+ clk_writel(val, clock->reg);
}
static int cpg_div6_clock_is_enabled(struct clk_hw *hw)
@@ -83,6 +90,9 @@
{
unsigned int div;
+ if (!rate)
+ rate = 1;
+
div = DIV_ROUND_CLOSEST(parent_rate, rate);
return clamp_t(unsigned int, div, 1, 64);
}
diff --git a/drivers/clk/shmobile/clk-r8a73a4.c b/drivers/clk/shmobile/clk-r8a73a4.c
new file mode 100644
index 0000000..29b9a0b0
--- /dev/null
+++ b/drivers/clk/shmobile/clk-r8a73a4.c
@@ -0,0 +1,241 @@
+/*
+ * r8a73a4 Core CPG Clocks
+ *
+ * Copyright (C) 2014 Ulrich Hecht
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/shmobile.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/spinlock.h>
+
+struct r8a73a4_cpg {
+ struct clk_onecell_data data;
+ spinlock_t lock;
+ void __iomem *reg;
+};
+
+#define CPG_CKSCR 0xc0
+#define CPG_FRQCRA 0x00
+#define CPG_FRQCRB 0x04
+#define CPG_FRQCRC 0xe0
+#define CPG_PLL0CR 0xd8
+#define CPG_PLL1CR 0x28
+#define CPG_PLL2CR 0x2c
+#define CPG_PLL2HCR 0xe4
+#define CPG_PLL2SCR 0xf4
+
+#define CLK_ENABLE_ON_INIT BIT(0)
+
+struct div4_clk {
+ const char *name;
+ unsigned int reg;
+ unsigned int shift;
+};
+
+static struct div4_clk div4_clks[] = {
+ { "i", CPG_FRQCRA, 20 },
+ { "m3", CPG_FRQCRA, 12 },
+ { "b", CPG_FRQCRA, 8 },
+ { "m1", CPG_FRQCRA, 4 },
+ { "m2", CPG_FRQCRA, 0 },
+ { "zx", CPG_FRQCRB, 12 },
+ { "zs", CPG_FRQCRB, 8 },
+ { "hp", CPG_FRQCRB, 4 },
+ { NULL, 0, 0 },
+};
+
+static const struct clk_div_table div4_div_table[] = {
+ { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 }, { 5, 12 },
+ { 6, 16 }, { 7, 18 }, { 8, 24 }, { 10, 36 }, { 11, 48 },
+ { 12, 10 }, { 0, 0 }
+};
+
+static struct clk * __init
+r8a73a4_cpg_register_clock(struct device_node *np, struct r8a73a4_cpg *cpg,
+ const char *name)
+{
+ const struct clk_div_table *table = NULL;
+ const char *parent_name;
+ unsigned int shift, reg;
+ unsigned int mult = 1;
+ unsigned int div = 1;
+
+
+ if (!strcmp(name, "main")) {
+ u32 ckscr = clk_readl(cpg->reg + CPG_CKSCR);
+
+ switch ((ckscr >> 28) & 3) {
+ case 0: /* extal1 */
+ parent_name = of_clk_get_parent_name(np, 0);
+ break;
+ case 1: /* extal1 / 2 */
+ parent_name = of_clk_get_parent_name(np, 0);
+ div = 2;
+ break;
+ case 2: /* extal2 */
+ parent_name = of_clk_get_parent_name(np, 1);
+ break;
+ case 3: /* extal2 / 2 */
+ parent_name = of_clk_get_parent_name(np, 1);
+ div = 2;
+ break;
+ }
+ } else if (!strcmp(name, "pll0")) {
+ /* PLL0/1 are configurable multiplier clocks. Register them as
+ * fixed factor clocks for now as there's no generic multiplier
+ * clock implementation and we currently have no need to change
+ * the multiplier value.
+ */
+ u32 value = clk_readl(cpg->reg + CPG_PLL0CR);
+
+ parent_name = "main";
+ mult = ((value >> 24) & 0x7f) + 1;
+ if (value & BIT(20))
+ div = 2;
+ } else if (!strcmp(name, "pll1")) {
+ u32 value = clk_readl(cpg->reg + CPG_PLL1CR);
+
+ parent_name = "main";
+ /* XXX: enable bit? */
+ mult = ((value >> 24) & 0x7f) + 1;
+ if (value & BIT(7))
+ div = 2;
+ } else if (!strncmp(name, "pll2", 4)) {
+ u32 value, cr;
+
+ switch (name[4]) {
+ case 0:
+ cr = CPG_PLL2CR;
+ break;
+ case 's':
+ cr = CPG_PLL2SCR;
+ break;
+ case 'h':
+ cr = CPG_PLL2HCR;
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+ value = clk_readl(cpg->reg + cr);
+ switch ((value >> 5) & 7) {
+ case 0:
+ parent_name = "main";
+ div = 2;
+ break;
+ case 1:
+ parent_name = "extal2";
+ div = 2;
+ break;
+ case 3:
+ parent_name = "extal2";
+ div = 4;
+ break;
+ case 4:
+ parent_name = "main";
+ break;
+ case 5:
+ parent_name = "extal2";
+ break;
+ default:
+ pr_warn("%s: unexpected parent of %s\n", __func__,
+ name);
+ return ERR_PTR(-EINVAL);
+ }
+ /* XXX: enable bit? */
+ mult = ((value >> 24) & 0x7f) + 1;
+ } else if (!strcmp(name, "z") || !strcmp(name, "z2")) {
+ u32 shift = 8;
+
+ parent_name = "pll0";
+ if (name[1] == '2') {
+ div = 2;
+ shift = 0;
+ }
+ div *= 32;
+ mult = 0x20 - ((clk_readl(cpg->reg + CPG_FRQCRC) >> shift)
+ & 0x1f);
+ } else {
+ struct div4_clk *c;
+
+ for (c = div4_clks; c->name; c++) {
+ if (!strcmp(name, c->name))
+ break;
+ }
+ if (!c->name)
+ return ERR_PTR(-EINVAL);
+
+ parent_name = "pll1";
+ table = div4_div_table;
+ reg = c->reg;
+ shift = c->shift;
+ }
+
+ if (!table) {
+ return clk_register_fixed_factor(NULL, name, parent_name, 0,
+ mult, div);
+ } else {
+ return clk_register_divider_table(NULL, name, parent_name, 0,
+ cpg->reg + reg, shift, 4, 0,
+ table, &cpg->lock);
+ }
+}
+
+static void __init r8a73a4_cpg_clocks_init(struct device_node *np)
+{
+ struct r8a73a4_cpg *cpg;
+ struct clk **clks;
+ unsigned int i;
+ int num_clks;
+
+ num_clks = of_property_count_strings(np, "clock-output-names");
+ if (num_clks < 0) {
+ pr_err("%s: failed to count clocks\n", __func__);
+ return;
+ }
+
+ cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
+ clks = kcalloc(num_clks, sizeof(*clks), GFP_KERNEL);
+ if (cpg == NULL || clks == NULL) {
+ /* We're leaking memory on purpose, there's no point in cleaning
+ * up as the system won't boot anyway.
+ */
+ return;
+ }
+
+ spin_lock_init(&cpg->lock);
+
+ cpg->data.clks = clks;
+ cpg->data.clk_num = num_clks;
+
+ cpg->reg = of_iomap(np, 0);
+ if (WARN_ON(cpg->reg == NULL))
+ return;
+
+ for (i = 0; i < num_clks; ++i) {
+ const char *name;
+ struct clk *clk;
+
+ of_property_read_string_index(np, "clock-output-names", i,
+ &name);
+
+ clk = r8a73a4_cpg_register_clock(np, cpg, name);
+ if (IS_ERR(clk))
+ pr_err("%s: failed to register %s %s clock (%ld)\n",
+ __func__, np->name, name, PTR_ERR(clk));
+ else
+ cpg->data.clks[i] = clk;
+ }
+
+ of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
+}
+CLK_OF_DECLARE(r8a73a4_cpg_clks, "renesas,r8a73a4-cpg-clocks",
+ r8a73a4_cpg_clocks_init);
diff --git a/drivers/clk/shmobile/clk-rcar-gen2.c b/drivers/clk/shmobile/clk-rcar-gen2.c
index e996425..acfb6d7 100644
--- a/drivers/clk/shmobile/clk-rcar-gen2.c
+++ b/drivers/clk/shmobile/clk-rcar-gen2.c
@@ -33,6 +33,8 @@
#define CPG_FRQCRC 0x000000e0
#define CPG_FRQCRC_ZFC_MASK (0x1f << 8)
#define CPG_FRQCRC_ZFC_SHIFT 8
+#define CPG_ADSPCKCR 0x0000025c
+#define CPG_RCANCKCR 0x00000270
/* -----------------------------------------------------------------------------
* Z Clock
@@ -161,6 +163,88 @@
return clk;
}
+static struct clk * __init cpg_rcan_clk_register(struct rcar_gen2_cpg *cpg,
+ struct device_node *np)
+{
+ const char *parent_name = of_clk_get_parent_name(np, 1);
+ struct clk_fixed_factor *fixed;
+ struct clk_gate *gate;
+ struct clk *clk;
+
+ fixed = kzalloc(sizeof(*fixed), GFP_KERNEL);
+ if (!fixed)
+ return ERR_PTR(-ENOMEM);
+
+ fixed->mult = 1;
+ fixed->div = 6;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate) {
+ kfree(fixed);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ gate->reg = cpg->reg + CPG_RCANCKCR;
+ gate->bit_idx = 8;
+ gate->flags = CLK_GATE_SET_TO_DISABLE;
+ gate->lock = &cpg->lock;
+
+ clk = clk_register_composite(NULL, "rcan", &parent_name, 1, NULL, NULL,
+ &fixed->hw, &clk_fixed_factor_ops,
+ &gate->hw, &clk_gate_ops, 0);
+ if (IS_ERR(clk)) {
+ kfree(gate);
+ kfree(fixed);
+ }
+
+ return clk;
+}
+
+/* ADSP divisors */
+static const struct clk_div_table cpg_adsp_div_table[] = {
+ { 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 },
+ { 5, 12 }, { 6, 16 }, { 7, 18 }, { 8, 24 },
+ { 10, 36 }, { 11, 48 }, { 0, 0 },
+};
+
+static struct clk * __init cpg_adsp_clk_register(struct rcar_gen2_cpg *cpg)
+{
+ const char *parent_name = "pll1";
+ struct clk_divider *div;
+ struct clk_gate *gate;
+ struct clk *clk;
+
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+ if (!div)
+ return ERR_PTR(-ENOMEM);
+
+ div->reg = cpg->reg + CPG_ADSPCKCR;
+ div->width = 4;
+ div->table = cpg_adsp_div_table;
+ div->lock = &cpg->lock;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate) {
+ kfree(div);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ gate->reg = cpg->reg + CPG_ADSPCKCR;
+ gate->bit_idx = 8;
+ gate->flags = CLK_GATE_SET_TO_DISABLE;
+ gate->lock = &cpg->lock;
+
+ clk = clk_register_composite(NULL, "adsp", &parent_name, 1, NULL, NULL,
+ &div->hw, &clk_divider_ops,
+ &gate->hw, &clk_gate_ops, 0);
+ if (IS_ERR(clk)) {
+ kfree(gate);
+ kfree(div);
+ }
+
+ return clk;
+}
+
/* -----------------------------------------------------------------------------
* CPG Clock Data
*/
@@ -263,6 +347,10 @@
shift = 0;
} else if (!strcmp(name, "z")) {
return cpg_z_clk_register(cpg);
+ } else if (!strcmp(name, "rcan")) {
+ return cpg_rcan_clk_register(cpg, np);
+ } else if (!strcmp(name, "adsp")) {
+ return cpg_adsp_clk_register(cpg);
} else {
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/clk/st/clk-flexgen.c b/drivers/clk/st/clk-flexgen.c
index 2282cef..bf12a25 100644
--- a/drivers/clk/st/clk-flexgen.c
+++ b/drivers/clk/st/clk-flexgen.c
@@ -37,8 +37,8 @@
struct clk_hw *pgate_hw = &flexgen->pgate.hw;
struct clk_hw *fgate_hw = &flexgen->fgate.hw;
- pgate_hw->clk = hw->clk;
- fgate_hw->clk = hw->clk;
+ __clk_hw_set_clk(pgate_hw, hw);
+ __clk_hw_set_clk(fgate_hw, hw);
clk_gate_ops.enable(pgate_hw);
@@ -54,7 +54,7 @@
struct clk_hw *fgate_hw = &flexgen->fgate.hw;
/* disable only the final gate */
- fgate_hw->clk = hw->clk;
+ __clk_hw_set_clk(fgate_hw, hw);
clk_gate_ops.disable(fgate_hw);
@@ -66,7 +66,7 @@
struct flexgen *flexgen = to_flexgen(hw);
struct clk_hw *fgate_hw = &flexgen->fgate.hw;
- fgate_hw->clk = hw->clk;
+ __clk_hw_set_clk(fgate_hw, hw);
if (!clk_gate_ops.is_enabled(fgate_hw))
return 0;
@@ -79,7 +79,7 @@
struct flexgen *flexgen = to_flexgen(hw);
struct clk_hw *mux_hw = &flexgen->mux.hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
return clk_mux_ops.get_parent(mux_hw);
}
@@ -89,7 +89,7 @@
struct flexgen *flexgen = to_flexgen(hw);
struct clk_hw *mux_hw = &flexgen->mux.hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
return clk_mux_ops.set_parent(mux_hw, index);
}
@@ -124,8 +124,8 @@
struct clk_hw *fdiv_hw = &flexgen->fdiv.hw;
unsigned long mid_rate;
- pdiv_hw->clk = hw->clk;
- fdiv_hw->clk = hw->clk;
+ __clk_hw_set_clk(pdiv_hw, hw);
+ __clk_hw_set_clk(fdiv_hw, hw);
mid_rate = clk_divider_ops.recalc_rate(pdiv_hw, parent_rate);
@@ -138,16 +138,27 @@
struct flexgen *flexgen = to_flexgen(hw);
struct clk_hw *pdiv_hw = &flexgen->pdiv.hw;
struct clk_hw *fdiv_hw = &flexgen->fdiv.hw;
- unsigned long primary_div = 0;
+ unsigned long div = 0;
int ret = 0;
- pdiv_hw->clk = hw->clk;
- fdiv_hw->clk = hw->clk;
+ __clk_hw_set_clk(pdiv_hw, hw);
+ __clk_hw_set_clk(fdiv_hw, hw);
- primary_div = clk_best_div(parent_rate, rate);
+ div = clk_best_div(parent_rate, rate);
- clk_divider_ops.set_rate(fdiv_hw, parent_rate, parent_rate);
- ret = clk_divider_ops.set_rate(pdiv_hw, rate, rate * primary_div);
+ /*
+ * pdiv is mainly targeted for low freq results, while fdiv
+ * should be used for div <= 64. The other way round can
+ * lead to 'duty cycle' issues.
+ */
+
+ if (div <= 64) {
+ clk_divider_ops.set_rate(pdiv_hw, parent_rate, parent_rate);
+ ret = clk_divider_ops.set_rate(fdiv_hw, rate, rate * div);
+ } else {
+ clk_divider_ops.set_rate(fdiv_hw, parent_rate, parent_rate);
+ ret = clk_divider_ops.set_rate(pdiv_hw, rate, rate * div);
+ }
return ret;
}
diff --git a/drivers/clk/st/clkgen-mux.c b/drivers/clk/st/clkgen-mux.c
index 79dc40b..9a15ec3 100644
--- a/drivers/clk/st/clkgen-mux.c
+++ b/drivers/clk/st/clkgen-mux.c
@@ -94,7 +94,7 @@
unsigned long timeout;
int ret = 0;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
ret = clk_mux_ops.set_parent(mux_hw, genamux->muxsel);
if (ret)
@@ -116,7 +116,7 @@
struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
struct clk_hw *mux_hw = &genamux->mux.hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
clk_mux_ops.set_parent(mux_hw, CKGAX_CLKOPSRC_SWITCH_OFF);
}
@@ -126,7 +126,7 @@
struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
struct clk_hw *mux_hw = &genamux->mux.hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
return (s8)clk_mux_ops.get_parent(mux_hw) > 0;
}
@@ -136,7 +136,7 @@
struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
struct clk_hw *mux_hw = &genamux->mux.hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
genamux->muxsel = clk_mux_ops.get_parent(mux_hw);
if ((s8)genamux->muxsel < 0) {
@@ -174,7 +174,7 @@
struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw;
- div_hw->clk = hw->clk;
+ __clk_hw_set_clk(div_hw, hw);
return clk_divider_ops.recalc_rate(div_hw, parent_rate);
}
@@ -185,7 +185,7 @@
struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw;
- div_hw->clk = hw->clk;
+ __clk_hw_set_clk(div_hw, hw);
return clk_divider_ops.set_rate(div_hw, rate, parent_rate);
}
@@ -196,7 +196,7 @@
struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw;
- div_hw->clk = hw->clk;
+ __clk_hw_set_clk(div_hw, hw);
return clk_divider_ops.round_rate(div_hw, rate, prate);
}
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index a66953c..3a5292e 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -8,6 +8,7 @@
obj-y += clk-mod0.o
obj-y += clk-sun8i-mbus.o
obj-y += clk-sun9i-core.o
+obj-y += clk-sun9i-mmc.o
obj-$(CONFIG_MFD_SUN6I_PRCM) += \
clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c
index 62e08fb..8c20190 100644
--- a/drivers/clk/sunxi/clk-factors.c
+++ b/drivers/clk/sunxi/clk-factors.c
@@ -80,6 +80,8 @@
}
static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_p)
{
@@ -156,9 +158,10 @@
.set_rate = clk_factors_set_rate,
};
-struct clk * __init sunxi_factors_register(struct device_node *node,
- const struct factors_data *data,
- spinlock_t *lock)
+struct clk *sunxi_factors_register(struct device_node *node,
+ const struct factors_data *data,
+ spinlock_t *lock,
+ void __iomem *reg)
{
struct clk *clk;
struct clk_factors *factors;
@@ -168,11 +171,8 @@
struct clk_hw *mux_hw = NULL;
const char *clk_name = node->name;
const char *parents[FACTORS_MAX_PARENTS];
- void __iomem *reg;
int i = 0;
- reg = of_iomap(node, 0);
-
/* if we have a mux, we will have >1 parents */
while (i < FACTORS_MAX_PARENTS &&
(parents[i] = of_clk_get_parent_name(node, i)) != NULL)
diff --git a/drivers/clk/sunxi/clk-factors.h b/drivers/clk/sunxi/clk-factors.h
index 912238f..171085a 100644
--- a/drivers/clk/sunxi/clk-factors.h
+++ b/drivers/clk/sunxi/clk-factors.h
@@ -36,8 +36,9 @@
spinlock_t *lock;
};
-struct clk * __init sunxi_factors_register(struct device_node *node,
- const struct factors_data *data,
- spinlock_t *lock);
+struct clk *sunxi_factors_register(struct device_node *node,
+ const struct factors_data *data,
+ spinlock_t *lock,
+ void __iomem *reg);
#endif
diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c
index da0524ea..ec8f5a1 100644
--- a/drivers/clk/sunxi/clk-mod0.c
+++ b/drivers/clk/sunxi/clk-mod0.c
@@ -17,6 +17,7 @@
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/of_address.h>
+#include <linux/platform_device.h>
#include "clk-factors.h"
@@ -67,7 +68,7 @@
.pwidth = 2,
};
-static const struct factors_data sun4i_a10_mod0_data __initconst = {
+static const struct factors_data sun4i_a10_mod0_data = {
.enable = 31,
.mux = 24,
.muxmask = BIT(1) | BIT(0),
@@ -79,15 +80,95 @@
static void __init sun4i_a10_mod0_setup(struct device_node *node)
{
- sunxi_factors_register(node, &sun4i_a10_mod0_data, &sun4i_a10_mod0_lock);
+ void __iomem *reg;
+
+ reg = of_iomap(node, 0);
+ if (!reg) {
+ /*
+ * This happens with mod0 clk nodes instantiated through
+ * mfd, as those do not have their resources assigned at
+ * CLK_OF_DECLARE time yet, so do not print an error.
+ */
+ return;
+ }
+
+ sunxi_factors_register(node, &sun4i_a10_mod0_data,
+ &sun4i_a10_mod0_lock, reg);
}
CLK_OF_DECLARE(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", sun4i_a10_mod0_setup);
+static int sun4i_a10_mod0_clk_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *r;
+ void __iomem *reg;
+
+ if (!np)
+ return -ENODEV;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ reg = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(reg))
+ return PTR_ERR(reg);
+
+ sunxi_factors_register(np, &sun4i_a10_mod0_data,
+ &sun4i_a10_mod0_lock, reg);
+ return 0;
+}
+
+static const struct of_device_id sun4i_a10_mod0_clk_dt_ids[] = {
+ { .compatible = "allwinner,sun4i-a10-mod0-clk" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver sun4i_a10_mod0_clk_driver = {
+ .driver = {
+ .name = "sun4i-a10-mod0-clk",
+ .of_match_table = sun4i_a10_mod0_clk_dt_ids,
+ },
+ .probe = sun4i_a10_mod0_clk_probe,
+};
+module_platform_driver(sun4i_a10_mod0_clk_driver);
+
+static const struct factors_data sun9i_a80_mod0_data __initconst = {
+ .enable = 31,
+ .mux = 24,
+ .muxmask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
+ .table = &sun4i_a10_mod0_config,
+ .getter = sun4i_a10_get_mod0_factors,
+};
+
+static void __init sun9i_a80_mod0_setup(struct device_node *node)
+{
+ void __iomem *reg;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (IS_ERR(reg)) {
+ pr_err("Could not get registers for mod0-clk: %s\n",
+ node->name);
+ return;
+ }
+
+ sunxi_factors_register(node, &sun9i_a80_mod0_data,
+ &sun4i_a10_mod0_lock, reg);
+}
+CLK_OF_DECLARE(sun9i_a80_mod0, "allwinner,sun9i-a80-mod0-clk", sun9i_a80_mod0_setup);
+
static DEFINE_SPINLOCK(sun5i_a13_mbus_lock);
static void __init sun5i_a13_mbus_setup(struct device_node *node)
{
- struct clk *mbus = sunxi_factors_register(node, &sun4i_a10_mod0_data, &sun5i_a13_mbus_lock);
+ struct clk *mbus;
+ void __iomem *reg;
+
+ reg = of_iomap(node, 0);
+ if (!reg) {
+ pr_err("Could not get registers for a13-mbus-clk\n");
+ return;
+ }
+
+ mbus = sunxi_factors_register(node, &sun4i_a10_mod0_data,
+ &sun5i_a13_mbus_lock, reg);
/* The MBUS clocks needs to be always enabled */
__clk_get(mbus);
@@ -95,14 +176,10 @@
}
CLK_OF_DECLARE(sun5i_a13_mbus, "allwinner,sun5i-a13-mbus-clk", sun5i_a13_mbus_setup);
-struct mmc_phase_data {
- u8 offset;
-};
-
struct mmc_phase {
struct clk_hw hw;
+ u8 offset;
void __iomem *reg;
- struct mmc_phase_data *data;
spinlock_t *lock;
};
@@ -118,7 +195,7 @@
u8 delay;
value = readl(phase->reg);
- delay = (value >> phase->data->offset) & 0x3;
+ delay = (value >> phase->offset) & 0x3;
if (!delay)
return 180;
@@ -206,8 +283,8 @@
spin_lock_irqsave(phase->lock, flags);
value = readl(phase->reg);
- value &= ~GENMASK(phase->data->offset + 3, phase->data->offset);
- value |= delay << phase->data->offset;
+ value &= ~GENMASK(phase->offset + 3, phase->offset);
+ value |= delay << phase->offset;
writel(value, phase->reg);
spin_unlock_irqrestore(phase->lock, flags);
@@ -219,66 +296,97 @@
.set_phase = mmc_set_phase,
};
-static void __init sun4i_a10_mmc_phase_setup(struct device_node *node,
- struct mmc_phase_data *data)
+/*
+ * sunxi_mmc_setup - Common setup function for mmc module clocks
+ *
+ * The only difference between module clocks on different platforms is the
+ * width of the mux register bits and the valid values, which are passed in
+ * through struct factors_data. The phase clocks parts are identical.
+ */
+static void __init sunxi_mmc_setup(struct device_node *node,
+ const struct factors_data *data,
+ spinlock_t *lock)
{
- const char *parent_names[1] = { of_clk_get_parent_name(node, 0) };
- struct clk_init_data init = {
- .num_parents = 1,
- .parent_names = parent_names,
- .ops = &mmc_clk_ops,
- };
+ struct clk_onecell_data *clk_data;
+ const char *parent;
+ void __iomem *reg;
+ int i;
- struct mmc_phase *phase;
- struct clk *clk;
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (IS_ERR(reg)) {
+ pr_err("Couldn't map the %s clock registers\n", node->name);
+ return;
+ }
- phase = kmalloc(sizeof(*phase), GFP_KERNEL);
- if (!phase)
+ clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
+ if (!clk_data)
return;
- phase->hw.init = &init;
+ clk_data->clks = kcalloc(3, sizeof(*clk_data->clks), GFP_KERNEL);
+ if (!clk_data->clks)
+ goto err_free_data;
- phase->reg = of_iomap(node, 0);
- if (!phase->reg)
- goto err_free;
+ clk_data->clk_num = 3;
+ clk_data->clks[0] = sunxi_factors_register(node, data, lock, reg);
+ if (!clk_data->clks[0])
+ goto err_free_clks;
- phase->data = data;
- phase->lock = &sun4i_a10_mod0_lock;
+ parent = __clk_get_name(clk_data->clks[0]);
- if (of_property_read_string(node, "clock-output-names", &init.name))
- init.name = node->name;
+ for (i = 1; i < 3; i++) {
+ struct clk_init_data init = {
+ .num_parents = 1,
+ .parent_names = &parent,
+ .ops = &mmc_clk_ops,
+ };
+ struct mmc_phase *phase;
- clk = clk_register(NULL, &phase->hw);
- if (IS_ERR(clk))
- goto err_unmap;
+ phase = kmalloc(sizeof(*phase), GFP_KERNEL);
+ if (!phase)
+ continue;
- of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ phase->hw.init = &init;
+ phase->reg = reg;
+ phase->lock = lock;
+
+ if (i == 1)
+ phase->offset = 8;
+ else
+ phase->offset = 20;
+
+ if (of_property_read_string_index(node, "clock-output-names",
+ i, &init.name))
+ init.name = node->name;
+
+ clk_data->clks[i] = clk_register(NULL, &phase->hw);
+ if (IS_ERR(clk_data->clks[i])) {
+ kfree(phase);
+ continue;
+ }
+ }
+
+ of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
return;
-err_unmap:
- iounmap(phase->reg);
-err_free:
- kfree(phase);
+err_free_clks:
+ kfree(clk_data->clks);
+err_free_data:
+ kfree(clk_data);
}
+static DEFINE_SPINLOCK(sun4i_a10_mmc_lock);
-static struct mmc_phase_data mmc_output_clk = {
- .offset = 8,
-};
-
-static struct mmc_phase_data mmc_sample_clk = {
- .offset = 20,
-};
-
-static void __init sun4i_a10_mmc_output_setup(struct device_node *node)
+static void __init sun4i_a10_mmc_setup(struct device_node *node)
{
- sun4i_a10_mmc_phase_setup(node, &mmc_output_clk);
+ sunxi_mmc_setup(node, &sun4i_a10_mod0_data, &sun4i_a10_mmc_lock);
}
-CLK_OF_DECLARE(sun4i_a10_mmc_output, "allwinner,sun4i-a10-mmc-output-clk", sun4i_a10_mmc_output_setup);
+CLK_OF_DECLARE(sun4i_a10_mmc, "allwinner,sun4i-a10-mmc-clk", sun4i_a10_mmc_setup);
-static void __init sun4i_a10_mmc_sample_setup(struct device_node *node)
+static DEFINE_SPINLOCK(sun9i_a80_mmc_lock);
+
+static void __init sun9i_a80_mmc_setup(struct device_node *node)
{
- sun4i_a10_mmc_phase_setup(node, &mmc_sample_clk);
+ sunxi_mmc_setup(node, &sun9i_a80_mod0_data, &sun9i_a80_mmc_lock);
}
-CLK_OF_DECLARE(sun4i_a10_mmc_sample, "allwinner,sun4i-a10-mmc-sample-clk", sun4i_a10_mmc_sample_setup);
+CLK_OF_DECLARE(sun9i_a80_mmc, "allwinner,sun9i-a80-mmc-clk", sun9i_a80_mmc_setup);
diff --git a/drivers/clk/sunxi/clk-sun6i-ar100.c b/drivers/clk/sunxi/clk-sun6i-ar100.c
index 3d282fb..63cf149 100644
--- a/drivers/clk/sunxi/clk-sun6i-ar100.c
+++ b/drivers/clk/sunxi/clk-sun6i-ar100.c
@@ -45,6 +45,8 @@
}
static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk)
{
diff --git a/drivers/clk/sunxi/clk-sun8i-mbus.c b/drivers/clk/sunxi/clk-sun8i-mbus.c
index ef49786..14cd026 100644
--- a/drivers/clk/sunxi/clk-sun8i-mbus.c
+++ b/drivers/clk/sunxi/clk-sun8i-mbus.c
@@ -69,8 +69,17 @@
static void __init sun8i_a23_mbus_setup(struct device_node *node)
{
- struct clk *mbus = sunxi_factors_register(node, &sun8i_a23_mbus_data,
- &sun8i_a23_mbus_lock);
+ struct clk *mbus;
+ void __iomem *reg;
+
+ reg = of_iomap(node, 0);
+ if (!reg) {
+ pr_err("Could not get registers for a23-mbus-clk\n");
+ return;
+ }
+
+ mbus = sunxi_factors_register(node, &sun8i_a23_mbus_data,
+ &sun8i_a23_mbus_lock, reg);
/* The MBUS clocks needs to be always enabled */
__clk_get(mbus);
diff --git a/drivers/clk/sunxi/clk-sun9i-core.c b/drivers/clk/sunxi/clk-sun9i-core.c
index 3cb9036..d8da77d 100644
--- a/drivers/clk/sunxi/clk-sun9i-core.c
+++ b/drivers/clk/sunxi/clk-sun9i-core.c
@@ -24,50 +24,51 @@
/**
- * sun9i_a80_get_pll4_factors() - calculates n, p, m factors for PLL1
+ * sun9i_a80_get_pll4_factors() - calculates n, p, m factors for PLL4
* PLL4 rate is calculated as follows
* rate = (parent_rate * n >> p) / (m + 1);
- * parent_rate is always 24Mhz
+ * parent_rate is always 24MHz
*
* p and m are named div1 and div2 in Allwinner's SDK
*/
static void sun9i_a80_get_pll4_factors(u32 *freq, u32 parent_rate,
- u8 *n, u8 *k, u8 *m, u8 *p)
+ u8 *n_ret, u8 *k, u8 *m_ret, u8 *p_ret)
{
- int div;
+ int n;
+ int m = 1;
+ int p = 1;
- /* Normalize value to a 6M multiple */
- div = DIV_ROUND_UP(*freq, 6000000);
+ /* Normalize value to a 6 MHz multiple (24 MHz / 4) */
+ n = DIV_ROUND_UP(*freq, 6000000);
- /* divs above 256 cannot be odd */
- if (div > 256)
- div = round_up(div, 2);
+ /* If n is too large switch to steps of 12 MHz */
+ if (n > 255) {
+ m = 0;
+ n = (n + 1) / 2;
+ }
- /* divs above 512 must be a multiple of 4 */
- if (div > 512)
- div = round_up(div, 4);
+ /* If n is still too large switch to steps of 24 MHz */
+ if (n > 255) {
+ p = 0;
+ n = (n + 1) / 2;
+ }
- *freq = 6000000 * div;
+ /* n must be between 12 and 255 */
+ if (n > 255)
+ n = 255;
+ else if (n < 12)
+ n = 12;
+
+ *freq = ((24000000 * n) >> p) / (m + 1);
/* we were called to round the frequency, we can now return */
- if (n == NULL)
+ if (n_ret == NULL)
return;
- /* p will be 1 for divs under 512 */
- if (div < 512)
- *p = 1;
- else
- *p = 0;
-
- /* m will be 1 if div is odd */
- if (div & 1)
- *m = 1;
- else
- *m = 0;
-
- /* calculate a suitable n based on m and p */
- *n = div / (*p + 1) / (*m + 1);
+ *n_ret = n;
+ *m_ret = m;
+ *p_ret = p;
}
static struct clk_factors_config sun9i_a80_pll4_config = {
@@ -89,7 +90,17 @@
static void __init sun9i_a80_pll4_setup(struct device_node *node)
{
- sunxi_factors_register(node, &sun9i_a80_pll4_data, &sun9i_a80_pll4_lock);
+ void __iomem *reg;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (!reg) {
+ pr_err("Could not get registers for a80-pll4-clk: %s\n",
+ node->name);
+ return;
+ }
+
+ sunxi_factors_register(node, &sun9i_a80_pll4_data,
+ &sun9i_a80_pll4_lock, reg);
}
CLK_OF_DECLARE(sun9i_a80_pll4, "allwinner,sun9i-a80-pll4-clk", sun9i_a80_pll4_setup);
@@ -139,8 +150,18 @@
static void __init sun9i_a80_gt_setup(struct device_node *node)
{
- struct clk *gt = sunxi_factors_register(node, &sun9i_a80_gt_data,
- &sun9i_a80_gt_lock);
+ void __iomem *reg;
+ struct clk *gt;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (!reg) {
+ pr_err("Could not get registers for a80-gt-clk: %s\n",
+ node->name);
+ return;
+ }
+
+ gt = sunxi_factors_register(node, &sun9i_a80_gt_data,
+ &sun9i_a80_gt_lock, reg);
/* The GT bus clock needs to be always enabled */
__clk_get(gt);
@@ -194,7 +215,17 @@
static void __init sun9i_a80_ahb_setup(struct device_node *node)
{
- sunxi_factors_register(node, &sun9i_a80_ahb_data, &sun9i_a80_ahb_lock);
+ void __iomem *reg;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (!reg) {
+ pr_err("Could not get registers for a80-ahb-clk: %s\n",
+ node->name);
+ return;
+ }
+
+ sunxi_factors_register(node, &sun9i_a80_ahb_data,
+ &sun9i_a80_ahb_lock, reg);
}
CLK_OF_DECLARE(sun9i_a80_ahb, "allwinner,sun9i-a80-ahb-clk", sun9i_a80_ahb_setup);
@@ -210,7 +241,17 @@
static void __init sun9i_a80_apb0_setup(struct device_node *node)
{
- sunxi_factors_register(node, &sun9i_a80_apb0_data, &sun9i_a80_apb0_lock);
+ void __iomem *reg;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (!reg) {
+ pr_err("Could not get registers for a80-apb0-clk: %s\n",
+ node->name);
+ return;
+ }
+
+ sunxi_factors_register(node, &sun9i_a80_apb0_data,
+ &sun9i_a80_apb0_lock, reg);
}
CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-clk", sun9i_a80_apb0_setup);
@@ -266,6 +307,16 @@
static void __init sun9i_a80_apb1_setup(struct device_node *node)
{
- sunxi_factors_register(node, &sun9i_a80_apb1_data, &sun9i_a80_apb1_lock);
+ void __iomem *reg;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (!reg) {
+ pr_err("Could not get registers for a80-apb1-clk: %s\n",
+ node->name);
+ return;
+ }
+
+ sunxi_factors_register(node, &sun9i_a80_apb1_data,
+ &sun9i_a80_apb1_lock, reg);
}
CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-clk", sun9i_a80_apb1_setup);
diff --git a/drivers/clk/sunxi/clk-sun9i-mmc.c b/drivers/clk/sunxi/clk-sun9i-mmc.c
new file mode 100644
index 0000000..710c273
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun9i-mmc.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2015 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/reset.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/spinlock.h>
+
+#define SUN9I_MMC_WIDTH 4
+
+#define SUN9I_MMC_GATE_BIT 16
+#define SUN9I_MMC_RESET_BIT 18
+
+struct sun9i_mmc_clk_data {
+ spinlock_t lock;
+ void __iomem *membase;
+ struct clk *clk;
+ struct reset_control *reset;
+ struct clk_onecell_data clk_data;
+ struct reset_controller_dev rcdev;
+};
+
+static int sun9i_mmc_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct sun9i_mmc_clk_data *data = container_of(rcdev,
+ struct sun9i_mmc_clk_data,
+ rcdev);
+ unsigned long flags;
+ void __iomem *reg = data->membase + SUN9I_MMC_WIDTH * id;
+ u32 val;
+
+ clk_prepare_enable(data->clk);
+ spin_lock_irqsave(&data->lock, flags);
+
+ val = readl(reg);
+ writel(val & ~BIT(SUN9I_MMC_RESET_BIT), reg);
+
+ spin_unlock_irqrestore(&data->lock, flags);
+ clk_disable_unprepare(data->clk);
+
+ return 0;
+}
+
+static int sun9i_mmc_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct sun9i_mmc_clk_data *data = container_of(rcdev,
+ struct sun9i_mmc_clk_data,
+ rcdev);
+ unsigned long flags;
+ void __iomem *reg = data->membase + SUN9I_MMC_WIDTH * id;
+ u32 val;
+
+ clk_prepare_enable(data->clk);
+ spin_lock_irqsave(&data->lock, flags);
+
+ val = readl(reg);
+ writel(val | BIT(SUN9I_MMC_RESET_BIT), reg);
+
+ spin_unlock_irqrestore(&data->lock, flags);
+ clk_disable_unprepare(data->clk);
+
+ return 0;
+}
+
+static struct reset_control_ops sun9i_mmc_reset_ops = {
+ .assert = sun9i_mmc_reset_assert,
+ .deassert = sun9i_mmc_reset_deassert,
+};
+
+static int sun9i_a80_mmc_config_clk_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct sun9i_mmc_clk_data *data;
+ struct clk_onecell_data *clk_data;
+ const char *clk_name = np->name;
+ const char *clk_parent;
+ struct resource *r;
+ int count, i, ret;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ spin_lock_init(&data->lock);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ /* one clock/reset pair per word */
+ count = DIV_ROUND_UP((r->end - r->start + 1), SUN9I_MMC_WIDTH);
+ data->membase = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(data->membase))
+ return PTR_ERR(data->membase);
+
+ clk_data = &data->clk_data;
+ clk_data->clk_num = count;
+ clk_data->clks = devm_kcalloc(&pdev->dev, count, sizeof(struct clk *),
+ GFP_KERNEL);
+ if (!clk_data->clks)
+ return -ENOMEM;
+
+ data->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(data->clk)) {
+ dev_err(&pdev->dev, "Could not get clock\n");
+ return PTR_ERR(data->clk);
+ }
+
+ data->reset = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(data->reset)) {
+ dev_err(&pdev->dev, "Could not get reset control\n");
+ return PTR_ERR(data->reset);
+ }
+
+ ret = reset_control_deassert(data->reset);
+ if (ret) {
+ dev_err(&pdev->dev, "Reset deassert err %d\n", ret);
+ return ret;
+ }
+
+ clk_parent = __clk_get_name(data->clk);
+ for (i = 0; i < count; i++) {
+ of_property_read_string_index(np, "clock-output-names",
+ i, &clk_name);
+
+ clk_data->clks[i] = clk_register_gate(&pdev->dev, clk_name,
+ clk_parent, 0,
+ data->membase + SUN9I_MMC_WIDTH * i,
+ SUN9I_MMC_GATE_BIT, 0,
+ &data->lock);
+
+ if (IS_ERR(clk_data->clks[i])) {
+ ret = PTR_ERR(clk_data->clks[i]);
+ goto err_clk_register;
+ }
+ }
+
+ ret = of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+ if (ret)
+ goto err_clk_provider;
+
+ data->rcdev.owner = THIS_MODULE;
+ data->rcdev.nr_resets = count;
+ data->rcdev.ops = &sun9i_mmc_reset_ops;
+ data->rcdev.of_node = pdev->dev.of_node;
+
+ ret = reset_controller_register(&data->rcdev);
+ if (ret)
+ goto err_rc_reg;
+
+ platform_set_drvdata(pdev, data);
+
+ return 0;
+
+err_rc_reg:
+ of_clk_del_provider(np);
+
+err_clk_provider:
+ for (i = 0; i < count; i++)
+ clk_unregister(clk_data->clks[i]);
+
+err_clk_register:
+ reset_control_assert(data->reset);
+
+ return ret;
+}
+
+static int sun9i_a80_mmc_config_clk_remove(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct sun9i_mmc_clk_data *data = platform_get_drvdata(pdev);
+ struct clk_onecell_data *clk_data = &data->clk_data;
+ int i;
+
+ reset_controller_unregister(&data->rcdev);
+ of_clk_del_provider(np);
+ for (i = 0; i < clk_data->clk_num; i++)
+ clk_unregister(clk_data->clks[i]);
+
+ reset_control_assert(data->reset);
+
+ return 0;
+}
+
+static const struct of_device_id sun9i_a80_mmc_config_clk_dt_ids[] = {
+ { .compatible = "allwinner,sun9i-a80-mmc-config-clk" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver sun9i_a80_mmc_config_clk_driver = {
+ .driver = {
+ .name = "sun9i-a80-mmc-config-clk",
+ .of_match_table = sun9i_a80_mmc_config_clk_dt_ids,
+ },
+ .probe = sun9i_a80_mmc_config_clk_probe,
+ .remove = sun9i_a80_mmc_config_clk_remove,
+};
+module_platform_driver(sun9i_a80_mmc_config_clk_driver);
+
+MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
+MODULE_DESCRIPTION("Allwinner A80 MMC clock/reset Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 1818f40..379324e 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -20,11 +20,221 @@
#include <linux/of_address.h>
#include <linux/reset-controller.h>
#include <linux/spinlock.h>
+#include <linux/log2.h>
#include "clk-factors.h"
static DEFINE_SPINLOCK(clk_lock);
+/**
+ * sun6i_a31_ahb1_clk_setup() - Setup function for a31 ahb1 composite clk
+ */
+
+#define SUN6I_AHB1_MAX_PARENTS 4
+#define SUN6I_AHB1_MUX_PARENT_PLL6 3
+#define SUN6I_AHB1_MUX_SHIFT 12
+/* un-shifted mask is what mux_clk expects */
+#define SUN6I_AHB1_MUX_MASK 0x3
+#define SUN6I_AHB1_MUX_GET_PARENT(reg) ((reg >> SUN6I_AHB1_MUX_SHIFT) & \
+ SUN6I_AHB1_MUX_MASK)
+
+#define SUN6I_AHB1_DIV_SHIFT 4
+#define SUN6I_AHB1_DIV_MASK (0x3 << SUN6I_AHB1_DIV_SHIFT)
+#define SUN6I_AHB1_DIV_GET(reg) ((reg & SUN6I_AHB1_DIV_MASK) >> \
+ SUN6I_AHB1_DIV_SHIFT)
+#define SUN6I_AHB1_DIV_SET(reg, div) ((reg & ~SUN6I_AHB1_DIV_MASK) | \
+ (div << SUN6I_AHB1_DIV_SHIFT))
+#define SUN6I_AHB1_PLL6_DIV_SHIFT 6
+#define SUN6I_AHB1_PLL6_DIV_MASK (0x3 << SUN6I_AHB1_PLL6_DIV_SHIFT)
+#define SUN6I_AHB1_PLL6_DIV_GET(reg) ((reg & SUN6I_AHB1_PLL6_DIV_MASK) >> \
+ SUN6I_AHB1_PLL6_DIV_SHIFT)
+#define SUN6I_AHB1_PLL6_DIV_SET(reg, div) ((reg & ~SUN6I_AHB1_PLL6_DIV_MASK) | \
+ (div << SUN6I_AHB1_PLL6_DIV_SHIFT))
+
+struct sun6i_ahb1_clk {
+ struct clk_hw hw;
+ void __iomem *reg;
+};
+
+#define to_sun6i_ahb1_clk(_hw) container_of(_hw, struct sun6i_ahb1_clk, hw)
+
+static unsigned long sun6i_ahb1_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct sun6i_ahb1_clk *ahb1 = to_sun6i_ahb1_clk(hw);
+ unsigned long rate;
+ u32 reg;
+
+ /* Fetch the register value */
+ reg = readl(ahb1->reg);
+
+ /* apply pre-divider first if parent is pll6 */
+ if (SUN6I_AHB1_MUX_GET_PARENT(reg) == SUN6I_AHB1_MUX_PARENT_PLL6)
+ parent_rate /= SUN6I_AHB1_PLL6_DIV_GET(reg) + 1;
+
+ /* clk divider */
+ rate = parent_rate >> SUN6I_AHB1_DIV_GET(reg);
+
+ return rate;
+}
+
+static long sun6i_ahb1_clk_round(unsigned long rate, u8 *divp, u8 *pre_divp,
+ u8 parent, unsigned long parent_rate)
+{
+ u8 div, calcp, calcm = 1;
+
+ /*
+ * clock can only divide, so we will never be able to achieve
+ * frequencies higher than the parent frequency
+ */
+ if (parent_rate && rate > parent_rate)
+ rate = parent_rate;
+
+ div = DIV_ROUND_UP(parent_rate, rate);
+
+ /* calculate pre-divider if parent is pll6 */
+ if (parent == SUN6I_AHB1_MUX_PARENT_PLL6) {
+ if (div < 4)
+ calcp = 0;
+ else if (div / 2 < 4)
+ calcp = 1;
+ else if (div / 4 < 4)
+ calcp = 2;
+ else
+ calcp = 3;
+
+ calcm = DIV_ROUND_UP(div, 1 << calcp);
+ } else {
+ calcp = __roundup_pow_of_two(div);
+ calcp = calcp > 3 ? 3 : calcp;
+ }
+
+ /* we were asked to pass back divider values */
+ if (divp) {
+ *divp = calcp;
+ *pre_divp = calcm - 1;
+ }
+
+ return (parent_rate / calcm) >> calcp;
+}
+
+static long sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
+ unsigned long *best_parent_rate,
+ struct clk_hw **best_parent_clk)
+{
+ struct clk *clk = hw->clk, *parent, *best_parent = NULL;
+ int i, num_parents;
+ unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
+
+ /* find the parent that can help provide the fastest rate <= rate */
+ num_parents = __clk_get_num_parents(clk);
+ for (i = 0; i < num_parents; i++) {
+ parent = clk_get_parent_by_index(clk, i);
+ if (!parent)
+ continue;
+ if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT)
+ parent_rate = __clk_round_rate(parent, rate);
+ else
+ parent_rate = __clk_get_rate(parent);
+
+ child_rate = sun6i_ahb1_clk_round(rate, NULL, NULL, i,
+ parent_rate);
+
+ if (child_rate <= rate && child_rate > best_child_rate) {
+ best_parent = parent;
+ best = parent_rate;
+ best_child_rate = child_rate;
+ }
+ }
+
+ if (best_parent)
+ *best_parent_clk = __clk_get_hw(best_parent);
+ *best_parent_rate = best;
+
+ return best_child_rate;
+}
+
+static int sun6i_ahb1_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct sun6i_ahb1_clk *ahb1 = to_sun6i_ahb1_clk(hw);
+ unsigned long flags;
+ u8 div, pre_div, parent;
+ u32 reg;
+
+ spin_lock_irqsave(&clk_lock, flags);
+
+ reg = readl(ahb1->reg);
+
+ /* need to know which parent is used to apply pre-divider */
+ parent = SUN6I_AHB1_MUX_GET_PARENT(reg);
+ sun6i_ahb1_clk_round(rate, &div, &pre_div, parent, parent_rate);
+
+ reg = SUN6I_AHB1_DIV_SET(reg, div);
+ reg = SUN6I_AHB1_PLL6_DIV_SET(reg, pre_div);
+ writel(reg, ahb1->reg);
+
+ spin_unlock_irqrestore(&clk_lock, flags);
+
+ return 0;
+}
+
+static const struct clk_ops sun6i_ahb1_clk_ops = {
+ .determine_rate = sun6i_ahb1_clk_determine_rate,
+ .recalc_rate = sun6i_ahb1_clk_recalc_rate,
+ .set_rate = sun6i_ahb1_clk_set_rate,
+};
+
+static void __init sun6i_ahb1_clk_setup(struct device_node *node)
+{
+ struct clk *clk;
+ struct sun6i_ahb1_clk *ahb1;
+ struct clk_mux *mux;
+ const char *clk_name = node->name;
+ const char *parents[SUN6I_AHB1_MAX_PARENTS];
+ void __iomem *reg;
+ int i = 0;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+
+ /* we have a mux, we will have >1 parents */
+ while (i < SUN6I_AHB1_MAX_PARENTS &&
+ (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
+ i++;
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+
+ ahb1 = kzalloc(sizeof(struct sun6i_ahb1_clk), GFP_KERNEL);
+ if (!ahb1)
+ return;
+
+ mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
+ if (!mux) {
+ kfree(ahb1);
+ return;
+ }
+
+ /* set up clock properties */
+ mux->reg = reg;
+ mux->shift = SUN6I_AHB1_MUX_SHIFT;
+ mux->mask = SUN6I_AHB1_MUX_MASK;
+ mux->lock = &clk_lock;
+ ahb1->reg = reg;
+
+ clk = clk_register_composite(NULL, clk_name, parents, i,
+ &mux->hw, &clk_mux_ops,
+ &ahb1->hw, &sun6i_ahb1_clk_ops,
+ NULL, NULL, 0);
+
+ if (!IS_ERR(clk)) {
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ clk_register_clkdev(clk, clk_name, NULL);
+ }
+}
+CLK_OF_DECLARE(sun6i_a31_ahb1, "allwinner,sun6i-a31-ahb1-clk", sun6i_ahb1_clk_setup);
+
/* Maximum number of parents our clocks have */
#define SUNXI_MAX_PARENTS 5
@@ -355,43 +565,6 @@
}
/**
- * clk_sunxi_mmc_phase_control() - configures MMC clock phase control
- */
-
-void clk_sunxi_mmc_phase_control(struct clk *clk, u8 sample, u8 output)
-{
- #define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw)
- #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw)
-
- struct clk_hw *hw = __clk_get_hw(clk);
- struct clk_composite *composite = to_clk_composite(hw);
- struct clk_hw *rate_hw = composite->rate_hw;
- struct clk_factors *factors = to_clk_factors(rate_hw);
- unsigned long flags = 0;
- u32 reg;
-
- if (factors->lock)
- spin_lock_irqsave(factors->lock, flags);
-
- reg = readl(factors->reg);
-
- /* set sample clock phase control */
- reg &= ~(0x7 << 20);
- reg |= ((sample & 0x7) << 20);
-
- /* set output clock phase control */
- reg &= ~(0x7 << 8);
- reg |= ((output & 0x7) << 8);
-
- writel(reg, factors->reg);
-
- if (factors->lock)
- spin_unlock_irqrestore(factors->lock, flags);
-}
-EXPORT_SYMBOL(clk_sunxi_mmc_phase_control);
-
-
-/**
* sunxi_factors_clk_setup() - Setup function for factor clocks
*/
@@ -413,6 +586,7 @@
.kwidth = 2,
.mshift = 0,
.mwidth = 2,
+ .n_start = 1,
};
static struct clk_factors_config sun8i_a23_pll1_config = {
@@ -520,7 +694,16 @@
static struct clk * __init sunxi_factors_clk_setup(struct device_node *node,
const struct factors_data *data)
{
- return sunxi_factors_register(node, data, &clk_lock);
+ void __iomem *reg;
+
+ reg = of_iomap(node, 0);
+ if (!reg) {
+ pr_err("Could not get registers for factors-clk: %s\n",
+ node->name);
+ return NULL;
+ }
+
+ return sunxi_factors_register(node, data, &clk_lock, reg);
}
@@ -561,7 +744,7 @@
of_property_read_string(node, "clock-output-names", &clk_name);
clk = clk_register_mux(NULL, clk_name, parents, i,
- CLK_SET_RATE_NO_REPARENT, reg,
+ CLK_SET_RATE_PARENT, reg,
data->shift, SUNXI_MUX_GATE_WIDTH,
0, &clk_lock);
@@ -1217,7 +1400,6 @@
static const char *sun6i_critical_clocks[] __initdata = {
"cpu",
- "ahb1_sdram",
};
static void __init sun6i_init_clocks(struct device_node *node)
diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile
index f7dfb72..edb8358 100644
--- a/drivers/clk/tegra/Makefile
+++ b/drivers/clk/tegra/Makefile
@@ -15,3 +15,4 @@
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o
obj-$(CONFIG_ARCH_TEGRA_114_SOC) += clk-tegra114.o
obj-$(CONFIG_ARCH_TEGRA_124_SOC) += clk-tegra124.o
+obj-$(CONFIG_ARCH_TEGRA_132_SOC) += clk-tegra124.o
diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h
index 0011d54..60738cc 100644
--- a/drivers/clk/tegra/clk-id.h
+++ b/drivers/clk/tegra/clk-id.h
@@ -64,10 +64,8 @@
tegra_clk_disp2,
tegra_clk_dp2,
tegra_clk_dpaux,
- tegra_clk_dsia,
tegra_clk_dsialp,
tegra_clk_dsia_mux,
- tegra_clk_dsib,
tegra_clk_dsiblp,
tegra_clk_dsib_mux,
tegra_clk_dtv,
diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c
index 9e899c18..d84ae49 100644
--- a/drivers/clk/tegra/clk-periph.c
+++ b/drivers/clk/tegra/clk-periph.c
@@ -28,7 +28,7 @@
const struct clk_ops *mux_ops = periph->mux_ops;
struct clk_hw *mux_hw = &periph->mux.hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
return mux_ops->get_parent(mux_hw);
}
@@ -39,7 +39,7 @@
const struct clk_ops *mux_ops = periph->mux_ops;
struct clk_hw *mux_hw = &periph->mux.hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
return mux_ops->set_parent(mux_hw, index);
}
@@ -51,7 +51,7 @@
const struct clk_ops *div_ops = periph->div_ops;
struct clk_hw *div_hw = &periph->divider.hw;
- div_hw->clk = hw->clk;
+ __clk_hw_set_clk(div_hw, hw);
return div_ops->recalc_rate(div_hw, parent_rate);
}
@@ -63,7 +63,7 @@
const struct clk_ops *div_ops = periph->div_ops;
struct clk_hw *div_hw = &periph->divider.hw;
- div_hw->clk = hw->clk;
+ __clk_hw_set_clk(div_hw, hw);
return div_ops->round_rate(div_hw, rate, prate);
}
@@ -75,7 +75,7 @@
const struct clk_ops *div_ops = periph->div_ops;
struct clk_hw *div_hw = &periph->divider.hw;
- div_hw->clk = hw->clk;
+ __clk_hw_set_clk(div_hw, hw);
return div_ops->set_rate(div_hw, rate, parent_rate);
}
@@ -86,7 +86,7 @@
const struct clk_ops *gate_ops = periph->gate_ops;
struct clk_hw *gate_hw = &periph->gate.hw;
- gate_hw->clk = hw->clk;
+ __clk_hw_set_clk(gate_hw, hw);
return gate_ops->is_enabled(gate_hw);
}
@@ -97,7 +97,7 @@
const struct clk_ops *gate_ops = periph->gate_ops;
struct clk_hw *gate_hw = &periph->gate.hw;
- gate_hw->clk = hw->clk;
+ __clk_hw_set_clk(gate_hw, hw);
return gate_ops->enable(gate_hw);
}
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index c7c6d8f..bfef9ab 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -816,7 +816,9 @@
.enable = clk_plle_enable,
};
-#if defined(CONFIG_ARCH_TEGRA_114_SOC) || defined(CONFIG_ARCH_TEGRA_124_SOC)
+#if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_124_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_132_SOC)
static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params,
unsigned long parent_rate)
@@ -1505,7 +1507,9 @@
return clk;
}
-#if defined(CONFIG_ARCH_TEGRA_114_SOC) || defined(CONFIG_ARCH_TEGRA_124_SOC)
+#if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_124_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_132_SOC)
static const struct clk_ops tegra_clk_pllxc_ops = {
.is_enabled = clk_pll_is_enabled,
.enable = clk_pll_iddq_enable,
@@ -1565,7 +1569,7 @@
parent = __clk_lookup(parent_name);
if (!parent) {
WARN(1, "parent clk %s of %s must be registered first\n",
- name, parent_name);
+ parent_name, name);
return ERR_PTR(-EINVAL);
}
@@ -1665,7 +1669,7 @@
parent = __clk_lookup(parent_name);
if (!parent) {
WARN(1, "parent clk %s of %s must be registered first\n",
- name, parent_name);
+ parent_name, name);
return ERR_PTR(-EINVAL);
}
@@ -1706,7 +1710,7 @@
parent = __clk_lookup(parent_name);
if (!parent) {
WARN(1, "parent clk %s of %s must be registered first\n",
- name, parent_name);
+ parent_name, name);
return ERR_PTR(-EINVAL);
}
@@ -1802,7 +1806,7 @@
}
#endif
-#ifdef CONFIG_ARCH_TEGRA_124_SOC
+#if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)
static const struct clk_ops tegra_clk_pllss_ops = {
.is_enabled = clk_pll_is_enabled,
.enable = clk_pll_iddq_enable,
@@ -1830,7 +1834,7 @@
parent = __clk_lookup(parent_name);
if (!parent) {
WARN(1, "parent clk %s of %s must be registered first\n",
- name, parent_name);
+ parent_name, name);
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c
index 37f32c4..cef0727 100644
--- a/drivers/clk/tegra/clk-tegra-periph.c
+++ b/drivers/clk/tegra/clk-tegra-periph.c
@@ -434,10 +434,10 @@
MUX("hda", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA, 125, TEGRA_PERIPH_ON_APB, tegra_clk_hda),
MUX("hda2codec_2x", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA2CODEC_2X, 111, TEGRA_PERIPH_ON_APB, tegra_clk_hda2codec_2x),
MUX("vfir", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_VFIR, 7, TEGRA_PERIPH_ON_APB, tegra_clk_vfir),
- MUX("sdmmc1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC1, 14, 0, tegra_clk_sdmmc1),
- MUX("sdmmc2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC2, 9, 0, tegra_clk_sdmmc2),
- MUX("sdmmc3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC3, 69, 0, tegra_clk_sdmmc3),
- MUX("sdmmc4", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC4, 15, 0, tegra_clk_sdmmc4),
+ MUX("sdmmc1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC1, 14, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc1),
+ MUX("sdmmc2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC2, 9, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc2),
+ MUX("sdmmc3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC3, 69, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc3),
+ MUX("sdmmc4", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC4, 15, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc4),
MUX("la", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_LA, 76, TEGRA_PERIPH_ON_APB, tegra_clk_la),
MUX("trace", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_TRACE, 77, TEGRA_PERIPH_ON_APB, tegra_clk_trace),
MUX("owr", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_OWR, 71, TEGRA_PERIPH_ON_APB, tegra_clk_owr),
@@ -470,10 +470,10 @@
MUX("adx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX1, 180, TEGRA_PERIPH_ON_APB, tegra_clk_adx1),
MUX("amx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX1, 185, TEGRA_PERIPH_ON_APB, tegra_clk_amx1),
MUX("vi_sensor2", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR2, 165, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor2),
- MUX8("sdmmc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC1, 14, 0, tegra_clk_sdmmc1_8),
- MUX8("sdmmc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC2, 9, 0, tegra_clk_sdmmc2_8),
- MUX8("sdmmc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC3, 69, 0, tegra_clk_sdmmc3_8),
- MUX8("sdmmc4", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC4, 15, 0, tegra_clk_sdmmc4_8),
+ MUX8("sdmmc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC1, 14, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc1_8),
+ MUX8("sdmmc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC2, 9, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc2_8),
+ MUX8("sdmmc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC3, 69, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc3_8),
+ MUX8("sdmmc4", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC4, 15, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc4_8),
MUX8("sbc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC1, 41, TEGRA_PERIPH_ON_APB, tegra_clk_sbc1_8),
MUX8("sbc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC2, 44, TEGRA_PERIPH_ON_APB, tegra_clk_sbc2_8),
MUX8("sbc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC3, 46, TEGRA_PERIPH_ON_APB, tegra_clk_sbc3_8),
@@ -537,8 +537,6 @@
GATE("xusb_host", "xusb_host_src", 89, 0, tegra_clk_xusb_host, 0),
GATE("xusb_ss", "xusb_ss_src", 156, 0, tegra_clk_xusb_ss, 0),
GATE("xusb_dev", "xusb_dev_src", 95, 0, tegra_clk_xusb_dev, 0),
- GATE("dsia", "dsia_mux", 48, 0, tegra_clk_dsia, 0),
- GATE("dsib", "dsib_mux", 82, 0, tegra_clk_dsib, 0),
GATE("emc", "emc_mux", 57, 0, tegra_clk_emc, CLK_IGNORE_UNUSED),
GATE("sata_cold", "clk_m", 129, TEGRA_PERIPH_ON_APB, tegra_clk_sata_cold, 0),
GATE("ispb", "clk_m", 3, 0, tegra_clk_ispb, 0),
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index 0b03d2c..d076642 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -715,7 +715,6 @@
[tegra_clk_sbc2_8] = { .dt_id = TEGRA114_CLK_SBC2, .present = true },
[tegra_clk_sbc3_8] = { .dt_id = TEGRA114_CLK_SBC3, .present = true },
[tegra_clk_i2c5] = { .dt_id = TEGRA114_CLK_I2C5, .present = true },
- [tegra_clk_dsia] = { .dt_id = TEGRA114_CLK_DSIA, .present = true },
[tegra_clk_mipi] = { .dt_id = TEGRA114_CLK_MIPI, .present = true },
[tegra_clk_hdmi] = { .dt_id = TEGRA114_CLK_HDMI, .present = true },
[tegra_clk_csi] = { .dt_id = TEGRA114_CLK_CSI, .present = true },
@@ -739,7 +738,6 @@
[tegra_clk_dtv] = { .dt_id = TEGRA114_CLK_DTV, .present = true },
[tegra_clk_ndspeed] = { .dt_id = TEGRA114_CLK_NDSPEED, .present = true },
[tegra_clk_i2cslow] = { .dt_id = TEGRA114_CLK_I2CSLOW, .present = true },
- [tegra_clk_dsib] = { .dt_id = TEGRA114_CLK_DSIB, .present = true },
[tegra_clk_tsec] = { .dt_id = TEGRA114_CLK_TSEC, .present = true },
[tegra_clk_xusb_host] = { .dt_id = TEGRA114_CLK_XUSB_HOST, .present = true },
[tegra_clk_msenc] = { .dt_id = TEGRA114_CLK_MSENC, .present = true },
@@ -1224,6 +1222,14 @@
clk_base + PLLD2_BASE, 25, 1, 0, &pll_d2_lock);
clks[TEGRA114_CLK_DSIB_MUX] = clk;
+ clk = tegra_clk_register_periph_gate("dsia", "dsia_mux", 0, clk_base,
+ 0, 48, periph_clk_enb_refcnt);
+ clks[TEGRA114_CLK_DSIA] = clk;
+
+ clk = tegra_clk_register_periph_gate("dsib", "dsib_mux", 0, clk_base,
+ 0, 82, periph_clk_enb_refcnt);
+ clks[TEGRA114_CLK_DSIB] = clk;
+
/* emc mux */
clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
ARRAY_SIZE(mux_pllmcp_clkm),
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c
index f5f9bac..9a893f2 100644
--- a/drivers/clk/tegra/clk-tegra124.c
+++ b/drivers/clk/tegra/clk-tegra124.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2012-2014 NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -28,6 +28,14 @@
#include "clk.h"
#include "clk-id.h"
+/*
+ * TEGRA124_CAR_BANK_COUNT: the number of peripheral clock register
+ * banks present in the Tegra124/132 CAR IP block. The banks are
+ * identified by single letters, e.g.: L, H, U, V, W, X. See
+ * periph_regs[] in drivers/clk/tegra/clk.c
+ */
+#define TEGRA124_CAR_BANK_COUNT 6
+
#define CLK_SOURCE_CSITE 0x1d4
#define CLK_SOURCE_EMC 0x19c
@@ -128,7 +136,6 @@
static unsigned long pll_ref_freq;
static DEFINE_SPINLOCK(pll_d_lock);
-static DEFINE_SPINLOCK(pll_d2_lock);
static DEFINE_SPINLOCK(pll_e_lock);
static DEFINE_SPINLOCK(pll_re_lock);
static DEFINE_SPINLOCK(pll_u_lock);
@@ -145,11 +152,6 @@
[12] = 260000000,
};
-static const char *mux_plld_out0_plld2_out0[] = {
- "pll_d_out0", "pll_d2_out0",
-};
-#define mux_plld_out0_plld2_out0_idx NULL
-
static const char *mux_pllmcp_clkm[] = {
"pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_c2", "pll_c3",
};
@@ -783,7 +785,6 @@
[tegra_clk_sbc2] = { .dt_id = TEGRA124_CLK_SBC2, .present = true },
[tegra_clk_sbc3] = { .dt_id = TEGRA124_CLK_SBC3, .present = true },
[tegra_clk_i2c5] = { .dt_id = TEGRA124_CLK_I2C5, .present = true },
- [tegra_clk_dsia] = { .dt_id = TEGRA124_CLK_DSIA, .present = true },
[tegra_clk_mipi] = { .dt_id = TEGRA124_CLK_MIPI, .present = true },
[tegra_clk_hdmi] = { .dt_id = TEGRA124_CLK_HDMI, .present = true },
[tegra_clk_csi] = { .dt_id = TEGRA124_CLK_CSI, .present = true },
@@ -809,7 +810,6 @@
[tegra_clk_soc_therm] = { .dt_id = TEGRA124_CLK_SOC_THERM, .present = true },
[tegra_clk_dtv] = { .dt_id = TEGRA124_CLK_DTV, .present = true },
[tegra_clk_i2cslow] = { .dt_id = TEGRA124_CLK_I2CSLOW, .present = true },
- [tegra_clk_dsib] = { .dt_id = TEGRA124_CLK_DSIB, .present = true },
[tegra_clk_tsec] = { .dt_id = TEGRA124_CLK_TSEC, .present = true },
[tegra_clk_xusb_host] = { .dt_id = TEGRA124_CLK_XUSB_HOST, .present = true },
[tegra_clk_msenc] = { .dt_id = TEGRA124_CLK_MSENC, .present = true },
@@ -949,8 +949,6 @@
[tegra_clk_clk_out_1_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_1_MUX, .present = true },
[tegra_clk_clk_out_2_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_2_MUX, .present = true },
[tegra_clk_clk_out_3_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_3_MUX, .present = true },
- [tegra_clk_dsia_mux] = { .dt_id = TEGRA124_CLK_DSIA_MUX, .present = true },
- [tegra_clk_dsib_mux] = { .dt_id = TEGRA124_CLK_DSIB_MUX, .present = true },
};
static struct tegra_devclk devclks[] __initdata = {
@@ -1112,17 +1110,17 @@
1, 2);
clks[TEGRA124_CLK_XUSB_SS_DIV2] = clk;
- /* dsia mux */
- clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0,
- ARRAY_SIZE(mux_plld_out0_plld2_out0), 0,
- clk_base + PLLD_BASE, 25, 1, 0, &pll_d_lock);
- clks[TEGRA124_CLK_DSIA_MUX] = clk;
+ clk = clk_register_gate(NULL, "plld_dsi", "plld_out0", 0,
+ clk_base + PLLD_MISC, 30, 0, &pll_d_lock);
+ clks[TEGRA124_CLK_PLLD_DSI] = clk;
- /* dsib mux */
- clk = clk_register_mux(NULL, "dsib_mux", mux_plld_out0_plld2_out0,
- ARRAY_SIZE(mux_plld_out0_plld2_out0), 0,
- clk_base + PLLD2_BASE, 25, 1, 0, &pll_d2_lock);
- clks[TEGRA124_CLK_DSIB_MUX] = clk;
+ clk = tegra_clk_register_periph_gate("dsia", "plld_dsi", 0, clk_base,
+ 0, 48, periph_clk_enb_refcnt);
+ clks[TEGRA124_CLK_DSIA] = clk;
+
+ clk = tegra_clk_register_periph_gate("dsib", "plld_dsi", 0, clk_base,
+ 0, 82, periph_clk_enb_refcnt);
+ clks[TEGRA124_CLK_DSIB] = clk;
/* emc mux */
clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
@@ -1351,7 +1349,7 @@
{},
};
-static struct tegra_clk_init_table init_table[] __initdata = {
+static struct tegra_clk_init_table common_init_table[] __initdata = {
{TEGRA124_CLK_UARTA, TEGRA124_CLK_PLL_P, 408000000, 0},
{TEGRA124_CLK_UARTB, TEGRA124_CLK_PLL_P, 408000000, 0},
{TEGRA124_CLK_UARTC, TEGRA124_CLK_PLL_P, 408000000, 0},
@@ -1368,6 +1366,8 @@
{TEGRA124_CLK_I2S4, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0},
{TEGRA124_CLK_VDE, TEGRA124_CLK_PLL_P, 0, 0},
{TEGRA124_CLK_HOST1X, TEGRA124_CLK_PLL_P, 136000000, 1},
+ {TEGRA124_CLK_DSIALP, TEGRA124_CLK_PLL_P, 68000000, 0},
+ {TEGRA124_CLK_DSIBLP, TEGRA124_CLK_PLL_P, 68000000, 0},
{TEGRA124_CLK_SCLK, TEGRA124_CLK_PLL_P_OUT2, 102000000, 1},
{TEGRA124_CLK_DFLL_SOC, TEGRA124_CLK_PLL_P, 51000000, 1},
{TEGRA124_CLK_DFLL_REF, TEGRA124_CLK_PLL_P, 51000000, 1},
@@ -1385,27 +1385,73 @@
{TEGRA124_CLK_SATA, TEGRA124_CLK_PLL_P, 104000000, 0},
{TEGRA124_CLK_SATA_OOB, TEGRA124_CLK_PLL_P, 204000000, 0},
{TEGRA124_CLK_EMC, TEGRA124_CLK_CLK_MAX, 0, 1},
- {TEGRA124_CLK_CCLK_G, TEGRA124_CLK_CLK_MAX, 0, 1},
{TEGRA124_CLK_MSELECT, TEGRA124_CLK_CLK_MAX, 0, 1},
{TEGRA124_CLK_CSITE, TEGRA124_CLK_CLK_MAX, 0, 1},
{TEGRA124_CLK_TSENSOR, TEGRA124_CLK_CLK_M, 400000, 0},
- {TEGRA124_CLK_SOC_THERM, TEGRA124_CLK_PLL_P, 51000000, 0},
/* This MUST be the last entry. */
{TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
};
+static struct tegra_clk_init_table tegra124_init_table[] __initdata = {
+ {TEGRA124_CLK_SOC_THERM, TEGRA124_CLK_PLL_P, 51000000, 0},
+ {TEGRA124_CLK_CCLK_G, TEGRA124_CLK_CLK_MAX, 0, 1},
+ /* This MUST be the last entry. */
+ {TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
+};
+
+/* Tegra132 requires the SOC_THERM clock to remain active */
+static struct tegra_clk_init_table tegra132_init_table[] __initdata = {
+ {TEGRA124_CLK_SOC_THERM, TEGRA124_CLK_PLL_P, 51000000, 1},
+ /* This MUST be the last entry. */
+ {TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
+};
+
+/**
+ * tegra124_clock_apply_init_table - initialize clocks on Tegra124 SoCs
+ *
+ * Program an initial clock rate and enable or disable clocks needed
+ * by the rest of the kernel, for Tegra124 SoCs. It is intended to be
+ * called by assigning a pointer to it to tegra_clk_apply_init_table -
+ * this will be called as an arch_initcall. No return value.
+ */
static void __init tegra124_clock_apply_init_table(void)
{
- tegra_init_from_table(init_table, clks, TEGRA124_CLK_CLK_MAX);
+ tegra_init_from_table(common_init_table, clks, TEGRA124_CLK_CLK_MAX);
+ tegra_init_from_table(tegra124_init_table, clks, TEGRA124_CLK_CLK_MAX);
}
-static void __init tegra124_clock_init(struct device_node *np)
+/**
+ * tegra132_clock_apply_init_table - initialize clocks on Tegra132 SoCs
+ *
+ * Program an initial clock rate and enable or disable clocks needed
+ * by the rest of the kernel, for Tegra132 SoCs. It is intended to be
+ * called by assigning a pointer to it to tegra_clk_apply_init_table -
+ * this will be called as an arch_initcall. No return value.
+ */
+static void __init tegra132_clock_apply_init_table(void)
+{
+ tegra_init_from_table(common_init_table, clks, TEGRA124_CLK_CLK_MAX);
+ tegra_init_from_table(tegra132_init_table, clks, TEGRA124_CLK_CLK_MAX);
+}
+
+/**
+ * tegra124_132_clock_init_pre - clock initialization preamble for T124/T132
+ * @np: struct device_node * of the DT node for the SoC CAR IP block
+ *
+ * Register most of the clocks controlled by the CAR IP block, along
+ * with a few clocks controlled by the PMC IP block. Everything in
+ * this function should be common to Tegra124 and Tegra132. XXX The
+ * PMC clock initialization should probably be moved to PMC-specific
+ * driver code. No return value.
+ */
+static void __init tegra124_132_clock_init_pre(struct device_node *np)
{
struct device_node *node;
+ u32 plld_base;
clk_base = of_iomap(np, 0);
if (!clk_base) {
- pr_err("ioremap tegra124 CAR failed\n");
+ pr_err("ioremap tegra124/tegra132 CAR failed\n");
return;
}
@@ -1423,7 +1469,8 @@
return;
}
- clks = tegra_clk_init(clk_base, TEGRA124_CLK_CLK_MAX, 6);
+ clks = tegra_clk_init(clk_base, TEGRA124_CLK_CLK_MAX,
+ TEGRA124_CAR_BANK_COUNT);
if (!clks)
return;
@@ -1437,13 +1484,76 @@
tegra_audio_clk_init(clk_base, pmc_base, tegra124_clks, &pll_a_params);
tegra_pmc_clk_init(pmc_base, tegra124_clks);
+ /* For Tegra124 & Tegra132, PLLD is the only source for DSIA & DSIB */
+ plld_base = clk_readl(clk_base + PLLD_BASE);
+ plld_base &= ~BIT(25);
+ clk_writel(plld_base, clk_base + PLLD_BASE);
+}
+
+/**
+ * tegra124_132_clock_init_post - clock initialization postamble for T124/T132
+ * @np: struct device_node * of the DT node for the SoC CAR IP block
+ *
+ * Register most of the along with a few clocks controlled by the PMC
+ * IP block. Everything in this function should be common to Tegra124
+ * and Tegra132. This function must be called after
+ * tegra124_132_clock_init_pre(), otherwise clk_base and pmc_base will
+ * not be set. No return value.
+ */
+static void __init tegra124_132_clock_init_post(struct device_node *np)
+{
tegra_super_clk_gen4_init(clk_base, pmc_base, tegra124_clks,
- &pll_x_params);
+ &pll_x_params);
tegra_add_of_provider(np);
tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
- tegra_clk_apply_init_table = tegra124_clock_apply_init_table;
-
tegra_cpu_car_ops = &tegra124_cpu_car_ops;
}
+
+/**
+ * tegra124_clock_init - Tegra124-specific clock initialization
+ * @np: struct device_node * of the DT node for the SoC CAR IP block
+ *
+ * Register most SoC clocks for the Tegra124 system-on-chip. Most of
+ * this code is shared between the Tegra124 and Tegra132 SoCs,
+ * although some of the initial clock settings and CPU clocks differ.
+ * Intended to be called by the OF init code when a DT node with the
+ * "nvidia,tegra124-car" string is encountered, and declared with
+ * CLK_OF_DECLARE. No return value.
+ */
+static void __init tegra124_clock_init(struct device_node *np)
+{
+ tegra124_132_clock_init_pre(np);
+ tegra_clk_apply_init_table = tegra124_clock_apply_init_table;
+ tegra124_132_clock_init_post(np);
+}
+
+/**
+ * tegra132_clock_init - Tegra132-specific clock initialization
+ * @np: struct device_node * of the DT node for the SoC CAR IP block
+ *
+ * Register most SoC clocks for the Tegra132 system-on-chip. Most of
+ * this code is shared between the Tegra124 and Tegra132 SoCs,
+ * although some of the initial clock settings and CPU clocks differ.
+ * Intended to be called by the OF init code when a DT node with the
+ * "nvidia,tegra132-car" string is encountered, and declared with
+ * CLK_OF_DECLARE. No return value.
+ */
+static void __init tegra132_clock_init(struct device_node *np)
+{
+ tegra124_132_clock_init_pre(np);
+
+ /*
+ * On Tegra132, these clocks are controlled by the
+ * CLUSTER_clocks IP block, located in the CPU complex
+ */
+ tegra124_clks[tegra_clk_cclk_g].present = false;
+ tegra124_clks[tegra_clk_cclk_lp].present = false;
+ tegra124_clks[tegra_clk_pll_x].present = false;
+ tegra124_clks[tegra_clk_pll_x_out0].present = false;
+
+ tegra_clk_apply_init_table = tegra132_clock_apply_init_table;
+ tegra124_132_clock_init_post(np);
+}
CLK_OF_DECLARE(tegra124, "nvidia,tegra124-car", tegra124_clock_init);
+CLK_OF_DECLARE(tegra132, "nvidia,tegra132-car", tegra132_clock_init);
diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c
index 97dc859..9ddb754 100644
--- a/drivers/clk/tegra/clk.c
+++ b/drivers/clk/tegra/clk.c
@@ -302,10 +302,13 @@
tegra_clk_apply_init_table_func tegra_clk_apply_init_table;
-void __init tegra_clocks_apply_init_table(void)
+static int __init tegra_clocks_apply_init_table(void)
{
if (!tegra_clk_apply_init_table)
- return;
+ return 0;
tegra_clk_apply_init_table();
+
+ return 0;
}
+arch_initcall(tegra_clocks_apply_init_table);
diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile
index ed4d0aa..105ffd0 100644
--- a/drivers/clk/ti/Makefile
+++ b/drivers/clk/ti/Makefile
@@ -1,13 +1,17 @@
-ifneq ($(CONFIG_OF),)
obj-y += clk.o autoidle.o clockdomain.o
clk-common = dpll.o composite.o divider.o gate.o \
fixed-factor.o mux.o apll.o
obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o
+obj-$(CONFIG_SOC_TI81XX) += $(clk-common) fapll.o clk-816x.o
obj-$(CONFIG_ARCH_OMAP2) += $(clk-common) interface.o clk-2xxx.o
-obj-$(CONFIG_ARCH_OMAP3) += $(clk-common) interface.o clk-3xxx.o
+obj-$(CONFIG_ARCH_OMAP3) += $(clk-common) interface.o \
+ clk-3xxx.o
obj-$(CONFIG_ARCH_OMAP4) += $(clk-common) clk-44xx.o
obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o
obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o \
clk-dra7-atl.o
obj-$(CONFIG_SOC_AM43XX) += $(clk-common) clk-43xx.o
+
+ifdef CONFIG_ATAGS
+obj-$(CONFIG_ARCH_OMAP3) += clk-3xxx-legacy.o
endif
diff --git a/drivers/clk/ti/clk-3xxx-legacy.c b/drivers/clk/ti/clk-3xxx-legacy.c
new file mode 100644
index 0000000..e0732a4
--- /dev/null
+++ b/drivers/clk/ti/clk-3xxx-legacy.c
@@ -0,0 +1,4653 @@
+/*
+ * OMAP3 Legacy clock data
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc
+ * Tero Kristo (t-kristo@ti.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/ti.h>
+
+#include "clock.h"
+
+static struct ti_clk_fixed virt_12m_ck_data = {
+ .frequency = 12000000,
+};
+
+static struct ti_clk virt_12m_ck = {
+ .name = "virt_12m_ck",
+ .type = TI_CLK_FIXED,
+ .data = &virt_12m_ck_data,
+};
+
+static struct ti_clk_fixed virt_13m_ck_data = {
+ .frequency = 13000000,
+};
+
+static struct ti_clk virt_13m_ck = {
+ .name = "virt_13m_ck",
+ .type = TI_CLK_FIXED,
+ .data = &virt_13m_ck_data,
+};
+
+static struct ti_clk_fixed virt_19200000_ck_data = {
+ .frequency = 19200000,
+};
+
+static struct ti_clk virt_19200000_ck = {
+ .name = "virt_19200000_ck",
+ .type = TI_CLK_FIXED,
+ .data = &virt_19200000_ck_data,
+};
+
+static struct ti_clk_fixed virt_26000000_ck_data = {
+ .frequency = 26000000,
+};
+
+static struct ti_clk virt_26000000_ck = {
+ .name = "virt_26000000_ck",
+ .type = TI_CLK_FIXED,
+ .data = &virt_26000000_ck_data,
+};
+
+static struct ti_clk_fixed virt_38_4m_ck_data = {
+ .frequency = 38400000,
+};
+
+static struct ti_clk virt_38_4m_ck = {
+ .name = "virt_38_4m_ck",
+ .type = TI_CLK_FIXED,
+ .data = &virt_38_4m_ck_data,
+};
+
+static struct ti_clk_fixed virt_16_8m_ck_data = {
+ .frequency = 16800000,
+};
+
+static struct ti_clk virt_16_8m_ck = {
+ .name = "virt_16_8m_ck",
+ .type = TI_CLK_FIXED,
+ .data = &virt_16_8m_ck_data,
+};
+
+static const char *osc_sys_ck_parents[] = {
+ "virt_12m_ck",
+ "virt_13m_ck",
+ "virt_19200000_ck",
+ "virt_26000000_ck",
+ "virt_38_4m_ck",
+ "virt_16_8m_ck",
+};
+
+static struct ti_clk_mux osc_sys_ck_data = {
+ .num_parents = ARRAY_SIZE(osc_sys_ck_parents),
+ .reg = 0xd40,
+ .module = TI_CLKM_PRM,
+ .parents = osc_sys_ck_parents,
+};
+
+static struct ti_clk osc_sys_ck = {
+ .name = "osc_sys_ck",
+ .type = TI_CLK_MUX,
+ .data = &osc_sys_ck_data,
+};
+
+static struct ti_clk_divider sys_ck_data = {
+ .parent = "osc_sys_ck",
+ .bit_shift = 6,
+ .max_div = 3,
+ .reg = 0x1270,
+ .module = TI_CLKM_PRM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk sys_ck = {
+ .name = "sys_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &sys_ck_data,
+};
+
+static const char *dpll3_ck_parents[] = {
+ "sys_ck",
+ "sys_ck",
+};
+
+static struct ti_clk_dpll dpll3_ck_data = {
+ .num_parents = ARRAY_SIZE(dpll3_ck_parents),
+ .control_reg = 0xd00,
+ .idlest_reg = 0xd20,
+ .mult_div1_reg = 0xd40,
+ .autoidle_reg = 0xd30,
+ .module = TI_CLKM_CM,
+ .parents = dpll3_ck_parents,
+ .flags = CLKF_CORE,
+ .freqsel_mask = 0xf0,
+ .div1_mask = 0x7f00,
+ .idlest_mask = 0x1,
+ .auto_recal_bit = 0x3,
+ .max_divider = 0x80,
+ .min_divider = 0x1,
+ .recal_en_bit = 0x5,
+ .max_multiplier = 0x7ff,
+ .enable_mask = 0x7,
+ .mult_mask = 0x7ff0000,
+ .recal_st_bit = 0x5,
+ .autoidle_mask = 0x7,
+};
+
+static struct ti_clk dpll3_ck = {
+ .name = "dpll3_ck",
+ .clkdm_name = "dpll3_clkdm",
+ .type = TI_CLK_DPLL,
+ .data = &dpll3_ck_data,
+};
+
+static struct ti_clk_divider dpll3_m2_ck_data = {
+ .parent = "dpll3_ck",
+ .bit_shift = 27,
+ .max_div = 31,
+ .reg = 0xd40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll3_m2_ck = {
+ .name = "dpll3_m2_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll3_m2_ck_data,
+};
+
+static struct ti_clk_fixed_factor core_ck_data = {
+ .parent = "dpll3_m2_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk core_ck = {
+ .name = "core_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_ck_data,
+};
+
+static struct ti_clk_divider l3_ick_data = {
+ .parent = "core_ck",
+ .max_div = 3,
+ .reg = 0xa40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk l3_ick = {
+ .name = "l3_ick",
+ .type = TI_CLK_DIVIDER,
+ .data = &l3_ick_data,
+};
+
+static struct ti_clk_fixed_factor security_l3_ick_data = {
+ .parent = "l3_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk security_l3_ick = {
+ .name = "security_l3_ick",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &security_l3_ick_data,
+};
+
+static struct ti_clk_fixed_factor wkup_l4_ick_data = {
+ .parent = "sys_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk wkup_l4_ick = {
+ .name = "wkup_l4_ick",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &wkup_l4_ick_data,
+};
+
+static struct ti_clk_gate usim_ick_data = {
+ .parent = "wkup_l4_ick",
+ .bit_shift = 9,
+ .reg = 0xc10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk usim_ick = {
+ .name = "usim_ick",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &usim_ick_data,
+};
+
+static struct ti_clk_gate dss2_alwon_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 1,
+ .reg = 0xe00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk dss2_alwon_fck = {
+ .name = "dss2_alwon_fck",
+ .clkdm_name = "dss_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &dss2_alwon_fck_data,
+};
+
+static struct ti_clk_divider l4_ick_data = {
+ .parent = "l3_ick",
+ .bit_shift = 2,
+ .max_div = 3,
+ .reg = 0xa40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk l4_ick = {
+ .name = "l4_ick",
+ .type = TI_CLK_DIVIDER,
+ .data = &l4_ick_data,
+};
+
+static struct ti_clk_fixed_factor core_l4_ick_data = {
+ .parent = "l4_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk core_l4_ick = {
+ .name = "core_l4_ick",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_l4_ick_data,
+};
+
+static struct ti_clk_gate mmchs2_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 25,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mmchs2_ick = {
+ .name = "mmchs2_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mmchs2_ick_data,
+};
+
+static const char *dpll4_ck_parents[] = {
+ "sys_ck",
+ "sys_ck",
+};
+
+static struct ti_clk_dpll dpll4_ck_data = {
+ .num_parents = ARRAY_SIZE(dpll4_ck_parents),
+ .control_reg = 0xd00,
+ .idlest_reg = 0xd20,
+ .mult_div1_reg = 0xd44,
+ .autoidle_reg = 0xd30,
+ .module = TI_CLKM_CM,
+ .parents = dpll4_ck_parents,
+ .flags = CLKF_PER,
+ .freqsel_mask = 0xf00000,
+ .modes = 0x82,
+ .div1_mask = 0x7f,
+ .idlest_mask = 0x2,
+ .auto_recal_bit = 0x13,
+ .max_divider = 0x80,
+ .min_divider = 0x1,
+ .recal_en_bit = 0x6,
+ .max_multiplier = 0x7ff,
+ .enable_mask = 0x70000,
+ .mult_mask = 0x7ff00,
+ .recal_st_bit = 0x6,
+ .autoidle_mask = 0x38,
+};
+
+static struct ti_clk dpll4_ck = {
+ .name = "dpll4_ck",
+ .clkdm_name = "dpll4_clkdm",
+ .type = TI_CLK_DPLL,
+ .data = &dpll4_ck_data,
+};
+
+static struct ti_clk_divider dpll4_m2_ck_data = {
+ .parent = "dpll4_ck",
+ .max_div = 63,
+ .reg = 0xd48,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll4_m2_ck = {
+ .name = "dpll4_m2_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll4_m2_ck_data,
+};
+
+static struct ti_clk_fixed_factor dpll4_m2x2_mul_ck_data = {
+ .parent = "dpll4_m2_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll4_m2x2_mul_ck = {
+ .name = "dpll4_m2x2_mul_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll4_m2x2_mul_ck_data,
+};
+
+static struct ti_clk_gate dpll4_m2x2_ck_data = {
+ .parent = "dpll4_m2x2_mul_ck",
+ .bit_shift = 0x1b,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m2x2_ck = {
+ .name = "dpll4_m2x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m2x2_ck_data,
+};
+
+static struct ti_clk_fixed_factor omap_96m_alwon_fck_data = {
+ .parent = "dpll4_m2x2_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk omap_96m_alwon_fck = {
+ .name = "omap_96m_alwon_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &omap_96m_alwon_fck_data,
+};
+
+static struct ti_clk_fixed_factor cm_96m_fck_data = {
+ .parent = "omap_96m_alwon_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk cm_96m_fck = {
+ .name = "cm_96m_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &cm_96m_fck_data,
+};
+
+static const char *omap_96m_fck_parents[] = {
+ "cm_96m_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux omap_96m_fck_data = {
+ .bit_shift = 6,
+ .num_parents = ARRAY_SIZE(omap_96m_fck_parents),
+ .reg = 0xd40,
+ .module = TI_CLKM_CM,
+ .parents = omap_96m_fck_parents,
+};
+
+static struct ti_clk omap_96m_fck = {
+ .name = "omap_96m_fck",
+ .type = TI_CLK_MUX,
+ .data = &omap_96m_fck_data,
+};
+
+static struct ti_clk_fixed_factor core_96m_fck_data = {
+ .parent = "omap_96m_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk core_96m_fck = {
+ .name = "core_96m_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_96m_fck_data,
+};
+
+static struct ti_clk_gate mspro_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 23,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mspro_fck = {
+ .name = "mspro_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mspro_fck_data,
+};
+
+static struct ti_clk_gate dss_ick_3430es2_data = {
+ .parent = "l4_ick",
+ .bit_shift = 0,
+ .reg = 0xe10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_DSS | CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk dss_ick_3430es2 = {
+ .name = "dss_ick",
+ .clkdm_name = "dss_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &dss_ick_3430es2_data,
+};
+
+static struct ti_clk_gate uart4_ick_am35xx_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 23,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk uart4_ick_am35xx = {
+ .name = "uart4_ick_am35xx",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart4_ick_am35xx_data,
+};
+
+static struct ti_clk_fixed_factor security_l4_ick2_data = {
+ .parent = "l4_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk security_l4_ick2 = {
+ .name = "security_l4_ick2",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &security_l4_ick2_data,
+};
+
+static struct ti_clk_gate aes1_ick_data = {
+ .parent = "security_l4_ick2",
+ .bit_shift = 3,
+ .reg = 0xa14,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk aes1_ick = {
+ .name = "aes1_ick",
+ .type = TI_CLK_GATE,
+ .data = &aes1_ick_data,
+};
+
+static const char *dpll5_ck_parents[] = {
+ "sys_ck",
+ "sys_ck",
+};
+
+static struct ti_clk_dpll dpll5_ck_data = {
+ .num_parents = ARRAY_SIZE(dpll5_ck_parents),
+ .control_reg = 0xd04,
+ .idlest_reg = 0xd24,
+ .mult_div1_reg = 0xd4c,
+ .autoidle_reg = 0xd34,
+ .module = TI_CLKM_CM,
+ .parents = dpll5_ck_parents,
+ .freqsel_mask = 0xf0,
+ .modes = 0x82,
+ .div1_mask = 0x7f,
+ .idlest_mask = 0x1,
+ .auto_recal_bit = 0x3,
+ .max_divider = 0x80,
+ .min_divider = 0x1,
+ .recal_en_bit = 0x19,
+ .max_multiplier = 0x7ff,
+ .enable_mask = 0x7,
+ .mult_mask = 0x7ff00,
+ .recal_st_bit = 0x19,
+ .autoidle_mask = 0x7,
+};
+
+static struct ti_clk dpll5_ck = {
+ .name = "dpll5_ck",
+ .clkdm_name = "dpll5_clkdm",
+ .type = TI_CLK_DPLL,
+ .data = &dpll5_ck_data,
+};
+
+static struct ti_clk_divider dpll5_m2_ck_data = {
+ .parent = "dpll5_ck",
+ .max_div = 31,
+ .reg = 0xd50,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll5_m2_ck = {
+ .name = "dpll5_m2_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll5_m2_ck_data,
+};
+
+static struct ti_clk_gate usbhost_120m_fck_data = {
+ .parent = "dpll5_m2_ck",
+ .bit_shift = 1,
+ .reg = 0x1400,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk usbhost_120m_fck = {
+ .name = "usbhost_120m_fck",
+ .clkdm_name = "usbhost_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &usbhost_120m_fck_data,
+};
+
+static struct ti_clk_fixed_factor cm_96m_d2_fck_data = {
+ .parent = "cm_96m_fck",
+ .div = 2,
+ .mult = 1,
+};
+
+static struct ti_clk cm_96m_d2_fck = {
+ .name = "cm_96m_d2_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &cm_96m_d2_fck_data,
+};
+
+static struct ti_clk_fixed sys_altclk_data = {
+ .frequency = 0x0,
+};
+
+static struct ti_clk sys_altclk = {
+ .name = "sys_altclk",
+ .type = TI_CLK_FIXED,
+ .data = &sys_altclk_data,
+};
+
+static const char *omap_48m_fck_parents[] = {
+ "cm_96m_d2_fck",
+ "sys_altclk",
+};
+
+static struct ti_clk_mux omap_48m_fck_data = {
+ .bit_shift = 3,
+ .num_parents = ARRAY_SIZE(omap_48m_fck_parents),
+ .reg = 0xd40,
+ .module = TI_CLKM_CM,
+ .parents = omap_48m_fck_parents,
+};
+
+static struct ti_clk omap_48m_fck = {
+ .name = "omap_48m_fck",
+ .type = TI_CLK_MUX,
+ .data = &omap_48m_fck_data,
+};
+
+static struct ti_clk_fixed_factor core_48m_fck_data = {
+ .parent = "omap_48m_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk core_48m_fck = {
+ .name = "core_48m_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_48m_fck_data,
+};
+
+static struct ti_clk_fixed mcbsp_clks_data = {
+ .frequency = 0x0,
+};
+
+static struct ti_clk mcbsp_clks = {
+ .name = "mcbsp_clks",
+ .type = TI_CLK_FIXED,
+ .data = &mcbsp_clks_data,
+};
+
+static struct ti_clk_gate mcbsp2_gate_fck_data = {
+ .parent = "mcbsp_clks",
+ .bit_shift = 0,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_fixed_factor per_96m_fck_data = {
+ .parent = "omap_96m_alwon_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk per_96m_fck = {
+ .name = "per_96m_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &per_96m_fck_data,
+};
+
+static const char *mcbsp2_mux_fck_parents[] = {
+ "per_96m_fck",
+ "mcbsp_clks",
+};
+
+static struct ti_clk_mux mcbsp2_mux_fck_data = {
+ .bit_shift = 6,
+ .num_parents = ARRAY_SIZE(mcbsp2_mux_fck_parents),
+ .reg = 0x274,
+ .module = TI_CLKM_SCRM,
+ .parents = mcbsp2_mux_fck_parents,
+};
+
+static struct ti_clk_composite mcbsp2_fck_data = {
+ .mux = &mcbsp2_mux_fck_data,
+ .gate = &mcbsp2_gate_fck_data,
+};
+
+static struct ti_clk mcbsp2_fck = {
+ .name = "mcbsp2_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &mcbsp2_fck_data,
+};
+
+static struct ti_clk_fixed_factor dpll3_m2x2_ck_data = {
+ .parent = "dpll3_m2_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll3_m2x2_ck = {
+ .name = "dpll3_m2x2_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll3_m2x2_ck_data,
+};
+
+static struct ti_clk_fixed_factor corex2_fck_data = {
+ .parent = "dpll3_m2x2_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk corex2_fck = {
+ .name = "corex2_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &corex2_fck_data,
+};
+
+static struct ti_clk_gate ssi_ssr_gate_fck_3430es1_data = {
+ .parent = "corex2_fck",
+ .bit_shift = 0,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_NO_WAIT,
+};
+
+static int ssi_ssr_div_fck_3430es1_divs[] = {
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 0,
+ 6,
+ 0,
+ 8,
+};
+
+static struct ti_clk_divider ssi_ssr_div_fck_3430es1_data = {
+ .num_dividers = ARRAY_SIZE(ssi_ssr_div_fck_3430es1_divs),
+ .parent = "corex2_fck",
+ .bit_shift = 8,
+ .dividers = ssi_ssr_div_fck_3430es1_divs,
+ .reg = 0xa40,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_composite ssi_ssr_fck_3430es1_data = {
+ .gate = &ssi_ssr_gate_fck_3430es1_data,
+ .divider = &ssi_ssr_div_fck_3430es1_data,
+};
+
+static struct ti_clk ssi_ssr_fck_3430es1 = {
+ .name = "ssi_ssr_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &ssi_ssr_fck_3430es1_data,
+};
+
+static struct ti_clk_fixed_factor ssi_sst_fck_3430es1_data = {
+ .parent = "ssi_ssr_fck",
+ .div = 2,
+ .mult = 1,
+};
+
+static struct ti_clk ssi_sst_fck_3430es1 = {
+ .name = "ssi_sst_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &ssi_sst_fck_3430es1_data,
+};
+
+static struct ti_clk_fixed omap_32k_fck_data = {
+ .frequency = 32768,
+};
+
+static struct ti_clk omap_32k_fck = {
+ .name = "omap_32k_fck",
+ .type = TI_CLK_FIXED,
+ .data = &omap_32k_fck_data,
+};
+
+static struct ti_clk_fixed_factor per_32k_alwon_fck_data = {
+ .parent = "omap_32k_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk per_32k_alwon_fck = {
+ .name = "per_32k_alwon_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &per_32k_alwon_fck_data,
+};
+
+static struct ti_clk_gate gpio5_dbck_data = {
+ .parent = "per_32k_alwon_fck",
+ .bit_shift = 16,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk gpio5_dbck = {
+ .name = "gpio5_dbck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio5_dbck_data,
+};
+
+static struct ti_clk_gate gpt1_ick_data = {
+ .parent = "wkup_l4_ick",
+ .bit_shift = 0,
+ .reg = 0xc10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt1_ick = {
+ .name = "gpt1_ick",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt1_ick_data,
+};
+
+static struct ti_clk_gate mcspi3_fck_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 20,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mcspi3_fck = {
+ .name = "mcspi3_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi3_fck_data,
+};
+
+static struct ti_clk_gate gpt2_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 3,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static const char *gpt2_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt2_mux_fck_data = {
+ .num_parents = ARRAY_SIZE(gpt2_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt2_mux_fck_parents,
+};
+
+static struct ti_clk_composite gpt2_fck_data = {
+ .mux = &gpt2_mux_fck_data,
+ .gate = &gpt2_gate_fck_data,
+};
+
+static struct ti_clk gpt2_fck = {
+ .name = "gpt2_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt2_fck_data,
+};
+
+static struct ti_clk_gate gpt10_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 11,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt10_ick = {
+ .name = "gpt10_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt10_ick_data,
+};
+
+static struct ti_clk_gate uart2_fck_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 14,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk uart2_fck = {
+ .name = "uart2_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart2_fck_data,
+};
+
+static struct ti_clk_fixed_factor sr_l4_ick_data = {
+ .parent = "l4_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk sr_l4_ick = {
+ .name = "sr_l4_ick",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &sr_l4_ick_data,
+};
+
+static struct ti_clk_fixed_factor omap_96m_d8_fck_data = {
+ .parent = "omap_96m_fck",
+ .div = 8,
+ .mult = 1,
+};
+
+static struct ti_clk omap_96m_d8_fck = {
+ .name = "omap_96m_d8_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &omap_96m_d8_fck_data,
+};
+
+static struct ti_clk_divider dpll4_m5_ck_data = {
+ .parent = "dpll4_ck",
+ .max_div = 63,
+ .reg = 0xf40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll4_m5_ck = {
+ .name = "dpll4_m5_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll4_m5_ck_data,
+};
+
+static struct ti_clk_fixed_factor dpll4_m5x2_mul_ck_data = {
+ .parent = "dpll4_m5_ck",
+ .div = 1,
+ .mult = 2,
+ .flags = CLKF_SET_RATE_PARENT,
+};
+
+static struct ti_clk dpll4_m5x2_mul_ck = {
+ .name = "dpll4_m5x2_mul_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll4_m5x2_mul_ck_data,
+};
+
+static struct ti_clk_gate dpll4_m5x2_ck_data = {
+ .parent = "dpll4_m5x2_mul_ck",
+ .bit_shift = 0x1e,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m5x2_ck = {
+ .name = "dpll4_m5x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m5x2_ck_data,
+};
+
+static struct ti_clk_gate cam_mclk_data = {
+ .parent = "dpll4_m5x2_ck",
+ .bit_shift = 0,
+ .reg = 0xf00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_RATE_PARENT,
+};
+
+static struct ti_clk cam_mclk = {
+ .name = "cam_mclk",
+ .type = TI_CLK_GATE,
+ .data = &cam_mclk_data,
+};
+
+static struct ti_clk_gate mcbsp3_gate_fck_data = {
+ .parent = "mcbsp_clks",
+ .bit_shift = 1,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static const char *mcbsp3_mux_fck_parents[] = {
+ "per_96m_fck",
+ "mcbsp_clks",
+};
+
+static struct ti_clk_mux mcbsp3_mux_fck_data = {
+ .num_parents = ARRAY_SIZE(mcbsp3_mux_fck_parents),
+ .reg = 0x2d8,
+ .module = TI_CLKM_SCRM,
+ .parents = mcbsp3_mux_fck_parents,
+};
+
+static struct ti_clk_composite mcbsp3_fck_data = {
+ .mux = &mcbsp3_mux_fck_data,
+ .gate = &mcbsp3_gate_fck_data,
+};
+
+static struct ti_clk mcbsp3_fck = {
+ .name = "mcbsp3_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &mcbsp3_fck_data,
+};
+
+static struct ti_clk_gate csi2_96m_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 1,
+ .reg = 0xf00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk csi2_96m_fck = {
+ .name = "csi2_96m_fck",
+ .clkdm_name = "cam_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &csi2_96m_fck_data,
+};
+
+static struct ti_clk_gate gpt9_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 10,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static const char *gpt9_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt9_mux_fck_data = {
+ .bit_shift = 7,
+ .num_parents = ARRAY_SIZE(gpt9_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt9_mux_fck_parents,
+};
+
+static struct ti_clk_composite gpt9_fck_data = {
+ .mux = &gpt9_mux_fck_data,
+ .gate = &gpt9_gate_fck_data,
+};
+
+static struct ti_clk gpt9_fck = {
+ .name = "gpt9_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt9_fck_data,
+};
+
+static struct ti_clk_divider dpll3_m3_ck_data = {
+ .parent = "dpll3_ck",
+ .bit_shift = 16,
+ .max_div = 31,
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll3_m3_ck = {
+ .name = "dpll3_m3_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll3_m3_ck_data,
+};
+
+static struct ti_clk_fixed_factor dpll3_m3x2_mul_ck_data = {
+ .parent = "dpll3_m3_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll3_m3x2_mul_ck = {
+ .name = "dpll3_m3x2_mul_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll3_m3x2_mul_ck_data,
+};
+
+static struct ti_clk_gate sr2_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 7,
+ .reg = 0xc00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk sr2_fck = {
+ .name = "sr2_fck",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &sr2_fck_data,
+};
+
+static struct ti_clk_fixed pclk_ck_data = {
+ .frequency = 27000000,
+};
+
+static struct ti_clk pclk_ck = {
+ .name = "pclk_ck",
+ .type = TI_CLK_FIXED,
+ .data = &pclk_ck_data,
+};
+
+static struct ti_clk_gate wdt2_ick_data = {
+ .parent = "wkup_l4_ick",
+ .bit_shift = 5,
+ .reg = 0xc10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk wdt2_ick = {
+ .name = "wdt2_ick",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &wdt2_ick_data,
+};
+
+static struct ti_clk_fixed_factor core_l3_ick_data = {
+ .parent = "l3_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk core_l3_ick = {
+ .name = "core_l3_ick",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_l3_ick_data,
+};
+
+static struct ti_clk_gate mcspi4_fck_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 21,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mcspi4_fck = {
+ .name = "mcspi4_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi4_fck_data,
+};
+
+static struct ti_clk_fixed_factor per_48m_fck_data = {
+ .parent = "omap_48m_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk per_48m_fck = {
+ .name = "per_48m_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &per_48m_fck_data,
+};
+
+static struct ti_clk_gate uart4_fck_data = {
+ .parent = "per_48m_fck",
+ .bit_shift = 18,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk uart4_fck = {
+ .name = "uart4_fck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart4_fck_data,
+};
+
+static struct ti_clk_fixed_factor omap_96m_d10_fck_data = {
+ .parent = "omap_96m_fck",
+ .div = 10,
+ .mult = 1,
+};
+
+static struct ti_clk omap_96m_d10_fck = {
+ .name = "omap_96m_d10_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &omap_96m_d10_fck_data,
+};
+
+static struct ti_clk_gate usim_gate_fck_data = {
+ .parent = "omap_96m_fck",
+ .bit_shift = 9,
+ .reg = 0xc00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_fixed_factor per_l4_ick_data = {
+ .parent = "l4_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk per_l4_ick = {
+ .name = "per_l4_ick",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &per_l4_ick_data,
+};
+
+static struct ti_clk_gate gpt5_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 6,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt5_ick = {
+ .name = "gpt5_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt5_ick_data,
+};
+
+static struct ti_clk_gate mcspi2_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 19,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcspi2_ick = {
+ .name = "mcspi2_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi2_ick_data,
+};
+
+static struct ti_clk_fixed_factor ssi_l4_ick_data = {
+ .parent = "l4_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk ssi_l4_ick = {
+ .name = "ssi_l4_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &ssi_l4_ick_data,
+};
+
+static struct ti_clk_gate ssi_ick_3430es1_data = {
+ .parent = "ssi_l4_ick",
+ .bit_shift = 0,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_NO_WAIT | CLKF_INTERFACE,
+};
+
+static struct ti_clk ssi_ick_3430es1 = {
+ .name = "ssi_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &ssi_ick_3430es1_data,
+};
+
+static struct ti_clk_gate i2c2_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 16,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk i2c2_fck = {
+ .name = "i2c2_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &i2c2_fck_data,
+};
+
+static struct ti_clk_divider dpll1_fck_data = {
+ .parent = "core_ck",
+ .bit_shift = 19,
+ .max_div = 7,
+ .reg = 0x940,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll1_fck = {
+ .name = "dpll1_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll1_fck_data,
+};
+
+static const char *dpll1_ck_parents[] = {
+ "sys_ck",
+ "dpll1_fck",
+};
+
+static struct ti_clk_dpll dpll1_ck_data = {
+ .num_parents = ARRAY_SIZE(dpll1_ck_parents),
+ .control_reg = 0x904,
+ .idlest_reg = 0x924,
+ .mult_div1_reg = 0x940,
+ .autoidle_reg = 0x934,
+ .module = TI_CLKM_CM,
+ .parents = dpll1_ck_parents,
+ .freqsel_mask = 0xf0,
+ .modes = 0xa0,
+ .div1_mask = 0x7f,
+ .idlest_mask = 0x1,
+ .auto_recal_bit = 0x3,
+ .max_divider = 0x80,
+ .min_divider = 0x1,
+ .recal_en_bit = 0x7,
+ .max_multiplier = 0x7ff,
+ .enable_mask = 0x7,
+ .mult_mask = 0x7ff00,
+ .recal_st_bit = 0x7,
+ .autoidle_mask = 0x7,
+};
+
+static struct ti_clk dpll1_ck = {
+ .name = "dpll1_ck",
+ .clkdm_name = "dpll1_clkdm",
+ .type = TI_CLK_DPLL,
+ .data = &dpll1_ck_data,
+};
+
+static struct ti_clk_fixed secure_32k_fck_data = {
+ .frequency = 32768,
+};
+
+static struct ti_clk secure_32k_fck = {
+ .name = "secure_32k_fck",
+ .type = TI_CLK_FIXED,
+ .data = &secure_32k_fck_data,
+};
+
+static struct ti_clk_gate gpio5_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 16,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpio5_ick = {
+ .name = "gpio5_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio5_ick_data,
+};
+
+static struct ti_clk_divider dpll4_m4_ck_data = {
+ .parent = "dpll4_ck",
+ .max_div = 32,
+ .reg = 0xe40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll4_m4_ck = {
+ .name = "dpll4_m4_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll4_m4_ck_data,
+};
+
+static struct ti_clk_fixed_factor dpll4_m4x2_mul_ck_data = {
+ .parent = "dpll4_m4_ck",
+ .div = 1,
+ .mult = 2,
+ .flags = CLKF_SET_RATE_PARENT,
+};
+
+static struct ti_clk dpll4_m4x2_mul_ck = {
+ .name = "dpll4_m4x2_mul_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll4_m4x2_mul_ck_data,
+};
+
+static struct ti_clk_gate dpll4_m4x2_ck_data = {
+ .parent = "dpll4_m4x2_mul_ck",
+ .bit_shift = 0x1d,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_RATE_PARENT | CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m4x2_ck = {
+ .name = "dpll4_m4x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m4x2_ck_data,
+};
+
+static struct ti_clk_gate dss1_alwon_fck_3430es2_data = {
+ .parent = "dpll4_m4x2_ck",
+ .bit_shift = 0,
+ .reg = 0xe00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_DSS | CLKF_SET_RATE_PARENT,
+};
+
+static struct ti_clk dss1_alwon_fck_3430es2 = {
+ .name = "dss1_alwon_fck",
+ .clkdm_name = "dss_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &dss1_alwon_fck_3430es2_data,
+};
+
+static struct ti_clk_gate uart3_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 11,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk uart3_ick = {
+ .name = "uart3_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart3_ick_data,
+};
+
+static struct ti_clk_divider dpll4_m3_ck_data = {
+ .parent = "dpll4_ck",
+ .bit_shift = 8,
+ .max_div = 32,
+ .reg = 0xe40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll4_m3_ck = {
+ .name = "dpll4_m3_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll4_m3_ck_data,
+};
+
+static struct ti_clk_gate mcbsp3_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 1,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcbsp3_ick = {
+ .name = "mcbsp3_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcbsp3_ick_data,
+};
+
+static struct ti_clk_gate gpio3_dbck_data = {
+ .parent = "per_32k_alwon_fck",
+ .bit_shift = 14,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk gpio3_dbck = {
+ .name = "gpio3_dbck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio3_dbck_data,
+};
+
+static struct ti_clk_gate fac_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 8,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk fac_ick = {
+ .name = "fac_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &fac_ick_data,
+};
+
+static struct ti_clk_gate clkout2_src_gate_ck_data = {
+ .parent = "core_ck",
+ .bit_shift = 7,
+ .reg = 0xd70,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_NO_WAIT,
+};
+
+static struct ti_clk_fixed_factor dpll4_m3x2_mul_ck_data = {
+ .parent = "dpll4_m3_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll4_m3x2_mul_ck = {
+ .name = "dpll4_m3x2_mul_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll4_m3x2_mul_ck_data,
+};
+
+static struct ti_clk_gate dpll4_m3x2_ck_data = {
+ .parent = "dpll4_m3x2_mul_ck",
+ .bit_shift = 0x1c,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m3x2_ck = {
+ .name = "dpll4_m3x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m3x2_ck_data,
+};
+
+static const char *omap_54m_fck_parents[] = {
+ "dpll4_m3x2_ck",
+ "sys_altclk",
+};
+
+static struct ti_clk_mux omap_54m_fck_data = {
+ .bit_shift = 5,
+ .num_parents = ARRAY_SIZE(omap_54m_fck_parents),
+ .reg = 0xd40,
+ .module = TI_CLKM_CM,
+ .parents = omap_54m_fck_parents,
+};
+
+static struct ti_clk omap_54m_fck = {
+ .name = "omap_54m_fck",
+ .type = TI_CLK_MUX,
+ .data = &omap_54m_fck_data,
+};
+
+static const char *clkout2_src_mux_ck_parents[] = {
+ "core_ck",
+ "sys_ck",
+ "cm_96m_fck",
+ "omap_54m_fck",
+};
+
+static struct ti_clk_mux clkout2_src_mux_ck_data = {
+ .num_parents = ARRAY_SIZE(clkout2_src_mux_ck_parents),
+ .reg = 0xd70,
+ .module = TI_CLKM_CM,
+ .parents = clkout2_src_mux_ck_parents,
+};
+
+static struct ti_clk_composite clkout2_src_ck_data = {
+ .mux = &clkout2_src_mux_ck_data,
+ .gate = &clkout2_src_gate_ck_data,
+};
+
+static struct ti_clk clkout2_src_ck = {
+ .name = "clkout2_src_ck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &clkout2_src_ck_data,
+};
+
+static struct ti_clk_gate i2c1_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 15,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk i2c1_fck = {
+ .name = "i2c1_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &i2c1_fck_data,
+};
+
+static struct ti_clk_gate wdt3_fck_data = {
+ .parent = "per_32k_alwon_fck",
+ .bit_shift = 12,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk wdt3_fck = {
+ .name = "wdt3_fck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &wdt3_fck_data,
+};
+
+static struct ti_clk_gate gpt7_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 8,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static const char *gpt7_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt7_mux_fck_data = {
+ .bit_shift = 5,
+ .num_parents = ARRAY_SIZE(gpt7_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt7_mux_fck_parents,
+};
+
+static struct ti_clk_composite gpt7_fck_data = {
+ .mux = &gpt7_mux_fck_data,
+ .gate = &gpt7_gate_fck_data,
+};
+
+static struct ti_clk gpt7_fck = {
+ .name = "gpt7_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt7_fck_data,
+};
+
+static struct ti_clk_gate usb_l4_gate_ick_data = {
+ .parent = "l4_ick",
+ .bit_shift = 5,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INTERFACE,
+};
+
+static struct ti_clk_divider usb_l4_div_ick_data = {
+ .parent = "l4_ick",
+ .bit_shift = 4,
+ .max_div = 1,
+ .reg = 0xa40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk_composite usb_l4_ick_data = {
+ .gate = &usb_l4_gate_ick_data,
+ .divider = &usb_l4_div_ick_data,
+};
+
+static struct ti_clk usb_l4_ick = {
+ .name = "usb_l4_ick",
+ .type = TI_CLK_COMPOSITE,
+ .data = &usb_l4_ick_data,
+};
+
+static struct ti_clk_gate uart4_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 18,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk uart4_ick = {
+ .name = "uart4_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart4_ick_data,
+};
+
+static struct ti_clk_fixed dummy_ck_data = {
+ .frequency = 0,
+};
+
+static struct ti_clk dummy_ck = {
+ .name = "dummy_ck",
+ .type = TI_CLK_FIXED,
+ .data = &dummy_ck_data,
+};
+
+static const char *gpt3_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt3_mux_fck_data = {
+ .bit_shift = 1,
+ .num_parents = ARRAY_SIZE(gpt3_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt3_mux_fck_parents,
+};
+
+static struct ti_clk_gate gpt9_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 10,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt9_ick = {
+ .name = "gpt9_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt9_ick_data,
+};
+
+static struct ti_clk_gate gpt10_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 11,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_gate dss_ick_3430es1_data = {
+ .parent = "l4_ick",
+ .bit_shift = 0,
+ .reg = 0xe10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_NO_WAIT | CLKF_INTERFACE,
+};
+
+static struct ti_clk dss_ick_3430es1 = {
+ .name = "dss_ick",
+ .clkdm_name = "dss_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &dss_ick_3430es1_data,
+};
+
+static struct ti_clk_gate gpt11_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 12,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt11_ick = {
+ .name = "gpt11_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt11_ick_data,
+};
+
+static struct ti_clk_divider dpll2_fck_data = {
+ .parent = "core_ck",
+ .bit_shift = 19,
+ .max_div = 7,
+ .reg = 0x40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll2_fck = {
+ .name = "dpll2_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll2_fck_data,
+};
+
+static struct ti_clk_gate uart1_fck_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 13,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk uart1_fck = {
+ .name = "uart1_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart1_fck_data,
+};
+
+static struct ti_clk_gate hsotgusb_ick_3430es1_data = {
+ .parent = "core_l3_ick",
+ .bit_shift = 4,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_NO_WAIT | CLKF_INTERFACE,
+};
+
+static struct ti_clk hsotgusb_ick_3430es1 = {
+ .name = "hsotgusb_ick_3430es1",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &hsotgusb_ick_3430es1_data,
+};
+
+static struct ti_clk_gate gpio2_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 13,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpio2_ick = {
+ .name = "gpio2_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio2_ick_data,
+};
+
+static struct ti_clk_gate mmchs1_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 24,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mmchs1_ick = {
+ .name = "mmchs1_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mmchs1_ick_data,
+};
+
+static struct ti_clk_gate modem_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 31,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk modem_fck = {
+ .name = "modem_fck",
+ .clkdm_name = "d2d_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &modem_fck_data,
+};
+
+static struct ti_clk_gate mcbsp4_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 2,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcbsp4_ick = {
+ .name = "mcbsp4_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcbsp4_ick_data,
+};
+
+static struct ti_clk_gate gpio1_ick_data = {
+ .parent = "wkup_l4_ick",
+ .bit_shift = 3,
+ .reg = 0xc10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpio1_ick = {
+ .name = "gpio1_ick",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio1_ick_data,
+};
+
+static const char *gpt6_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt6_mux_fck_data = {
+ .bit_shift = 4,
+ .num_parents = ARRAY_SIZE(gpt6_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt6_mux_fck_parents,
+};
+
+static struct ti_clk_fixed_factor dpll1_x2_ck_data = {
+ .parent = "dpll1_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll1_x2_ck = {
+ .name = "dpll1_x2_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll1_x2_ck_data,
+};
+
+static struct ti_clk_divider dpll1_x2m2_ck_data = {
+ .parent = "dpll1_x2_ck",
+ .max_div = 31,
+ .reg = 0x944,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll1_x2m2_ck = {
+ .name = "dpll1_x2m2_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll1_x2m2_ck_data,
+};
+
+static struct ti_clk_fixed_factor mpu_ck_data = {
+ .parent = "dpll1_x2m2_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk mpu_ck = {
+ .name = "mpu_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &mpu_ck_data,
+};
+
+static struct ti_clk_divider arm_fck_data = {
+ .parent = "mpu_ck",
+ .max_div = 2,
+ .reg = 0x924,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk arm_fck = {
+ .name = "arm_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &arm_fck_data,
+};
+
+static struct ti_clk_fixed_factor core_d3_ck_data = {
+ .parent = "core_ck",
+ .div = 3,
+ .mult = 1,
+};
+
+static struct ti_clk core_d3_ck = {
+ .name = "core_d3_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_d3_ck_data,
+};
+
+static struct ti_clk_gate gpt11_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 12,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+};
+
+static const char *gpt11_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt11_mux_fck_data = {
+ .bit_shift = 7,
+ .num_parents = ARRAY_SIZE(gpt11_mux_fck_parents),
+ .reg = 0xa40,
+ .module = TI_CLKM_CM,
+ .parents = gpt11_mux_fck_parents,
+};
+
+static struct ti_clk_composite gpt11_fck_data = {
+ .mux = &gpt11_mux_fck_data,
+ .gate = &gpt11_gate_fck_data,
+};
+
+static struct ti_clk gpt11_fck = {
+ .name = "gpt11_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt11_fck_data,
+};
+
+static struct ti_clk_fixed_factor core_d6_ck_data = {
+ .parent = "core_ck",
+ .div = 6,
+ .mult = 1,
+};
+
+static struct ti_clk core_d6_ck = {
+ .name = "core_d6_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_d6_ck_data,
+};
+
+static struct ti_clk_gate uart4_fck_am35xx_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 23,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk uart4_fck_am35xx = {
+ .name = "uart4_fck_am35xx",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart4_fck_am35xx_data,
+};
+
+static struct ti_clk_gate dpll3_m3x2_ck_data = {
+ .parent = "dpll3_m3x2_mul_ck",
+ .bit_shift = 0xc,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll3_m3x2_ck = {
+ .name = "dpll3_m3x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll3_m3x2_ck_data,
+};
+
+static struct ti_clk_fixed_factor emu_core_alwon_ck_data = {
+ .parent = "dpll3_m3x2_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk emu_core_alwon_ck = {
+ .name = "emu_core_alwon_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &emu_core_alwon_ck_data,
+};
+
+static struct ti_clk_divider dpll4_m6_ck_data = {
+ .parent = "dpll4_ck",
+ .bit_shift = 24,
+ .max_div = 63,
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll4_m6_ck = {
+ .name = "dpll4_m6_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll4_m6_ck_data,
+};
+
+static struct ti_clk_fixed_factor dpll4_m6x2_mul_ck_data = {
+ .parent = "dpll4_m6_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll4_m6x2_mul_ck = {
+ .name = "dpll4_m6x2_mul_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll4_m6x2_mul_ck_data,
+};
+
+static struct ti_clk_gate dpll4_m6x2_ck_data = {
+ .parent = "dpll4_m6x2_mul_ck",
+ .bit_shift = 0x1f,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m6x2_ck = {
+ .name = "dpll4_m6x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m6x2_ck_data,
+};
+
+static struct ti_clk_fixed_factor emu_per_alwon_ck_data = {
+ .parent = "dpll4_m6x2_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk emu_per_alwon_ck = {
+ .name = "emu_per_alwon_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &emu_per_alwon_ck_data,
+};
+
+static struct ti_clk_fixed_factor emu_mpu_alwon_ck_data = {
+ .parent = "mpu_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk emu_mpu_alwon_ck = {
+ .name = "emu_mpu_alwon_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &emu_mpu_alwon_ck_data,
+};
+
+static const char *emu_src_mux_ck_parents[] = {
+ "sys_ck",
+ "emu_core_alwon_ck",
+ "emu_per_alwon_ck",
+ "emu_mpu_alwon_ck",
+};
+
+static struct ti_clk_mux emu_src_mux_ck_data = {
+ .num_parents = ARRAY_SIZE(emu_src_mux_ck_parents),
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .parents = emu_src_mux_ck_parents,
+};
+
+static struct ti_clk emu_src_mux_ck = {
+ .name = "emu_src_mux_ck",
+ .type = TI_CLK_MUX,
+ .data = &emu_src_mux_ck_data,
+};
+
+static struct ti_clk_gate emu_src_ck_data = {
+ .parent = "emu_src_mux_ck",
+ .flags = CLKF_CLKDM,
+};
+
+static struct ti_clk emu_src_ck = {
+ .name = "emu_src_ck",
+ .clkdm_name = "emu_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &emu_src_ck_data,
+};
+
+static struct ti_clk_divider atclk_fck_data = {
+ .parent = "emu_src_ck",
+ .bit_shift = 4,
+ .max_div = 3,
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk atclk_fck = {
+ .name = "atclk_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &atclk_fck_data,
+};
+
+static struct ti_clk_gate ipss_ick_data = {
+ .parent = "core_l3_ick",
+ .bit_shift = 4,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_AM35XX | CLKF_INTERFACE,
+};
+
+static struct ti_clk ipss_ick = {
+ .name = "ipss_ick",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &ipss_ick_data,
+};
+
+static struct ti_clk_gate emac_ick_data = {
+ .parent = "ipss_ick",
+ .bit_shift = 1,
+ .reg = 0x59c,
+ .module = TI_CLKM_SCRM,
+ .flags = CLKF_AM35XX,
+};
+
+static struct ti_clk emac_ick = {
+ .name = "emac_ick",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &emac_ick_data,
+};
+
+static struct ti_clk_gate vpfe_ick_data = {
+ .parent = "ipss_ick",
+ .bit_shift = 2,
+ .reg = 0x59c,
+ .module = TI_CLKM_SCRM,
+ .flags = CLKF_AM35XX,
+};
+
+static struct ti_clk vpfe_ick = {
+ .name = "vpfe_ick",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &vpfe_ick_data,
+};
+
+static const char *dpll2_ck_parents[] = {
+ "sys_ck",
+ "dpll2_fck",
+};
+
+static struct ti_clk_dpll dpll2_ck_data = {
+ .num_parents = ARRAY_SIZE(dpll2_ck_parents),
+ .control_reg = 0x4,
+ .idlest_reg = 0x24,
+ .mult_div1_reg = 0x40,
+ .autoidle_reg = 0x34,
+ .module = TI_CLKM_CM,
+ .parents = dpll2_ck_parents,
+ .freqsel_mask = 0xf0,
+ .modes = 0xa2,
+ .div1_mask = 0x7f,
+ .idlest_mask = 0x1,
+ .auto_recal_bit = 0x3,
+ .max_divider = 0x80,
+ .min_divider = 0x1,
+ .recal_en_bit = 0x8,
+ .max_multiplier = 0x7ff,
+ .enable_mask = 0x7,
+ .mult_mask = 0x7ff00,
+ .recal_st_bit = 0x8,
+ .autoidle_mask = 0x7,
+};
+
+static struct ti_clk dpll2_ck = {
+ .name = "dpll2_ck",
+ .clkdm_name = "dpll2_clkdm",
+ .type = TI_CLK_DPLL,
+ .data = &dpll2_ck_data,
+};
+
+static struct ti_clk_divider dpll2_m2_ck_data = {
+ .parent = "dpll2_ck",
+ .max_div = 31,
+ .reg = 0x44,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll2_m2_ck = {
+ .name = "dpll2_m2_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll2_m2_ck_data,
+};
+
+static const char *mcbsp4_mux_fck_parents[] = {
+ "per_96m_fck",
+ "mcbsp_clks",
+};
+
+static struct ti_clk_mux mcbsp4_mux_fck_data = {
+ .bit_shift = 2,
+ .num_parents = ARRAY_SIZE(mcbsp4_mux_fck_parents),
+ .reg = 0x2d8,
+ .module = TI_CLKM_SCRM,
+ .parents = mcbsp4_mux_fck_parents,
+};
+
+static const char *mcbsp1_mux_fck_parents[] = {
+ "core_96m_fck",
+ "mcbsp_clks",
+};
+
+static struct ti_clk_mux mcbsp1_mux_fck_data = {
+ .bit_shift = 2,
+ .num_parents = ARRAY_SIZE(mcbsp1_mux_fck_parents),
+ .reg = 0x274,
+ .module = TI_CLKM_SCRM,
+ .parents = mcbsp1_mux_fck_parents,
+};
+
+static struct ti_clk_gate gpt8_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 9,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_gate gpt8_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 9,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt8_ick = {
+ .name = "gpt8_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt8_ick_data,
+};
+
+static const char *gpt10_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt10_mux_fck_data = {
+ .bit_shift = 6,
+ .num_parents = ARRAY_SIZE(gpt10_mux_fck_parents),
+ .reg = 0xa40,
+ .module = TI_CLKM_CM,
+ .parents = gpt10_mux_fck_parents,
+};
+
+static struct ti_clk_gate mmchs3_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 30,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mmchs3_ick = {
+ .name = "mmchs3_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mmchs3_ick_data,
+};
+
+static struct ti_clk_gate gpio3_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 14,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpio3_ick = {
+ .name = "gpio3_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio3_ick_data,
+};
+
+static const char *traceclk_src_fck_parents[] = {
+ "sys_ck",
+ "emu_core_alwon_ck",
+ "emu_per_alwon_ck",
+ "emu_mpu_alwon_ck",
+};
+
+static struct ti_clk_mux traceclk_src_fck_data = {
+ .bit_shift = 2,
+ .num_parents = ARRAY_SIZE(traceclk_src_fck_parents),
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .parents = traceclk_src_fck_parents,
+};
+
+static struct ti_clk traceclk_src_fck = {
+ .name = "traceclk_src_fck",
+ .type = TI_CLK_MUX,
+ .data = &traceclk_src_fck_data,
+};
+
+static struct ti_clk_divider traceclk_fck_data = {
+ .parent = "traceclk_src_fck",
+ .bit_shift = 11,
+ .max_div = 7,
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk traceclk_fck = {
+ .name = "traceclk_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &traceclk_fck_data,
+};
+
+static struct ti_clk_gate mcbsp5_gate_fck_data = {
+ .parent = "mcbsp_clks",
+ .bit_shift = 10,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_gate sad2d_ick_data = {
+ .parent = "l3_ick",
+ .bit_shift = 3,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk sad2d_ick = {
+ .name = "sad2d_ick",
+ .clkdm_name = "d2d_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &sad2d_ick_data,
+};
+
+static const char *gpt1_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt1_mux_fck_data = {
+ .num_parents = ARRAY_SIZE(gpt1_mux_fck_parents),
+ .reg = 0xc40,
+ .module = TI_CLKM_CM,
+ .parents = gpt1_mux_fck_parents,
+};
+
+static struct ti_clk_gate hecc_ck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 3,
+ .reg = 0x59c,
+ .module = TI_CLKM_SCRM,
+ .flags = CLKF_AM35XX,
+};
+
+static struct ti_clk hecc_ck = {
+ .name = "hecc_ck",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &hecc_ck_data,
+};
+
+static struct ti_clk_gate gpt1_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 0,
+ .reg = 0xc00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_composite gpt1_fck_data = {
+ .mux = &gpt1_mux_fck_data,
+ .gate = &gpt1_gate_fck_data,
+};
+
+static struct ti_clk gpt1_fck = {
+ .name = "gpt1_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt1_fck_data,
+};
+
+static struct ti_clk_gate dpll4_m2x2_ck_omap36xx_data = {
+ .parent = "dpll4_m2x2_mul_ck",
+ .bit_shift = 0x1b,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_HSDIV | CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m2x2_ck_omap36xx = {
+ .name = "dpll4_m2x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m2x2_ck_omap36xx_data,
+ .patch = &dpll4_m2x2_ck,
+};
+
+static struct ti_clk_divider gfx_l3_fck_data = {
+ .parent = "l3_ick",
+ .max_div = 7,
+ .reg = 0xb40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk gfx_l3_fck = {
+ .name = "gfx_l3_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &gfx_l3_fck_data,
+};
+
+static struct ti_clk_gate gfx_cg1_ck_data = {
+ .parent = "gfx_l3_fck",
+ .bit_shift = 1,
+ .reg = 0xb00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk gfx_cg1_ck = {
+ .name = "gfx_cg1_ck",
+ .clkdm_name = "gfx_3430es1_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gfx_cg1_ck_data,
+};
+
+static struct ti_clk_gate mailboxes_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 7,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mailboxes_ick = {
+ .name = "mailboxes_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mailboxes_ick_data,
+};
+
+static struct ti_clk_gate sha11_ick_data = {
+ .parent = "security_l4_ick2",
+ .bit_shift = 1,
+ .reg = 0xa14,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk sha11_ick = {
+ .name = "sha11_ick",
+ .type = TI_CLK_GATE,
+ .data = &sha11_ick_data,
+};
+
+static struct ti_clk_gate hsotgusb_ick_am35xx_data = {
+ .parent = "ipss_ick",
+ .bit_shift = 0,
+ .reg = 0x59c,
+ .module = TI_CLKM_SCRM,
+ .flags = CLKF_AM35XX,
+};
+
+static struct ti_clk hsotgusb_ick_am35xx = {
+ .name = "hsotgusb_ick_am35xx",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &hsotgusb_ick_am35xx_data,
+};
+
+static struct ti_clk_gate mmchs3_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 30,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mmchs3_fck = {
+ .name = "mmchs3_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mmchs3_fck_data,
+};
+
+static struct ti_clk_divider pclk_fck_data = {
+ .parent = "emu_src_ck",
+ .bit_shift = 8,
+ .max_div = 7,
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk pclk_fck = {
+ .name = "pclk_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &pclk_fck_data,
+};
+
+static const char *dpll4_ck_omap36xx_parents[] = {
+ "sys_ck",
+ "sys_ck",
+};
+
+static struct ti_clk_dpll dpll4_ck_omap36xx_data = {
+ .num_parents = ARRAY_SIZE(dpll4_ck_omap36xx_parents),
+ .control_reg = 0xd00,
+ .idlest_reg = 0xd20,
+ .mult_div1_reg = 0xd44,
+ .autoidle_reg = 0xd30,
+ .module = TI_CLKM_CM,
+ .parents = dpll4_ck_omap36xx_parents,
+ .modes = 0x82,
+ .div1_mask = 0x7f,
+ .idlest_mask = 0x2,
+ .auto_recal_bit = 0x13,
+ .max_divider = 0x80,
+ .min_divider = 0x1,
+ .recal_en_bit = 0x6,
+ .max_multiplier = 0xfff,
+ .enable_mask = 0x70000,
+ .mult_mask = 0xfff00,
+ .recal_st_bit = 0x6,
+ .autoidle_mask = 0x38,
+ .sddiv_mask = 0xff000000,
+ .dco_mask = 0xe00000,
+ .flags = CLKF_PER | CLKF_J_TYPE,
+};
+
+static struct ti_clk dpll4_ck_omap36xx = {
+ .name = "dpll4_ck",
+ .type = TI_CLK_DPLL,
+ .data = &dpll4_ck_omap36xx_data,
+ .patch = &dpll4_ck,
+};
+
+static struct ti_clk_gate uart3_fck_data = {
+ .parent = "per_48m_fck",
+ .bit_shift = 11,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk uart3_fck = {
+ .name = "uart3_fck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart3_fck_data,
+};
+
+static struct ti_clk_fixed_factor wkup_32k_fck_data = {
+ .parent = "omap_32k_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk wkup_32k_fck = {
+ .name = "wkup_32k_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &wkup_32k_fck_data,
+};
+
+static struct ti_clk_gate sys_clkout1_data = {
+ .parent = "osc_sys_ck",
+ .bit_shift = 7,
+ .reg = 0xd70,
+ .module = TI_CLKM_PRM,
+};
+
+static struct ti_clk sys_clkout1 = {
+ .name = "sys_clkout1",
+ .type = TI_CLK_GATE,
+ .data = &sys_clkout1_data,
+};
+
+static struct ti_clk_fixed_factor gpmc_fck_data = {
+ .parent = "core_l3_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk gpmc_fck = {
+ .name = "gpmc_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &gpmc_fck_data,
+};
+
+static struct ti_clk_fixed_factor dpll5_m2_d20_ck_data = {
+ .parent = "dpll5_m2_ck",
+ .div = 20,
+ .mult = 1,
+};
+
+static struct ti_clk dpll5_m2_d20_ck = {
+ .name = "dpll5_m2_d20_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll5_m2_d20_ck_data,
+};
+
+static struct ti_clk_gate dpll4_m5x2_ck_omap36xx_data = {
+ .parent = "dpll4_m5x2_mul_ck",
+ .bit_shift = 0x1e,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_HSDIV | CLKF_SET_RATE_PARENT | CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m5x2_ck_omap36xx = {
+ .name = "dpll4_m5x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m5x2_ck_omap36xx_data,
+ .patch = &dpll4_m5x2_ck,
+};
+
+static struct ti_clk_gate ssi_ssr_gate_fck_3430es2_data = {
+ .parent = "corex2_fck",
+ .bit_shift = 0,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_NO_WAIT,
+};
+
+static struct ti_clk_gate uart1_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 13,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk uart1_ick = {
+ .name = "uart1_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart1_ick_data,
+};
+
+static struct ti_clk_gate iva2_ck_data = {
+ .parent = "dpll2_m2_ck",
+ .bit_shift = 0,
+ .reg = 0x0,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk iva2_ck = {
+ .name = "iva2_ck",
+ .clkdm_name = "iva2_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &iva2_ck_data,
+};
+
+static struct ti_clk_gate pka_ick_data = {
+ .parent = "security_l3_ick",
+ .bit_shift = 4,
+ .reg = 0xa14,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk pka_ick = {
+ .name = "pka_ick",
+ .type = TI_CLK_GATE,
+ .data = &pka_ick_data,
+};
+
+static struct ti_clk_gate gpt12_ick_data = {
+ .parent = "wkup_l4_ick",
+ .bit_shift = 1,
+ .reg = 0xc10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt12_ick = {
+ .name = "gpt12_ick",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt12_ick_data,
+};
+
+static const char *mcbsp5_mux_fck_parents[] = {
+ "core_96m_fck",
+ "mcbsp_clks",
+};
+
+static struct ti_clk_mux mcbsp5_mux_fck_data = {
+ .bit_shift = 4,
+ .num_parents = ARRAY_SIZE(mcbsp5_mux_fck_parents),
+ .reg = 0x2d8,
+ .module = TI_CLKM_SCRM,
+ .parents = mcbsp5_mux_fck_parents,
+};
+
+static struct ti_clk_composite mcbsp5_fck_data = {
+ .mux = &mcbsp5_mux_fck_data,
+ .gate = &mcbsp5_gate_fck_data,
+};
+
+static struct ti_clk mcbsp5_fck = {
+ .name = "mcbsp5_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &mcbsp5_fck_data,
+};
+
+static struct ti_clk_gate usbhost_48m_fck_data = {
+ .parent = "omap_48m_fck",
+ .bit_shift = 0,
+ .reg = 0x1400,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_DSS,
+};
+
+static struct ti_clk usbhost_48m_fck = {
+ .name = "usbhost_48m_fck",
+ .clkdm_name = "usbhost_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &usbhost_48m_fck_data,
+};
+
+static struct ti_clk_gate des1_ick_data = {
+ .parent = "security_l4_ick2",
+ .bit_shift = 0,
+ .reg = 0xa14,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk des1_ick = {
+ .name = "des1_ick",
+ .type = TI_CLK_GATE,
+ .data = &des1_ick_data,
+};
+
+static struct ti_clk_gate sgx_gate_fck_data = {
+ .parent = "core_ck",
+ .bit_shift = 1,
+ .reg = 0xb00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_fixed_factor core_d4_ck_data = {
+ .parent = "core_ck",
+ .div = 4,
+ .mult = 1,
+};
+
+static struct ti_clk core_d4_ck = {
+ .name = "core_d4_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_d4_ck_data,
+};
+
+static struct ti_clk_fixed_factor omap_192m_alwon_fck_data = {
+ .parent = "dpll4_m2x2_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk omap_192m_alwon_fck = {
+ .name = "omap_192m_alwon_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &omap_192m_alwon_fck_data,
+};
+
+static struct ti_clk_fixed_factor core_d2_ck_data = {
+ .parent = "core_ck",
+ .div = 2,
+ .mult = 1,
+};
+
+static struct ti_clk core_d2_ck = {
+ .name = "core_d2_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_d2_ck_data,
+};
+
+static struct ti_clk_fixed_factor corex2_d3_fck_data = {
+ .parent = "corex2_fck",
+ .div = 3,
+ .mult = 1,
+};
+
+static struct ti_clk corex2_d3_fck = {
+ .name = "corex2_d3_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &corex2_d3_fck_data,
+};
+
+static struct ti_clk_fixed_factor corex2_d5_fck_data = {
+ .parent = "corex2_fck",
+ .div = 5,
+ .mult = 1,
+};
+
+static struct ti_clk corex2_d5_fck = {
+ .name = "corex2_d5_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &corex2_d5_fck_data,
+};
+
+static const char *sgx_mux_fck_parents[] = {
+ "core_d3_ck",
+ "core_d4_ck",
+ "core_d6_ck",
+ "cm_96m_fck",
+ "omap_192m_alwon_fck",
+ "core_d2_ck",
+ "corex2_d3_fck",
+ "corex2_d5_fck",
+};
+
+static struct ti_clk_mux sgx_mux_fck_data = {
+ .num_parents = ARRAY_SIZE(sgx_mux_fck_parents),
+ .reg = 0xb40,
+ .module = TI_CLKM_CM,
+ .parents = sgx_mux_fck_parents,
+};
+
+static struct ti_clk_composite sgx_fck_data = {
+ .mux = &sgx_mux_fck_data,
+ .gate = &sgx_gate_fck_data,
+};
+
+static struct ti_clk sgx_fck = {
+ .name = "sgx_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &sgx_fck_data,
+};
+
+static struct ti_clk_gate mcspi1_fck_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 18,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mcspi1_fck = {
+ .name = "mcspi1_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi1_fck_data,
+};
+
+static struct ti_clk_gate mmchs2_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 25,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mmchs2_fck = {
+ .name = "mmchs2_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mmchs2_fck_data,
+};
+
+static struct ti_clk_gate mcspi2_fck_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 19,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mcspi2_fck = {
+ .name = "mcspi2_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi2_fck_data,
+};
+
+static struct ti_clk_gate vpfe_fck_data = {
+ .parent = "pclk_ck",
+ .bit_shift = 10,
+ .reg = 0x59c,
+ .module = TI_CLKM_SCRM,
+};
+
+static struct ti_clk vpfe_fck = {
+ .name = "vpfe_fck",
+ .type = TI_CLK_GATE,
+ .data = &vpfe_fck_data,
+};
+
+static struct ti_clk_gate gpt4_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 5,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_gate mcbsp1_gate_fck_data = {
+ .parent = "mcbsp_clks",
+ .bit_shift = 9,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_gate gpt5_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 6,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static const char *gpt5_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt5_mux_fck_data = {
+ .bit_shift = 3,
+ .num_parents = ARRAY_SIZE(gpt5_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt5_mux_fck_parents,
+};
+
+static struct ti_clk_composite gpt5_fck_data = {
+ .mux = &gpt5_mux_fck_data,
+ .gate = &gpt5_gate_fck_data,
+};
+
+static struct ti_clk gpt5_fck = {
+ .name = "gpt5_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt5_fck_data,
+};
+
+static struct ti_clk_gate ts_fck_data = {
+ .parent = "omap_32k_fck",
+ .bit_shift = 1,
+ .reg = 0xa08,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk ts_fck = {
+ .name = "ts_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &ts_fck_data,
+};
+
+static struct ti_clk_fixed_factor wdt1_fck_data = {
+ .parent = "secure_32k_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk wdt1_fck = {
+ .name = "wdt1_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &wdt1_fck_data,
+};
+
+static struct ti_clk_gate dpll4_m6x2_ck_omap36xx_data = {
+ .parent = "dpll4_m6x2_mul_ck",
+ .bit_shift = 0x1f,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_HSDIV | CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m6x2_ck_omap36xx = {
+ .name = "dpll4_m6x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m6x2_ck_omap36xx_data,
+ .patch = &dpll4_m6x2_ck,
+};
+
+static const char *gpt4_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt4_mux_fck_data = {
+ .bit_shift = 2,
+ .num_parents = ARRAY_SIZE(gpt4_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt4_mux_fck_parents,
+};
+
+static struct ti_clk_gate usbhost_ick_data = {
+ .parent = "l4_ick",
+ .bit_shift = 0,
+ .reg = 0x1410,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_DSS | CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk usbhost_ick = {
+ .name = "usbhost_ick",
+ .clkdm_name = "usbhost_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &usbhost_ick_data,
+};
+
+static struct ti_clk_gate mcbsp2_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 0,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcbsp2_ick = {
+ .name = "mcbsp2_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcbsp2_ick_data,
+};
+
+static struct ti_clk_gate omapctrl_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 6,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk omapctrl_ick = {
+ .name = "omapctrl_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &omapctrl_ick_data,
+};
+
+static struct ti_clk_fixed_factor omap_96m_d4_fck_data = {
+ .parent = "omap_96m_fck",
+ .div = 4,
+ .mult = 1,
+};
+
+static struct ti_clk omap_96m_d4_fck = {
+ .name = "omap_96m_d4_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &omap_96m_d4_fck_data,
+};
+
+static struct ti_clk_gate gpt6_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 7,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt6_ick = {
+ .name = "gpt6_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt6_ick_data,
+};
+
+static struct ti_clk_gate dpll3_m3x2_ck_omap36xx_data = {
+ .parent = "dpll3_m3x2_mul_ck",
+ .bit_shift = 0xc,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_HSDIV | CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll3_m3x2_ck_omap36xx = {
+ .name = "dpll3_m3x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll3_m3x2_ck_omap36xx_data,
+ .patch = &dpll3_m3x2_ck,
+};
+
+static struct ti_clk_gate i2c3_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 17,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk i2c3_ick = {
+ .name = "i2c3_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &i2c3_ick_data,
+};
+
+static struct ti_clk_gate gpio6_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 17,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpio6_ick = {
+ .name = "gpio6_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio6_ick_data,
+};
+
+static struct ti_clk_gate mspro_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 23,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mspro_ick = {
+ .name = "mspro_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mspro_ick_data,
+};
+
+static struct ti_clk_composite mcbsp1_fck_data = {
+ .mux = &mcbsp1_mux_fck_data,
+ .gate = &mcbsp1_gate_fck_data,
+};
+
+static struct ti_clk mcbsp1_fck = {
+ .name = "mcbsp1_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &mcbsp1_fck_data,
+};
+
+static struct ti_clk_gate gpt3_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 4,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_fixed rmii_ck_data = {
+ .frequency = 50000000,
+};
+
+static struct ti_clk rmii_ck = {
+ .name = "rmii_ck",
+ .type = TI_CLK_FIXED,
+ .data = &rmii_ck_data,
+};
+
+static struct ti_clk_gate gpt6_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 7,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_composite gpt6_fck_data = {
+ .mux = &gpt6_mux_fck_data,
+ .gate = &gpt6_gate_fck_data,
+};
+
+static struct ti_clk gpt6_fck = {
+ .name = "gpt6_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt6_fck_data,
+};
+
+static struct ti_clk_fixed_factor dpll5_m2_d4_ck_data = {
+ .parent = "dpll5_m2_ck",
+ .div = 4,
+ .mult = 1,
+};
+
+static struct ti_clk dpll5_m2_d4_ck = {
+ .name = "dpll5_m2_d4_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll5_m2_d4_ck_data,
+};
+
+static struct ti_clk_fixed_factor sys_d2_ck_data = {
+ .parent = "sys_ck",
+ .div = 2,
+ .mult = 1,
+};
+
+static struct ti_clk sys_d2_ck = {
+ .name = "sys_d2_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &sys_d2_ck_data,
+};
+
+static struct ti_clk_fixed_factor omap_96m_d2_fck_data = {
+ .parent = "omap_96m_fck",
+ .div = 2,
+ .mult = 1,
+};
+
+static struct ti_clk omap_96m_d2_fck = {
+ .name = "omap_96m_d2_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &omap_96m_d2_fck_data,
+};
+
+static struct ti_clk_fixed_factor dpll5_m2_d8_ck_data = {
+ .parent = "dpll5_m2_ck",
+ .div = 8,
+ .mult = 1,
+};
+
+static struct ti_clk dpll5_m2_d8_ck = {
+ .name = "dpll5_m2_d8_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll5_m2_d8_ck_data,
+};
+
+static struct ti_clk_fixed_factor dpll5_m2_d16_ck_data = {
+ .parent = "dpll5_m2_ck",
+ .div = 16,
+ .mult = 1,
+};
+
+static struct ti_clk dpll5_m2_d16_ck = {
+ .name = "dpll5_m2_d16_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll5_m2_d16_ck_data,
+};
+
+static const char *usim_mux_fck_parents[] = {
+ "sys_ck",
+ "sys_d2_ck",
+ "omap_96m_d2_fck",
+ "omap_96m_d4_fck",
+ "omap_96m_d8_fck",
+ "omap_96m_d10_fck",
+ "dpll5_m2_d4_ck",
+ "dpll5_m2_d8_ck",
+ "dpll5_m2_d16_ck",
+ "dpll5_m2_d20_ck",
+};
+
+static struct ti_clk_mux usim_mux_fck_data = {
+ .bit_shift = 3,
+ .num_parents = ARRAY_SIZE(usim_mux_fck_parents),
+ .reg = 0xc40,
+ .module = TI_CLKM_CM,
+ .parents = usim_mux_fck_parents,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk_composite usim_fck_data = {
+ .mux = &usim_mux_fck_data,
+ .gate = &usim_gate_fck_data,
+};
+
+static struct ti_clk usim_fck = {
+ .name = "usim_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &usim_fck_data,
+};
+
+static int ssi_ssr_div_fck_3430es2_divs[] = {
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 0,
+ 6,
+ 0,
+ 8,
+};
+
+static struct ti_clk_divider ssi_ssr_div_fck_3430es2_data = {
+ .num_dividers = ARRAY_SIZE(ssi_ssr_div_fck_3430es2_divs),
+ .parent = "corex2_fck",
+ .bit_shift = 8,
+ .dividers = ssi_ssr_div_fck_3430es2_divs,
+ .reg = 0xa40,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_composite ssi_ssr_fck_3430es2_data = {
+ .gate = &ssi_ssr_gate_fck_3430es2_data,
+ .divider = &ssi_ssr_div_fck_3430es2_data,
+};
+
+static struct ti_clk ssi_ssr_fck_3430es2 = {
+ .name = "ssi_ssr_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &ssi_ssr_fck_3430es2_data,
+};
+
+static struct ti_clk_gate dss1_alwon_fck_3430es1_data = {
+ .parent = "dpll4_m4x2_ck",
+ .bit_shift = 0,
+ .reg = 0xe00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_RATE_PARENT,
+};
+
+static struct ti_clk dss1_alwon_fck_3430es1 = {
+ .name = "dss1_alwon_fck",
+ .clkdm_name = "dss_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &dss1_alwon_fck_3430es1_data,
+};
+
+static struct ti_clk_gate gpt3_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 4,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt3_ick = {
+ .name = "gpt3_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt3_ick_data,
+};
+
+static struct ti_clk_fixed_factor omap_12m_fck_data = {
+ .parent = "omap_48m_fck",
+ .div = 4,
+ .mult = 1,
+};
+
+static struct ti_clk omap_12m_fck = {
+ .name = "omap_12m_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &omap_12m_fck_data,
+};
+
+static struct ti_clk_fixed_factor core_12m_fck_data = {
+ .parent = "omap_12m_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk core_12m_fck = {
+ .name = "core_12m_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_12m_fck_data,
+};
+
+static struct ti_clk_gate hdq_fck_data = {
+ .parent = "core_12m_fck",
+ .bit_shift = 22,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk hdq_fck = {
+ .name = "hdq_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &hdq_fck_data,
+};
+
+static struct ti_clk_gate usbtll_fck_data = {
+ .parent = "dpll5_m2_ck",
+ .bit_shift = 2,
+ .reg = 0xa08,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk usbtll_fck = {
+ .name = "usbtll_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &usbtll_fck_data,
+};
+
+static struct ti_clk_gate hsotgusb_fck_am35xx_data = {
+ .parent = "sys_ck",
+ .bit_shift = 8,
+ .reg = 0x59c,
+ .module = TI_CLKM_SCRM,
+};
+
+static struct ti_clk hsotgusb_fck_am35xx = {
+ .name = "hsotgusb_fck_am35xx",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &hsotgusb_fck_am35xx_data,
+};
+
+static struct ti_clk_gate hsotgusb_ick_3430es2_data = {
+ .parent = "core_l3_ick",
+ .bit_shift = 4,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_HSOTGUSB | CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk hsotgusb_ick_3430es2 = {
+ .name = "hsotgusb_ick_3430es2",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &hsotgusb_ick_3430es2_data,
+};
+
+static struct ti_clk_gate gfx_l3_ck_data = {
+ .parent = "l3_ick",
+ .bit_shift = 0,
+ .reg = 0xb10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk gfx_l3_ck = {
+ .name = "gfx_l3_ck",
+ .clkdm_name = "gfx_3430es1_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gfx_l3_ck_data,
+};
+
+static struct ti_clk_fixed_factor gfx_l3_ick_data = {
+ .parent = "gfx_l3_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk gfx_l3_ick = {
+ .name = "gfx_l3_ick",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &gfx_l3_ick_data,
+};
+
+static struct ti_clk_gate mcbsp1_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 9,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcbsp1_ick = {
+ .name = "mcbsp1_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcbsp1_ick_data,
+};
+
+static struct ti_clk_fixed_factor gpt12_fck_data = {
+ .parent = "secure_32k_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk gpt12_fck = {
+ .name = "gpt12_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &gpt12_fck_data,
+};
+
+static struct ti_clk_gate gfx_cg2_ck_data = {
+ .parent = "gfx_l3_fck",
+ .bit_shift = 2,
+ .reg = 0xb00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk gfx_cg2_ck = {
+ .name = "gfx_cg2_ck",
+ .clkdm_name = "gfx_3430es1_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gfx_cg2_ck_data,
+};
+
+static struct ti_clk_gate i2c2_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 16,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk i2c2_ick = {
+ .name = "i2c2_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &i2c2_ick_data,
+};
+
+static struct ti_clk_gate gpio4_dbck_data = {
+ .parent = "per_32k_alwon_fck",
+ .bit_shift = 15,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk gpio4_dbck = {
+ .name = "gpio4_dbck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio4_dbck_data,
+};
+
+static struct ti_clk_gate i2c3_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 17,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk i2c3_fck = {
+ .name = "i2c3_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &i2c3_fck_data,
+};
+
+static struct ti_clk_composite gpt3_fck_data = {
+ .mux = &gpt3_mux_fck_data,
+ .gate = &gpt3_gate_fck_data,
+};
+
+static struct ti_clk gpt3_fck = {
+ .name = "gpt3_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt3_fck_data,
+};
+
+static struct ti_clk_gate i2c1_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 15,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk i2c1_ick = {
+ .name = "i2c1_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &i2c1_ick_data,
+};
+
+static struct ti_clk_gate omap_32ksync_ick_data = {
+ .parent = "wkup_l4_ick",
+ .bit_shift = 2,
+ .reg = 0xc10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk omap_32ksync_ick = {
+ .name = "omap_32ksync_ick",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &omap_32ksync_ick_data,
+};
+
+static struct ti_clk_gate aes2_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 28,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk aes2_ick = {
+ .name = "aes2_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &aes2_ick_data,
+};
+
+static const char *gpt8_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt8_mux_fck_data = {
+ .bit_shift = 6,
+ .num_parents = ARRAY_SIZE(gpt8_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt8_mux_fck_parents,
+};
+
+static struct ti_clk_composite gpt8_fck_data = {
+ .mux = &gpt8_mux_fck_data,
+ .gate = &gpt8_gate_fck_data,
+};
+
+static struct ti_clk gpt8_fck = {
+ .name = "gpt8_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt8_fck_data,
+};
+
+static struct ti_clk_gate mcbsp4_gate_fck_data = {
+ .parent = "mcbsp_clks",
+ .bit_shift = 2,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_composite mcbsp4_fck_data = {
+ .mux = &mcbsp4_mux_fck_data,
+ .gate = &mcbsp4_gate_fck_data,
+};
+
+static struct ti_clk mcbsp4_fck = {
+ .name = "mcbsp4_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &mcbsp4_fck_data,
+};
+
+static struct ti_clk_gate gpio2_dbck_data = {
+ .parent = "per_32k_alwon_fck",
+ .bit_shift = 13,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk gpio2_dbck = {
+ .name = "gpio2_dbck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio2_dbck_data,
+};
+
+static struct ti_clk_gate usbtll_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 2,
+ .reg = 0xa18,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk usbtll_ick = {
+ .name = "usbtll_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &usbtll_ick_data,
+};
+
+static struct ti_clk_gate mcspi4_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 21,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcspi4_ick = {
+ .name = "mcspi4_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi4_ick_data,
+};
+
+static struct ti_clk_gate dss_96m_fck_data = {
+ .parent = "omap_96m_fck",
+ .bit_shift = 2,
+ .reg = 0xe00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk dss_96m_fck = {
+ .name = "dss_96m_fck",
+ .clkdm_name = "dss_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &dss_96m_fck_data,
+};
+
+static struct ti_clk_divider rm_ick_data = {
+ .parent = "l4_ick",
+ .bit_shift = 1,
+ .max_div = 3,
+ .reg = 0xc40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk rm_ick = {
+ .name = "rm_ick",
+ .type = TI_CLK_DIVIDER,
+ .data = &rm_ick_data,
+};
+
+static struct ti_clk_gate hdq_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 22,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk hdq_ick = {
+ .name = "hdq_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &hdq_ick_data,
+};
+
+static struct ti_clk_fixed_factor dpll3_x2_ck_data = {
+ .parent = "dpll3_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll3_x2_ck = {
+ .name = "dpll3_x2_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll3_x2_ck_data,
+};
+
+static struct ti_clk_gate mad2d_ick_data = {
+ .parent = "l3_ick",
+ .bit_shift = 3,
+ .reg = 0xa18,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mad2d_ick = {
+ .name = "mad2d_ick",
+ .clkdm_name = "d2d_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mad2d_ick_data,
+};
+
+static struct ti_clk_gate fshostusb_fck_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 5,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk fshostusb_fck = {
+ .name = "fshostusb_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &fshostusb_fck_data,
+};
+
+static struct ti_clk_gate sr1_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 6,
+ .reg = 0xc00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk sr1_fck = {
+ .name = "sr1_fck",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &sr1_fck_data,
+};
+
+static struct ti_clk_gate des2_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 26,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk des2_ick = {
+ .name = "des2_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &des2_ick_data,
+};
+
+static struct ti_clk_gate sdrc_ick_data = {
+ .parent = "core_l3_ick",
+ .bit_shift = 1,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk sdrc_ick = {
+ .name = "sdrc_ick",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &sdrc_ick_data,
+};
+
+static struct ti_clk_composite gpt4_fck_data = {
+ .mux = &gpt4_mux_fck_data,
+ .gate = &gpt4_gate_fck_data,
+};
+
+static struct ti_clk gpt4_fck = {
+ .name = "gpt4_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt4_fck_data,
+};
+
+static struct ti_clk_gate dpll4_m3x2_ck_omap36xx_data = {
+ .parent = "dpll4_m3x2_mul_ck",
+ .bit_shift = 0x1c,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_HSDIV | CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m3x2_ck_omap36xx = {
+ .name = "dpll4_m3x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m3x2_ck_omap36xx_data,
+ .patch = &dpll4_m3x2_ck,
+};
+
+static struct ti_clk_gate cpefuse_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 0,
+ .reg = 0xa08,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk cpefuse_fck = {
+ .name = "cpefuse_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &cpefuse_fck_data,
+};
+
+static struct ti_clk_gate mcspi3_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 20,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcspi3_ick = {
+ .name = "mcspi3_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi3_ick_data,
+};
+
+static struct ti_clk_fixed_factor ssi_sst_fck_3430es2_data = {
+ .parent = "ssi_ssr_fck",
+ .div = 2,
+ .mult = 1,
+};
+
+static struct ti_clk ssi_sst_fck_3430es2 = {
+ .name = "ssi_sst_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &ssi_sst_fck_3430es2_data,
+};
+
+static struct ti_clk_gate gpio1_dbck_data = {
+ .parent = "wkup_32k_fck",
+ .bit_shift = 3,
+ .reg = 0xc00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk gpio1_dbck = {
+ .name = "gpio1_dbck",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio1_dbck_data,
+};
+
+static struct ti_clk_gate gpt4_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 5,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt4_ick = {
+ .name = "gpt4_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt4_ick_data,
+};
+
+static struct ti_clk_gate gpt2_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 3,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt2_ick = {
+ .name = "gpt2_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt2_ick_data,
+};
+
+static struct ti_clk_gate mmchs1_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 24,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mmchs1_fck = {
+ .name = "mmchs1_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mmchs1_fck_data,
+};
+
+static struct ti_clk_fixed dummy_apb_pclk_data = {
+ .frequency = 0x0,
+};
+
+static struct ti_clk dummy_apb_pclk = {
+ .name = "dummy_apb_pclk",
+ .type = TI_CLK_FIXED,
+ .data = &dummy_apb_pclk_data,
+};
+
+static struct ti_clk_gate gpio6_dbck_data = {
+ .parent = "per_32k_alwon_fck",
+ .bit_shift = 17,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk gpio6_dbck = {
+ .name = "gpio6_dbck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio6_dbck_data,
+};
+
+static struct ti_clk_gate uart2_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 14,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk uart2_ick = {
+ .name = "uart2_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart2_ick_data,
+};
+
+static struct ti_clk_fixed_factor dpll4_x2_ck_data = {
+ .parent = "dpll4_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll4_x2_ck = {
+ .name = "dpll4_x2_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll4_x2_ck_data,
+};
+
+static struct ti_clk_gate gpt7_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 8,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt7_ick = {
+ .name = "gpt7_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt7_ick_data,
+};
+
+static struct ti_clk_gate dss_tv_fck_data = {
+ .parent = "omap_54m_fck",
+ .bit_shift = 2,
+ .reg = 0xe00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk dss_tv_fck = {
+ .name = "dss_tv_fck",
+ .clkdm_name = "dss_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &dss_tv_fck_data,
+};
+
+static struct ti_clk_gate mcbsp5_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 10,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcbsp5_ick = {
+ .name = "mcbsp5_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcbsp5_ick_data,
+};
+
+static struct ti_clk_gate mcspi1_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 18,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcspi1_ick = {
+ .name = "mcspi1_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi1_ick_data,
+};
+
+static struct ti_clk_gate d2d_26m_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 3,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk d2d_26m_fck = {
+ .name = "d2d_26m_fck",
+ .clkdm_name = "d2d_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &d2d_26m_fck_data,
+};
+
+static struct ti_clk_gate wdt3_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 12,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk wdt3_ick = {
+ .name = "wdt3_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &wdt3_ick_data,
+};
+
+static struct ti_clk_divider pclkx2_fck_data = {
+ .parent = "emu_src_ck",
+ .bit_shift = 6,
+ .max_div = 3,
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk pclkx2_fck = {
+ .name = "pclkx2_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &pclkx2_fck_data,
+};
+
+static struct ti_clk_gate sha12_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 27,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk sha12_ick = {
+ .name = "sha12_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &sha12_ick_data,
+};
+
+static struct ti_clk_gate emac_fck_data = {
+ .parent = "rmii_ck",
+ .bit_shift = 9,
+ .reg = 0x59c,
+ .module = TI_CLKM_SCRM,
+};
+
+static struct ti_clk emac_fck = {
+ .name = "emac_fck",
+ .type = TI_CLK_GATE,
+ .data = &emac_fck_data,
+};
+
+static struct ti_clk_composite gpt10_fck_data = {
+ .mux = &gpt10_mux_fck_data,
+ .gate = &gpt10_gate_fck_data,
+};
+
+static struct ti_clk gpt10_fck = {
+ .name = "gpt10_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt10_fck_data,
+};
+
+static struct ti_clk_gate wdt2_fck_data = {
+ .parent = "wkup_32k_fck",
+ .bit_shift = 5,
+ .reg = 0xc00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk wdt2_fck = {
+ .name = "wdt2_fck",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &wdt2_fck_data,
+};
+
+static struct ti_clk_gate cam_ick_data = {
+ .parent = "l4_ick",
+ .bit_shift = 0,
+ .reg = 0xf10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_NO_WAIT | CLKF_INTERFACE,
+};
+
+static struct ti_clk cam_ick = {
+ .name = "cam_ick",
+ .clkdm_name = "cam_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &cam_ick_data,
+};
+
+static struct ti_clk_gate ssi_ick_3430es2_data = {
+ .parent = "ssi_l4_ick",
+ .bit_shift = 0,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SSI | CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk ssi_ick_3430es2 = {
+ .name = "ssi_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &ssi_ick_3430es2_data,
+};
+
+static struct ti_clk_gate gpio4_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 15,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpio4_ick = {
+ .name = "gpio4_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio4_ick_data,
+};
+
+static struct ti_clk_gate wdt1_ick_data = {
+ .parent = "wkup_l4_ick",
+ .bit_shift = 4,
+ .reg = 0xc10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk wdt1_ick = {
+ .name = "wdt1_ick",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &wdt1_ick_data,
+};
+
+static struct ti_clk_gate rng_ick_data = {
+ .parent = "security_l4_ick2",
+ .bit_shift = 2,
+ .reg = 0xa14,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk rng_ick = {
+ .name = "rng_ick",
+ .type = TI_CLK_GATE,
+ .data = &rng_ick_data,
+};
+
+static struct ti_clk_gate icr_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 29,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk icr_ick = {
+ .name = "icr_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &icr_ick_data,
+};
+
+static struct ti_clk_gate sgx_ick_data = {
+ .parent = "l3_ick",
+ .bit_shift = 0,
+ .reg = 0xb10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk sgx_ick = {
+ .name = "sgx_ick",
+ .clkdm_name = "sgx_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &sgx_ick_data,
+};
+
+static struct ti_clk_divider sys_clkout2_data = {
+ .parent = "clkout2_src_ck",
+ .bit_shift = 3,
+ .max_div = 64,
+ .reg = 0xd70,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_POWER_OF_TWO,
+};
+
+static struct ti_clk sys_clkout2 = {
+ .name = "sys_clkout2",
+ .type = TI_CLK_DIVIDER,
+ .data = &sys_clkout2_data,
+};
+
+static struct ti_clk_alias omap34xx_omap36xx_clks[] = {
+ CLK(NULL, "security_l4_ick2", &security_l4_ick2),
+ CLK(NULL, "aes1_ick", &aes1_ick),
+ CLK("omap_rng", "ick", &rng_ick),
+ CLK("omap3-rom-rng", "ick", &rng_ick),
+ CLK(NULL, "sha11_ick", &sha11_ick),
+ CLK(NULL, "des1_ick", &des1_ick),
+ CLK(NULL, "cam_mclk", &cam_mclk),
+ CLK(NULL, "cam_ick", &cam_ick),
+ CLK(NULL, "csi2_96m_fck", &csi2_96m_fck),
+ CLK(NULL, "security_l3_ick", &security_l3_ick),
+ CLK(NULL, "pka_ick", &pka_ick),
+ CLK(NULL, "icr_ick", &icr_ick),
+ CLK(NULL, "des2_ick", &des2_ick),
+ CLK(NULL, "mspro_ick", &mspro_ick),
+ CLK(NULL, "mailboxes_ick", &mailboxes_ick),
+ CLK(NULL, "ssi_l4_ick", &ssi_l4_ick),
+ CLK(NULL, "sr1_fck", &sr1_fck),
+ CLK(NULL, "sr2_fck", &sr2_fck),
+ CLK(NULL, "sr_l4_ick", &sr_l4_ick),
+ CLK(NULL, "dpll2_fck", &dpll2_fck),
+ CLK(NULL, "dpll2_ck", &dpll2_ck),
+ CLK(NULL, "dpll2_m2_ck", &dpll2_m2_ck),
+ CLK(NULL, "iva2_ck", &iva2_ck),
+ CLK(NULL, "modem_fck", &modem_fck),
+ CLK(NULL, "sad2d_ick", &sad2d_ick),
+ CLK(NULL, "mad2d_ick", &mad2d_ick),
+ CLK(NULL, "mspro_fck", &mspro_fck),
+ { NULL },
+};
+
+static struct ti_clk_alias omap36xx_omap3430es2plus_clks[] = {
+ CLK(NULL, "ssi_ssr_fck", &ssi_ssr_fck_3430es2),
+ CLK(NULL, "ssi_sst_fck", &ssi_sst_fck_3430es2),
+ CLK("musb-omap2430", "ick", &hsotgusb_ick_3430es2),
+ CLK(NULL, "hsotgusb_ick", &hsotgusb_ick_3430es2),
+ CLK(NULL, "ssi_ick", &ssi_ick_3430es2),
+ CLK(NULL, "sys_d2_ck", &sys_d2_ck),
+ CLK(NULL, "omap_96m_d2_fck", &omap_96m_d2_fck),
+ CLK(NULL, "omap_96m_d4_fck", &omap_96m_d4_fck),
+ CLK(NULL, "omap_96m_d8_fck", &omap_96m_d8_fck),
+ CLK(NULL, "omap_96m_d10_fck", &omap_96m_d10_fck),
+ CLK(NULL, "dpll5_m2_d4_ck", &dpll5_m2_d4_ck),
+ CLK(NULL, "dpll5_m2_d8_ck", &dpll5_m2_d8_ck),
+ CLK(NULL, "dpll5_m2_d16_ck", &dpll5_m2_d16_ck),
+ CLK(NULL, "dpll5_m2_d20_ck", &dpll5_m2_d20_ck),
+ CLK(NULL, "usim_fck", &usim_fck),
+ CLK(NULL, "usim_ick", &usim_ick),
+ { NULL },
+};
+
+static struct ti_clk_alias omap3xxx_clks[] = {
+ CLK(NULL, "apb_pclk", &dummy_apb_pclk),
+ CLK(NULL, "omap_32k_fck", &omap_32k_fck),
+ CLK(NULL, "virt_12m_ck", &virt_12m_ck),
+ CLK(NULL, "virt_13m_ck", &virt_13m_ck),
+ CLK(NULL, "virt_19200000_ck", &virt_19200000_ck),
+ CLK(NULL, "virt_26000000_ck", &virt_26000000_ck),
+ CLK(NULL, "virt_38_4m_ck", &virt_38_4m_ck),
+ CLK(NULL, "virt_16_8m_ck", &virt_16_8m_ck),
+ CLK(NULL, "osc_sys_ck", &osc_sys_ck),
+ CLK("twl", "fck", &osc_sys_ck),
+ CLK(NULL, "sys_ck", &sys_ck),
+ CLK(NULL, "timer_sys_ck", &sys_ck),
+ CLK(NULL, "dpll4_ck", &dpll4_ck),
+ CLK(NULL, "dpll4_m2_ck", &dpll4_m2_ck),
+ CLK(NULL, "dpll4_m2x2_mul_ck", &dpll4_m2x2_mul_ck),
+ CLK(NULL, "dpll4_m2x2_ck", &dpll4_m2x2_ck),
+ CLK(NULL, "omap_96m_alwon_fck", &omap_96m_alwon_fck),
+ CLK(NULL, "dpll3_ck", &dpll3_ck),
+ CLK(NULL, "dpll3_m3_ck", &dpll3_m3_ck),
+ CLK(NULL, "dpll3_m3x2_mul_ck", &dpll3_m3x2_mul_ck),
+ CLK(NULL, "dpll3_m3x2_ck", &dpll3_m3x2_ck),
+ CLK("etb", "emu_core_alwon_ck", &emu_core_alwon_ck),
+ CLK(NULL, "sys_altclk", &sys_altclk),
+ CLK(NULL, "mcbsp_clks", &mcbsp_clks),
+ CLK(NULL, "sys_clkout1", &sys_clkout1),
+ CLK(NULL, "dpll3_m2_ck", &dpll3_m2_ck),
+ CLK(NULL, "core_ck", &core_ck),
+ CLK(NULL, "dpll1_fck", &dpll1_fck),
+ CLK(NULL, "dpll1_ck", &dpll1_ck),
+ CLK(NULL, "cpufreq_ck", &dpll1_ck),
+ CLK(NULL, "dpll1_x2_ck", &dpll1_x2_ck),
+ CLK(NULL, "dpll1_x2m2_ck", &dpll1_x2m2_ck),
+ CLK(NULL, "dpll3_x2_ck", &dpll3_x2_ck),
+ CLK(NULL, "dpll3_m2x2_ck", &dpll3_m2x2_ck),
+ CLK(NULL, "dpll4_x2_ck", &dpll4_x2_ck),
+ CLK(NULL, "cm_96m_fck", &cm_96m_fck),
+ CLK(NULL, "omap_96m_fck", &omap_96m_fck),
+ CLK(NULL, "dpll4_m3_ck", &dpll4_m3_ck),
+ CLK(NULL, "dpll4_m3x2_mul_ck", &dpll4_m3x2_mul_ck),
+ CLK(NULL, "dpll4_m3x2_ck", &dpll4_m3x2_ck),
+ CLK(NULL, "omap_54m_fck", &omap_54m_fck),
+ CLK(NULL, "cm_96m_d2_fck", &cm_96m_d2_fck),
+ CLK(NULL, "omap_48m_fck", &omap_48m_fck),
+ CLK(NULL, "omap_12m_fck", &omap_12m_fck),
+ CLK(NULL, "dpll4_m4_ck", &dpll4_m4_ck),
+ CLK(NULL, "dpll4_m4x2_mul_ck", &dpll4_m4x2_mul_ck),
+ CLK(NULL, "dpll4_m4x2_ck", &dpll4_m4x2_ck),
+ CLK(NULL, "dpll4_m5_ck", &dpll4_m5_ck),
+ CLK(NULL, "dpll4_m5x2_mul_ck", &dpll4_m5x2_mul_ck),
+ CLK(NULL, "dpll4_m5x2_ck", &dpll4_m5x2_ck),
+ CLK(NULL, "dpll4_m6_ck", &dpll4_m6_ck),
+ CLK(NULL, "dpll4_m6x2_mul_ck", &dpll4_m6x2_mul_ck),
+ CLK(NULL, "dpll4_m6x2_ck", &dpll4_m6x2_ck),
+ CLK("etb", "emu_per_alwon_ck", &emu_per_alwon_ck),
+ CLK(NULL, "clkout2_src_ck", &clkout2_src_ck),
+ CLK(NULL, "sys_clkout2", &sys_clkout2),
+ CLK(NULL, "corex2_fck", &corex2_fck),
+ CLK(NULL, "mpu_ck", &mpu_ck),
+ CLK(NULL, "arm_fck", &arm_fck),
+ CLK("etb", "emu_mpu_alwon_ck", &emu_mpu_alwon_ck),
+ CLK(NULL, "l3_ick", &l3_ick),
+ CLK(NULL, "l4_ick", &l4_ick),
+ CLK(NULL, "rm_ick", &rm_ick),
+ CLK(NULL, "timer_32k_ck", &omap_32k_fck),
+ CLK(NULL, "gpt10_fck", &gpt10_fck),
+ CLK(NULL, "gpt11_fck", &gpt11_fck),
+ CLK(NULL, "core_96m_fck", &core_96m_fck),
+ CLK(NULL, "mmchs2_fck", &mmchs2_fck),
+ CLK(NULL, "mmchs1_fck", &mmchs1_fck),
+ CLK(NULL, "i2c3_fck", &i2c3_fck),
+ CLK(NULL, "i2c2_fck", &i2c2_fck),
+ CLK(NULL, "i2c1_fck", &i2c1_fck),
+ CLK(NULL, "mcbsp5_fck", &mcbsp5_fck),
+ CLK(NULL, "mcbsp1_fck", &mcbsp1_fck),
+ CLK(NULL, "core_48m_fck", &core_48m_fck),
+ CLK(NULL, "mcspi4_fck", &mcspi4_fck),
+ CLK(NULL, "mcspi3_fck", &mcspi3_fck),
+ CLK(NULL, "mcspi2_fck", &mcspi2_fck),
+ CLK(NULL, "mcspi1_fck", &mcspi1_fck),
+ CLK(NULL, "uart2_fck", &uart2_fck),
+ CLK(NULL, "uart1_fck", &uart1_fck),
+ CLK(NULL, "core_12m_fck", &core_12m_fck),
+ CLK("omap_hdq.0", "fck", &hdq_fck),
+ CLK(NULL, "hdq_fck", &hdq_fck),
+ CLK(NULL, "core_l3_ick", &core_l3_ick),
+ CLK(NULL, "sdrc_ick", &sdrc_ick),
+ CLK(NULL, "gpmc_fck", &gpmc_fck),
+ CLK(NULL, "core_l4_ick", &core_l4_ick),
+ CLK("omap_hsmmc.1", "ick", &mmchs2_ick),
+ CLK("omap_hsmmc.0", "ick", &mmchs1_ick),
+ CLK(NULL, "mmchs2_ick", &mmchs2_ick),
+ CLK(NULL, "mmchs1_ick", &mmchs1_ick),
+ CLK("omap_hdq.0", "ick", &hdq_ick),
+ CLK(NULL, "hdq_ick", &hdq_ick),
+ CLK("omap2_mcspi.4", "ick", &mcspi4_ick),
+ CLK("omap2_mcspi.3", "ick", &mcspi3_ick),
+ CLK("omap2_mcspi.2", "ick", &mcspi2_ick),
+ CLK("omap2_mcspi.1", "ick", &mcspi1_ick),
+ CLK(NULL, "mcspi4_ick", &mcspi4_ick),
+ CLK(NULL, "mcspi3_ick", &mcspi3_ick),
+ CLK(NULL, "mcspi2_ick", &mcspi2_ick),
+ CLK(NULL, "mcspi1_ick", &mcspi1_ick),
+ CLK("omap_i2c.3", "ick", &i2c3_ick),
+ CLK("omap_i2c.2", "ick", &i2c2_ick),
+ CLK("omap_i2c.1", "ick", &i2c1_ick),
+ CLK(NULL, "i2c3_ick", &i2c3_ick),
+ CLK(NULL, "i2c2_ick", &i2c2_ick),
+ CLK(NULL, "i2c1_ick", &i2c1_ick),
+ CLK(NULL, "uart2_ick", &uart2_ick),
+ CLK(NULL, "uart1_ick", &uart1_ick),
+ CLK(NULL, "gpt11_ick", &gpt11_ick),
+ CLK(NULL, "gpt10_ick", &gpt10_ick),
+ CLK("omap-mcbsp.5", "ick", &mcbsp5_ick),
+ CLK("omap-mcbsp.1", "ick", &mcbsp1_ick),
+ CLK(NULL, "mcbsp5_ick", &mcbsp5_ick),
+ CLK(NULL, "mcbsp1_ick", &mcbsp1_ick),
+ CLK(NULL, "omapctrl_ick", &omapctrl_ick),
+ CLK(NULL, "dss_tv_fck", &dss_tv_fck),
+ CLK(NULL, "dss_96m_fck", &dss_96m_fck),
+ CLK(NULL, "dss2_alwon_fck", &dss2_alwon_fck),
+ CLK(NULL, "init_60m_fclk", &dummy_ck),
+ CLK(NULL, "gpt1_fck", &gpt1_fck),
+ CLK(NULL, "aes2_ick", &aes2_ick),
+ CLK(NULL, "wkup_32k_fck", &wkup_32k_fck),
+ CLK(NULL, "gpio1_dbck", &gpio1_dbck),
+ CLK(NULL, "sha12_ick", &sha12_ick),
+ CLK(NULL, "wdt2_fck", &wdt2_fck),
+ CLK(NULL, "wkup_l4_ick", &wkup_l4_ick),
+ CLK("omap_wdt", "ick", &wdt2_ick),
+ CLK(NULL, "wdt2_ick", &wdt2_ick),
+ CLK(NULL, "wdt1_ick", &wdt1_ick),
+ CLK(NULL, "gpio1_ick", &gpio1_ick),
+ CLK(NULL, "omap_32ksync_ick", &omap_32ksync_ick),
+ CLK(NULL, "gpt12_ick", &gpt12_ick),
+ CLK(NULL, "gpt1_ick", &gpt1_ick),
+ CLK(NULL, "per_96m_fck", &per_96m_fck),
+ CLK(NULL, "per_48m_fck", &per_48m_fck),
+ CLK(NULL, "uart3_fck", &uart3_fck),
+ CLK(NULL, "gpt2_fck", &gpt2_fck),
+ CLK(NULL, "gpt3_fck", &gpt3_fck),
+ CLK(NULL, "gpt4_fck", &gpt4_fck),
+ CLK(NULL, "gpt5_fck", &gpt5_fck),
+ CLK(NULL, "gpt6_fck", &gpt6_fck),
+ CLK(NULL, "gpt7_fck", &gpt7_fck),
+ CLK(NULL, "gpt8_fck", &gpt8_fck),
+ CLK(NULL, "gpt9_fck", &gpt9_fck),
+ CLK(NULL, "per_32k_alwon_fck", &per_32k_alwon_fck),
+ CLK(NULL, "gpio6_dbck", &gpio6_dbck),
+ CLK(NULL, "gpio5_dbck", &gpio5_dbck),
+ CLK(NULL, "gpio4_dbck", &gpio4_dbck),
+ CLK(NULL, "gpio3_dbck", &gpio3_dbck),
+ CLK(NULL, "gpio2_dbck", &gpio2_dbck),
+ CLK(NULL, "wdt3_fck", &wdt3_fck),
+ CLK(NULL, "per_l4_ick", &per_l4_ick),
+ CLK(NULL, "gpio6_ick", &gpio6_ick),
+ CLK(NULL, "gpio5_ick", &gpio5_ick),
+ CLK(NULL, "gpio4_ick", &gpio4_ick),
+ CLK(NULL, "gpio3_ick", &gpio3_ick),
+ CLK(NULL, "gpio2_ick", &gpio2_ick),
+ CLK(NULL, "wdt3_ick", &wdt3_ick),
+ CLK(NULL, "uart3_ick", &uart3_ick),
+ CLK(NULL, "uart4_ick", &uart4_ick),
+ CLK(NULL, "gpt9_ick", &gpt9_ick),
+ CLK(NULL, "gpt8_ick", &gpt8_ick),
+ CLK(NULL, "gpt7_ick", &gpt7_ick),
+ CLK(NULL, "gpt6_ick", &gpt6_ick),
+ CLK(NULL, "gpt5_ick", &gpt5_ick),
+ CLK(NULL, "gpt4_ick", &gpt4_ick),
+ CLK(NULL, "gpt3_ick", &gpt3_ick),
+ CLK(NULL, "gpt2_ick", &gpt2_ick),
+ CLK("omap-mcbsp.2", "ick", &mcbsp2_ick),
+ CLK("omap-mcbsp.3", "ick", &mcbsp3_ick),
+ CLK("omap-mcbsp.4", "ick", &mcbsp4_ick),
+ CLK(NULL, "mcbsp4_ick", &mcbsp2_ick),
+ CLK(NULL, "mcbsp3_ick", &mcbsp3_ick),
+ CLK(NULL, "mcbsp2_ick", &mcbsp4_ick),
+ CLK(NULL, "mcbsp2_fck", &mcbsp2_fck),
+ CLK(NULL, "mcbsp3_fck", &mcbsp3_fck),
+ CLK(NULL, "mcbsp4_fck", &mcbsp4_fck),
+ CLK(NULL, "emu_src_mux_ck", &emu_src_mux_ck),
+ CLK("etb", "emu_src_ck", &emu_src_ck),
+ CLK(NULL, "emu_src_mux_ck", &emu_src_mux_ck),
+ CLK(NULL, "emu_src_ck", &emu_src_ck),
+ CLK(NULL, "pclk_fck", &pclk_fck),
+ CLK(NULL, "pclkx2_fck", &pclkx2_fck),
+ CLK(NULL, "atclk_fck", &atclk_fck),
+ CLK(NULL, "traceclk_src_fck", &traceclk_src_fck),
+ CLK(NULL, "traceclk_fck", &traceclk_fck),
+ CLK(NULL, "secure_32k_fck", &secure_32k_fck),
+ CLK(NULL, "gpt12_fck", &gpt12_fck),
+ CLK(NULL, "wdt1_fck", &wdt1_fck),
+ { NULL },
+};
+
+static struct ti_clk_alias omap36xx_am35xx_omap3430es2plus_clks[] = {
+ CLK(NULL, "dpll5_ck", &dpll5_ck),
+ CLK(NULL, "dpll5_m2_ck", &dpll5_m2_ck),
+ CLK(NULL, "core_d3_ck", &core_d3_ck),
+ CLK(NULL, "core_d4_ck", &core_d4_ck),
+ CLK(NULL, "core_d6_ck", &core_d6_ck),
+ CLK(NULL, "omap_192m_alwon_fck", &omap_192m_alwon_fck),
+ CLK(NULL, "core_d2_ck", &core_d2_ck),
+ CLK(NULL, "corex2_d3_fck", &corex2_d3_fck),
+ CLK(NULL, "corex2_d5_fck", &corex2_d5_fck),
+ CLK(NULL, "sgx_fck", &sgx_fck),
+ CLK(NULL, "sgx_ick", &sgx_ick),
+ CLK(NULL, "cpefuse_fck", &cpefuse_fck),
+ CLK(NULL, "ts_fck", &ts_fck),
+ CLK(NULL, "usbtll_fck", &usbtll_fck),
+ CLK(NULL, "usbtll_ick", &usbtll_ick),
+ CLK("omap_hsmmc.2", "ick", &mmchs3_ick),
+ CLK(NULL, "mmchs3_ick", &mmchs3_ick),
+ CLK(NULL, "mmchs3_fck", &mmchs3_fck),
+ CLK(NULL, "dss1_alwon_fck", &dss1_alwon_fck_3430es2),
+ CLK("omapdss_dss", "ick", &dss_ick_3430es2),
+ CLK(NULL, "dss_ick", &dss_ick_3430es2),
+ CLK(NULL, "usbhost_120m_fck", &usbhost_120m_fck),
+ CLK(NULL, "usbhost_48m_fck", &usbhost_48m_fck),
+ CLK(NULL, "usbhost_ick", &usbhost_ick),
+ { NULL },
+};
+
+static struct ti_clk_alias omap3430es1_clks[] = {
+ CLK(NULL, "gfx_l3_ck", &gfx_l3_ck),
+ CLK(NULL, "gfx_l3_fck", &gfx_l3_fck),
+ CLK(NULL, "gfx_l3_ick", &gfx_l3_ick),
+ CLK(NULL, "gfx_cg1_ck", &gfx_cg1_ck),
+ CLK(NULL, "gfx_cg2_ck", &gfx_cg2_ck),
+ CLK(NULL, "d2d_26m_fck", &d2d_26m_fck),
+ CLK(NULL, "fshostusb_fck", &fshostusb_fck),
+ CLK(NULL, "ssi_ssr_fck", &ssi_ssr_fck_3430es1),
+ CLK(NULL, "ssi_sst_fck", &ssi_sst_fck_3430es1),
+ CLK("musb-omap2430", "ick", &hsotgusb_ick_3430es1),
+ CLK(NULL, "hsotgusb_ick", &hsotgusb_ick_3430es1),
+ CLK(NULL, "fac_ick", &fac_ick),
+ CLK(NULL, "ssi_ick", &ssi_ick_3430es1),
+ CLK(NULL, "usb_l4_ick", &usb_l4_ick),
+ CLK(NULL, "dss1_alwon_fck", &dss1_alwon_fck_3430es1),
+ CLK("omapdss_dss", "ick", &dss_ick_3430es1),
+ CLK(NULL, "dss_ick", &dss_ick_3430es1),
+ { NULL },
+};
+
+static struct ti_clk_alias omap36xx_clks[] = {
+ CLK(NULL, "uart4_fck", &uart4_fck),
+ { NULL },
+};
+
+static struct ti_clk_alias am35xx_clks[] = {
+ CLK(NULL, "ipss_ick", &ipss_ick),
+ CLK(NULL, "rmii_ck", &rmii_ck),
+ CLK(NULL, "pclk_ck", &pclk_ck),
+ CLK(NULL, "emac_ick", &emac_ick),
+ CLK(NULL, "emac_fck", &emac_fck),
+ CLK("davinci_emac.0", NULL, &emac_ick),
+ CLK("davinci_mdio.0", NULL, &emac_fck),
+ CLK("vpfe-capture", "master", &vpfe_ick),
+ CLK("vpfe-capture", "slave", &vpfe_fck),
+ CLK(NULL, "hsotgusb_ick", &hsotgusb_ick_am35xx),
+ CLK(NULL, "hsotgusb_fck", &hsotgusb_fck_am35xx),
+ CLK(NULL, "hecc_ck", &hecc_ck),
+ CLK(NULL, "uart4_ick", &uart4_ick_am35xx),
+ CLK(NULL, "uart4_fck", &uart4_fck_am35xx),
+ { NULL },
+};
+
+static struct ti_clk *omap36xx_clk_patches[] = {
+ &dpll4_m3x2_ck_omap36xx,
+ &dpll3_m3x2_ck_omap36xx,
+ &dpll4_m6x2_ck_omap36xx,
+ &dpll4_m2x2_ck_omap36xx,
+ &dpll4_m5x2_ck_omap36xx,
+ &dpll4_ck_omap36xx,
+ NULL,
+};
+
+static const char *enable_init_clks[] = {
+ "sdrc_ick",
+ "gpmc_fck",
+ "omapctrl_ick",
+};
+
+static void __init omap3_clk_legacy_common_init(void)
+{
+ omap2_clk_disable_autoidle_all();
+
+ omap2_clk_enable_init_clocks(enable_init_clks,
+ ARRAY_SIZE(enable_init_clks));
+
+ pr_info("Clocking rate (Crystal/Core/MPU): %ld.%01ld/%ld/%ld MHz\n",
+ (clk_get_rate(osc_sys_ck.clk) / 1000000),
+ (clk_get_rate(osc_sys_ck.clk) / 100000) % 10,
+ (clk_get_rate(core_ck.clk) / 1000000),
+ (clk_get_rate(arm_fck.clk) / 1000000));
+}
+
+int __init omap3430es1_clk_legacy_init(void)
+{
+ int r;
+
+ r = ti_clk_register_legacy_clks(omap3430es1_clks);
+ r |= ti_clk_register_legacy_clks(omap34xx_omap36xx_clks);
+ r |= ti_clk_register_legacy_clks(omap3xxx_clks);
+
+ omap3_clk_legacy_common_init();
+
+ return r;
+}
+
+int __init omap3430_clk_legacy_init(void)
+{
+ int r;
+
+ r = ti_clk_register_legacy_clks(omap34xx_omap36xx_clks);
+ r |= ti_clk_register_legacy_clks(omap36xx_omap3430es2plus_clks);
+ r |= ti_clk_register_legacy_clks(omap36xx_am35xx_omap3430es2plus_clks);
+ r |= ti_clk_register_legacy_clks(omap3xxx_clks);
+
+ omap3_clk_legacy_common_init();
+ omap3_clk_lock_dpll5();
+
+ return r;
+}
+
+int __init omap36xx_clk_legacy_init(void)
+{
+ int r;
+
+ ti_clk_patch_legacy_clks(omap36xx_clk_patches);
+ r = ti_clk_register_legacy_clks(omap36xx_clks);
+ r |= ti_clk_register_legacy_clks(omap36xx_omap3430es2plus_clks);
+ r |= ti_clk_register_legacy_clks(omap34xx_omap36xx_clks);
+ r |= ti_clk_register_legacy_clks(omap36xx_am35xx_omap3430es2plus_clks);
+ r |= ti_clk_register_legacy_clks(omap3xxx_clks);
+
+ omap3_clk_legacy_common_init();
+ omap3_clk_lock_dpll5();
+
+ return r;
+}
+
+int __init am35xx_clk_legacy_init(void)
+{
+ int r;
+
+ r = ti_clk_register_legacy_clks(am35xx_clks);
+ r |= ti_clk_register_legacy_clks(omap36xx_am35xx_omap3430es2plus_clks);
+ r |= ti_clk_register_legacy_clks(omap3xxx_clks);
+
+ omap3_clk_legacy_common_init();
+ omap3_clk_lock_dpll5();
+
+ return r;
+}
diff --git a/drivers/clk/ti/clk-3xxx.c b/drivers/clk/ti/clk-3xxx.c
index 0d1750a..383a06e 100644
--- a/drivers/clk/ti/clk-3xxx.c
+++ b/drivers/clk/ti/clk-3xxx.c
@@ -327,7 +327,6 @@
OMAP3_SOC_OMAP3430_ES1,
OMAP3_SOC_OMAP3430_ES2_PLUS,
OMAP3_SOC_OMAP3630,
- OMAP3_SOC_TI81XX,
};
static int __init omap3xxx_dt_clk_init(int soc_type)
@@ -370,7 +369,7 @@
(clk_get_rate(clk_get_sys(NULL, "core_ck")) / 1000000),
(clk_get_rate(clk_get_sys(NULL, "arm_fck")) / 1000000));
- if (soc_type != OMAP3_SOC_TI81XX && soc_type != OMAP3_SOC_OMAP3430_ES1)
+ if (soc_type != OMAP3_SOC_OMAP3430_ES1)
omap3_clk_lock_dpll5();
return 0;
@@ -390,8 +389,3 @@
{
return omap3xxx_dt_clk_init(OMAP3_SOC_AM35XX);
}
-
-int __init ti81xx_dt_clk_init(void)
-{
- return omap3xxx_dt_clk_init(OMAP3_SOC_TI81XX);
-}
diff --git a/drivers/clk/ti/clk-44xx.c b/drivers/clk/ti/clk-44xx.c
index 02517a8..4f4c877 100644
--- a/drivers/clk/ti/clk-44xx.c
+++ b/drivers/clk/ti/clk-44xx.c
@@ -12,7 +12,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
-#include <linux/clk-private.h>
+#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk/ti.h>
diff --git a/drivers/clk/ti/clk-54xx.c b/drivers/clk/ti/clk-54xx.c
index 5e18399..14160b2 100644
--- a/drivers/clk/ti/clk-54xx.c
+++ b/drivers/clk/ti/clk-54xx.c
@@ -12,7 +12,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
-#include <linux/clk-private.h>
+#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/io.h>
#include <linux/clk/ti.h>
diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c
index 62ac8f6..ee32f4de 100644
--- a/drivers/clk/ti/clk-7xx.c
+++ b/drivers/clk/ti/clk-7xx.c
@@ -12,7 +12,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
-#include <linux/clk-private.h>
+#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk/ti.h>
diff --git a/drivers/clk/ti/clk-816x.c b/drivers/clk/ti/clk-816x.c
new file mode 100644
index 0000000..9451e65
--- /dev/null
+++ b/drivers/clk/ti/clk-816x.c
@@ -0,0 +1,53 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/ti.h>
+
+static struct ti_dt_clk dm816x_clks[] = {
+ DT_CLK(NULL, "sys_clkin", "sys_clkin_ck"),
+ DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"),
+ DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"),
+ DT_CLK(NULL, "mpu_ck", "mpu_ck"),
+ DT_CLK(NULL, "timer1_fck", "timer1_fck"),
+ DT_CLK(NULL, "timer2_fck", "timer2_fck"),
+ DT_CLK(NULL, "timer3_fck", "timer3_fck"),
+ DT_CLK(NULL, "timer4_fck", "timer4_fck"),
+ DT_CLK(NULL, "timer5_fck", "timer5_fck"),
+ DT_CLK(NULL, "timer6_fck", "timer6_fck"),
+ DT_CLK(NULL, "timer7_fck", "timer7_fck"),
+ DT_CLK(NULL, "sysclk4_ck", "sysclk4_ck"),
+ DT_CLK(NULL, "sysclk5_ck", "sysclk5_ck"),
+ DT_CLK(NULL, "sysclk6_ck", "sysclk6_ck"),
+ DT_CLK(NULL, "sysclk10_ck", "sysclk10_ck"),
+ DT_CLK(NULL, "sysclk18_ck", "sysclk18_ck"),
+ DT_CLK(NULL, "sysclk24_ck", "sysclk24_ck"),
+ DT_CLK("4a100000.ethernet", "sysclk24_ck", "sysclk24_ck"),
+ { .node_name = NULL },
+};
+
+static const char *enable_init_clks[] = {
+ "ddr_pll_clk1",
+ "ddr_pll_clk2",
+ "ddr_pll_clk3",
+};
+
+int __init ti81xx_dt_clk_init(void)
+{
+ ti_dt_clocks_register(dm816x_clks);
+ omap2_clk_disable_autoidle_all();
+ omap2_clk_enable_init_clocks(enable_init_clks,
+ ARRAY_SIZE(enable_init_clks));
+
+ return 0;
+}
diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c
index 337abe5..e22b956 100644
--- a/drivers/clk/ti/clk.c
+++ b/drivers/clk/ti/clk.c
@@ -22,6 +22,8 @@
#include <linux/of_address.h>
#include <linux/list.h>
+#include "clock.h"
+
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -183,3 +185,128 @@
retries--;
}
}
+
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS)
+void __init ti_clk_patch_legacy_clks(struct ti_clk **patch)
+{
+ while (*patch) {
+ memcpy((*patch)->patch, *patch, sizeof(**patch));
+ patch++;
+ }
+}
+
+struct clk __init *ti_clk_register_clk(struct ti_clk *setup)
+{
+ struct clk *clk;
+ struct ti_clk_fixed *fixed;
+ struct ti_clk_fixed_factor *fixed_factor;
+ struct clk_hw *clk_hw;
+
+ if (setup->clk)
+ return setup->clk;
+
+ switch (setup->type) {
+ case TI_CLK_FIXED:
+ fixed = setup->data;
+
+ clk = clk_register_fixed_rate(NULL, setup->name, NULL,
+ CLK_IS_ROOT, fixed->frequency);
+ break;
+ case TI_CLK_MUX:
+ clk = ti_clk_register_mux(setup);
+ break;
+ case TI_CLK_DIVIDER:
+ clk = ti_clk_register_divider(setup);
+ break;
+ case TI_CLK_COMPOSITE:
+ clk = ti_clk_register_composite(setup);
+ break;
+ case TI_CLK_FIXED_FACTOR:
+ fixed_factor = setup->data;
+
+ clk = clk_register_fixed_factor(NULL, setup->name,
+ fixed_factor->parent,
+ 0, fixed_factor->mult,
+ fixed_factor->div);
+ break;
+ case TI_CLK_GATE:
+ clk = ti_clk_register_gate(setup);
+ break;
+ case TI_CLK_DPLL:
+ clk = ti_clk_register_dpll(setup);
+ break;
+ default:
+ pr_err("bad type for %s!\n", setup->name);
+ clk = ERR_PTR(-EINVAL);
+ }
+
+ if (!IS_ERR(clk)) {
+ setup->clk = clk;
+ if (setup->clkdm_name) {
+ if (__clk_get_flags(clk) & CLK_IS_BASIC) {
+ pr_warn("can't setup clkdm for basic clk %s\n",
+ setup->name);
+ } else {
+ clk_hw = __clk_get_hw(clk);
+ to_clk_hw_omap(clk_hw)->clkdm_name =
+ setup->clkdm_name;
+ omap2_init_clk_clkdm(clk_hw);
+ }
+ }
+ }
+
+ return clk;
+}
+
+int __init ti_clk_register_legacy_clks(struct ti_clk_alias *clks)
+{
+ struct clk *clk;
+ bool retry;
+ struct ti_clk_alias *retry_clk;
+ struct ti_clk_alias *tmp;
+
+ while (clks->clk) {
+ clk = ti_clk_register_clk(clks->clk);
+ if (IS_ERR(clk)) {
+ if (PTR_ERR(clk) == -EAGAIN) {
+ list_add(&clks->link, &retry_list);
+ } else {
+ pr_err("register for %s failed: %ld\n",
+ clks->clk->name, PTR_ERR(clk));
+ return PTR_ERR(clk);
+ }
+ } else {
+ clks->lk.clk = clk;
+ clkdev_add(&clks->lk);
+ }
+ clks++;
+ }
+
+ retry = true;
+
+ while (!list_empty(&retry_list) && retry) {
+ retry = false;
+ list_for_each_entry_safe(retry_clk, tmp, &retry_list, link) {
+ pr_debug("retry-init: %s\n", retry_clk->clk->name);
+ clk = ti_clk_register_clk(retry_clk->clk);
+ if (IS_ERR(clk)) {
+ if (PTR_ERR(clk) == -EAGAIN) {
+ continue;
+ } else {
+ pr_err("register for %s failed: %ld\n",
+ retry_clk->clk->name,
+ PTR_ERR(clk));
+ return PTR_ERR(clk);
+ }
+ } else {
+ retry = true;
+ retry_clk->lk.clk = clk;
+ clkdev_add(&retry_clk->lk);
+ list_del(&retry_clk->link);
+ }
+ }
+ }
+
+ return 0;
+}
+#endif
diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h
new file mode 100644
index 0000000..404158d
--- /dev/null
+++ b/drivers/clk/ti/clock.h
@@ -0,0 +1,172 @@
+/*
+ * TI Clock driver internal definitions
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc
+ * Tero Kristo (t-kristo@ti.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __DRIVERS_CLK_TI_CLOCK__
+#define __DRIVERS_CLK_TI_CLOCK__
+
+enum {
+ TI_CLK_FIXED,
+ TI_CLK_MUX,
+ TI_CLK_DIVIDER,
+ TI_CLK_COMPOSITE,
+ TI_CLK_FIXED_FACTOR,
+ TI_CLK_GATE,
+ TI_CLK_DPLL,
+};
+
+/* Global flags */
+#define CLKF_INDEX_POWER_OF_TWO (1 << 0)
+#define CLKF_INDEX_STARTS_AT_ONE (1 << 1)
+#define CLKF_SET_RATE_PARENT (1 << 2)
+#define CLKF_OMAP3 (1 << 3)
+#define CLKF_AM35XX (1 << 4)
+
+/* Gate flags */
+#define CLKF_SET_BIT_TO_DISABLE (1 << 5)
+#define CLKF_INTERFACE (1 << 6)
+#define CLKF_SSI (1 << 7)
+#define CLKF_DSS (1 << 8)
+#define CLKF_HSOTGUSB (1 << 9)
+#define CLKF_WAIT (1 << 10)
+#define CLKF_NO_WAIT (1 << 11)
+#define CLKF_HSDIV (1 << 12)
+#define CLKF_CLKDM (1 << 13)
+
+/* DPLL flags */
+#define CLKF_LOW_POWER_STOP (1 << 5)
+#define CLKF_LOCK (1 << 6)
+#define CLKF_LOW_POWER_BYPASS (1 << 7)
+#define CLKF_PER (1 << 8)
+#define CLKF_CORE (1 << 9)
+#define CLKF_J_TYPE (1 << 10)
+
+#define CLK(dev, con, ck) \
+ { \
+ .lk = { \
+ .dev_id = dev, \
+ .con_id = con, \
+ }, \
+ .clk = ck, \
+ }
+
+struct ti_clk {
+ const char *name;
+ const char *clkdm_name;
+ int type;
+ void *data;
+ struct ti_clk *patch;
+ struct clk *clk;
+};
+
+struct ti_clk_alias {
+ struct ti_clk *clk;
+ struct clk_lookup lk;
+ struct list_head link;
+};
+
+struct ti_clk_fixed {
+ u32 frequency;
+ u16 flags;
+};
+
+struct ti_clk_mux {
+ u8 bit_shift;
+ int num_parents;
+ u16 reg;
+ u8 module;
+ const char **parents;
+ u16 flags;
+};
+
+struct ti_clk_divider {
+ const char *parent;
+ u8 bit_shift;
+ u16 max_div;
+ u16 reg;
+ u8 module;
+ int *dividers;
+ int num_dividers;
+ u16 flags;
+};
+
+struct ti_clk_fixed_factor {
+ const char *parent;
+ u16 div;
+ u16 mult;
+ u16 flags;
+};
+
+struct ti_clk_gate {
+ const char *parent;
+ u8 bit_shift;
+ u16 reg;
+ u8 module;
+ u16 flags;
+};
+
+struct ti_clk_composite {
+ struct ti_clk_divider *divider;
+ struct ti_clk_mux *mux;
+ struct ti_clk_gate *gate;
+ u16 flags;
+};
+
+struct ti_clk_clkdm_gate {
+ const char *parent;
+ u16 flags;
+};
+
+struct ti_clk_dpll {
+ int num_parents;
+ u16 control_reg;
+ u16 idlest_reg;
+ u16 autoidle_reg;
+ u16 mult_div1_reg;
+ u8 module;
+ const char **parents;
+ u16 flags;
+ u8 modes;
+ u32 mult_mask;
+ u32 div1_mask;
+ u32 enable_mask;
+ u32 autoidle_mask;
+ u32 freqsel_mask;
+ u32 idlest_mask;
+ u32 dco_mask;
+ u32 sddiv_mask;
+ u16 max_multiplier;
+ u16 max_divider;
+ u8 min_divider;
+ u8 auto_recal_bit;
+ u8 recal_en_bit;
+ u8 recal_st_bit;
+};
+
+struct clk *ti_clk_register_gate(struct ti_clk *setup);
+struct clk *ti_clk_register_interface(struct ti_clk *setup);
+struct clk *ti_clk_register_mux(struct ti_clk *setup);
+struct clk *ti_clk_register_divider(struct ti_clk *setup);
+struct clk *ti_clk_register_composite(struct ti_clk *setup);
+struct clk *ti_clk_register_dpll(struct ti_clk *setup);
+
+struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup);
+struct clk_hw *ti_clk_build_component_gate(struct ti_clk_gate *setup);
+struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup);
+
+void ti_clk_patch_legacy_clks(struct ti_clk **patch);
+struct clk *ti_clk_register_clk(struct ti_clk *setup);
+int ti_clk_register_legacy_clks(struct ti_clk_alias *clks);
+
+#endif
diff --git a/drivers/clk/ti/composite.c b/drivers/clk/ti/composite.c
index 19d8980..3654f61 100644
--- a/drivers/clk/ti/composite.c
+++ b/drivers/clk/ti/composite.c
@@ -23,6 +23,8 @@
#include <linux/clk/ti.h>
#include <linux/list.h>
+#include "clock.h"
+
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -116,8 +118,46 @@
#define to_clk_hw_comp(_hw) container_of(_hw, struct clk_hw_omap_comp, hw)
-static void __init ti_clk_register_composite(struct clk_hw *hw,
- struct device_node *node)
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS)
+struct clk *ti_clk_register_composite(struct ti_clk *setup)
+{
+ struct ti_clk_composite *comp;
+ struct clk_hw *gate;
+ struct clk_hw *mux;
+ struct clk_hw *div;
+ int num_parents = 1;
+ const char **parent_names = NULL;
+ struct clk *clk;
+
+ comp = setup->data;
+
+ div = ti_clk_build_component_div(comp->divider);
+ gate = ti_clk_build_component_gate(comp->gate);
+ mux = ti_clk_build_component_mux(comp->mux);
+
+ if (div)
+ parent_names = &comp->divider->parent;
+
+ if (gate)
+ parent_names = &comp->gate->parent;
+
+ if (mux) {
+ num_parents = comp->mux->num_parents;
+ parent_names = comp->mux->parents;
+ }
+
+ clk = clk_register_composite(NULL, setup->name,
+ parent_names, num_parents, mux,
+ &ti_clk_mux_ops, div,
+ &ti_composite_divider_ops, gate,
+ &ti_composite_gate_ops, 0);
+
+ return clk;
+}
+#endif
+
+static void __init _register_composite(struct clk_hw *hw,
+ struct device_node *node)
{
struct clk *clk;
struct clk_hw_omap_comp *cclk = to_clk_hw_comp(hw);
@@ -136,7 +176,7 @@
pr_debug("component %s not ready for %s, retry\n",
cclk->comp_nodes[i]->name, node->name);
if (!ti_clk_retry_init(node, hw,
- ti_clk_register_composite))
+ _register_composite))
return;
goto cleanup;
@@ -216,7 +256,7 @@
for (i = 0; i < num_clks; i++)
cclk->comp_nodes[i] = _get_component_node(node, i);
- ti_clk_register_composite(&cclk->hw, node);
+ _register_composite(&cclk->hw, node);
}
CLK_OF_DECLARE(ti_composite_clock, "ti,composite-clock",
of_ti_composite_clk_setup);
diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c
index bff2b5b..6211893 100644
--- a/drivers/clk/ti/divider.c
+++ b/drivers/clk/ti/divider.c
@@ -21,6 +21,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clk/ti.h>
+#include "clock.h"
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -301,6 +302,134 @@
}
static struct clk_div_table *
+_get_div_table_from_setup(struct ti_clk_divider *setup, u8 *width)
+{
+ int valid_div = 0;
+ struct clk_div_table *table;
+ int i;
+ int div;
+ u32 val;
+ u8 flags;
+
+ if (!setup->num_dividers) {
+ /* Clk divider table not provided, determine min/max divs */
+ flags = setup->flags;
+
+ if (flags & CLKF_INDEX_STARTS_AT_ONE)
+ val = 1;
+ else
+ val = 0;
+
+ div = 1;
+
+ while (div < setup->max_div) {
+ if (flags & CLKF_INDEX_POWER_OF_TWO)
+ div <<= 1;
+ else
+ div++;
+ val++;
+ }
+
+ *width = fls(val);
+
+ return NULL;
+ }
+
+ for (i = 0; i < setup->num_dividers; i++)
+ if (setup->dividers[i])
+ valid_div++;
+
+ table = kzalloc(sizeof(*table) * (valid_div + 1), GFP_KERNEL);
+ if (!table)
+ return ERR_PTR(-ENOMEM);
+
+ valid_div = 0;
+ *width = 0;
+
+ for (i = 0; i < setup->num_dividers; i++)
+ if (setup->dividers[i]) {
+ table[valid_div].div = setup->dividers[i];
+ table[valid_div].val = i;
+ valid_div++;
+ *width = i;
+ }
+
+ *width = fls(*width);
+
+ return table;
+}
+
+struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup)
+{
+ struct clk_divider *div;
+ struct clk_omap_reg *reg;
+
+ if (!setup)
+ return NULL;
+
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+ if (!div)
+ return ERR_PTR(-ENOMEM);
+
+ reg = (struct clk_omap_reg *)&div->reg;
+ reg->index = setup->module;
+ reg->offset = setup->reg;
+
+ if (setup->flags & CLKF_INDEX_STARTS_AT_ONE)
+ div->flags |= CLK_DIVIDER_ONE_BASED;
+
+ if (setup->flags & CLKF_INDEX_POWER_OF_TWO)
+ div->flags |= CLK_DIVIDER_POWER_OF_TWO;
+
+ div->table = _get_div_table_from_setup(setup, &div->width);
+
+ div->shift = setup->bit_shift;
+
+ return &div->hw;
+}
+
+struct clk *ti_clk_register_divider(struct ti_clk *setup)
+{
+ struct ti_clk_divider *div;
+ struct clk_omap_reg *reg_setup;
+ u32 reg;
+ u8 width;
+ u32 flags = 0;
+ u8 div_flags = 0;
+ struct clk_div_table *table;
+ struct clk *clk;
+
+ div = setup->data;
+
+ reg_setup = (struct clk_omap_reg *)®
+
+ reg_setup->index = div->module;
+ reg_setup->offset = div->reg;
+
+ if (div->flags & CLKF_INDEX_STARTS_AT_ONE)
+ div_flags |= CLK_DIVIDER_ONE_BASED;
+
+ if (div->flags & CLKF_INDEX_POWER_OF_TWO)
+ div_flags |= CLK_DIVIDER_POWER_OF_TWO;
+
+ if (div->flags & CLKF_SET_RATE_PARENT)
+ flags |= CLK_SET_RATE_PARENT;
+
+ table = _get_div_table_from_setup(div, &width);
+ if (IS_ERR(table))
+ return (struct clk *)table;
+
+ clk = _register_divider(NULL, setup->name, div->parent,
+ flags, (void __iomem *)reg, div->bit_shift,
+ width, div_flags, table, NULL);
+
+ if (IS_ERR(clk))
+ kfree(table);
+
+ return clk;
+}
+
+static struct clk_div_table *
__init ti_clk_get_div_table(struct device_node *node)
{
struct clk_div_table *table;
@@ -455,7 +584,8 @@
goto cleanup;
clk = _register_divider(NULL, node->name, parent_name, flags, reg,
- shift, width, clk_divider_flags, table, NULL);
+ shift, width, clk_divider_flags, table,
+ NULL);
if (!IS_ERR(clk)) {
of_clk_add_provider(node, of_clk_src_simple_get, clk);
diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c
index 85ac0dd..81dc469 100644
--- a/drivers/clk/ti/dpll.c
+++ b/drivers/clk/ti/dpll.c
@@ -21,6 +21,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clk/ti.h>
+#include "clock.h"
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -130,7 +131,7 @@
};
/**
- * ti_clk_register_dpll - low level registration of a DPLL clock
+ * _register_dpll - low level registration of a DPLL clock
* @hw: hardware clock definition for the clock
* @node: device node for the clock
*
@@ -138,8 +139,8 @@
* clk-bypass is missing), the clock is added to retry list and
* the initialization is retried on later stage.
*/
-static void __init ti_clk_register_dpll(struct clk_hw *hw,
- struct device_node *node)
+static void __init _register_dpll(struct clk_hw *hw,
+ struct device_node *node)
{
struct clk_hw_omap *clk_hw = to_clk_hw_omap(hw);
struct dpll_data *dd = clk_hw->dpll_data;
@@ -151,7 +152,7 @@
if (IS_ERR(dd->clk_ref) || IS_ERR(dd->clk_bypass)) {
pr_debug("clk-ref or clk-bypass missing for %s, retry later\n",
node->name);
- if (!ti_clk_retry_init(node, hw, ti_clk_register_dpll))
+ if (!ti_clk_retry_init(node, hw, _register_dpll))
return;
goto cleanup;
@@ -175,20 +176,118 @@
kfree(clk_hw);
}
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS)
+void __iomem *_get_reg(u8 module, u16 offset)
+{
+ u32 reg;
+ struct clk_omap_reg *reg_setup;
+
+ reg_setup = (struct clk_omap_reg *)®
+
+ reg_setup->index = module;
+ reg_setup->offset = offset;
+
+ return (void __iomem *)reg;
+}
+
+struct clk *ti_clk_register_dpll(struct ti_clk *setup)
+{
+ struct clk_hw_omap *clk_hw;
+ struct clk_init_data init = { NULL };
+ struct dpll_data *dd;
+ struct clk *clk;
+ struct ti_clk_dpll *dpll;
+ const struct clk_ops *ops = &omap3_dpll_ck_ops;
+ struct clk *clk_ref;
+ struct clk *clk_bypass;
+
+ dpll = setup->data;
+
+ if (dpll->num_parents < 2)
+ return ERR_PTR(-EINVAL);
+
+ clk_ref = clk_get_sys(NULL, dpll->parents[0]);
+ clk_bypass = clk_get_sys(NULL, dpll->parents[1]);
+
+ if (IS_ERR_OR_NULL(clk_ref) || IS_ERR_OR_NULL(clk_bypass))
+ return ERR_PTR(-EAGAIN);
+
+ dd = kzalloc(sizeof(*dd), GFP_KERNEL);
+ clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
+ if (!dd || !clk_hw) {
+ clk = ERR_PTR(-ENOMEM);
+ goto cleanup;
+ }
+
+ clk_hw->dpll_data = dd;
+ clk_hw->ops = &clkhwops_omap3_dpll;
+ clk_hw->hw.init = &init;
+ clk_hw->flags = MEMMAP_ADDRESSING;
+
+ init.name = setup->name;
+ init.ops = ops;
+
+ init.num_parents = dpll->num_parents;
+ init.parent_names = dpll->parents;
+
+ dd->control_reg = _get_reg(dpll->module, dpll->control_reg);
+ dd->idlest_reg = _get_reg(dpll->module, dpll->idlest_reg);
+ dd->mult_div1_reg = _get_reg(dpll->module, dpll->mult_div1_reg);
+ dd->autoidle_reg = _get_reg(dpll->module, dpll->autoidle_reg);
+
+ dd->modes = dpll->modes;
+ dd->div1_mask = dpll->div1_mask;
+ dd->idlest_mask = dpll->idlest_mask;
+ dd->mult_mask = dpll->mult_mask;
+ dd->autoidle_mask = dpll->autoidle_mask;
+ dd->enable_mask = dpll->enable_mask;
+ dd->sddiv_mask = dpll->sddiv_mask;
+ dd->dco_mask = dpll->dco_mask;
+ dd->max_divider = dpll->max_divider;
+ dd->min_divider = dpll->min_divider;
+ dd->max_multiplier = dpll->max_multiplier;
+ dd->auto_recal_bit = dpll->auto_recal_bit;
+ dd->recal_en_bit = dpll->recal_en_bit;
+ dd->recal_st_bit = dpll->recal_st_bit;
+
+ dd->clk_ref = clk_ref;
+ dd->clk_bypass = clk_bypass;
+
+ if (dpll->flags & CLKF_CORE)
+ ops = &omap3_dpll_core_ck_ops;
+
+ if (dpll->flags & CLKF_PER)
+ ops = &omap3_dpll_per_ck_ops;
+
+ if (dpll->flags & CLKF_J_TYPE)
+ dd->flags |= DPLL_J_TYPE;
+
+ clk = clk_register(NULL, &clk_hw->hw);
+
+ if (!IS_ERR(clk))
+ return clk;
+
+cleanup:
+ kfree(dd);
+ kfree(clk_hw);
+ return clk;
+}
+#endif
+
#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \
defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM33XX) || \
defined(CONFIG_SOC_AM43XX)
/**
- * ti_clk_register_dpll_x2 - Registers a DPLLx2 clock
+ * _register_dpll_x2 - Registers a DPLLx2 clock
* @node: device node for this clock
* @ops: clk_ops for this clock
* @hw_ops: clk_hw_ops for this clock
*
* Initializes a DPLL x 2 clock from device tree data.
*/
-static void ti_clk_register_dpll_x2(struct device_node *node,
- const struct clk_ops *ops,
- const struct clk_hw_omap_ops *hw_ops)
+static void _register_dpll_x2(struct device_node *node,
+ const struct clk_ops *ops,
+ const struct clk_hw_omap_ops *hw_ops)
{
struct clk *clk;
struct clk_init_data init = { NULL };
@@ -318,7 +417,7 @@
if (dpll_mode)
dd->modes = dpll_mode;
- ti_clk_register_dpll(&clk_hw->hw, node);
+ _register_dpll(&clk_hw->hw, node);
return;
cleanup:
@@ -332,7 +431,7 @@
defined(CONFIG_SOC_DRA7XX)
static void __init of_ti_omap4_dpll_x2_setup(struct device_node *node)
{
- ti_clk_register_dpll_x2(node, &dpll_x2_ck_ops, &clkhwops_omap4_dpllmx);
+ _register_dpll_x2(node, &dpll_x2_ck_ops, &clkhwops_omap4_dpllmx);
}
CLK_OF_DECLARE(ti_omap4_dpll_x2_clock, "ti,omap4-dpll-x2-clock",
of_ti_omap4_dpll_x2_setup);
@@ -341,7 +440,7 @@
#if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX)
static void __init of_ti_am3_dpll_x2_setup(struct device_node *node)
{
- ti_clk_register_dpll_x2(node, &dpll_x2_ck_ops, NULL);
+ _register_dpll_x2(node, &dpll_x2_ck_ops, NULL);
}
CLK_OF_DECLARE(ti_am3_dpll_x2_clock, "ti,am3-dpll-x2-clock",
of_ti_am3_dpll_x2_setup);
diff --git a/drivers/clk/ti/fapll.c b/drivers/clk/ti/fapll.c
new file mode 100644
index 0000000..6ef8963
--- /dev/null
+++ b/drivers/clk/ti/fapll.c
@@ -0,0 +1,410 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk/ti.h>
+#include <asm/div64.h>
+
+/* FAPLL Control Register PLL_CTRL */
+#define FAPLL_MAIN_LOCK BIT(7)
+#define FAPLL_MAIN_PLLEN BIT(3)
+#define FAPLL_MAIN_BP BIT(2)
+#define FAPLL_MAIN_LOC_CTL BIT(0)
+
+/* FAPLL powerdown register PWD */
+#define FAPLL_PWD_OFFSET 4
+
+#define MAX_FAPLL_OUTPUTS 7
+#define FAPLL_MAX_RETRIES 1000
+
+#define to_fapll(_hw) container_of(_hw, struct fapll_data, hw)
+#define to_synth(_hw) container_of(_hw, struct fapll_synth, hw)
+
+/* The bypass bit is inverted on the ddr_pll.. */
+#define fapll_is_ddr_pll(va) (((u32)(va) & 0xffff) == 0x0440)
+
+/*
+ * The audio_pll_clk1 input is hard wired to the 27MHz bypass clock,
+ * and the audio_pll_clk1 synthesizer is hardwared to 32KiHz output.
+ */
+#define is_ddr_pll_clk1(va) (((u32)(va) & 0xffff) == 0x044c)
+#define is_audio_pll_clk1(va) (((u32)(va) & 0xffff) == 0x04a8)
+
+/* Synthesizer divider register */
+#define SYNTH_LDMDIV1 BIT(8)
+
+/* Synthesizer frequency register */
+#define SYNTH_LDFREQ BIT(31)
+
+struct fapll_data {
+ struct clk_hw hw;
+ void __iomem *base;
+ const char *name;
+ struct clk *clk_ref;
+ struct clk *clk_bypass;
+ struct clk_onecell_data outputs;
+ bool bypass_bit_inverted;
+};
+
+struct fapll_synth {
+ struct clk_hw hw;
+ struct fapll_data *fd;
+ int index;
+ void __iomem *freq;
+ void __iomem *div;
+ const char *name;
+ struct clk *clk_pll;
+};
+
+static bool ti_fapll_clock_is_bypass(struct fapll_data *fd)
+{
+ u32 v = readl_relaxed(fd->base);
+
+ if (fd->bypass_bit_inverted)
+ return !(v & FAPLL_MAIN_BP);
+ else
+ return !!(v & FAPLL_MAIN_BP);
+}
+
+static int ti_fapll_enable(struct clk_hw *hw)
+{
+ struct fapll_data *fd = to_fapll(hw);
+ u32 v = readl_relaxed(fd->base);
+
+ v |= (1 << FAPLL_MAIN_PLLEN);
+ writel_relaxed(v, fd->base);
+
+ return 0;
+}
+
+static void ti_fapll_disable(struct clk_hw *hw)
+{
+ struct fapll_data *fd = to_fapll(hw);
+ u32 v = readl_relaxed(fd->base);
+
+ v &= ~(1 << FAPLL_MAIN_PLLEN);
+ writel_relaxed(v, fd->base);
+}
+
+static int ti_fapll_is_enabled(struct clk_hw *hw)
+{
+ struct fapll_data *fd = to_fapll(hw);
+ u32 v = readl_relaxed(fd->base);
+
+ return v & (1 << FAPLL_MAIN_PLLEN);
+}
+
+static unsigned long ti_fapll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct fapll_data *fd = to_fapll(hw);
+ u32 fapll_n, fapll_p, v;
+ long long rate;
+
+ if (ti_fapll_clock_is_bypass(fd))
+ return parent_rate;
+
+ rate = parent_rate;
+
+ /* PLL pre-divider is P and multiplier is N */
+ v = readl_relaxed(fd->base);
+ fapll_p = (v >> 8) & 0xff;
+ if (fapll_p)
+ do_div(rate, fapll_p);
+ fapll_n = v >> 16;
+ if (fapll_n)
+ rate *= fapll_n;
+
+ return rate;
+}
+
+static u8 ti_fapll_get_parent(struct clk_hw *hw)
+{
+ struct fapll_data *fd = to_fapll(hw);
+
+ if (ti_fapll_clock_is_bypass(fd))
+ return 1;
+
+ return 0;
+}
+
+static struct clk_ops ti_fapll_ops = {
+ .enable = ti_fapll_enable,
+ .disable = ti_fapll_disable,
+ .is_enabled = ti_fapll_is_enabled,
+ .recalc_rate = ti_fapll_recalc_rate,
+ .get_parent = ti_fapll_get_parent,
+};
+
+static int ti_fapll_synth_enable(struct clk_hw *hw)
+{
+ struct fapll_synth *synth = to_synth(hw);
+ u32 v = readl_relaxed(synth->fd->base + FAPLL_PWD_OFFSET);
+
+ v &= ~(1 << synth->index);
+ writel_relaxed(v, synth->fd->base + FAPLL_PWD_OFFSET);
+
+ return 0;
+}
+
+static void ti_fapll_synth_disable(struct clk_hw *hw)
+{
+ struct fapll_synth *synth = to_synth(hw);
+ u32 v = readl_relaxed(synth->fd->base + FAPLL_PWD_OFFSET);
+
+ v |= 1 << synth->index;
+ writel_relaxed(v, synth->fd->base + FAPLL_PWD_OFFSET);
+}
+
+static int ti_fapll_synth_is_enabled(struct clk_hw *hw)
+{
+ struct fapll_synth *synth = to_synth(hw);
+ u32 v = readl_relaxed(synth->fd->base + FAPLL_PWD_OFFSET);
+
+ return !(v & (1 << synth->index));
+}
+
+/*
+ * See dm816x TRM chapter 1.10.3 Flying Adder PLL fore more info
+ */
+static unsigned long ti_fapll_synth_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct fapll_synth *synth = to_synth(hw);
+ u32 synth_div_m;
+ long long rate;
+
+ /* The audio_pll_clk1 is hardwired to produce 32.768KiHz clock */
+ if (!synth->div)
+ return 32768;
+
+ /*
+ * PLL in bypass sets the synths in bypass mode too. The PLL rate
+ * can be also be set to 27MHz, so we can't use parent_rate to
+ * check for bypass mode.
+ */
+ if (ti_fapll_clock_is_bypass(synth->fd))
+ return parent_rate;
+
+ rate = parent_rate;
+
+ /*
+ * Synth frequency integer and fractional divider.
+ * Note that the phase output K is 8, so the result needs
+ * to be multiplied by 8.
+ */
+ if (synth->freq) {
+ u32 v, synth_int_div, synth_frac_div, synth_div_freq;
+
+ v = readl_relaxed(synth->freq);
+ synth_int_div = (v >> 24) & 0xf;
+ synth_frac_div = v & 0xffffff;
+ synth_div_freq = (synth_int_div * 10000000) + synth_frac_div;
+ rate *= 10000000;
+ do_div(rate, synth_div_freq);
+ rate *= 8;
+ }
+
+ /* Synth ost-divider M */
+ synth_div_m = readl_relaxed(synth->div) & 0xff;
+ do_div(rate, synth_div_m);
+
+ return rate;
+}
+
+static struct clk_ops ti_fapll_synt_ops = {
+ .enable = ti_fapll_synth_enable,
+ .disable = ti_fapll_synth_disable,
+ .is_enabled = ti_fapll_synth_is_enabled,
+ .recalc_rate = ti_fapll_synth_recalc_rate,
+};
+
+static struct clk * __init ti_fapll_synth_setup(struct fapll_data *fd,
+ void __iomem *freq,
+ void __iomem *div,
+ int index,
+ const char *name,
+ const char *parent,
+ struct clk *pll_clk)
+{
+ struct clk_init_data *init;
+ struct fapll_synth *synth;
+
+ init = kzalloc(sizeof(*init), GFP_KERNEL);
+ if (!init)
+ return ERR_PTR(-ENOMEM);
+
+ init->ops = &ti_fapll_synt_ops;
+ init->name = name;
+ init->parent_names = &parent;
+ init->num_parents = 1;
+
+ synth = kzalloc(sizeof(*synth), GFP_KERNEL);
+ if (!synth)
+ goto free;
+
+ synth->fd = fd;
+ synth->index = index;
+ synth->freq = freq;
+ synth->div = div;
+ synth->name = name;
+ synth->hw.init = init;
+ synth->clk_pll = pll_clk;
+
+ return clk_register(NULL, &synth->hw);
+
+free:
+ kfree(synth);
+ kfree(init);
+
+ return ERR_PTR(-ENOMEM);
+}
+
+static void __init ti_fapll_setup(struct device_node *node)
+{
+ struct fapll_data *fd;
+ struct clk_init_data *init = NULL;
+ const char *parent_name[2];
+ struct clk *pll_clk;
+ int i;
+
+ fd = kzalloc(sizeof(*fd), GFP_KERNEL);
+ if (!fd)
+ return;
+
+ fd->outputs.clks = kzalloc(sizeof(struct clk *) *
+ MAX_FAPLL_OUTPUTS + 1,
+ GFP_KERNEL);
+ if (!fd->outputs.clks)
+ goto free;
+
+ init = kzalloc(sizeof(*init), GFP_KERNEL);
+ if (!init)
+ goto free;
+
+ init->ops = &ti_fapll_ops;
+ init->name = node->name;
+
+ init->num_parents = of_clk_get_parent_count(node);
+ if (init->num_parents != 2) {
+ pr_err("%s must have two parents\n", node->name);
+ goto free;
+ }
+
+ parent_name[0] = of_clk_get_parent_name(node, 0);
+ parent_name[1] = of_clk_get_parent_name(node, 1);
+ init->parent_names = parent_name;
+
+ fd->clk_ref = of_clk_get(node, 0);
+ if (IS_ERR(fd->clk_ref)) {
+ pr_err("%s could not get clk_ref\n", node->name);
+ goto free;
+ }
+
+ fd->clk_bypass = of_clk_get(node, 1);
+ if (IS_ERR(fd->clk_bypass)) {
+ pr_err("%s could not get clk_bypass\n", node->name);
+ goto free;
+ }
+
+ fd->base = of_iomap(node, 0);
+ if (!fd->base) {
+ pr_err("%s could not get IO base\n", node->name);
+ goto free;
+ }
+
+ if (fapll_is_ddr_pll(fd->base))
+ fd->bypass_bit_inverted = true;
+
+ fd->name = node->name;
+ fd->hw.init = init;
+
+ /* Register the parent PLL */
+ pll_clk = clk_register(NULL, &fd->hw);
+ if (IS_ERR(pll_clk))
+ goto unmap;
+
+ fd->outputs.clks[0] = pll_clk;
+ fd->outputs.clk_num++;
+
+ /*
+ * Set up the child synthesizers starting at index 1 as the
+ * PLL output is at index 0. We need to check the clock-indices
+ * for numbering in case there are holes in the synth mapping,
+ * and then probe the synth register to see if it has a FREQ
+ * register available.
+ */
+ for (i = 0; i < MAX_FAPLL_OUTPUTS; i++) {
+ const char *output_name;
+ void __iomem *freq, *div;
+ struct clk *synth_clk;
+ int output_instance;
+ u32 v;
+
+ if (of_property_read_string_index(node, "clock-output-names",
+ i, &output_name))
+ continue;
+
+ if (of_property_read_u32_index(node, "clock-indices", i,
+ &output_instance))
+ output_instance = i;
+
+ freq = fd->base + (output_instance * 8);
+ div = freq + 4;
+
+ /* Check for hardwired audio_pll_clk1 */
+ if (is_audio_pll_clk1(freq)) {
+ freq = 0;
+ div = 0;
+ } else {
+ /* Does the synthesizer have a FREQ register? */
+ v = readl_relaxed(freq);
+ if (!v)
+ freq = 0;
+ }
+ synth_clk = ti_fapll_synth_setup(fd, freq, div, output_instance,
+ output_name, node->name,
+ pll_clk);
+ if (IS_ERR(synth_clk))
+ continue;
+
+ fd->outputs.clks[output_instance] = synth_clk;
+ fd->outputs.clk_num++;
+
+ clk_register_clkdev(synth_clk, output_name, NULL);
+ }
+
+ /* Register the child synthesizers as the FAPLL outputs */
+ of_clk_add_provider(node, of_clk_src_onecell_get, &fd->outputs);
+ /* Add clock alias for the outputs */
+
+ kfree(init);
+
+ return;
+
+unmap:
+ iounmap(fd->base);
+free:
+ if (fd->clk_bypass)
+ clk_put(fd->clk_bypass);
+ if (fd->clk_ref)
+ clk_put(fd->clk_ref);
+ kfree(fd->outputs.clks);
+ kfree(fd);
+ kfree(init);
+}
+
+CLK_OF_DECLARE(ti_fapll_clock, "ti,dm816-fapll-clock", ti_fapll_setup);
diff --git a/drivers/clk/ti/gate.c b/drivers/clk/ti/gate.c
index b326d27..d493307 100644
--- a/drivers/clk/ti/gate.c
+++ b/drivers/clk/ti/gate.c
@@ -22,6 +22,8 @@
#include <linux/of_address.h>
#include <linux/clk/ti.h>
+#include "clock.h"
+
#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
#undef pr_fmt
@@ -90,63 +92,164 @@
return ret;
}
+static struct clk *_register_gate(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ void __iomem *reg, u8 bit_idx,
+ u8 clk_gate_flags, const struct clk_ops *ops,
+ const struct clk_hw_omap_ops *hw_ops)
+{
+ struct clk_init_data init = { NULL };
+ struct clk_hw_omap *clk_hw;
+ struct clk *clk;
+
+ clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
+ if (!clk_hw)
+ return ERR_PTR(-ENOMEM);
+
+ clk_hw->hw.init = &init;
+
+ init.name = name;
+ init.ops = ops;
+
+ clk_hw->enable_reg = reg;
+ clk_hw->enable_bit = bit_idx;
+ clk_hw->ops = hw_ops;
+
+ clk_hw->flags = MEMMAP_ADDRESSING | clk_gate_flags;
+
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ init.flags = flags;
+
+ clk = clk_register(NULL, &clk_hw->hw);
+
+ if (IS_ERR(clk))
+ kfree(clk_hw);
+
+ return clk;
+}
+
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS)
+struct clk *ti_clk_register_gate(struct ti_clk *setup)
+{
+ const struct clk_ops *ops = &omap_gate_clk_ops;
+ const struct clk_hw_omap_ops *hw_ops = NULL;
+ u32 reg;
+ struct clk_omap_reg *reg_setup;
+ u32 flags = 0;
+ u8 clk_gate_flags = 0;
+ struct ti_clk_gate *gate;
+
+ gate = setup->data;
+
+ if (gate->flags & CLKF_INTERFACE)
+ return ti_clk_register_interface(setup);
+
+ reg_setup = (struct clk_omap_reg *)®
+
+ if (gate->flags & CLKF_SET_RATE_PARENT)
+ flags |= CLK_SET_RATE_PARENT;
+
+ if (gate->flags & CLKF_SET_BIT_TO_DISABLE)
+ clk_gate_flags |= INVERT_ENABLE;
+
+ if (gate->flags & CLKF_HSDIV) {
+ ops = &omap_gate_clk_hsdiv_restore_ops;
+ hw_ops = &clkhwops_wait;
+ }
+
+ if (gate->flags & CLKF_DSS)
+ hw_ops = &clkhwops_omap3430es2_dss_usbhost_wait;
+
+ if (gate->flags & CLKF_WAIT)
+ hw_ops = &clkhwops_wait;
+
+ if (gate->flags & CLKF_CLKDM)
+ ops = &omap_gate_clkdm_clk_ops;
+
+ if (gate->flags & CLKF_AM35XX)
+ hw_ops = &clkhwops_am35xx_ipss_module_wait;
+
+ reg_setup->index = gate->module;
+ reg_setup->offset = gate->reg;
+
+ return _register_gate(NULL, setup->name, gate->parent, flags,
+ (void __iomem *)reg, gate->bit_shift,
+ clk_gate_flags, ops, hw_ops);
+}
+
+struct clk_hw *ti_clk_build_component_gate(struct ti_clk_gate *setup)
+{
+ struct clk_hw_omap *gate;
+ struct clk_omap_reg *reg;
+ const struct clk_hw_omap_ops *ops = &clkhwops_wait;
+
+ if (!setup)
+ return NULL;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ return ERR_PTR(-ENOMEM);
+
+ reg = (struct clk_omap_reg *)&gate->enable_reg;
+ reg->index = setup->module;
+ reg->offset = setup->reg;
+
+ gate->enable_bit = setup->bit_shift;
+
+ if (setup->flags & CLKF_NO_WAIT)
+ ops = NULL;
+
+ if (setup->flags & CLKF_INTERFACE)
+ ops = &clkhwops_iclk_wait;
+
+ gate->ops = ops;
+ gate->flags = MEMMAP_ADDRESSING;
+
+ return &gate->hw;
+}
+#endif
+
static void __init _of_ti_gate_clk_setup(struct device_node *node,
const struct clk_ops *ops,
const struct clk_hw_omap_ops *hw_ops)
{
struct clk *clk;
- struct clk_init_data init = { NULL };
- struct clk_hw_omap *clk_hw;
- const char *clk_name = node->name;
const char *parent_name;
+ void __iomem *reg = NULL;
+ u8 enable_bit = 0;
u32 val;
-
- clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
- if (!clk_hw)
- return;
-
- clk_hw->hw.init = &init;
-
- init.name = clk_name;
- init.ops = ops;
+ u32 flags = 0;
+ u8 clk_gate_flags = 0;
if (ops != &omap_gate_clkdm_clk_ops) {
- clk_hw->enable_reg = ti_clk_get_reg_addr(node, 0);
- if (!clk_hw->enable_reg)
- goto cleanup;
+ reg = ti_clk_get_reg_addr(node, 0);
+ if (!reg)
+ return;
if (!of_property_read_u32(node, "ti,bit-shift", &val))
- clk_hw->enable_bit = val;
+ enable_bit = val;
}
- clk_hw->ops = hw_ops;
-
- clk_hw->flags = MEMMAP_ADDRESSING;
-
if (of_clk_get_parent_count(node) != 1) {
- pr_err("%s must have 1 parent\n", clk_name);
- goto cleanup;
+ pr_err("%s must have 1 parent\n", node->name);
+ return;
}
parent_name = of_clk_get_parent_name(node, 0);
- init.parent_names = &parent_name;
- init.num_parents = 1;
if (of_property_read_bool(node, "ti,set-rate-parent"))
- init.flags |= CLK_SET_RATE_PARENT;
+ flags |= CLK_SET_RATE_PARENT;
if (of_property_read_bool(node, "ti,set-bit-to-disable"))
- clk_hw->flags |= INVERT_ENABLE;
+ clk_gate_flags |= INVERT_ENABLE;
- clk = clk_register(NULL, &clk_hw->hw);
+ clk = _register_gate(NULL, node->name, parent_name, flags, reg,
+ enable_bit, clk_gate_flags, ops, hw_ops);
- if (!IS_ERR(clk)) {
+ if (!IS_ERR(clk))
of_clk_add_provider(node, of_clk_src_simple_get, clk);
- return;
- }
-
-cleanup:
- kfree(clk_hw);
}
static void __init
diff --git a/drivers/clk/ti/interface.c b/drivers/clk/ti/interface.c
index 9c3e8c4..265d91f 100644
--- a/drivers/clk/ti/interface.c
+++ b/drivers/clk/ti/interface.c
@@ -20,6 +20,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clk/ti.h>
+#include "clock.h"
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -31,53 +32,102 @@
.is_enabled = &omap2_dflt_clk_is_enabled,
};
-static void __init _of_ti_interface_clk_setup(struct device_node *node,
- const struct clk_hw_omap_ops *ops)
+static struct clk *_register_interface(struct device *dev, const char *name,
+ const char *parent_name,
+ void __iomem *reg, u8 bit_idx,
+ const struct clk_hw_omap_ops *ops)
{
- struct clk *clk;
struct clk_init_data init = { NULL };
struct clk_hw_omap *clk_hw;
- const char *parent_name;
- u32 val;
+ struct clk *clk;
clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
if (!clk_hw)
- return;
+ return ERR_PTR(-ENOMEM);
clk_hw->hw.init = &init;
clk_hw->ops = ops;
clk_hw->flags = MEMMAP_ADDRESSING;
+ clk_hw->enable_reg = reg;
+ clk_hw->enable_bit = bit_idx;
- clk_hw->enable_reg = ti_clk_get_reg_addr(node, 0);
- if (!clk_hw->enable_reg)
- goto cleanup;
-
- if (!of_property_read_u32(node, "ti,bit-shift", &val))
- clk_hw->enable_bit = val;
-
- init.name = node->name;
+ init.name = name;
init.ops = &ti_interface_clk_ops;
init.flags = 0;
- parent_name = of_clk_get_parent_name(node, 0);
- if (!parent_name) {
- pr_err("%s must have a parent\n", node->name);
- goto cleanup;
- }
-
init.num_parents = 1;
init.parent_names = &parent_name;
clk = clk_register(NULL, &clk_hw->hw);
- if (!IS_ERR(clk)) {
- of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ if (IS_ERR(clk))
+ kfree(clk_hw);
+ else
omap2_init_clk_hw_omap_clocks(clk);
+
+ return clk;
+}
+
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS)
+struct clk *ti_clk_register_interface(struct ti_clk *setup)
+{
+ const struct clk_hw_omap_ops *ops = &clkhwops_iclk_wait;
+ u32 reg;
+ struct clk_omap_reg *reg_setup;
+ struct ti_clk_gate *gate;
+
+ gate = setup->data;
+ reg_setup = (struct clk_omap_reg *)®
+ reg_setup->index = gate->module;
+ reg_setup->offset = gate->reg;
+
+ if (gate->flags & CLKF_NO_WAIT)
+ ops = &clkhwops_iclk;
+
+ if (gate->flags & CLKF_HSOTGUSB)
+ ops = &clkhwops_omap3430es2_iclk_hsotgusb_wait;
+
+ if (gate->flags & CLKF_DSS)
+ ops = &clkhwops_omap3430es2_iclk_dss_usbhost_wait;
+
+ if (gate->flags & CLKF_SSI)
+ ops = &clkhwops_omap3430es2_iclk_ssi_wait;
+
+ if (gate->flags & CLKF_AM35XX)
+ ops = &clkhwops_am35xx_ipss_wait;
+
+ return _register_interface(NULL, setup->name, gate->parent,
+ (void __iomem *)reg, gate->bit_shift, ops);
+}
+#endif
+
+static void __init _of_ti_interface_clk_setup(struct device_node *node,
+ const struct clk_hw_omap_ops *ops)
+{
+ struct clk *clk;
+ const char *parent_name;
+ void __iomem *reg;
+ u8 enable_bit = 0;
+ u32 val;
+
+ reg = ti_clk_get_reg_addr(node, 0);
+ if (!reg)
+ return;
+
+ if (!of_property_read_u32(node, "ti,bit-shift", &val))
+ enable_bit = val;
+
+ parent_name = of_clk_get_parent_name(node, 0);
+ if (!parent_name) {
+ pr_err("%s must have a parent\n", node->name);
return;
}
-cleanup:
- kfree(clk_hw);
+ clk = _register_interface(NULL, node->name, parent_name, reg,
+ enable_bit, ops);
+
+ if (!IS_ERR(clk))
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
}
static void __init of_ti_interface_clk_setup(struct device_node *node)
diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c
index e9d650e..728e253 100644
--- a/drivers/clk/ti/mux.c
+++ b/drivers/clk/ti/mux.c
@@ -21,6 +21,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clk/ti.h>
+#include "clock.h"
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -144,6 +145,39 @@
return clk;
}
+struct clk *ti_clk_register_mux(struct ti_clk *setup)
+{
+ struct ti_clk_mux *mux;
+ u32 flags;
+ u8 mux_flags = 0;
+ struct clk_omap_reg *reg_setup;
+ u32 reg;
+ u32 mask;
+
+ reg_setup = (struct clk_omap_reg *)®
+
+ mux = setup->data;
+ flags = CLK_SET_RATE_NO_REPARENT;
+
+ mask = mux->num_parents;
+ if (!(mux->flags & CLKF_INDEX_STARTS_AT_ONE))
+ mask--;
+
+ mask = (1 << fls(mask)) - 1;
+ reg_setup->index = mux->module;
+ reg_setup->offset = mux->reg;
+
+ if (mux->flags & CLKF_INDEX_STARTS_AT_ONE)
+ mux_flags |= CLK_MUX_INDEX_ONE;
+
+ if (mux->flags & CLKF_SET_RATE_PARENT)
+ flags |= CLK_SET_RATE_PARENT;
+
+ return _register_mux(NULL, setup->name, mux->parents, mux->num_parents,
+ flags, (void __iomem *)reg, mux->bit_shift, mask,
+ mux_flags, NULL, NULL);
+}
+
/**
* of_mux_clk_setup - Setup function for simple mux rate clock
* @node: DT node for the clock
@@ -194,8 +228,9 @@
mask = (1 << fls(mask)) - 1;
- clk = _register_mux(NULL, node->name, parent_names, num_parents, flags,
- reg, shift, mask, clk_mux_flags, NULL, NULL);
+ clk = _register_mux(NULL, node->name, parent_names, num_parents,
+ flags, reg, shift, mask, clk_mux_flags, NULL,
+ NULL);
if (!IS_ERR(clk))
of_clk_add_provider(node, of_clk_src_simple_get, clk);
@@ -205,6 +240,37 @@
}
CLK_OF_DECLARE(mux_clk, "ti,mux-clock", of_mux_clk_setup);
+struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup)
+{
+ struct clk_mux *mux;
+ struct clk_omap_reg *reg;
+ int num_parents;
+
+ if (!setup)
+ return NULL;
+
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ if (!mux)
+ return ERR_PTR(-ENOMEM);
+
+ reg = (struct clk_omap_reg *)&mux->reg;
+
+ mux->shift = setup->bit_shift;
+
+ reg->index = setup->module;
+ reg->offset = setup->reg;
+
+ if (setup->flags & CLKF_INDEX_STARTS_AT_ONE)
+ mux->flags |= CLK_MUX_INDEX_ONE;
+
+ num_parents = setup->num_parents;
+
+ mux->mask = num_parents - 1;
+ mux->mask = (1 << fls(mux->mask)) - 1;
+
+ return &mux->hw;
+}
+
static void __init of_ti_composite_mux_clk_setup(struct device_node *node)
{
struct clk_mux *mux;
diff --git a/drivers/clk/ux500/clk-prcc.c b/drivers/clk/ux500/clk-prcc.c
index bd4769a..0e95076 100644
--- a/drivers/clk/ux500/clk-prcc.c
+++ b/drivers/clk/ux500/clk-prcc.c
@@ -8,7 +8,6 @@
*/
#include <linux/clk-provider.h>
-#include <linux/clk-private.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/err.h>
diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c
index e2d63bc..bf63c96 100644
--- a/drivers/clk/ux500/clk-prcmu.c
+++ b/drivers/clk/ux500/clk-prcmu.c
@@ -8,7 +8,6 @@
*/
#include <linux/clk-provider.h>
-#include <linux/clk-private.h>
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/slab.h>
#include <linux/io.h>
diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c
index 9037beb..f870aad 100644
--- a/drivers/clk/zynq/clkc.c
+++ b/drivers/clk/zynq/clkc.c
@@ -303,6 +303,7 @@
clks[cpu_2x] = clk_register_gate(NULL, clk_output_name[cpu_2x],
"cpu_2x_div", CLK_IGNORE_UNUSED, SLCR_ARM_CLK_CTRL,
26, 0, &armclk_lock);
+ clk_prepare_enable(clks[cpu_2x]);
clk = clk_register_fixed_factor(NULL, "cpu_1x_div", "cpu_div", 0, 1,
4 + 2 * tmp);
diff --git a/drivers/cpufreq/Kconfig.powerpc b/drivers/cpufreq/Kconfig.powerpc
index 72564b7..7ea24413 100644
--- a/drivers/cpufreq/Kconfig.powerpc
+++ b/drivers/cpufreq/Kconfig.powerpc
@@ -26,7 +26,7 @@
config PPC_CORENET_CPUFREQ
tristate "CPU frequency scaling driver for Freescale E500MC SoCs"
depends on PPC_E500MC && OF && COMMON_CLK
- select CLK_PPC_CORENET
+ select CLK_QORIQ
help
This adds the CPUFreq driver support for Freescale e500mc,
e5500 and e6500 series SoCs which are capable of changing
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index af5d63c..2fe1950 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -75,29 +75,25 @@
unsigned long key;
u32 desc_version;
- *map_size = 0;
- *desc_size = 0;
- key = 0;
- status = efi_call_early(get_memory_map, map_size, NULL,
- &key, desc_size, &desc_version);
- if (status != EFI_BUFFER_TOO_SMALL)
- return EFI_LOAD_ERROR;
-
+ *map_size = sizeof(*m) * 32;
+again:
/*
* Add an additional efi_memory_desc_t because we're doing an
* allocation which may be in a new descriptor region.
*/
- *map_size += *desc_size;
+ *map_size += sizeof(*m);
status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
*map_size, (void **)&m);
if (status != EFI_SUCCESS)
goto fail;
+ *desc_size = 0;
+ key = 0;
status = efi_call_early(get_memory_map, map_size, m,
&key, desc_size, &desc_version);
if (status == EFI_BUFFER_TOO_SMALL) {
efi_call_early(free_pool, m);
- return EFI_LOAD_ERROR;
+ goto again;
}
if (status != EFI_SUCCESS)
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index ab838d9..22da9c2 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -79,7 +79,7 @@
config I2C_HIX5HD2
tristate "Hix5hd2 high-speed I2C driver"
- depends on ARCH_HIX5HD2
+ depends on ARCH_HIX5HD2 || COMPILE_TEST
help
Say Y here to include support for high-speed I2C controller in the
Hisilicon based hix5hd2 SoCs.
@@ -372,6 +372,16 @@
This support is also available as a module. If so, the module
will be called i2c-bcm2835.
+config I2C_BCM_IPROC
+ tristate "Broadcom iProc I2C controller"
+ depends on ARCH_BCM_IPROC || COMPILE_TEST
+ default ARCH_BCM_IPROC
+ help
+ If you say yes to this option, support will be included for the
+ Broadcom iProc I2C controller.
+
+ If you don't know what to do here, say N.
+
config I2C_BCM_KONA
tristate "BCM Kona I2C adapter"
depends on ARCH_BCM_MOBILE
@@ -465,6 +475,16 @@
This driver can also be built as a module. If so, the module
will be called i2c-designware-pci.
+config I2C_DESIGNWARE_BAYTRAIL
+ bool "Intel Baytrail I2C semaphore support"
+ depends on I2C_DESIGNWARE_PLATFORM && IOSF_MBI=y && ACPI
+ help
+ This driver enables managed host access to the PMIC I2C bus on select
+ Intel BayTrail platforms using the X-Powers AXP288 PMIC. It allows
+ the host to request uninterrupted access to the PMIC's I2C bus from
+ the platform firmware controlling it. You should say Y if running on
+ a BayTrail system using the AXP288.
+
config I2C_EFM32
tristate "EFM32 I2C controller"
depends on ARCH_EFM32 || COMPILE_TEST
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 56388f6..3638feb 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -33,6 +33,7 @@
obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o
obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o
+obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o
obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o
obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
@@ -41,6 +42,7 @@
obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o
obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
i2c-designware-platform-objs := i2c-designware-platdrv.o
+i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o
obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o
i2c-designware-pci-objs := i2c-designware-pcidrv.o
obj-$(CONFIG_I2C_EFM32) += i2c-efm32.o
diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c
new file mode 100644
index 0000000..d3c8915
--- /dev/null
+++ b/drivers/i2c/busses/i2c-bcm-iproc.c
@@ -0,0 +1,461 @@
+/*
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define CFG_OFFSET 0x00
+#define CFG_RESET_SHIFT 31
+#define CFG_EN_SHIFT 30
+#define CFG_M_RETRY_CNT_SHIFT 16
+#define CFG_M_RETRY_CNT_MASK 0x0f
+
+#define TIM_CFG_OFFSET 0x04
+#define TIM_CFG_MODE_400_SHIFT 31
+
+#define M_FIFO_CTRL_OFFSET 0x0c
+#define M_FIFO_RX_FLUSH_SHIFT 31
+#define M_FIFO_TX_FLUSH_SHIFT 30
+#define M_FIFO_RX_CNT_SHIFT 16
+#define M_FIFO_RX_CNT_MASK 0x7f
+#define M_FIFO_RX_THLD_SHIFT 8
+#define M_FIFO_RX_THLD_MASK 0x3f
+
+#define M_CMD_OFFSET 0x30
+#define M_CMD_START_BUSY_SHIFT 31
+#define M_CMD_STATUS_SHIFT 25
+#define M_CMD_STATUS_MASK 0x07
+#define M_CMD_STATUS_SUCCESS 0x0
+#define M_CMD_STATUS_LOST_ARB 0x1
+#define M_CMD_STATUS_NACK_ADDR 0x2
+#define M_CMD_STATUS_NACK_DATA 0x3
+#define M_CMD_STATUS_TIMEOUT 0x4
+#define M_CMD_PROTOCOL_SHIFT 9
+#define M_CMD_PROTOCOL_MASK 0xf
+#define M_CMD_PROTOCOL_BLK_WR 0x7
+#define M_CMD_PROTOCOL_BLK_RD 0x8
+#define M_CMD_PEC_SHIFT 8
+#define M_CMD_RD_CNT_SHIFT 0
+#define M_CMD_RD_CNT_MASK 0xff
+
+#define IE_OFFSET 0x38
+#define IE_M_RX_FIFO_FULL_SHIFT 31
+#define IE_M_RX_THLD_SHIFT 30
+#define IE_M_START_BUSY_SHIFT 28
+
+#define IS_OFFSET 0x3c
+#define IS_M_RX_FIFO_FULL_SHIFT 31
+#define IS_M_RX_THLD_SHIFT 30
+#define IS_M_START_BUSY_SHIFT 28
+
+#define M_TX_OFFSET 0x40
+#define M_TX_WR_STATUS_SHIFT 31
+#define M_TX_DATA_SHIFT 0
+#define M_TX_DATA_MASK 0xff
+
+#define M_RX_OFFSET 0x44
+#define M_RX_STATUS_SHIFT 30
+#define M_RX_STATUS_MASK 0x03
+#define M_RX_PEC_ERR_SHIFT 29
+#define M_RX_DATA_SHIFT 0
+#define M_RX_DATA_MASK 0xff
+
+#define I2C_TIMEOUT_MESC 100
+#define M_TX_RX_FIFO_SIZE 64
+
+enum bus_speed_index {
+ I2C_SPD_100K = 0,
+ I2C_SPD_400K,
+};
+
+struct bcm_iproc_i2c_dev {
+ struct device *device;
+ int irq;
+
+ void __iomem *base;
+
+ struct i2c_adapter adapter;
+
+ struct completion done;
+ int xfer_is_done;
+};
+
+/*
+ * Can be expanded in the future if more interrupt status bits are utilized
+ */
+#define ISR_MASK (1 << IS_M_START_BUSY_SHIFT)
+
+static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data)
+{
+ struct bcm_iproc_i2c_dev *iproc_i2c = data;
+ u32 status = readl(iproc_i2c->base + IS_OFFSET);
+
+ status &= ISR_MASK;
+
+ if (!status)
+ return IRQ_NONE;
+
+ writel(status, iproc_i2c->base + IS_OFFSET);
+ iproc_i2c->xfer_is_done = 1;
+ complete_all(&iproc_i2c->done);
+
+ return IRQ_HANDLED;
+}
+
+static int bcm_iproc_i2c_check_status(struct bcm_iproc_i2c_dev *iproc_i2c,
+ struct i2c_msg *msg)
+{
+ u32 val;
+
+ val = readl(iproc_i2c->base + M_CMD_OFFSET);
+ val = (val >> M_CMD_STATUS_SHIFT) & M_CMD_STATUS_MASK;
+
+ switch (val) {
+ case M_CMD_STATUS_SUCCESS:
+ return 0;
+
+ case M_CMD_STATUS_LOST_ARB:
+ dev_dbg(iproc_i2c->device, "lost bus arbitration\n");
+ return -EAGAIN;
+
+ case M_CMD_STATUS_NACK_ADDR:
+ dev_dbg(iproc_i2c->device, "NAK addr:0x%02x\n", msg->addr);
+ return -ENXIO;
+
+ case M_CMD_STATUS_NACK_DATA:
+ dev_dbg(iproc_i2c->device, "NAK data\n");
+ return -ENXIO;
+
+ case M_CMD_STATUS_TIMEOUT:
+ dev_dbg(iproc_i2c->device, "bus timeout\n");
+ return -ETIMEDOUT;
+
+ default:
+ dev_dbg(iproc_i2c->device, "unknown error code=%d\n", val);
+ return -EIO;
+ }
+}
+
+static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
+ struct i2c_msg *msg)
+{
+ int ret, i;
+ u8 addr;
+ u32 val;
+ unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT_MESC);
+
+ /* need to reserve one byte in the FIFO for the slave address */
+ if (msg->len > M_TX_RX_FIFO_SIZE - 1) {
+ dev_err(iproc_i2c->device,
+ "only support data length up to %u bytes\n",
+ M_TX_RX_FIFO_SIZE - 1);
+ return -EOPNOTSUPP;
+ }
+
+ /* check if bus is busy */
+ if (!!(readl(iproc_i2c->base + M_CMD_OFFSET) &
+ BIT(M_CMD_START_BUSY_SHIFT))) {
+ dev_warn(iproc_i2c->device, "bus is busy\n");
+ return -EBUSY;
+ }
+
+ /* format and load slave address into the TX FIFO */
+ addr = msg->addr << 1 | (msg->flags & I2C_M_RD ? 1 : 0);
+ writel(addr, iproc_i2c->base + M_TX_OFFSET);
+
+ /* for a write transaction, load data into the TX FIFO */
+ if (!(msg->flags & I2C_M_RD)) {
+ for (i = 0; i < msg->len; i++) {
+ val = msg->buf[i];
+
+ /* mark the last byte */
+ if (i == msg->len - 1)
+ val |= 1 << M_TX_WR_STATUS_SHIFT;
+
+ writel(val, iproc_i2c->base + M_TX_OFFSET);
+ }
+ }
+
+ /* mark as incomplete before starting the transaction */
+ reinit_completion(&iproc_i2c->done);
+ iproc_i2c->xfer_is_done = 0;
+
+ /*
+ * Enable the "start busy" interrupt, which will be triggered after the
+ * transaction is done, i.e., the internal start_busy bit, transitions
+ * from 1 to 0.
+ */
+ writel(1 << IE_M_START_BUSY_SHIFT, iproc_i2c->base + IE_OFFSET);
+
+ /*
+ * Now we can activate the transfer. For a read operation, specify the
+ * number of bytes to read
+ */
+ val = 1 << M_CMD_START_BUSY_SHIFT;
+ if (msg->flags & I2C_M_RD) {
+ val |= (M_CMD_PROTOCOL_BLK_RD << M_CMD_PROTOCOL_SHIFT) |
+ (msg->len << M_CMD_RD_CNT_SHIFT);
+ } else {
+ val |= (M_CMD_PROTOCOL_BLK_WR << M_CMD_PROTOCOL_SHIFT);
+ }
+ writel(val, iproc_i2c->base + M_CMD_OFFSET);
+
+ time_left = wait_for_completion_timeout(&iproc_i2c->done, time_left);
+
+ /* disable all interrupts */
+ writel(0, iproc_i2c->base + IE_OFFSET);
+ /* read it back to flush the write */
+ readl(iproc_i2c->base + IE_OFFSET);
+
+ /* make sure the interrupt handler isn't running */
+ synchronize_irq(iproc_i2c->irq);
+
+ if (!time_left && !iproc_i2c->xfer_is_done) {
+ dev_err(iproc_i2c->device, "transaction timed out\n");
+
+ /* flush FIFOs */
+ val = (1 << M_FIFO_RX_FLUSH_SHIFT) |
+ (1 << M_FIFO_TX_FLUSH_SHIFT);
+ writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
+ return -ETIMEDOUT;
+ }
+
+ ret = bcm_iproc_i2c_check_status(iproc_i2c, msg);
+ if (ret) {
+ /* flush both TX/RX FIFOs */
+ val = (1 << M_FIFO_RX_FLUSH_SHIFT) |
+ (1 << M_FIFO_TX_FLUSH_SHIFT);
+ writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
+ return ret;
+ }
+
+ /*
+ * For a read operation, we now need to load the data from FIFO
+ * into the memory buffer
+ */
+ if (msg->flags & I2C_M_RD) {
+ for (i = 0; i < msg->len; i++) {
+ msg->buf[i] = (readl(iproc_i2c->base + M_RX_OFFSET) >>
+ M_RX_DATA_SHIFT) & M_RX_DATA_MASK;
+ }
+ }
+
+ return 0;
+}
+
+static int bcm_iproc_i2c_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg msgs[], int num)
+{
+ struct bcm_iproc_i2c_dev *iproc_i2c = i2c_get_adapdata(adapter);
+ int ret, i;
+
+ /* go through all messages */
+ for (i = 0; i < num; i++) {
+ ret = bcm_iproc_i2c_xfer_single_msg(iproc_i2c, &msgs[i]);
+ if (ret) {
+ dev_dbg(iproc_i2c->device, "xfer failed\n");
+ return ret;
+ }
+ }
+
+ return num;
+}
+
+static uint32_t bcm_iproc_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm bcm_iproc_algo = {
+ .master_xfer = bcm_iproc_i2c_xfer,
+ .functionality = bcm_iproc_i2c_functionality,
+};
+
+static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c)
+{
+ unsigned int bus_speed;
+ u32 val;
+ int ret = of_property_read_u32(iproc_i2c->device->of_node,
+ "clock-frequency", &bus_speed);
+ if (ret < 0) {
+ dev_info(iproc_i2c->device,
+ "unable to interpret clock-frequency DT property\n");
+ bus_speed = 100000;
+ }
+
+ if (bus_speed < 100000) {
+ dev_err(iproc_i2c->device, "%d Hz bus speed not supported\n",
+ bus_speed);
+ dev_err(iproc_i2c->device,
+ "valid speeds are 100khz and 400khz\n");
+ return -EINVAL;
+ } else if (bus_speed < 400000) {
+ bus_speed = 100000;
+ } else {
+ bus_speed = 400000;
+ }
+
+ val = readl(iproc_i2c->base + TIM_CFG_OFFSET);
+ val &= ~(1 << TIM_CFG_MODE_400_SHIFT);
+ val |= (bus_speed == 400000) << TIM_CFG_MODE_400_SHIFT;
+ writel(val, iproc_i2c->base + TIM_CFG_OFFSET);
+
+ dev_info(iproc_i2c->device, "bus set to %u Hz\n", bus_speed);
+
+ return 0;
+}
+
+static int bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev *iproc_i2c)
+{
+ u32 val;
+
+ /* put controller in reset */
+ val = readl(iproc_i2c->base + CFG_OFFSET);
+ val |= 1 << CFG_RESET_SHIFT;
+ val &= ~(1 << CFG_EN_SHIFT);
+ writel(val, iproc_i2c->base + CFG_OFFSET);
+
+ /* wait 100 usec per spec */
+ udelay(100);
+
+ /* bring controller out of reset */
+ val &= ~(1 << CFG_RESET_SHIFT);
+ writel(val, iproc_i2c->base + CFG_OFFSET);
+
+ /* flush TX/RX FIFOs and set RX FIFO threshold to zero */
+ val = (1 << M_FIFO_RX_FLUSH_SHIFT) | (1 << M_FIFO_TX_FLUSH_SHIFT);
+ writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
+
+ /* disable all interrupts */
+ writel(0, iproc_i2c->base + IE_OFFSET);
+
+ /* clear all pending interrupts */
+ writel(0xffffffff, iproc_i2c->base + IS_OFFSET);
+
+ return 0;
+}
+
+static void bcm_iproc_i2c_enable_disable(struct bcm_iproc_i2c_dev *iproc_i2c,
+ bool enable)
+{
+ u32 val;
+
+ val = readl(iproc_i2c->base + CFG_OFFSET);
+ if (enable)
+ val |= BIT(CFG_EN_SHIFT);
+ else
+ val &= ~BIT(CFG_EN_SHIFT);
+ writel(val, iproc_i2c->base + CFG_OFFSET);
+}
+
+static int bcm_iproc_i2c_probe(struct platform_device *pdev)
+{
+ int irq, ret = 0;
+ struct bcm_iproc_i2c_dev *iproc_i2c;
+ struct i2c_adapter *adap;
+ struct resource *res;
+
+ iproc_i2c = devm_kzalloc(&pdev->dev, sizeof(*iproc_i2c),
+ GFP_KERNEL);
+ if (!iproc_i2c)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, iproc_i2c);
+ iproc_i2c->device = &pdev->dev;
+ init_completion(&iproc_i2c->done);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ iproc_i2c->base = devm_ioremap_resource(iproc_i2c->device, res);
+ if (IS_ERR(iproc_i2c->base))
+ return PTR_ERR(iproc_i2c->base);
+
+ ret = bcm_iproc_i2c_init(iproc_i2c);
+ if (ret)
+ return ret;
+
+ ret = bcm_iproc_i2c_cfg_speed(iproc_i2c);
+ if (ret)
+ return ret;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(iproc_i2c->device, "no irq resource\n");
+ return irq;
+ }
+ iproc_i2c->irq = irq;
+
+ ret = devm_request_irq(iproc_i2c->device, irq, bcm_iproc_i2c_isr, 0,
+ pdev->name, iproc_i2c);
+ if (ret < 0) {
+ dev_err(iproc_i2c->device, "unable to request irq %i\n", irq);
+ return ret;
+ }
+
+ bcm_iproc_i2c_enable_disable(iproc_i2c, true);
+
+ adap = &iproc_i2c->adapter;
+ i2c_set_adapdata(adap, iproc_i2c);
+ strlcpy(adap->name, "Broadcom iProc I2C adapter", sizeof(adap->name));
+ adap->algo = &bcm_iproc_algo;
+ adap->dev.parent = &pdev->dev;
+ adap->dev.of_node = pdev->dev.of_node;
+
+ ret = i2c_add_adapter(adap);
+ if (ret) {
+ dev_err(iproc_i2c->device, "failed to add adapter\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int bcm_iproc_i2c_remove(struct platform_device *pdev)
+{
+ struct bcm_iproc_i2c_dev *iproc_i2c = platform_get_drvdata(pdev);
+
+ /* make sure there's no pending interrupt when we remove the adapter */
+ writel(0, iproc_i2c->base + IE_OFFSET);
+ readl(iproc_i2c->base + IE_OFFSET);
+ synchronize_irq(iproc_i2c->irq);
+
+ i2c_del_adapter(&iproc_i2c->adapter);
+ bcm_iproc_i2c_enable_disable(iproc_i2c, false);
+
+ return 0;
+}
+
+static const struct of_device_id bcm_iproc_i2c_of_match[] = {
+ { .compatible = "brcm,iproc-i2c" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, bcm_iproc_i2c_of_match);
+
+static struct platform_driver bcm_iproc_i2c_driver = {
+ .driver = {
+ .name = "bcm-iproc-i2c",
+ .of_match_table = bcm_iproc_i2c_of_match,
+ },
+ .probe = bcm_iproc_i2c_probe,
+ .remove = bcm_iproc_i2c_remove,
+};
+module_platform_driver(bcm_iproc_i2c_driver);
+
+MODULE_AUTHOR("Ray Jui <rjui@broadcom.com>");
+MODULE_DESCRIPTION("Broadcom iProc I2C Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index 626f74e..7d7a14c 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -128,6 +128,7 @@
* @suspended: Flag holding the device's PM status
* @send_count: Number of bytes still expected to send
* @recv_count: Number of bytes still expected to receive
+ * @curr_recv_count: Number of bytes to be received in current transfer
* @irq: IRQ number
* @input_clk: Input clock to I2C controller
* @i2c_clk: Maximum I2C clock speed
@@ -146,6 +147,7 @@
u8 suspended;
unsigned int send_count;
unsigned int recv_count;
+ unsigned int curr_recv_count;
int irq;
unsigned long input_clk;
unsigned int i2c_clk;
@@ -182,14 +184,15 @@
*/
static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
{
- unsigned int isr_status, avail_bytes;
- unsigned int bytes_to_recv, bytes_to_send;
+ unsigned int isr_status, avail_bytes, updatetx;
+ unsigned int bytes_to_send;
struct cdns_i2c *id = ptr;
/* Signal completion only after everything is updated */
int done_flag = 0;
irqreturn_t status = IRQ_NONE;
isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
+ cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
/* Handling nack and arbitration lost interrupt */
if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_ARB_LOST)) {
@@ -197,89 +200,112 @@
status = IRQ_HANDLED;
}
- /* Handling Data interrupt */
- if ((isr_status & CDNS_I2C_IXR_DATA) &&
- (id->recv_count >= CDNS_I2C_DATA_INTR_DEPTH)) {
- /* Always read data interrupt threshold bytes */
- bytes_to_recv = CDNS_I2C_DATA_INTR_DEPTH;
- id->recv_count -= CDNS_I2C_DATA_INTR_DEPTH;
- avail_bytes = cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
+ /*
+ * Check if transfer size register needs to be updated again for a
+ * large data receive operation.
+ */
+ updatetx = 0;
+ if (id->recv_count > id->curr_recv_count)
+ updatetx = 1;
- /*
- * if the tranfer size register value is zero, then
- * check for the remaining bytes and update the
- * transfer size register.
- */
- if (!avail_bytes) {
- if (id->recv_count > CDNS_I2C_TRANSFER_SIZE)
- cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
- CDNS_I2C_XFER_SIZE_OFFSET);
- else
- cdns_i2c_writereg(id->recv_count,
- CDNS_I2C_XFER_SIZE_OFFSET);
- }
+ /* When receiving, handle data interrupt and completion interrupt */
+ if (id->p_recv_buf &&
+ ((isr_status & CDNS_I2C_IXR_COMP) ||
+ (isr_status & CDNS_I2C_IXR_DATA))) {
+ /* Read data if receive data valid is set */
+ while (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) &
+ CDNS_I2C_SR_RXDV) {
+ /*
+ * Clear hold bit that was set for FIFO control if
+ * RX data left is less than FIFO depth, unless
+ * repeated start is selected.
+ */
+ if ((id->recv_count < CDNS_I2C_FIFO_DEPTH) &&
+ !id->bus_hold_flag)
+ cdns_i2c_clear_bus_hold(id);
- /* Process the data received */
- while (bytes_to_recv--)
*(id->p_recv_buf)++ =
cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
+ id->recv_count--;
+ id->curr_recv_count--;
- if (!id->bus_hold_flag &&
- (id->recv_count <= CDNS_I2C_FIFO_DEPTH))
- cdns_i2c_clear_bus_hold(id);
+ if (updatetx &&
+ (id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1))
+ break;
+ }
+
+ /*
+ * The controller sends NACK to the slave when transfer size
+ * register reaches zero without considering the HOLD bit.
+ * This workaround is implemented for large data transfers to
+ * maintain transfer size non-zero while performing a large
+ * receive operation.
+ */
+ if (updatetx &&
+ (id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1)) {
+ /* wait while fifo is full */
+ while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) !=
+ (id->curr_recv_count - CDNS_I2C_FIFO_DEPTH))
+ ;
+
+ /*
+ * Check number of bytes to be received against maximum
+ * transfer size and update register accordingly.
+ */
+ if (((int)(id->recv_count) - CDNS_I2C_FIFO_DEPTH) >
+ CDNS_I2C_TRANSFER_SIZE) {
+ cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
+ CDNS_I2C_XFER_SIZE_OFFSET);
+ id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE +
+ CDNS_I2C_FIFO_DEPTH;
+ } else {
+ cdns_i2c_writereg(id->recv_count -
+ CDNS_I2C_FIFO_DEPTH,
+ CDNS_I2C_XFER_SIZE_OFFSET);
+ id->curr_recv_count = id->recv_count;
+ }
+ }
+
+ /* Clear hold (if not repeated start) and signal completion */
+ if ((isr_status & CDNS_I2C_IXR_COMP) && !id->recv_count) {
+ if (!id->bus_hold_flag)
+ cdns_i2c_clear_bus_hold(id);
+ done_flag = 1;
+ }
status = IRQ_HANDLED;
}
- /* Handling Transfer Complete interrupt */
- if (isr_status & CDNS_I2C_IXR_COMP) {
- if (!id->p_recv_buf) {
- /*
- * If the device is sending data If there is further
- * data to be sent. Calculate the available space
- * in FIFO and fill the FIFO with that many bytes.
- */
- if (id->send_count) {
- avail_bytes = CDNS_I2C_FIFO_DEPTH -
- cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
- if (id->send_count > avail_bytes)
- bytes_to_send = avail_bytes;
- else
- bytes_to_send = id->send_count;
+ /* When sending, handle transfer complete interrupt */
+ if ((isr_status & CDNS_I2C_IXR_COMP) && !id->p_recv_buf) {
+ /*
+ * If there is more data to be sent, calculate the
+ * space available in FIFO and fill with that many bytes.
+ */
+ if (id->send_count) {
+ avail_bytes = CDNS_I2C_FIFO_DEPTH -
+ cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
+ if (id->send_count > avail_bytes)
+ bytes_to_send = avail_bytes;
+ else
+ bytes_to_send = id->send_count;
- while (bytes_to_send--) {
- cdns_i2c_writereg(
- (*(id->p_send_buf)++),
- CDNS_I2C_DATA_OFFSET);
- id->send_count--;
- }
- } else {
- /*
- * Signal the completion of transaction and
- * clear the hold bus bit if there are no
- * further messages to be processed.
- */
- done_flag = 1;
+ while (bytes_to_send--) {
+ cdns_i2c_writereg(
+ (*(id->p_send_buf)++),
+ CDNS_I2C_DATA_OFFSET);
+ id->send_count--;
}
- if (!id->send_count && !id->bus_hold_flag)
- cdns_i2c_clear_bus_hold(id);
} else {
- if (!id->bus_hold_flag)
- cdns_i2c_clear_bus_hold(id);
/*
- * If the device is receiving data, then signal
- * the completion of transaction and read the data
- * present in the FIFO. Signal the completion of
- * transaction.
+ * Signal the completion of transaction and
+ * clear the hold bus bit if there are no
+ * further messages to be processed.
*/
- while (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) &
- CDNS_I2C_SR_RXDV) {
- *(id->p_recv_buf)++ =
- cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
- id->recv_count--;
- }
done_flag = 1;
}
+ if (!id->send_count && !id->bus_hold_flag)
+ cdns_i2c_clear_bus_hold(id);
status = IRQ_HANDLED;
}
@@ -289,8 +315,6 @@
if (id->err_status)
status = IRQ_HANDLED;
- cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
-
if (done_flag)
complete(&id->xfer_done);
@@ -316,6 +340,8 @@
if (id->p_msg->flags & I2C_M_RECV_LEN)
id->recv_count = I2C_SMBUS_BLOCK_MAX + 1;
+ id->curr_recv_count = id->recv_count;
+
/*
* Check for the message size against FIFO depth and set the
* 'hold bus' bit if it is greater than FIFO depth.
@@ -335,11 +361,14 @@
* receive if it is less than transfer size and transfer size if
* it is more. Enable the interrupts.
*/
- if (id->recv_count > CDNS_I2C_TRANSFER_SIZE)
+ if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) {
cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
CDNS_I2C_XFER_SIZE_OFFSET);
- else
+ id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE;
+ } else {
cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);
+ }
+
/* Clear the bus hold flag if bytes to receive is less than FIFO size */
if (!id->bus_hold_flag &&
((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
@@ -516,6 +545,20 @@
* processed with a repeated start.
*/
if (num > 1) {
+ /*
+ * This controller does not give completion interrupt after a
+ * master receive message if HOLD bit is set (repeated start),
+ * resulting in SW timeout. Hence, if a receive message is
+ * followed by any other message, an error is returned
+ * indicating that this sequence is not supported.
+ */
+ for (count = 0; count < num - 1; count++) {
+ if (msgs[count].flags & I2C_M_RD) {
+ dev_warn(adap->dev.parent,
+ "Can't do repeated start after a receive message\n");
+ return -EOPNOTSUPP;
+ }
+ }
id->bus_hold_flag = 1;
reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
reg |= CDNS_I2C_CR_HOLD;
diff --git a/drivers/i2c/busses/i2c-designware-baytrail.c b/drivers/i2c/busses/i2c-designware-baytrail.c
new file mode 100644
index 0000000..5f1ff4c
--- /dev/null
+++ b/drivers/i2c/busses/i2c-designware-baytrail.c
@@ -0,0 +1,160 @@
+/*
+ * Intel BayTrail PMIC I2C bus semaphore implementaion
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/acpi.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <asm/iosf_mbi.h>
+#include "i2c-designware-core.h"
+
+#define SEMAPHORE_TIMEOUT 100
+#define PUNIT_SEMAPHORE 0x7
+
+static unsigned long acquired;
+
+static int get_sem(struct device *dev, u32 *sem)
+{
+ u32 reg_val;
+ int ret;
+
+ ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, PUNIT_SEMAPHORE,
+ ®_val);
+ if (ret) {
+ dev_err(dev, "iosf failed to read punit semaphore\n");
+ return ret;
+ }
+
+ *sem = reg_val & 0x1;
+
+ return 0;
+}
+
+static void reset_semaphore(struct device *dev)
+{
+ u32 data;
+
+ if (iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ,
+ PUNIT_SEMAPHORE, &data)) {
+ dev_err(dev, "iosf failed to reset punit semaphore during read\n");
+ return;
+ }
+
+ data = data & 0xfffffffe;
+ if (iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE,
+ PUNIT_SEMAPHORE, data))
+ dev_err(dev, "iosf failed to reset punit semaphore during write\n");
+}
+
+int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
+{
+ u32 sem = 0;
+ int ret;
+ unsigned long start, end;
+
+ if (!dev || !dev->dev)
+ return -ENODEV;
+
+ if (!dev->acquire_lock)
+ return 0;
+
+ /* host driver writes 0x2 to side band semaphore register */
+ ret = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE,
+ PUNIT_SEMAPHORE, 0x2);
+ if (ret) {
+ dev_err(dev->dev, "iosf punit semaphore request failed\n");
+ return ret;
+ }
+
+ /* host driver waits for bit 0 to be set in semaphore register */
+ start = jiffies;
+ end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT);
+ while (!time_after(jiffies, end)) {
+ ret = get_sem(dev->dev, &sem);
+ if (!ret && sem) {
+ acquired = jiffies;
+ dev_dbg(dev->dev, "punit semaphore acquired after %ums\n",
+ jiffies_to_msecs(jiffies - start));
+ return 0;
+ }
+
+ usleep_range(1000, 2000);
+ }
+
+ dev_err(dev->dev, "punit semaphore timed out, resetting\n");
+ reset_semaphore(dev->dev);
+
+ ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ,
+ PUNIT_SEMAPHORE, &sem);
+ if (!ret)
+ dev_err(dev->dev, "iosf failed to read punit semaphore\n");
+ else
+ dev_err(dev->dev, "PUNIT SEM: %d\n", sem);
+
+ WARN_ON(1);
+
+ return -ETIMEDOUT;
+}
+EXPORT_SYMBOL(baytrail_i2c_acquire);
+
+void baytrail_i2c_release(struct dw_i2c_dev *dev)
+{
+ if (!dev || !dev->dev)
+ return;
+
+ if (!dev->acquire_lock)
+ return;
+
+ reset_semaphore(dev->dev);
+ dev_dbg(dev->dev, "punit semaphore held for %ums\n",
+ jiffies_to_msecs(jiffies - acquired));
+}
+EXPORT_SYMBOL(baytrail_i2c_release);
+
+int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev)
+{
+ acpi_status status;
+ unsigned long long shared_host = 0;
+ acpi_handle handle;
+
+ if (!dev || !dev->dev)
+ return 0;
+
+ handle = ACPI_HANDLE(dev->dev);
+ if (!handle)
+ return 0;
+
+ status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host);
+
+ if (ACPI_FAILURE(status))
+ return 0;
+
+ if (shared_host) {
+ dev_info(dev->dev, "I2C bus managed by PUNIT\n");
+ dev->acquire_lock = baytrail_i2c_acquire;
+ dev->release_lock = baytrail_i2c_release;
+ dev->pm_runtime_disabled = true;
+ }
+
+ if (!iosf_mbi_available())
+ return -EPROBE_DEFER;
+
+ return 0;
+}
+EXPORT_SYMBOL(i2c_dw_eval_lock_support);
+
+MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
+MODULE_DESCRIPTION("Baytrail I2C Semaphore driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index 23628b7..6e25c01 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -170,10 +170,10 @@
u32 value;
if (dev->accessor_flags & ACCESS_16BIT)
- value = readw(dev->base + offset) |
- (readw(dev->base + offset + 2) << 16);
+ value = readw_relaxed(dev->base + offset) |
+ (readw_relaxed(dev->base + offset + 2) << 16);
else
- value = readl(dev->base + offset);
+ value = readl_relaxed(dev->base + offset);
if (dev->accessor_flags & ACCESS_SWAP)
return swab32(value);
@@ -187,10 +187,10 @@
b = swab32(b);
if (dev->accessor_flags & ACCESS_16BIT) {
- writew((u16)b, dev->base + offset);
- writew((u16)(b >> 16), dev->base + offset + 2);
+ writew_relaxed((u16)b, dev->base + offset);
+ writew_relaxed((u16)(b >> 16), dev->base + offset + 2);
} else {
- writel(b, dev->base + offset);
+ writel_relaxed(b, dev->base + offset);
}
}
@@ -285,6 +285,15 @@
u32 hcnt, lcnt;
u32 reg;
u32 sda_falling_time, scl_falling_time;
+ int ret;
+
+ if (dev->acquire_lock) {
+ ret = dev->acquire_lock(dev);
+ if (ret) {
+ dev_err(dev->dev, "couldn't acquire bus ownership\n");
+ return ret;
+ }
+ }
input_clock_khz = dev->get_clk_rate_khz(dev);
@@ -298,6 +307,8 @@
} else if (reg != DW_IC_COMP_TYPE_VALUE) {
dev_err(dev->dev, "Unknown Synopsys component type: "
"0x%08x\n", reg);
+ if (dev->release_lock)
+ dev->release_lock(dev);
return -ENODEV;
}
@@ -309,40 +320,39 @@
sda_falling_time = dev->sda_falling_time ?: 300; /* ns */
scl_falling_time = dev->scl_falling_time ?: 300; /* ns */
- /* Standard-mode */
- hcnt = i2c_dw_scl_hcnt(input_clock_khz,
- 4000, /* tHD;STA = tHIGH = 4.0 us */
- sda_falling_time,
- 0, /* 0: DW default, 1: Ideal */
- 0); /* No offset */
- lcnt = i2c_dw_scl_lcnt(input_clock_khz,
- 4700, /* tLOW = 4.7 us */
- scl_falling_time,
- 0); /* No offset */
-
- /* Allow platforms to specify the ideal HCNT and LCNT values */
+ /* Set SCL timing parameters for standard-mode */
if (dev->ss_hcnt && dev->ss_lcnt) {
hcnt = dev->ss_hcnt;
lcnt = dev->ss_lcnt;
+ } else {
+ hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+ 4000, /* tHD;STA = tHIGH = 4.0 us */
+ sda_falling_time,
+ 0, /* 0: DW default, 1: Ideal */
+ 0); /* No offset */
+ lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+ 4700, /* tLOW = 4.7 us */
+ scl_falling_time,
+ 0); /* No offset */
}
dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT);
dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT);
dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
- /* Fast-mode */
- hcnt = i2c_dw_scl_hcnt(input_clock_khz,
- 600, /* tHD;STA = tHIGH = 0.6 us */
- sda_falling_time,
- 0, /* 0: DW default, 1: Ideal */
- 0); /* No offset */
- lcnt = i2c_dw_scl_lcnt(input_clock_khz,
- 1300, /* tLOW = 1.3 us */
- scl_falling_time,
- 0); /* No offset */
-
+ /* Set SCL timing parameters for fast-mode */
if (dev->fs_hcnt && dev->fs_lcnt) {
hcnt = dev->fs_hcnt;
lcnt = dev->fs_lcnt;
+ } else {
+ hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+ 600, /* tHD;STA = tHIGH = 0.6 us */
+ sda_falling_time,
+ 0, /* 0: DW default, 1: Ideal */
+ 0); /* No offset */
+ lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+ 1300, /* tLOW = 1.3 us */
+ scl_falling_time,
+ 0); /* No offset */
}
dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT);
dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
@@ -364,6 +374,9 @@
/* configure the i2c master */
dw_writel(dev, dev->master_cfg , DW_IC_CON);
+
+ if (dev->release_lock)
+ dev->release_lock(dev);
return 0;
}
EXPORT_SYMBOL_GPL(i2c_dw_init);
@@ -627,6 +640,14 @@
dev->abort_source = 0;
dev->rx_outstanding = 0;
+ if (dev->acquire_lock) {
+ ret = dev->acquire_lock(dev);
+ if (ret) {
+ dev_err(dev->dev, "couldn't acquire bus ownership\n");
+ goto done_nolock;
+ }
+ }
+
ret = i2c_dw_wait_bus_not_busy(dev);
if (ret < 0)
goto done;
@@ -672,6 +693,10 @@
ret = -EIO;
done:
+ if (dev->release_lock)
+ dev->release_lock(dev);
+
+done_nolock:
pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
mutex_unlock(&dev->lock);
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 5a410ef..9630222 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -61,6 +61,9 @@
* @ss_lcnt: standard speed LCNT value
* @fs_hcnt: fast speed HCNT value
* @fs_lcnt: fast speed LCNT value
+ * @acquire_lock: function to acquire a hardware lock on the bus
+ * @release_lock: function to release a hardware lock on the bus
+ * @pm_runtime_disabled: true if pm runtime is disabled
*
* HCNT and LCNT parameters can be used if the platform knows more accurate
* values than the one computed based only on the input clock frequency.
@@ -101,6 +104,9 @@
u16 ss_lcnt;
u16 fs_hcnt;
u16 fs_lcnt;
+ int (*acquire_lock)(struct dw_i2c_dev *dev);
+ void (*release_lock)(struct dw_i2c_dev *dev);
+ bool pm_runtime_disabled;
};
#define ACCESS_SWAP 0x00000001
@@ -119,3 +125,9 @@
extern void i2c_dw_clear_int(struct dw_i2c_dev *dev);
extern void i2c_dw_disable_int(struct dw_i2c_dev *dev);
extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev);
+
+#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL)
+extern int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev);
+#else
+static inline int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev) { return 0; }
+#endif
diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
index acb40f9..6643d2d 100644
--- a/drivers/i2c/busses/i2c-designware-pcidrv.c
+++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
@@ -6,7 +6,7 @@
* Copyright (C) 2006 Texas Instruments.
* Copyright (C) 2007 MontaVista Software Inc.
* Copyright (C) 2009 Provigent Ltd.
- * Copyright (C) 2011 Intel corporation.
+ * Copyright (C) 2011, 2015 Intel Corporation.
*
* ----------------------------------------------------------------------------
*
@@ -40,10 +40,6 @@
#define DRIVER_NAME "i2c-designware-pci"
enum dw_pci_ctl_id_t {
- moorestown_0,
- moorestown_1,
- moorestown_2,
-
medfield_0,
medfield_1,
medfield_2,
@@ -101,28 +97,7 @@
.sda_hold = 0x9,
};
-static struct dw_pci_controller dw_pci_controllers[] = {
- [moorestown_0] = {
- .bus_num = 0,
- .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
- .tx_fifo_depth = 32,
- .rx_fifo_depth = 32,
- .clk_khz = 25000,
- },
- [moorestown_1] = {
- .bus_num = 1,
- .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
- .tx_fifo_depth = 32,
- .rx_fifo_depth = 32,
- .clk_khz = 25000,
- },
- [moorestown_2] = {
- .bus_num = 2,
- .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
- .tx_fifo_depth = 32,
- .rx_fifo_depth = 32,
- .clk_khz = 25000,
- },
+static struct dw_pci_controller dw_pci_controllers[] = {
[medfield_0] = {
.bus_num = 0,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
@@ -170,7 +145,6 @@
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
- .clk_khz = 100000,
.functionality = I2C_FUNC_10BIT_ADDR,
.scl_sda_cfg = &byt_config,
},
@@ -179,7 +153,6 @@
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
- .clk_khz = 100000,
.functionality = I2C_FUNC_10BIT_ADDR,
.scl_sda_cfg = &hsw_config,
},
@@ -259,7 +232,7 @@
dev->functionality = controller->functionality |
DW_DEFAULT_FUNCTIONALITY;
- dev->master_cfg = controller->bus_cfg;
+ dev->master_cfg = controller->bus_cfg;
if (controller->scl_sda_cfg) {
cfg = controller->scl_sda_cfg;
dev->ss_hcnt = cfg->ss_hcnt;
@@ -325,12 +298,8 @@
MODULE_ALIAS("i2c_designware-pci");
static const struct pci_device_id i2_designware_pci_ids[] = {
- /* Moorestown */
- { PCI_VDEVICE(INTEL, 0x0802), moorestown_0 },
- { PCI_VDEVICE(INTEL, 0x0803), moorestown_1 },
- { PCI_VDEVICE(INTEL, 0x0804), moorestown_2 },
/* Medfield */
- { PCI_VDEVICE(INTEL, 0x0817), medfield_3,},
+ { PCI_VDEVICE(INTEL, 0x0817), medfield_3 },
{ PCI_VDEVICE(INTEL, 0x0818), medfield_4 },
{ PCI_VDEVICE(INTEL, 0x0819), medfield_5 },
{ PCI_VDEVICE(INTEL, 0x082C), medfield_0 },
@@ -348,7 +317,7 @@
{ PCI_VDEVICE(INTEL, 0x9c61), haswell },
{ PCI_VDEVICE(INTEL, 0x9c62), haswell },
/* Braswell / Cherrytrail */
- { PCI_VDEVICE(INTEL, 0x22C1), baytrail,},
+ { PCI_VDEVICE(INTEL, 0x22C1), baytrail },
{ PCI_VDEVICE(INTEL, 0x22C2), baytrail },
{ PCI_VDEVICE(INTEL, 0x22C3), baytrail },
{ PCI_VDEVICE(INTEL, 0x22C4), baytrail },
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 2b463c3..c270f5f 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -195,6 +195,10 @@
clk_freq = pdata->i2c_scl_freq;
}
+ r = i2c_dw_eval_lock_support(dev);
+ if (r)
+ return r;
+
dev->functionality =
I2C_FUNC_I2C |
I2C_FUNC_10BIT_ADDR |
@@ -257,10 +261,14 @@
return r;
}
- pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
- pm_runtime_use_autosuspend(&pdev->dev);
- pm_runtime_set_active(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
+ if (dev->pm_runtime_disabled) {
+ pm_runtime_forbid(&pdev->dev);
+ } else {
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ }
return 0;
}
@@ -310,7 +318,9 @@
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
clk_prepare_enable(i_dev->clk);
- i2c_dw_init(i_dev);
+
+ if (!i_dev->pm_runtime_disabled)
+ i2c_dw_init(i_dev);
return 0;
}
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 7f3a9fe..d7b26fc 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -201,7 +201,7 @@
void __iomem *base;
wait_queue_head_t queue;
unsigned long i2csr;
- unsigned int disable_delay;
+ unsigned int disable_delay;
int stopped;
unsigned int ifdr; /* IMX_I2C_IFDR */
unsigned int cur_clk;
@@ -295,7 +295,6 @@
dma->chan_tx = dma_request_slave_channel(dev, "tx");
if (!dma->chan_tx) {
dev_dbg(dev, "can't request DMA tx channel\n");
- ret = -ENODEV;
goto fail_al;
}
@@ -313,7 +312,6 @@
dma->chan_rx = dma_request_slave_channel(dev, "rx");
if (!dma->chan_rx) {
dev_dbg(dev, "can't request DMA rx channel\n");
- ret = -ENODEV;
goto fail_tx;
}
@@ -481,8 +479,8 @@
i2c_clk_rate = clk_get_rate(i2c_imx->clk);
if (i2c_imx->cur_clk == i2c_clk_rate)
return;
- else
- i2c_imx->cur_clk = i2c_clk_rate;
+
+ i2c_imx->cur_clk = i2c_clk_rate;
div = (i2c_clk_rate + i2c_imx->bitrate - 1) / i2c_imx->bitrate;
if (div < i2c_clk_div[0].div)
@@ -490,7 +488,8 @@
else if (div > i2c_clk_div[i2c_imx->hwdata->ndivs - 1].div)
i = i2c_imx->hwdata->ndivs - 1;
else
- for (i = 0; i2c_clk_div[i].div < div; i++);
+ for (i = 0; i2c_clk_div[i].div < div; i++)
+ ;
/* Store divider value */
i2c_imx->ifdr = i2c_clk_div[i].val;
@@ -628,9 +627,9 @@
result = wait_for_completion_timeout(
&i2c_imx->dma->cmd_complete,
msecs_to_jiffies(DMA_TIMEOUT));
- if (result <= 0) {
+ if (result == 0) {
dmaengine_terminate_all(dma->chan_using);
- return result ?: -ETIMEDOUT;
+ return -ETIMEDOUT;
}
/* Waiting for transfer complete. */
@@ -686,9 +685,9 @@
result = wait_for_completion_timeout(
&i2c_imx->dma->cmd_complete,
msecs_to_jiffies(DMA_TIMEOUT));
- if (result <= 0) {
+ if (result == 0) {
dmaengine_terminate_all(dma->chan_using);
- return result ?: -ETIMEDOUT;
+ return -ETIMEDOUT;
}
/* waiting for transfer complete. */
@@ -822,6 +821,7 @@
/* read data */
for (i = 0; i < msgs->len; i++) {
u8 len = 0;
+
result = i2c_imx_trx_complete(i2c_imx);
if (result)
return result;
@@ -917,15 +917,16 @@
/* write/read data */
#ifdef CONFIG_I2C_DEBUG_BUS
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
- dev_dbg(&i2c_imx->adapter.dev, "<%s> CONTROL: IEN=%d, IIEN=%d, "
- "MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n", __func__,
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> CONTROL: IEN=%d, IIEN=%d, MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n",
+ __func__,
(temp & I2CR_IEN ? 1 : 0), (temp & I2CR_IIEN ? 1 : 0),
(temp & I2CR_MSTA ? 1 : 0), (temp & I2CR_MTX ? 1 : 0),
(temp & I2CR_TXAK ? 1 : 0), (temp & I2CR_RSTA ? 1 : 0));
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
dev_dbg(&i2c_imx->adapter.dev,
- "<%s> STATUS: ICF=%d, IAAS=%d, IBB=%d, "
- "IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n", __func__,
+ "<%s> STATUS: ICF=%d, IAAS=%d, IBB=%d, IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n",
+ __func__,
(temp & I2SR_ICF ? 1 : 0), (temp & I2SR_IAAS ? 1 : 0),
(temp & I2SR_IBB ? 1 : 0), (temp & I2SR_IAL ? 1 : 0),
(temp & I2SR_SRW ? 1 : 0), (temp & I2SR_IIF ? 1 : 0),
@@ -1004,7 +1005,7 @@
i2c_imx->adapter.owner = THIS_MODULE;
i2c_imx->adapter.algo = &i2c_imx_algo;
i2c_imx->adapter.dev.parent = &pdev->dev;
- i2c_imx->adapter.nr = pdev->id;
+ i2c_imx->adapter.nr = pdev->id;
i2c_imx->adapter.dev.of_node = pdev->dev.of_node;
i2c_imx->base = base;
@@ -1063,7 +1064,7 @@
i2c_imx->adapter.name);
dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
- /* Init DMA config if support*/
+ /* Init DMA config if supported */
i2c_imx_dma_request(i2c_imx, phy_addr);
return 0; /* Return OK */
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index 7249b5b..abf5db7 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -12,6 +12,7 @@
* kind, whether express or implied.
*/
+#include <linux/clk.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -35,7 +36,9 @@
int pos;
int nmsgs;
int state; /* see STATE_ */
- int clock_khz;
+ struct clk *clk;
+ int ip_clock_khz;
+ int bus_clock_khz;
void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value);
u8 (*getreg)(struct ocores_i2c *i2c, int reg);
};
@@ -215,21 +218,34 @@
return -ETIMEDOUT;
}
-static void ocores_init(struct ocores_i2c *i2c)
+static int ocores_init(struct device *dev, struct ocores_i2c *i2c)
{
int prescale;
+ int diff;
u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);
/* make sure the device is disabled */
oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
- prescale = (i2c->clock_khz / (5*100)) - 1;
+ prescale = (i2c->ip_clock_khz / (5 * i2c->bus_clock_khz)) - 1;
+ prescale = clamp(prescale, 0, 0xffff);
+
+ diff = i2c->ip_clock_khz / (5 * (prescale + 1)) - i2c->bus_clock_khz;
+ if (abs(diff) > i2c->bus_clock_khz / 10) {
+ dev_err(dev,
+ "Unsupported clock settings: core: %d KHz, bus: %d KHz\n",
+ i2c->ip_clock_khz, i2c->bus_clock_khz);
+ return -EINVAL;
+ }
+
oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff);
oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8);
/* Init the device */
oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN | OCI2C_CTRL_EN);
+
+ return 0;
}
@@ -304,6 +320,8 @@
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match;
u32 val;
+ u32 clock_frequency;
+ bool clock_frequency_present;
if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) {
/* no 'reg-shift', check for deprecated 'regstep' */
@@ -319,12 +337,42 @@
}
}
- if (of_property_read_u32(np, "clock-frequency", &val)) {
- dev_err(&pdev->dev,
- "Missing required parameter 'clock-frequency'\n");
- return -ENODEV;
+ clock_frequency_present = !of_property_read_u32(np, "clock-frequency",
+ &clock_frequency);
+ i2c->bus_clock_khz = 100;
+
+ i2c->clk = devm_clk_get(&pdev->dev, NULL);
+
+ if (!IS_ERR(i2c->clk)) {
+ int ret = clk_prepare_enable(i2c->clk);
+
+ if (ret) {
+ dev_err(&pdev->dev,
+ "clk_prepare_enable failed: %d\n", ret);
+ return ret;
+ }
+ i2c->ip_clock_khz = clk_get_rate(i2c->clk) / 1000;
+ if (clock_frequency_present)
+ i2c->bus_clock_khz = clock_frequency / 1000;
}
- i2c->clock_khz = val / 1000;
+
+ if (i2c->ip_clock_khz == 0) {
+ if (of_property_read_u32(np, "opencores,ip-clock-frequency",
+ &val)) {
+ if (!clock_frequency_present) {
+ dev_err(&pdev->dev,
+ "Missing required parameter 'opencores,ip-clock-frequency'\n");
+ return -ENODEV;
+ }
+ i2c->ip_clock_khz = clock_frequency / 1000;
+ dev_warn(&pdev->dev,
+ "Deprecated usage of the 'clock-frequency' property, please update to 'opencores,ip-clock-frequency'\n");
+ } else {
+ i2c->ip_clock_khz = val / 1000;
+ if (clock_frequency_present)
+ i2c->bus_clock_khz = clock_frequency / 1000;
+ }
+ }
of_property_read_u32(pdev->dev.of_node, "reg-io-width",
&i2c->reg_io_width);
@@ -368,7 +416,8 @@
if (pdata) {
i2c->reg_shift = pdata->reg_shift;
i2c->reg_io_width = pdata->reg_io_width;
- i2c->clock_khz = pdata->clock_khz;
+ i2c->ip_clock_khz = pdata->clock_khz;
+ i2c->bus_clock_khz = 100;
} else {
ret = ocores_i2c_of_probe(pdev, i2c);
if (ret)
@@ -402,7 +451,9 @@
}
}
- ocores_init(i2c);
+ ret = ocores_init(&pdev->dev, i2c);
+ if (ret)
+ return ret;
init_waitqueue_head(&i2c->wait);
ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0,
@@ -446,6 +497,9 @@
/* remove adapter & data */
i2c_del_adapter(&i2c->adap);
+ if (!IS_ERR(i2c->clk))
+ clk_disable_unprepare(i2c->clk);
+
return 0;
}
@@ -458,6 +512,8 @@
/* make sure the device is disabled */
oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
+ if (!IS_ERR(i2c->clk))
+ clk_disable_unprepare(i2c->clk);
return 0;
}
@@ -465,9 +521,20 @@
{
struct ocores_i2c *i2c = dev_get_drvdata(dev);
- ocores_init(i2c);
+ if (!IS_ERR(i2c->clk)) {
+ unsigned long rate;
+ int ret = clk_prepare_enable(i2c->clk);
- return 0;
+ if (ret) {
+ dev_err(dev,
+ "clk_prepare_enable failed: %d\n", ret);
+ return ret;
+ }
+ rate = clk_get_rate(i2c->clk) / 1000;
+ if (rate)
+ i2c->ip_clock_khz = rate;
+ }
+ return ocores_init(dev, i2c);
}
static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume);
diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c
index 44f03ee..d37d9db 100644
--- a/drivers/i2c/busses/i2c-pmcmsp.c
+++ b/drivers/i2c/busses/i2c-pmcmsp.c
@@ -148,13 +148,6 @@
return ((clock->filter & 0xf) << 12) | (clock->clock & 0x03ff);
}
-static inline void pmcmsptwi_reg_to_clock(
- u32 reg, struct pmcmsptwi_clock *clock)
-{
- clock->filter = (reg >> 12) & 0xf;
- clock->clock = reg & 0x03ff;
-}
-
static inline u32 pmcmsptwi_cfg_to_reg(const struct pmcmsptwi_cfg *cfg)
{
return ((cfg->arbf & 0xf) << 12) |
diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 9246284..5f96b1b 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -102,6 +102,9 @@
/* Settings */
unsigned int scl_frequency;
+ unsigned int scl_rise_ns;
+ unsigned int scl_fall_ns;
+ unsigned int sda_fall_ns;
/* Synchronization & notification */
spinlock_t lock;
@@ -435,6 +438,9 @@
*
* @clk_rate: I2C input clock rate
* @scl_rate: Desired SCL rate
+ * @scl_rise_ns: How many ns it takes for SCL to rise.
+ * @scl_fall_ns: How many ns it takes for SCL to fall.
+ * @sda_fall_ns: How many ns it takes for SDA to fall.
* @div_low: Divider output for low
* @div_high: Divider output for high
*
@@ -443,11 +449,16 @@
* too high, we silently use the highest possible rate.
*/
static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
+ unsigned long scl_rise_ns,
+ unsigned long scl_fall_ns,
+ unsigned long sda_fall_ns,
unsigned long *div_low, unsigned long *div_high)
{
- unsigned long min_low_ns, min_high_ns;
- unsigned long max_data_hold_ns;
+ unsigned long spec_min_low_ns, spec_min_high_ns;
+ unsigned long spec_setup_start, spec_max_data_hold_ns;
unsigned long data_hold_buffer_ns;
+
+ unsigned long min_low_ns, min_high_ns;
unsigned long max_low_ns, min_total_ns;
unsigned long clk_rate_khz, scl_rate_khz;
@@ -469,29 +480,50 @@
scl_rate = 1000;
/*
- * min_low_ns: The minimum number of ns we need to hold low
- * to meet i2c spec
- * min_high_ns: The minimum number of ns we need to hold high
- * to meet i2c spec
- * max_low_ns: The maximum number of ns we can hold low
- * to meet i2c spec
+ * min_low_ns: The minimum number of ns we need to hold low to
+ * meet I2C specification, should include fall time.
+ * min_high_ns: The minimum number of ns we need to hold high to
+ * meet I2C specification, should include rise time.
+ * max_low_ns: The maximum number of ns we can hold low to meet
+ * I2C specification.
*
- * Note: max_low_ns should be (max data hold time * 2 - buffer)
+ * Note: max_low_ns should be (maximum data hold time * 2 - buffer)
* This is because the i2c host on Rockchip holds the data line
* for half the low time.
*/
if (scl_rate <= 100000) {
- min_low_ns = 4700;
- min_high_ns = 4000;
- max_data_hold_ns = 3450;
+ /* Standard-mode */
+ spec_min_low_ns = 4700;
+ spec_setup_start = 4700;
+ spec_min_high_ns = 4000;
+ spec_max_data_hold_ns = 3450;
data_hold_buffer_ns = 50;
} else {
- min_low_ns = 1300;
- min_high_ns = 600;
- max_data_hold_ns = 900;
+ /* Fast-mode */
+ spec_min_low_ns = 1300;
+ spec_setup_start = 600;
+ spec_min_high_ns = 600;
+ spec_max_data_hold_ns = 900;
data_hold_buffer_ns = 50;
}
- max_low_ns = max_data_hold_ns * 2 - data_hold_buffer_ns;
+ min_high_ns = scl_rise_ns + spec_min_high_ns;
+
+ /*
+ * Timings for repeated start:
+ * - controller appears to drop SDA at .875x (7/8) programmed clk high.
+ * - controller appears to keep SCL high for 2x programmed clk high.
+ *
+ * We need to account for those rules in picking our "high" time so
+ * we meet tSU;STA and tHD;STA times.
+ */
+ min_high_ns = max(min_high_ns,
+ DIV_ROUND_UP((scl_rise_ns + spec_setup_start) * 1000, 875));
+ min_high_ns = max(min_high_ns,
+ DIV_ROUND_UP((scl_rise_ns + spec_setup_start +
+ sda_fall_ns + spec_min_high_ns), 2));
+
+ min_low_ns = scl_fall_ns + spec_min_low_ns;
+ max_low_ns = spec_max_data_hold_ns * 2 - data_hold_buffer_ns;
min_total_ns = min_low_ns + min_high_ns;
/* Adjust to avoid overflow */
@@ -510,8 +542,8 @@
min_div_for_hold = (min_low_div + min_high_div);
/*
- * This is the maximum divider so we don't go over the max.
- * We don't round up here (we round down) since this is a max.
+ * This is the maximum divider so we don't go over the maximum.
+ * We don't round up here (we round down) since this is a maximum.
*/
max_low_div = clk_rate_khz * max_low_ns / (8 * 1000000);
@@ -544,7 +576,7 @@
ideal_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns,
scl_rate_khz * 8 * min_total_ns);
- /* Don't allow it to go over the max */
+ /* Don't allow it to go over the maximum */
if (ideal_low_div > max_low_div)
ideal_low_div = max_low_div;
@@ -588,9 +620,9 @@
u64 t_low_ns, t_high_ns;
int ret;
- ret = rk3x_i2c_calc_divs(clk_rate, i2c->scl_frequency, &div_low,
- &div_high);
-
+ ret = rk3x_i2c_calc_divs(clk_rate, i2c->scl_frequency, i2c->scl_rise_ns,
+ i2c->scl_fall_ns, i2c->sda_fall_ns,
+ &div_low, &div_high);
WARN_ONCE(ret != 0, "Could not reach SCL freq %u", i2c->scl_frequency);
clk_enable(i2c->clk);
@@ -633,9 +665,10 @@
switch (event) {
case PRE_RATE_CHANGE:
if (rk3x_i2c_calc_divs(ndata->new_rate, i2c->scl_frequency,
- &div_low, &div_high) != 0) {
+ i2c->scl_rise_ns, i2c->scl_fall_ns,
+ i2c->sda_fall_ns,
+ &div_low, &div_high) != 0)
return NOTIFY_STOP;
- }
/* scale up */
if (ndata->new_rate > ndata->old_rate)
@@ -859,6 +892,24 @@
i2c->scl_frequency = DEFAULT_SCL_RATE;
}
+ /*
+ * Read rise and fall time from device tree. If not available use
+ * the default maximum timing from the specification.
+ */
+ if (of_property_read_u32(pdev->dev.of_node, "i2c-scl-rising-time-ns",
+ &i2c->scl_rise_ns)) {
+ if (i2c->scl_frequency <= 100000)
+ i2c->scl_rise_ns = 1000;
+ else
+ i2c->scl_rise_ns = 300;
+ }
+ if (of_property_read_u32(pdev->dev.of_node, "i2c-scl-falling-time-ns",
+ &i2c->scl_fall_ns))
+ i2c->scl_fall_ns = 300;
+ if (of_property_read_u32(pdev->dev.of_node, "i2c-sda-falling-time-ns",
+ &i2c->scl_fall_ns))
+ i2c->sda_fall_ns = i2c->scl_fall_ns;
+
strlcpy(i2c->adap.name, "rk3x-i2c", sizeof(i2c->adap.name));
i2c->adap.owner = THIS_MODULE;
i2c->adap.algo = &rk3x_i2c_algorithm;
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 28b87e6..29f1433 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -286,6 +286,7 @@
if (rx_fifo_avail > 0 && buf_remaining > 0) {
BUG_ON(buf_remaining > 3);
val = i2c_readl(i2c_dev, I2C_RX_FIFO);
+ val = cpu_to_le32(val);
memcpy(buf, &val, buf_remaining);
buf_remaining = 0;
rx_fifo_avail--;
@@ -344,6 +345,7 @@
if (tx_fifo_avail > 0 && buf_remaining > 0) {
BUG_ON(buf_remaining > 3);
memcpy(&val, buf, buf_remaining);
+ val = le32_to_cpu(val);
/* Again update before writing to FIFO to make sure isr sees. */
i2c_dev->msg_buf_remaining = 0;
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index e9eae57..210cf48 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -102,7 +102,7 @@
struct acpi_resource_i2c_serialbus *sb;
sb = &ares->data.i2c_serial_bus;
- if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
+ if (!info->addr && sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
info->addr = sb->slave_address;
if (sb->access_mode == ACPI_I2C_10BIT_MODE)
info->flags |= I2C_CLIENT_TEN;
@@ -698,101 +698,6 @@
driver->shutdown(client);
}
-#ifdef CONFIG_PM_SLEEP
-static int i2c_legacy_suspend(struct device *dev, pm_message_t mesg)
-{
- struct i2c_client *client = i2c_verify_client(dev);
- struct i2c_driver *driver;
-
- if (!client || !dev->driver)
- return 0;
- driver = to_i2c_driver(dev->driver);
- if (!driver->suspend)
- return 0;
- return driver->suspend(client, mesg);
-}
-
-static int i2c_legacy_resume(struct device *dev)
-{
- struct i2c_client *client = i2c_verify_client(dev);
- struct i2c_driver *driver;
-
- if (!client || !dev->driver)
- return 0;
- driver = to_i2c_driver(dev->driver);
- if (!driver->resume)
- return 0;
- return driver->resume(client);
-}
-
-static int i2c_device_pm_suspend(struct device *dev)
-{
- const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
- if (pm)
- return pm_generic_suspend(dev);
- else
- return i2c_legacy_suspend(dev, PMSG_SUSPEND);
-}
-
-static int i2c_device_pm_resume(struct device *dev)
-{
- const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
- if (pm)
- return pm_generic_resume(dev);
- else
- return i2c_legacy_resume(dev);
-}
-
-static int i2c_device_pm_freeze(struct device *dev)
-{
- const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
- if (pm)
- return pm_generic_freeze(dev);
- else
- return i2c_legacy_suspend(dev, PMSG_FREEZE);
-}
-
-static int i2c_device_pm_thaw(struct device *dev)
-{
- const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
- if (pm)
- return pm_generic_thaw(dev);
- else
- return i2c_legacy_resume(dev);
-}
-
-static int i2c_device_pm_poweroff(struct device *dev)
-{
- const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
- if (pm)
- return pm_generic_poweroff(dev);
- else
- return i2c_legacy_suspend(dev, PMSG_HIBERNATE);
-}
-
-static int i2c_device_pm_restore(struct device *dev)
-{
- const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
- if (pm)
- return pm_generic_restore(dev);
- else
- return i2c_legacy_resume(dev);
-}
-#else /* !CONFIG_PM_SLEEP */
-#define i2c_device_pm_suspend NULL
-#define i2c_device_pm_resume NULL
-#define i2c_device_pm_freeze NULL
-#define i2c_device_pm_thaw NULL
-#define i2c_device_pm_poweroff NULL
-#define i2c_device_pm_restore NULL
-#endif /* !CONFIG_PM_SLEEP */
-
static void i2c_client_dev_release(struct device *dev)
{
kfree(to_i2c_client(dev));
@@ -804,6 +709,7 @@
return sprintf(buf, "%s\n", dev->type == &i2c_client_type ?
to_i2c_client(dev)->name : to_i2c_adapter(dev)->name);
}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static ssize_t
show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
@@ -817,8 +723,6 @@
return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name);
}
-
-static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
static struct attribute *i2c_dev_attrs[] = {
@@ -827,29 +731,7 @@
&dev_attr_modalias.attr,
NULL
};
-
-static struct attribute_group i2c_dev_attr_group = {
- .attrs = i2c_dev_attrs,
-};
-
-static const struct attribute_group *i2c_dev_attr_groups[] = {
- &i2c_dev_attr_group,
- NULL
-};
-
-static const struct dev_pm_ops i2c_device_pm_ops = {
- .suspend = i2c_device_pm_suspend,
- .resume = i2c_device_pm_resume,
- .freeze = i2c_device_pm_freeze,
- .thaw = i2c_device_pm_thaw,
- .poweroff = i2c_device_pm_poweroff,
- .restore = i2c_device_pm_restore,
- SET_RUNTIME_PM_OPS(
- pm_generic_runtime_suspend,
- pm_generic_runtime_resume,
- NULL
- )
-};
+ATTRIBUTE_GROUPS(i2c_dev);
struct bus_type i2c_bus_type = {
.name = "i2c",
@@ -857,12 +739,11 @@
.probe = i2c_device_probe,
.remove = i2c_device_remove,
.shutdown = i2c_device_shutdown,
- .pm = &i2c_device_pm_ops,
};
EXPORT_SYMBOL_GPL(i2c_bus_type);
static struct device_type i2c_client_type = {
- .groups = i2c_dev_attr_groups,
+ .groups = i2c_dev_groups,
.uevent = i2c_device_uevent,
.release = i2c_client_dev_release,
};
@@ -1261,6 +1142,7 @@
return count;
}
+static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device);
/*
* And of course let the users delete the devices they instantiated, if
@@ -1315,8 +1197,6 @@
"delete_device");
return res;
}
-
-static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device);
static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, S_IWUSR, NULL,
i2c_sysfs_delete_device);
@@ -1326,18 +1206,10 @@
&dev_attr_delete_device.attr,
NULL
};
-
-static struct attribute_group i2c_adapter_attr_group = {
- .attrs = i2c_adapter_attrs,
-};
-
-static const struct attribute_group *i2c_adapter_attr_groups[] = {
- &i2c_adapter_attr_group,
- NULL
-};
+ATTRIBUTE_GROUPS(i2c_adapter);
struct device_type i2c_adapter_type = {
- .groups = i2c_adapter_attr_groups,
+ .groups = i2c_adapter_groups,
.release = i2c_adapter_dev_release,
};
EXPORT_SYMBOL_GPL(i2c_adapter_type);
@@ -1419,8 +1291,6 @@
if (of_get_property(node, "wakeup-source", NULL))
info.flags |= I2C_CLIENT_WAKE;
- request_module("%s%s", I2C_MODULE_PREFIX, info.type);
-
result = i2c_new_device(adap, &info);
if (result == NULL) {
dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
@@ -1796,11 +1666,15 @@
/* device name is gone after device_unregister */
dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
- /* clean up the sysfs representation */
+ /* wait until all references to the device are gone
+ *
+ * FIXME: This is old code and should ideally be replaced by an
+ * alternative which results in decoupling the lifetime of the struct
+ * device from the i2c_adapter, like spi or netdev do. Any solution
+ * should be throughly tested with DEBUG_KOBJECT_RELEASE enabled!
+ */
init_completion(&adap->dev_released);
device_unregister(&adap->dev);
-
- /* wait for sysfs to drop all references */
wait_for_completion(&adap->dev_released);
/* free bus id */
@@ -1859,14 +1733,6 @@
if (res)
return res;
- /* Drivers should switch to dev_pm_ops instead. */
- if (driver->suspend)
- pr_warn("i2c-core: driver [%s] using legacy suspend method\n",
- driver->driver.name);
- if (driver->resume)
- pr_warn("i2c-core: driver [%s] using legacy resume method\n",
- driver->driver.name);
-
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
INIT_LIST_HEAD(&driver->clients);
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index ec11b40..3d8f4fe 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -41,6 +41,7 @@
#include <linux/i2c-mux.h>
#include <linux/i2c/pca954x.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/pm.h>
#include <linux/slab.h>
@@ -186,6 +187,8 @@
{
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
+ struct device_node *of_node = client->dev.of_node;
+ bool idle_disconnect_dt;
struct gpio_desc *gpio;
int num, force, class;
struct pca954x *data;
@@ -217,8 +220,13 @@
data->type = id->driver_data;
data->last_chan = 0; /* force the first selection */
+ idle_disconnect_dt = of_node &&
+ of_property_read_bool(of_node, "i2c-mux-idle-disconnect");
+
/* Now create an adapter for each channel */
for (num = 0; num < chips[data->type].nchans; num++) {
+ bool idle_disconnect_pd = false;
+
force = 0; /* dynamic adap number */
class = 0; /* no class by default */
if (pdata) {
@@ -229,12 +237,13 @@
} else
/* discard unconfigured channels */
break;
+ idle_disconnect_pd = pdata->modes[num].deselect_on_exit;
}
data->virt_adaps[num] =
i2c_add_mux_adapter(adap, &client->dev, client,
force, num, class, pca954x_select_chan,
- (pdata && pdata->modes[num].deselect_on_exit)
+ (idle_disconnect_pd || idle_disconnect_dt)
? pca954x_deselect_mux : NULL);
if (data->virt_adaps[num] == NULL) {
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index 56a4b7c..45d67e9 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -1124,6 +1124,9 @@
if (!optlen)
return -EINVAL;
+ memset(&sa_path, 0, sizeof(sa_path));
+ sa_path.vlan_id = 0xffff;
+
ib_sa_unpack_path(path_data->path_rec, &sa_path);
ret = rdma_set_ib_paths(ctx->cm_id, &sa_path, 1);
if (ret)
diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c
index 6095872..8b8cc6f 100644
--- a/drivers/infiniband/core/umem_odp.c
+++ b/drivers/infiniband/core/umem_odp.c
@@ -294,7 +294,8 @@
if (likely(ib_umem_start(umem) != ib_umem_end(umem)))
rbt_ib_umem_insert(&umem->odp_data->interval_tree,
&context->umem_tree);
- if (likely(!atomic_read(&context->notifier_count)))
+ if (likely(!atomic_read(&context->notifier_count)) ||
+ context->odp_mrs_count == 1)
umem->odp_data->mn_counters_active = true;
else
list_add(&umem->odp_data->no_private_counters,
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index 643c08a..b716b08 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -258,5 +258,6 @@
IB_UVERBS_DECLARE_EX_CMD(create_flow);
IB_UVERBS_DECLARE_EX_CMD(destroy_flow);
+IB_UVERBS_DECLARE_EX_CMD(query_device);
#endif /* UVERBS_H */
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index b7943ff..a9f0489 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -400,6 +400,52 @@
return ret;
}
+static void copy_query_dev_fields(struct ib_uverbs_file *file,
+ struct ib_uverbs_query_device_resp *resp,
+ struct ib_device_attr *attr)
+{
+ resp->fw_ver = attr->fw_ver;
+ resp->node_guid = file->device->ib_dev->node_guid;
+ resp->sys_image_guid = attr->sys_image_guid;
+ resp->max_mr_size = attr->max_mr_size;
+ resp->page_size_cap = attr->page_size_cap;
+ resp->vendor_id = attr->vendor_id;
+ resp->vendor_part_id = attr->vendor_part_id;
+ resp->hw_ver = attr->hw_ver;
+ resp->max_qp = attr->max_qp;
+ resp->max_qp_wr = attr->max_qp_wr;
+ resp->device_cap_flags = attr->device_cap_flags;
+ resp->max_sge = attr->max_sge;
+ resp->max_sge_rd = attr->max_sge_rd;
+ resp->max_cq = attr->max_cq;
+ resp->max_cqe = attr->max_cqe;
+ resp->max_mr = attr->max_mr;
+ resp->max_pd = attr->max_pd;
+ resp->max_qp_rd_atom = attr->max_qp_rd_atom;
+ resp->max_ee_rd_atom = attr->max_ee_rd_atom;
+ resp->max_res_rd_atom = attr->max_res_rd_atom;
+ resp->max_qp_init_rd_atom = attr->max_qp_init_rd_atom;
+ resp->max_ee_init_rd_atom = attr->max_ee_init_rd_atom;
+ resp->atomic_cap = attr->atomic_cap;
+ resp->max_ee = attr->max_ee;
+ resp->max_rdd = attr->max_rdd;
+ resp->max_mw = attr->max_mw;
+ resp->max_raw_ipv6_qp = attr->max_raw_ipv6_qp;
+ resp->max_raw_ethy_qp = attr->max_raw_ethy_qp;
+ resp->max_mcast_grp = attr->max_mcast_grp;
+ resp->max_mcast_qp_attach = attr->max_mcast_qp_attach;
+ resp->max_total_mcast_qp_attach = attr->max_total_mcast_qp_attach;
+ resp->max_ah = attr->max_ah;
+ resp->max_fmr = attr->max_fmr;
+ resp->max_map_per_fmr = attr->max_map_per_fmr;
+ resp->max_srq = attr->max_srq;
+ resp->max_srq_wr = attr->max_srq_wr;
+ resp->max_srq_sge = attr->max_srq_sge;
+ resp->max_pkeys = attr->max_pkeys;
+ resp->local_ca_ack_delay = attr->local_ca_ack_delay;
+ resp->phys_port_cnt = file->device->ib_dev->phys_port_cnt;
+}
+
ssize_t ib_uverbs_query_device(struct ib_uverbs_file *file,
const char __user *buf,
int in_len, int out_len)
@@ -420,47 +466,7 @@
return ret;
memset(&resp, 0, sizeof resp);
-
- resp.fw_ver = attr.fw_ver;
- resp.node_guid = file->device->ib_dev->node_guid;
- resp.sys_image_guid = attr.sys_image_guid;
- resp.max_mr_size = attr.max_mr_size;
- resp.page_size_cap = attr.page_size_cap;
- resp.vendor_id = attr.vendor_id;
- resp.vendor_part_id = attr.vendor_part_id;
- resp.hw_ver = attr.hw_ver;
- resp.max_qp = attr.max_qp;
- resp.max_qp_wr = attr.max_qp_wr;
- resp.device_cap_flags = attr.device_cap_flags;
- resp.max_sge = attr.max_sge;
- resp.max_sge_rd = attr.max_sge_rd;
- resp.max_cq = attr.max_cq;
- resp.max_cqe = attr.max_cqe;
- resp.max_mr = attr.max_mr;
- resp.max_pd = attr.max_pd;
- resp.max_qp_rd_atom = attr.max_qp_rd_atom;
- resp.max_ee_rd_atom = attr.max_ee_rd_atom;
- resp.max_res_rd_atom = attr.max_res_rd_atom;
- resp.max_qp_init_rd_atom = attr.max_qp_init_rd_atom;
- resp.max_ee_init_rd_atom = attr.max_ee_init_rd_atom;
- resp.atomic_cap = attr.atomic_cap;
- resp.max_ee = attr.max_ee;
- resp.max_rdd = attr.max_rdd;
- resp.max_mw = attr.max_mw;
- resp.max_raw_ipv6_qp = attr.max_raw_ipv6_qp;
- resp.max_raw_ethy_qp = attr.max_raw_ethy_qp;
- resp.max_mcast_grp = attr.max_mcast_grp;
- resp.max_mcast_qp_attach = attr.max_mcast_qp_attach;
- resp.max_total_mcast_qp_attach = attr.max_total_mcast_qp_attach;
- resp.max_ah = attr.max_ah;
- resp.max_fmr = attr.max_fmr;
- resp.max_map_per_fmr = attr.max_map_per_fmr;
- resp.max_srq = attr.max_srq;
- resp.max_srq_wr = attr.max_srq_wr;
- resp.max_srq_sge = attr.max_srq_sge;
- resp.max_pkeys = attr.max_pkeys;
- resp.local_ca_ack_delay = attr.local_ca_ack_delay;
- resp.phys_port_cnt = file->device->ib_dev->phys_port_cnt;
+ copy_query_dev_fields(file, &resp, &attr);
if (copy_to_user((void __user *) (unsigned long) cmd.response,
&resp, sizeof resp))
@@ -2091,20 +2097,21 @@
if (qp->real_qp == qp) {
ret = ib_resolve_eth_l2_attrs(qp, attr, &cmd.attr_mask);
if (ret)
- goto out;
+ goto release_qp;
ret = qp->device->modify_qp(qp, attr,
modify_qp_mask(qp->qp_type, cmd.attr_mask), &udata);
} else {
ret = ib_modify_qp(qp, attr, modify_qp_mask(qp->qp_type, cmd.attr_mask));
}
- put_qp_read(qp);
-
if (ret)
- goto out;
+ goto release_qp;
ret = in_len;
+release_qp:
+ put_qp_read(qp);
+
out:
kfree(attr);
@@ -3287,3 +3294,64 @@
return ret ? ret : in_len;
}
+
+int ib_uverbs_ex_query_device(struct ib_uverbs_file *file,
+ struct ib_udata *ucore,
+ struct ib_udata *uhw)
+{
+ struct ib_uverbs_ex_query_device_resp resp;
+ struct ib_uverbs_ex_query_device cmd;
+ struct ib_device_attr attr;
+ struct ib_device *device;
+ int err;
+
+ device = file->device->ib_dev;
+ if (ucore->inlen < sizeof(cmd))
+ return -EINVAL;
+
+ err = ib_copy_from_udata(&cmd, ucore, sizeof(cmd));
+ if (err)
+ return err;
+
+ if (cmd.comp_mask)
+ return -EINVAL;
+
+ if (cmd.reserved)
+ return -EINVAL;
+
+ resp.response_length = offsetof(typeof(resp), odp_caps);
+
+ if (ucore->outlen < resp.response_length)
+ return -ENOSPC;
+
+ err = device->query_device(device, &attr);
+ if (err)
+ return err;
+
+ copy_query_dev_fields(file, &resp.base, &attr);
+ resp.comp_mask = 0;
+
+ if (ucore->outlen < resp.response_length + sizeof(resp.odp_caps))
+ goto end;
+
+#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
+ resp.odp_caps.general_caps = attr.odp_caps.general_caps;
+ resp.odp_caps.per_transport_caps.rc_odp_caps =
+ attr.odp_caps.per_transport_caps.rc_odp_caps;
+ resp.odp_caps.per_transport_caps.uc_odp_caps =
+ attr.odp_caps.per_transport_caps.uc_odp_caps;
+ resp.odp_caps.per_transport_caps.ud_odp_caps =
+ attr.odp_caps.per_transport_caps.ud_odp_caps;
+ resp.odp_caps.reserved = 0;
+#else
+ memset(&resp.odp_caps, 0, sizeof(resp.odp_caps));
+#endif
+ resp.response_length += sizeof(resp.odp_caps);
+
+end:
+ err = ib_copy_to_udata(ucore, &resp, resp.response_length);
+ if (err)
+ return err;
+
+ return 0;
+}
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 5db1a8c..259dcc7 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -123,6 +123,7 @@
struct ib_udata *uhw) = {
[IB_USER_VERBS_EX_CMD_CREATE_FLOW] = ib_uverbs_ex_create_flow,
[IB_USER_VERBS_EX_CMD_DESTROY_FLOW] = ib_uverbs_ex_destroy_flow,
+ [IB_USER_VERBS_EX_CMD_QUERY_DEVICE] = ib_uverbs_ex_query_device,
};
static void ib_uverbs_add_one(struct ib_device *device);
diff --git a/drivers/infiniband/hw/cxgb4/ev.c b/drivers/infiniband/hw/cxgb4/ev.c
index 794555d..bdfac2c 100644
--- a/drivers/infiniband/hw/cxgb4/ev.c
+++ b/drivers/infiniband/hw/cxgb4/ev.c
@@ -225,13 +225,20 @@
struct c4iw_cq *chp;
unsigned long flag;
+ spin_lock_irqsave(&dev->lock, flag);
chp = get_chp(dev, qid);
if (chp) {
+ atomic_inc(&chp->refcnt);
+ spin_unlock_irqrestore(&dev->lock, flag);
t4_clear_cq_armed(&chp->cq);
spin_lock_irqsave(&chp->comp_handler_lock, flag);
(*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
spin_unlock_irqrestore(&chp->comp_handler_lock, flag);
- } else
+ if (atomic_dec_and_test(&chp->refcnt))
+ wake_up(&chp->wait);
+ } else {
PDBG("%s unknown cqid 0x%x\n", __func__, qid);
+ spin_unlock_irqrestore(&dev->lock, flag);
+ }
return 0;
}
diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
index b5678ac..d87e165 100644
--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
@@ -196,7 +196,7 @@
return (int)(rdev->lldi.vr->stag.size >> 5);
}
-#define C4IW_WR_TO (30*HZ)
+#define C4IW_WR_TO (60*HZ)
struct c4iw_wr_wait {
struct completion completion;
@@ -220,22 +220,21 @@
u32 hwtid, u32 qpid,
const char *func)
{
- unsigned to = C4IW_WR_TO;
int ret;
- do {
- ret = wait_for_completion_timeout(&wr_waitp->completion, to);
- if (!ret) {
- printk(KERN_ERR MOD "%s - Device %s not responding - "
- "tid %u qpid %u\n", func,
- pci_name(rdev->lldi.pdev), hwtid, qpid);
- if (c4iw_fatal_error(rdev)) {
- wr_waitp->ret = -EIO;
- break;
- }
- to = to << 2;
- }
- } while (!ret);
+ if (c4iw_fatal_error(rdev)) {
+ wr_waitp->ret = -EIO;
+ goto out;
+ }
+
+ ret = wait_for_completion_timeout(&wr_waitp->completion, C4IW_WR_TO);
+ if (!ret) {
+ PDBG("%s - Device %s not responding (disabling device) - tid %u qpid %u\n",
+ func, pci_name(rdev->lldi.pdev), hwtid, qpid);
+ rdev->flags |= T4_FATAL_ERROR;
+ wr_waitp->ret = -EIO;
+ }
+out:
if (wr_waitp->ret)
PDBG("%s: FW reply %d tid %u qpid %u\n",
pci_name(rdev->lldi.pdev), wr_waitp->ret, hwtid, qpid);
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
index 6559af6..e08db70 100644
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
@@ -908,9 +908,6 @@
/* clean up any chip type-specific stuff */
void ipath_chip_done(void);
-/* check to see if we have to force ordering for write combining */
-int ipath_unordered_wc(void);
-
void ipath_disarm_piobufs(struct ipath_devdata *, unsigned first,
unsigned cnt);
void ipath_cancel_sends(struct ipath_devdata *, int);
diff --git a/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c b/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c
index 1d7bd82..1a7e20a 100644
--- a/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c
+++ b/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c
@@ -47,16 +47,3 @@
{
return 0;
}
-
-/**
- * ipath_unordered_wc - indicate whether write combining is unordered
- *
- * Because our performance depends on our ability to do write
- * combining mmio writes in the most efficient way, we need to
- * know if we are on a processor that may reorder stores when
- * write combining.
- */
-int ipath_unordered_wc(void)
-{
- return 1;
-}
diff --git a/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c b/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
index 3428acb..4ad0b93 100644
--- a/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
+++ b/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
@@ -167,18 +167,3 @@
dd->ipath_wc_cookie = 0; /* even on failure */
}
}
-
-/**
- * ipath_unordered_wc - indicate whether write combining is ordered
- *
- * Because our performance depends on our ability to do write combining mmio
- * writes in the most efficient way, we need to know if we are on an Intel
- * or AMD x86_64 processor. AMD x86_64 processors flush WC buffers out in
- * the order completed, and so no special flushing is required to get
- * correct ordering. Intel processors, however, will flush write buffers
- * out in "random" orders, and so explicit ordering is needed at times.
- */
-int ipath_unordered_wc(void)
-{
- return boot_cpu_data.x86_vendor != X86_VENDOR_AMD;
-}
diff --git a/drivers/infiniband/hw/mlx4/cm.c b/drivers/infiniband/hw/mlx4/cm.c
index 56a593e..39a4888 100644
--- a/drivers/infiniband/hw/mlx4/cm.c
+++ b/drivers/infiniband/hw/mlx4/cm.c
@@ -372,7 +372,7 @@
*slave = mlx4_ib_find_real_gid(ibdev, port, gid.global.interface_id);
if (*slave < 0) {
mlx4_ib_warn(ibdev, "failed matching slave_id by gid (0x%llx)\n",
- gid.global.interface_id);
+ be64_to_cpu(gid.global.interface_id));
return -ENOENT;
}
return 0;
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
index 543ecdd..0176caa 100644
--- a/drivers/infiniband/hw/mlx4/cq.c
+++ b/drivers/infiniband/hw/mlx4/cq.c
@@ -369,8 +369,7 @@
int err;
mutex_lock(&cq->resize_mutex);
-
- if (entries < 1) {
+ if (entries < 1 || entries > dev->dev->caps.max_cqes) {
err = -EINVAL;
goto out;
}
@@ -381,7 +380,7 @@
goto out;
}
- if (entries > dev->dev->caps.max_cqes) {
+ if (entries > dev->dev->caps.max_cqes + 1) {
err = -EINVAL;
goto out;
}
@@ -394,7 +393,7 @@
/* Can't be smaller than the number of outstanding CQEs */
outst_cqe = mlx4_ib_get_outstanding_cqes(cq);
if (entries < outst_cqe + 1) {
- err = 0;
+ err = -EINVAL;
goto out;
}
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index eb8e215f..ac6e2b7 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -1269,8 +1269,7 @@
struct mlx4_dev *dev = mdev->dev;
struct mlx4_ib_qp *mqp = to_mqp(ibqp);
struct mlx4_ib_steering *ib_steering = NULL;
- enum mlx4_protocol prot = (gid->raw[1] == 0x0e) ?
- MLX4_PROT_IB_IPV4 : MLX4_PROT_IB_IPV6;
+ enum mlx4_protocol prot = MLX4_PROT_IB_IPV6;
struct mlx4_flow_reg_id reg_id;
if (mdev->dev->caps.steering_mode ==
@@ -1284,8 +1283,10 @@
!!(mqp->flags &
MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK),
prot, ®_id.id);
- if (err)
+ if (err) {
+ pr_err("multicast attach op failed, err %d\n", err);
goto err_malloc;
+ }
reg_id.mirror = 0;
if (mlx4_is_bonded(dev)) {
@@ -1348,9 +1349,7 @@
struct net_device *ndev;
struct mlx4_ib_gid_entry *ge;
struct mlx4_flow_reg_id reg_id = {0, 0};
-
- enum mlx4_protocol prot = (gid->raw[1] == 0x0e) ?
- MLX4_PROT_IB_IPV4 : MLX4_PROT_IB_IPV6;
+ enum mlx4_protocol prot = MLX4_PROT_IB_IPV6;
if (mdev->dev->caps.steering_mode ==
MLX4_STEERING_MODE_DEVICE_MANAGED) {
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index dfc6ca1..ed2bd67 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -1696,8 +1696,10 @@
qp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_GSI ||
qp->mlx4_ib_qp_type == MLX4_IB_QPT_TUN_GSI) {
err = handle_eth_ud_smac_index(dev, qp, (u8 *)attr->smac, context);
- if (err)
- return -EINVAL;
+ if (err) {
+ err = -EINVAL;
+ goto out;
+ }
if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_GSI)
dev->qp1_proxy[qp->port - 1] = qp;
}
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index 03bf812..cc4ac1e 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -997,7 +997,7 @@
struct ib_device_attr *dprops = NULL;
struct ib_port_attr *pprops = NULL;
struct mlx5_general_caps *gen;
- int err = 0;
+ int err = -ENOMEM;
int port;
gen = &dev->mdev->caps.gen;
@@ -1331,6 +1331,8 @@
(1ull << IB_USER_VERBS_CMD_DESTROY_SRQ) |
(1ull << IB_USER_VERBS_CMD_CREATE_XSRQ) |
(1ull << IB_USER_VERBS_CMD_OPEN_QP);
+ dev->ib_dev.uverbs_ex_cmd_mask =
+ (1ull << IB_USER_VERBS_EX_CMD_QUERY_DEVICE);
dev->ib_dev.query_device = mlx5_ib_query_device;
dev->ib_dev.query_port = mlx5_ib_query_port;
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c
index 32a28bd..cd9822e 100644
--- a/drivers/infiniband/hw/mlx5/mr.c
+++ b/drivers/infiniband/hw/mlx5/mr.c
@@ -1012,6 +1012,7 @@
goto err_2;
}
mr->umem = umem;
+ mr->dev = dev;
mr->live = 1;
kvfree(in);
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma.h b/drivers/infiniband/hw/ocrdma/ocrdma.h
index b43456a..c9780d9 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma.h
@@ -40,7 +40,7 @@
#include <be_roce.h>
#include "ocrdma_sli.h"
-#define OCRDMA_ROCE_DRV_VERSION "10.2.287.0u"
+#define OCRDMA_ROCE_DRV_VERSION "10.4.205.0u"
#define OCRDMA_ROCE_DRV_DESC "Emulex OneConnect RoCE Driver"
#define OCRDMA_NODE_DESC "Emulex OneConnect RoCE HCA"
@@ -55,12 +55,19 @@
#define OCRDMA_UVERBS(CMD_NAME) (1ull << IB_USER_VERBS_CMD_##CMD_NAME)
#define convert_to_64bit(lo, hi) ((u64)hi << 32 | (u64)lo)
+#define EQ_INTR_PER_SEC_THRSH_HI 150000
+#define EQ_INTR_PER_SEC_THRSH_LOW 100000
+#define EQ_AIC_MAX_EQD 20
+#define EQ_AIC_MIN_EQD 0
+
+void ocrdma_eqd_set_task(struct work_struct *work);
struct ocrdma_dev_attr {
u8 fw_ver[32];
u32 vendor_id;
u32 device_id;
u16 max_pd;
+ u16 max_dpp_pds;
u16 max_cq;
u16 max_cqe;
u16 max_qp;
@@ -116,12 +123,19 @@
bool created;
};
+struct ocrdma_aic_obj { /* Adaptive interrupt coalescing (AIC) info */
+ u32 prev_eqd;
+ u64 eq_intr_cnt;
+ u64 prev_eq_intr_cnt;
+};
+
struct ocrdma_eq {
struct ocrdma_queue_info q;
u32 vector;
int cq_cnt;
struct ocrdma_dev *dev;
char irq_name[32];
+ struct ocrdma_aic_obj aic_obj;
};
struct ocrdma_mq {
@@ -171,6 +185,21 @@
struct ocrdma_dev *dev;
};
+struct ocrdma_pd_resource_mgr {
+ u32 pd_norm_start;
+ u16 pd_norm_count;
+ u16 pd_norm_thrsh;
+ u16 max_normal_pd;
+ u32 pd_dpp_start;
+ u16 pd_dpp_count;
+ u16 pd_dpp_thrsh;
+ u16 max_dpp_pd;
+ u16 dpp_page_index;
+ unsigned long *pd_norm_bitmap;
+ unsigned long *pd_dpp_bitmap;
+ bool pd_prealloc_valid;
+};
+
struct stats_mem {
struct ocrdma_mqe mqe;
void *va;
@@ -198,6 +227,7 @@
struct ocrdma_eq *eq_tbl;
int eq_cnt;
+ struct delayed_work eqd_work;
u16 base_eqid;
u16 max_eq;
@@ -255,7 +285,12 @@
struct ocrdma_stats rx_qp_err_stats;
struct ocrdma_stats tx_dbg_stats;
struct ocrdma_stats rx_dbg_stats;
+ struct ocrdma_stats driver_stats;
+ struct ocrdma_stats reset_stats;
struct dentry *dir;
+ atomic_t async_err_stats[OCRDMA_MAX_ASYNC_ERRORS];
+ atomic_t cqe_err_stats[OCRDMA_MAX_CQE_ERR];
+ struct ocrdma_pd_resource_mgr *pd_mgr;
};
struct ocrdma_cq {
@@ -335,7 +370,6 @@
struct ocrdma_qp {
struct ib_qp ibqp;
- struct ocrdma_dev *dev;
u8 __iomem *sq_db;
struct ocrdma_qp_hwq_info sq;
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_ah.c b/drivers/infiniband/hw/ocrdma/ocrdma_ah.c
index f3cc8c9..d812904 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_ah.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_ah.c
@@ -29,19 +29,22 @@
#include <net/netevent.h>
#include <rdma/ib_addr.h>
+#include <rdma/ib_mad.h>
#include "ocrdma.h"
#include "ocrdma_verbs.h"
#include "ocrdma_ah.h"
#include "ocrdma_hw.h"
+#include "ocrdma_stats.h"
#define OCRDMA_VID_PCP_SHIFT 0xD
static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
- struct ib_ah_attr *attr, union ib_gid *sgid, int pdid)
+ struct ib_ah_attr *attr, union ib_gid *sgid,
+ int pdid, bool *isvlan)
{
int status = 0;
- u16 vlan_tag; bool vlan_enabled = false;
+ u16 vlan_tag;
struct ocrdma_eth_vlan eth;
struct ocrdma_grh grh;
int eth_sz;
@@ -59,7 +62,7 @@
vlan_tag |= (dev->sl & 0x07) << OCRDMA_VID_PCP_SHIFT;
eth.vlan_tag = cpu_to_be16(vlan_tag);
eth_sz = sizeof(struct ocrdma_eth_vlan);
- vlan_enabled = true;
+ *isvlan = true;
} else {
eth.eth_type = cpu_to_be16(OCRDMA_ROCE_ETH_TYPE);
eth_sz = sizeof(struct ocrdma_eth_basic);
@@ -82,7 +85,7 @@
/* Eth HDR */
memcpy(&ah->av->eth_hdr, ð, eth_sz);
memcpy((u8 *)ah->av + eth_sz, &grh, sizeof(struct ocrdma_grh));
- if (vlan_enabled)
+ if (*isvlan)
ah->av->valid |= OCRDMA_AV_VLAN_VALID;
ah->av->valid = cpu_to_le32(ah->av->valid);
return status;
@@ -91,6 +94,7 @@
struct ib_ah *ocrdma_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr)
{
u32 *ahid_addr;
+ bool isvlan = false;
int status;
struct ocrdma_ah *ah;
struct ocrdma_pd *pd = get_ocrdma_pd(ibpd);
@@ -127,15 +131,20 @@
}
}
- status = set_av_attr(dev, ah, attr, &sgid, pd->id);
+ status = set_av_attr(dev, ah, attr, &sgid, pd->id, &isvlan);
if (status)
goto av_conf_err;
/* if pd is for the user process, pass the ah_id to user space */
if ((pd->uctx) && (pd->uctx->ah_tbl.va)) {
ahid_addr = pd->uctx->ah_tbl.va + attr->dlid;
- *ahid_addr = ah->id;
+ *ahid_addr = 0;
+ *ahid_addr |= ah->id & OCRDMA_AH_ID_MASK;
+ if (isvlan)
+ *ahid_addr |= (OCRDMA_AH_VLAN_VALID_MASK <<
+ OCRDMA_AH_VLAN_VALID_SHIFT);
}
+
return &ah->ibah;
av_conf_err:
@@ -191,5 +200,20 @@
struct ib_grh *in_grh,
struct ib_mad *in_mad, struct ib_mad *out_mad)
{
- return IB_MAD_RESULT_SUCCESS;
+ int status;
+ struct ocrdma_dev *dev;
+
+ switch (in_mad->mad_hdr.mgmt_class) {
+ case IB_MGMT_CLASS_PERF_MGMT:
+ dev = get_ocrdma_dev(ibdev);
+ if (!ocrdma_pma_counters(dev, out_mad))
+ status = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
+ else
+ status = IB_MAD_RESULT_SUCCESS;
+ break;
+ default:
+ status = IB_MAD_RESULT_SUCCESS;
+ break;
+ }
+ return status;
}
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_ah.h b/drivers/infiniband/hw/ocrdma/ocrdma_ah.h
index 8ac49e7..726a87c 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_ah.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_ah.h
@@ -28,6 +28,12 @@
#ifndef __OCRDMA_AH_H__
#define __OCRDMA_AH_H__
+enum {
+ OCRDMA_AH_ID_MASK = 0x3FF,
+ OCRDMA_AH_VLAN_VALID_MASK = 0x01,
+ OCRDMA_AH_VLAN_VALID_SHIFT = 0x1F
+};
+
struct ib_ah *ocrdma_create_ah(struct ib_pd *, struct ib_ah_attr *);
int ocrdma_destroy_ah(struct ib_ah *);
int ocrdma_query_ah(struct ib_ah *, struct ib_ah_attr *);
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
index 638bff1..0c9e959 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
@@ -734,6 +734,9 @@
break;
}
+ if (type < OCRDMA_MAX_ASYNC_ERRORS)
+ atomic_inc(&dev->async_err_stats[type]);
+
if (qp_event) {
if (qp->ibqp.event_handler)
qp->ibqp.event_handler(&ib_evt, qp->ibqp.qp_context);
@@ -831,20 +834,20 @@
return 0;
}
-static void ocrdma_qp_buddy_cq_handler(struct ocrdma_dev *dev,
- struct ocrdma_cq *cq)
+static struct ocrdma_cq *_ocrdma_qp_buddy_cq_handler(struct ocrdma_dev *dev,
+ struct ocrdma_cq *cq, bool sq)
{
- unsigned long flags;
struct ocrdma_qp *qp;
- bool buddy_cq_found = false;
- /* Go through list of QPs in error state which are using this CQ
- * and invoke its callback handler to trigger CQE processing for
- * error/flushed CQE. It is rare to find more than few entries in
- * this list as most consumers stops after getting error CQE.
- * List is traversed only once when a matching buddy cq found for a QP.
- */
- spin_lock_irqsave(&dev->flush_q_lock, flags);
- list_for_each_entry(qp, &cq->sq_head, sq_entry) {
+ struct list_head *cur;
+ struct ocrdma_cq *bcq = NULL;
+ struct list_head *head = sq?(&cq->sq_head):(&cq->rq_head);
+
+ list_for_each(cur, head) {
+ if (sq)
+ qp = list_entry(cur, struct ocrdma_qp, sq_entry);
+ else
+ qp = list_entry(cur, struct ocrdma_qp, rq_entry);
+
if (qp->srq)
continue;
/* if wq and rq share the same cq, than comp_handler
@@ -856,19 +859,41 @@
* if completion came on rq, sq's cq is buddy cq.
*/
if (qp->sq_cq == cq)
- cq = qp->rq_cq;
+ bcq = qp->rq_cq;
else
- cq = qp->sq_cq;
- buddy_cq_found = true;
- break;
+ bcq = qp->sq_cq;
+ return bcq;
}
+ return NULL;
+}
+
+static void ocrdma_qp_buddy_cq_handler(struct ocrdma_dev *dev,
+ struct ocrdma_cq *cq)
+{
+ unsigned long flags;
+ struct ocrdma_cq *bcq = NULL;
+
+ /* Go through list of QPs in error state which are using this CQ
+ * and invoke its callback handler to trigger CQE processing for
+ * error/flushed CQE. It is rare to find more than few entries in
+ * this list as most consumers stops after getting error CQE.
+ * List is traversed only once when a matching buddy cq found for a QP.
+ */
+ spin_lock_irqsave(&dev->flush_q_lock, flags);
+ /* Check if buddy CQ is present.
+ * true - Check for SQ CQ
+ * false - Check for RQ CQ
+ */
+ bcq = _ocrdma_qp_buddy_cq_handler(dev, cq, true);
+ if (bcq == NULL)
+ bcq = _ocrdma_qp_buddy_cq_handler(dev, cq, false);
spin_unlock_irqrestore(&dev->flush_q_lock, flags);
- if (buddy_cq_found == false)
- return;
- if (cq->ibcq.comp_handler) {
- spin_lock_irqsave(&cq->comp_handler_lock, flags);
- (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context);
- spin_unlock_irqrestore(&cq->comp_handler_lock, flags);
+
+ /* if there is valid buddy cq, look for its completion handler */
+ if (bcq && bcq->ibcq.comp_handler) {
+ spin_lock_irqsave(&bcq->comp_handler_lock, flags);
+ (*bcq->ibcq.comp_handler) (&bcq->ibcq, bcq->ibcq.cq_context);
+ spin_unlock_irqrestore(&bcq->comp_handler_lock, flags);
}
}
@@ -935,6 +960,7 @@
} while (budget);
+ eq->aic_obj.eq_intr_cnt++;
ocrdma_ring_eq_db(dev, eq->q.id, true, true, 0);
return IRQ_HANDLED;
}
@@ -1050,6 +1076,9 @@
attr->max_pd =
(rsp->max_pd_ca_ack_delay & OCRDMA_MBX_QUERY_CFG_MAX_PD_MASK) >>
OCRDMA_MBX_QUERY_CFG_MAX_PD_SHIFT;
+ attr->max_dpp_pds =
+ (rsp->max_dpp_pds_credits & OCRDMA_MBX_QUERY_CFG_MAX_DPP_PDS_MASK) >>
+ OCRDMA_MBX_QUERY_CFG_MAX_DPP_PDS_OFFSET;
attr->max_qp =
(rsp->qp_srq_cq_ird_ord & OCRDMA_MBX_QUERY_CFG_MAX_QP_MASK) >>
OCRDMA_MBX_QUERY_CFG_MAX_QP_SHIFT;
@@ -1396,6 +1425,122 @@
return status;
}
+
+static int ocrdma_mbx_alloc_pd_range(struct ocrdma_dev *dev)
+{
+ int status = -ENOMEM;
+ size_t pd_bitmap_size;
+ struct ocrdma_alloc_pd_range *cmd;
+ struct ocrdma_alloc_pd_range_rsp *rsp;
+
+ /* Pre allocate the DPP PDs */
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_ALLOC_PD_RANGE, sizeof(*cmd));
+ if (!cmd)
+ return -ENOMEM;
+ cmd->pd_count = dev->attr.max_dpp_pds;
+ cmd->enable_dpp_rsvd |= OCRDMA_ALLOC_PD_ENABLE_DPP;
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+ rsp = (struct ocrdma_alloc_pd_range_rsp *)cmd;
+
+ if ((rsp->dpp_page_pdid & OCRDMA_ALLOC_PD_RSP_DPP) && rsp->pd_count) {
+ dev->pd_mgr->dpp_page_index = rsp->dpp_page_pdid >>
+ OCRDMA_ALLOC_PD_RSP_DPP_PAGE_SHIFT;
+ dev->pd_mgr->pd_dpp_start = rsp->dpp_page_pdid &
+ OCRDMA_ALLOC_PD_RNG_RSP_START_PDID_MASK;
+ dev->pd_mgr->max_dpp_pd = rsp->pd_count;
+ pd_bitmap_size = BITS_TO_LONGS(rsp->pd_count) * sizeof(long);
+ dev->pd_mgr->pd_dpp_bitmap = kzalloc(pd_bitmap_size,
+ GFP_KERNEL);
+ }
+ kfree(cmd);
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_ALLOC_PD_RANGE, sizeof(*cmd));
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->pd_count = dev->attr.max_pd - dev->attr.max_dpp_pds;
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+ rsp = (struct ocrdma_alloc_pd_range_rsp *)cmd;
+ if (rsp->pd_count) {
+ dev->pd_mgr->pd_norm_start = rsp->dpp_page_pdid &
+ OCRDMA_ALLOC_PD_RNG_RSP_START_PDID_MASK;
+ dev->pd_mgr->max_normal_pd = rsp->pd_count;
+ pd_bitmap_size = BITS_TO_LONGS(rsp->pd_count) * sizeof(long);
+ dev->pd_mgr->pd_norm_bitmap = kzalloc(pd_bitmap_size,
+ GFP_KERNEL);
+ }
+
+ if (dev->pd_mgr->pd_norm_bitmap || dev->pd_mgr->pd_dpp_bitmap) {
+ /* Enable PD resource manager */
+ dev->pd_mgr->pd_prealloc_valid = true;
+ } else {
+ return -ENOMEM;
+ }
+mbx_err:
+ kfree(cmd);
+ return status;
+}
+
+static void ocrdma_mbx_dealloc_pd_range(struct ocrdma_dev *dev)
+{
+ struct ocrdma_dealloc_pd_range *cmd;
+
+ /* return normal PDs to firmware */
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_DEALLOC_PD_RANGE, sizeof(*cmd));
+ if (!cmd)
+ goto mbx_err;
+
+ if (dev->pd_mgr->max_normal_pd) {
+ cmd->start_pd_id = dev->pd_mgr->pd_norm_start;
+ cmd->pd_count = dev->pd_mgr->max_normal_pd;
+ ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ }
+
+ if (dev->pd_mgr->max_dpp_pd) {
+ kfree(cmd);
+ /* return DPP PDs to firmware */
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_DEALLOC_PD_RANGE,
+ sizeof(*cmd));
+ if (!cmd)
+ goto mbx_err;
+
+ cmd->start_pd_id = dev->pd_mgr->pd_dpp_start;
+ cmd->pd_count = dev->pd_mgr->max_dpp_pd;
+ ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ }
+mbx_err:
+ kfree(cmd);
+}
+
+void ocrdma_alloc_pd_pool(struct ocrdma_dev *dev)
+{
+ int status;
+
+ dev->pd_mgr = kzalloc(sizeof(struct ocrdma_pd_resource_mgr),
+ GFP_KERNEL);
+ if (!dev->pd_mgr) {
+ pr_err("%s(%d)Memory allocation failure.\n", __func__, dev->id);
+ return;
+ }
+ status = ocrdma_mbx_alloc_pd_range(dev);
+ if (status) {
+ pr_err("%s(%d) Unable to initialize PD pool, using default.\n",
+ __func__, dev->id);
+ }
+}
+
+static void ocrdma_free_pd_pool(struct ocrdma_dev *dev)
+{
+ ocrdma_mbx_dealloc_pd_range(dev);
+ kfree(dev->pd_mgr->pd_norm_bitmap);
+ kfree(dev->pd_mgr->pd_dpp_bitmap);
+ kfree(dev->pd_mgr);
+}
+
static int ocrdma_build_q_conf(u32 *num_entries, int entry_size,
int *num_pages, int *page_size)
{
@@ -1896,8 +2041,9 @@
{
bool found;
unsigned long flags;
+ struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
- spin_lock_irqsave(&qp->dev->flush_q_lock, flags);
+ spin_lock_irqsave(&dev->flush_q_lock, flags);
found = ocrdma_is_qp_in_sq_flushlist(qp->sq_cq, qp);
if (!found)
list_add_tail(&qp->sq_entry, &qp->sq_cq->sq_head);
@@ -1906,7 +2052,7 @@
if (!found)
list_add_tail(&qp->rq_entry, &qp->rq_cq->rq_head);
}
- spin_unlock_irqrestore(&qp->dev->flush_q_lock, flags);
+ spin_unlock_irqrestore(&dev->flush_q_lock, flags);
}
static void ocrdma_init_hwq_ptr(struct ocrdma_qp *qp)
@@ -1972,7 +2118,8 @@
int status;
u32 len, hw_pages, hw_page_size;
dma_addr_t pa;
- struct ocrdma_dev *dev = qp->dev;
+ struct ocrdma_pd *pd = qp->pd;
+ struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
struct pci_dev *pdev = dev->nic_info.pdev;
u32 max_wqe_allocated;
u32 max_sges = attrs->cap.max_send_sge;
@@ -2027,7 +2174,8 @@
int status;
u32 len, hw_pages, hw_page_size;
dma_addr_t pa = 0;
- struct ocrdma_dev *dev = qp->dev;
+ struct ocrdma_pd *pd = qp->pd;
+ struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
struct pci_dev *pdev = dev->nic_info.pdev;
u32 max_rqe_allocated = attrs->cap.max_recv_wr + 1;
@@ -2086,7 +2234,8 @@
static int ocrdma_set_create_qp_ird_cmd(struct ocrdma_create_qp_req *cmd,
struct ocrdma_qp *qp)
{
- struct ocrdma_dev *dev = qp->dev;
+ struct ocrdma_pd *pd = qp->pd;
+ struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
struct pci_dev *pdev = dev->nic_info.pdev;
dma_addr_t pa = 0;
int ird_page_size = dev->attr.ird_page_size;
@@ -2157,8 +2306,8 @@
{
int status = -ENOMEM;
u32 flags = 0;
- struct ocrdma_dev *dev = qp->dev;
struct ocrdma_pd *pd = qp->pd;
+ struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
struct pci_dev *pdev = dev->nic_info.pdev;
struct ocrdma_cq *cq;
struct ocrdma_create_qp_req *cmd;
@@ -2281,11 +2430,12 @@
union ib_gid sgid, zgid;
u32 vlan_id;
u8 mac_addr[6];
+ struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
if ((ah_attr->ah_flags & IB_AH_GRH) == 0)
return -EINVAL;
- if (atomic_cmpxchg(&qp->dev->update_sl, 1, 0))
- ocrdma_init_service_level(qp->dev);
+ if (atomic_cmpxchg(&dev->update_sl, 1, 0))
+ ocrdma_init_service_level(dev);
cmd->params.tclass_sq_psn |=
(ah_attr->grh.traffic_class << OCRDMA_QP_PARAMS_TCLASS_SHIFT);
cmd->params.rnt_rc_sl_fl |=
@@ -2296,7 +2446,7 @@
cmd->flags |= OCRDMA_QP_PARA_FLOW_LBL_VALID;
memcpy(&cmd->params.dgid[0], &ah_attr->grh.dgid.raw[0],
sizeof(cmd->params.dgid));
- status = ocrdma_query_gid(&qp->dev->ibdev, 1,
+ status = ocrdma_query_gid(&dev->ibdev, 1,
ah_attr->grh.sgid_index, &sgid);
if (status)
return status;
@@ -2307,7 +2457,9 @@
qp->sgid_idx = ah_attr->grh.sgid_index;
memcpy(&cmd->params.sgid[0], &sgid.raw[0], sizeof(cmd->params.sgid));
- ocrdma_resolve_dmac(qp->dev, ah_attr, &mac_addr[0]);
+ status = ocrdma_resolve_dmac(dev, ah_attr, &mac_addr[0]);
+ if (status)
+ return status;
cmd->params.dmac_b0_to_b3 = mac_addr[0] | (mac_addr[1] << 8) |
(mac_addr[2] << 16) | (mac_addr[3] << 24);
/* convert them to LE format. */
@@ -2320,7 +2472,7 @@
vlan_id << OCRDMA_QP_PARAMS_VLAN_SHIFT;
cmd->flags |= OCRDMA_QP_PARA_VLAN_EN_VALID;
cmd->params.rnt_rc_sl_fl |=
- (qp->dev->sl & 0x07) << OCRDMA_QP_PARAMS_SL_SHIFT;
+ (dev->sl & 0x07) << OCRDMA_QP_PARAMS_SL_SHIFT;
}
return 0;
}
@@ -2330,6 +2482,7 @@
struct ib_qp_attr *attrs, int attr_mask)
{
int status = 0;
+ struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
if (attr_mask & IB_QP_PKEY_INDEX) {
cmd->params.path_mtu_pkey_indx |= (attrs->pkey_index &
@@ -2347,12 +2500,12 @@
return status;
} else if (qp->qp_type == IB_QPT_GSI || qp->qp_type == IB_QPT_UD) {
/* set the default mac address for UD, GSI QPs */
- cmd->params.dmac_b0_to_b3 = qp->dev->nic_info.mac_addr[0] |
- (qp->dev->nic_info.mac_addr[1] << 8) |
- (qp->dev->nic_info.mac_addr[2] << 16) |
- (qp->dev->nic_info.mac_addr[3] << 24);
- cmd->params.vlan_dmac_b4_to_b5 = qp->dev->nic_info.mac_addr[4] |
- (qp->dev->nic_info.mac_addr[5] << 8);
+ cmd->params.dmac_b0_to_b3 = dev->nic_info.mac_addr[0] |
+ (dev->nic_info.mac_addr[1] << 8) |
+ (dev->nic_info.mac_addr[2] << 16) |
+ (dev->nic_info.mac_addr[3] << 24);
+ cmd->params.vlan_dmac_b4_to_b5 = dev->nic_info.mac_addr[4] |
+ (dev->nic_info.mac_addr[5] << 8);
}
if ((attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) &&
attrs->en_sqd_async_notify) {
@@ -2409,7 +2562,7 @@
cmd->flags |= OCRDMA_QP_PARA_RQPSN_VALID;
}
if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
- if (attrs->max_rd_atomic > qp->dev->attr.max_ord_per_qp) {
+ if (attrs->max_rd_atomic > dev->attr.max_ord_per_qp) {
status = -EINVAL;
goto pmtu_err;
}
@@ -2417,7 +2570,7 @@
cmd->flags |= OCRDMA_QP_PARA_MAX_ORD_VALID;
}
if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
- if (attrs->max_dest_rd_atomic > qp->dev->attr.max_ird_per_qp) {
+ if (attrs->max_dest_rd_atomic > dev->attr.max_ird_per_qp) {
status = -EINVAL;
goto pmtu_err;
}
@@ -2870,6 +3023,82 @@
return status;
}
+static int ocrdma_mbx_modify_eqd(struct ocrdma_dev *dev, struct ocrdma_eq *eq,
+ int num)
+{
+ int i, status = -ENOMEM;
+ struct ocrdma_modify_eqd_req *cmd;
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_MODIFY_EQ_DELAY, sizeof(*cmd));
+ if (!cmd)
+ return status;
+
+ ocrdma_init_mch(&cmd->cmd.req, OCRDMA_CMD_MODIFY_EQ_DELAY,
+ OCRDMA_SUBSYS_COMMON, sizeof(*cmd));
+
+ cmd->cmd.num_eq = num;
+ for (i = 0; i < num; i++) {
+ cmd->cmd.set_eqd[i].eq_id = eq[i].q.id;
+ cmd->cmd.set_eqd[i].phase = 0;
+ cmd->cmd.set_eqd[i].delay_multiplier =
+ (eq[i].aic_obj.prev_eqd * 65)/100;
+ }
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+mbx_err:
+ kfree(cmd);
+ return status;
+}
+
+static int ocrdma_modify_eqd(struct ocrdma_dev *dev, struct ocrdma_eq *eq,
+ int num)
+{
+ int num_eqs, i = 0;
+ if (num > 8) {
+ while (num) {
+ num_eqs = min(num, 8);
+ ocrdma_mbx_modify_eqd(dev, &eq[i], num_eqs);
+ i += num_eqs;
+ num -= num_eqs;
+ }
+ } else {
+ ocrdma_mbx_modify_eqd(dev, eq, num);
+ }
+ return 0;
+}
+
+void ocrdma_eqd_set_task(struct work_struct *work)
+{
+ struct ocrdma_dev *dev =
+ container_of(work, struct ocrdma_dev, eqd_work.work);
+ struct ocrdma_eq *eq = 0;
+ int i, num = 0, status = -EINVAL;
+ u64 eq_intr;
+
+ for (i = 0; i < dev->eq_cnt; i++) {
+ eq = &dev->eq_tbl[i];
+ if (eq->aic_obj.eq_intr_cnt > eq->aic_obj.prev_eq_intr_cnt) {
+ eq_intr = eq->aic_obj.eq_intr_cnt -
+ eq->aic_obj.prev_eq_intr_cnt;
+ if ((eq_intr > EQ_INTR_PER_SEC_THRSH_HI) &&
+ (eq->aic_obj.prev_eqd == EQ_AIC_MIN_EQD)) {
+ eq->aic_obj.prev_eqd = EQ_AIC_MAX_EQD;
+ num++;
+ } else if ((eq_intr < EQ_INTR_PER_SEC_THRSH_LOW) &&
+ (eq->aic_obj.prev_eqd == EQ_AIC_MAX_EQD)) {
+ eq->aic_obj.prev_eqd = EQ_AIC_MIN_EQD;
+ num++;
+ }
+ }
+ eq->aic_obj.prev_eq_intr_cnt = eq->aic_obj.eq_intr_cnt;
+ }
+
+ if (num)
+ status = ocrdma_modify_eqd(dev, &dev->eq_tbl[0], num);
+ schedule_delayed_work(&dev->eqd_work, msecs_to_jiffies(1000));
+}
+
int ocrdma_init_hw(struct ocrdma_dev *dev)
{
int status;
@@ -2915,6 +3144,7 @@
void ocrdma_cleanup_hw(struct ocrdma_dev *dev)
{
+ ocrdma_free_pd_pool(dev);
ocrdma_mbx_delete_ah_tbl(dev);
/* cleanup the eqs */
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.h b/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
index 6eed8f19..e905972 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
@@ -136,5 +136,7 @@
int ocrdma_mbx_rdma_stats(struct ocrdma_dev *, bool reset);
char *port_speed_string(struct ocrdma_dev *dev);
void ocrdma_init_service_level(struct ocrdma_dev *);
+void ocrdma_alloc_pd_pool(struct ocrdma_dev *dev);
+void ocrdma_free_pd_range(struct ocrdma_dev *dev);
#endif /* __OCRDMA_HW_H__ */
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
index b0b2257..7a2b59a 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
@@ -239,7 +239,7 @@
dev->ibdev.node_type = RDMA_NODE_IB_CA;
dev->ibdev.phys_port_cnt = 1;
- dev->ibdev.num_comp_vectors = 1;
+ dev->ibdev.num_comp_vectors = dev->eq_cnt;
/* mandatory verbs. */
dev->ibdev.query_device = ocrdma_query_device;
@@ -329,6 +329,8 @@
if (dev->stag_arr == NULL)
goto alloc_err;
+ ocrdma_alloc_pd_pool(dev);
+
spin_lock_init(&dev->av_tbl.lock);
spin_lock_init(&dev->flush_q_lock);
return 0;
@@ -491,6 +493,9 @@
spin_unlock(&ocrdma_devlist_lock);
/* Init stats */
ocrdma_add_port_stats(dev);
+ /* Interrupt Moderation */
+ INIT_DELAYED_WORK(&dev->eqd_work, ocrdma_eqd_set_task);
+ schedule_delayed_work(&dev->eqd_work, msecs_to_jiffies(1000));
pr_info("%s %s: %s \"%s\" port %d\n",
dev_name(&dev->nic_info.pdev->dev), hca_name(dev),
@@ -528,11 +533,12 @@
/* first unregister with stack to stop all the active traffic
* of the registered clients.
*/
- ocrdma_rem_port_stats(dev);
+ cancel_delayed_work_sync(&dev->eqd_work);
ocrdma_remove_sysfiles(dev);
-
ib_unregister_device(&dev->ibdev);
+ ocrdma_rem_port_stats(dev);
+
spin_lock(&ocrdma_devlist_lock);
list_del_rcu(&dev->entry);
spin_unlock(&ocrdma_devlist_lock);
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_sli.h b/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
index 4e03648..243c87c 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
@@ -75,6 +75,8 @@
OCRDMA_CMD_DESTROY_RBQ = 26,
OCRDMA_CMD_GET_RDMA_STATS = 27,
+ OCRDMA_CMD_ALLOC_PD_RANGE = 28,
+ OCRDMA_CMD_DEALLOC_PD_RANGE = 29,
OCRDMA_CMD_MAX
};
@@ -87,6 +89,7 @@
OCRDMA_CMD_CREATE_MQ = 21,
OCRDMA_CMD_GET_CTRL_ATTRIBUTES = 32,
OCRDMA_CMD_GET_FW_VER = 35,
+ OCRDMA_CMD_MODIFY_EQ_DELAY = 41,
OCRDMA_CMD_DELETE_MQ = 53,
OCRDMA_CMD_DELETE_CQ = 54,
OCRDMA_CMD_DELETE_EQ = 55,
@@ -101,7 +104,7 @@
QTYPE_MCCQ = 3
};
-#define OCRDMA_MAX_SGID 8
+#define OCRDMA_MAX_SGID 16
#define OCRDMA_MAX_QP 2048
#define OCRDMA_MAX_CQ 2048
@@ -314,6 +317,29 @@
#define OCRDMA_EQ_MINOR_OTHER 0x1
+struct ocrmda_set_eqd {
+ u32 eq_id;
+ u32 phase;
+ u32 delay_multiplier;
+};
+
+struct ocrdma_modify_eqd_cmd {
+ struct ocrdma_mbx_hdr req;
+ u32 num_eq;
+ struct ocrmda_set_eqd set_eqd[8];
+} __packed;
+
+struct ocrdma_modify_eqd_req {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_modify_eqd_cmd cmd;
+};
+
+
+struct ocrdma_modify_eq_delay_rsp {
+ struct ocrdma_mbx_rsp hdr;
+ u32 rsvd0;
+} __packed;
+
enum {
OCRDMA_MCQE_STATUS_SHIFT = 0,
OCRDMA_MCQE_STATUS_MASK = 0xFFFF,
@@ -441,7 +467,9 @@
OCRDMA_DEVICE_FATAL_EVENT = 0x08,
OCRDMA_SRQCAT_ERROR = 0x0E,
OCRDMA_SRQ_LIMIT_EVENT = 0x0F,
- OCRDMA_QP_LAST_WQE_EVENT = 0x10
+ OCRDMA_QP_LAST_WQE_EVENT = 0x10,
+
+ OCRDMA_MAX_ASYNC_ERRORS
};
/* mailbox command request and responses */
@@ -1297,6 +1325,37 @@
struct ocrdma_mbx_rsp rsp;
};
+struct ocrdma_alloc_pd_range {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+ u32 enable_dpp_rsvd;
+ u32 pd_count;
+};
+
+struct ocrdma_alloc_pd_range_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+ u32 dpp_page_pdid;
+ u32 pd_count;
+};
+
+enum {
+ OCRDMA_ALLOC_PD_RNG_RSP_START_PDID_MASK = 0xFFFF,
+};
+
+struct ocrdma_dealloc_pd_range {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+ u32 start_pd_id;
+ u32 pd_count;
+};
+
+struct ocrdma_dealloc_pd_range_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+ u32 rsvd;
+};
+
enum {
OCRDMA_ADDR_CHECK_ENABLE = 1,
OCRDMA_ADDR_CHECK_DISABLE = 0
@@ -1597,7 +1656,9 @@
OCRDMA_CQE_INV_EEC_STATE_ERR,
OCRDMA_CQE_FATAL_ERR,
OCRDMA_CQE_RESP_TIMEOUT_ERR,
- OCRDMA_CQE_GENERAL_ERR
+ OCRDMA_CQE_GENERAL_ERR,
+
+ OCRDMA_MAX_CQE_ERR
};
enum {
@@ -1673,6 +1734,7 @@
OCRDMA_FLAG_FENCE_R = 0x8,
OCRDMA_FLAG_SOLICIT = 0x10,
OCRDMA_FLAG_IMM = 0x20,
+ OCRDMA_FLAG_AH_VLAN_PR = 0x40,
/* Stag flags */
OCRDMA_LKEY_FLAG_LOCAL_WR = 0x1,
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_stats.c b/drivers/infiniband/hw/ocrdma/ocrdma_stats.c
index 41a9aec..48d7ef5 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_stats.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_stats.c
@@ -26,6 +26,7 @@
*******************************************************************/
#include <rdma/ib_addr.h>
+#include <rdma/ib_pma.h>
#include "ocrdma_stats.h"
static struct dentry *ocrdma_dbgfs_dir;
@@ -249,6 +250,27 @@
return stats;
}
+static u64 ocrdma_sysfs_rcv_pkts(struct ocrdma_dev *dev)
+{
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_rx_stats *rx_stats = &rdma_stats->rx_stats;
+
+ return convert_to_64bit(rx_stats->roce_frames_lo,
+ rx_stats->roce_frames_hi) + (u64)rx_stats->roce_frame_icrc_drops
+ + (u64)rx_stats->roce_frame_payload_len_drops;
+}
+
+static u64 ocrdma_sysfs_rcv_data(struct ocrdma_dev *dev)
+{
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_rx_stats *rx_stats = &rdma_stats->rx_stats;
+
+ return (convert_to_64bit(rx_stats->roce_frame_bytes_lo,
+ rx_stats->roce_frame_bytes_hi))/4;
+}
+
static char *ocrdma_tx_stats(struct ocrdma_dev *dev)
{
char *stats = dev->stats_mem.debugfs_mem, *pcur;
@@ -292,6 +314,37 @@
return stats;
}
+static u64 ocrdma_sysfs_xmit_pkts(struct ocrdma_dev *dev)
+{
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_tx_stats *tx_stats = &rdma_stats->tx_stats;
+
+ return (convert_to_64bit(tx_stats->send_pkts_lo,
+ tx_stats->send_pkts_hi) +
+ convert_to_64bit(tx_stats->write_pkts_lo, tx_stats->write_pkts_hi) +
+ convert_to_64bit(tx_stats->read_pkts_lo, tx_stats->read_pkts_hi) +
+ convert_to_64bit(tx_stats->read_rsp_pkts_lo,
+ tx_stats->read_rsp_pkts_hi) +
+ convert_to_64bit(tx_stats->ack_pkts_lo, tx_stats->ack_pkts_hi));
+}
+
+static u64 ocrdma_sysfs_xmit_data(struct ocrdma_dev *dev)
+{
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_tx_stats *tx_stats = &rdma_stats->tx_stats;
+
+ return (convert_to_64bit(tx_stats->send_bytes_lo,
+ tx_stats->send_bytes_hi) +
+ convert_to_64bit(tx_stats->write_bytes_lo,
+ tx_stats->write_bytes_hi) +
+ convert_to_64bit(tx_stats->read_req_bytes_lo,
+ tx_stats->read_req_bytes_hi) +
+ convert_to_64bit(tx_stats->read_rsp_bytes_lo,
+ tx_stats->read_rsp_bytes_hi))/4;
+}
+
static char *ocrdma_wqe_stats(struct ocrdma_dev *dev)
{
char *stats = dev->stats_mem.debugfs_mem, *pcur;
@@ -432,10 +485,118 @@
return dev->stats_mem.debugfs_mem;
}
+static char *ocrdma_driver_dbg_stats(struct ocrdma_dev *dev)
+{
+ char *stats = dev->stats_mem.debugfs_mem, *pcur;
+
+
+ memset(stats, 0, (OCRDMA_MAX_DBGFS_MEM));
+
+ pcur = stats;
+ pcur += ocrdma_add_stat(stats, pcur, "async_cq_err",
+ (u64)(dev->async_err_stats
+ [OCRDMA_CQ_ERROR].counter));
+ pcur += ocrdma_add_stat(stats, pcur, "async_cq_overrun_err",
+ (u64)dev->async_err_stats
+ [OCRDMA_CQ_OVERRUN_ERROR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_cq_qpcat_err",
+ (u64)dev->async_err_stats
+ [OCRDMA_CQ_QPCAT_ERROR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_qp_access_err",
+ (u64)dev->async_err_stats
+ [OCRDMA_QP_ACCESS_ERROR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_qp_commm_est_evt",
+ (u64)dev->async_err_stats
+ [OCRDMA_QP_COMM_EST_EVENT].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_sq_drained_evt",
+ (u64)dev->async_err_stats
+ [OCRDMA_SQ_DRAINED_EVENT].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_dev_fatal_evt",
+ (u64)dev->async_err_stats
+ [OCRDMA_DEVICE_FATAL_EVENT].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_srqcat_err",
+ (u64)dev->async_err_stats
+ [OCRDMA_SRQCAT_ERROR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_srq_limit_evt",
+ (u64)dev->async_err_stats
+ [OCRDMA_SRQ_LIMIT_EVENT].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_qp_last_wqe_evt",
+ (u64)dev->async_err_stats
+ [OCRDMA_QP_LAST_WQE_EVENT].counter);
+
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_len_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_LOC_LEN_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_qp_op_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_LOC_QP_OP_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_eec_op_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_LOC_EEC_OP_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_prot_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_LOC_PROT_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_wr_flush_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_WR_FLUSH_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_mw_bind_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_MW_BIND_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_bad_resp_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_BAD_RESP_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_access_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_LOC_ACCESS_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_rem_inv_req_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_REM_INV_REQ_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_rem_access_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_REM_ACCESS_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_rem_op_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_REM_OP_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_retry_exc_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_RETRY_EXC_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_rnr_retry_exc_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_RNR_RETRY_EXC_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_rdd_viol_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_LOC_RDD_VIOL_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_rem_inv_rd_req_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_REM_INV_RD_REQ_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_rem_abort_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_REM_ABORT_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_inv_eecn_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_INV_EECN_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_inv_eec_state_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_INV_EEC_STATE_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_fatal_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_FATAL_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_resp_timeout_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_RESP_TIMEOUT_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_general_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_GENERAL_ERR].counter);
+ return stats;
+}
+
static void ocrdma_update_stats(struct ocrdma_dev *dev)
{
ulong now = jiffies, secs;
int status = 0;
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_rsrc_stats *rsrc_stats = &rdma_stats->act_rsrc_stats;
secs = jiffies_to_msecs(now - dev->last_stats_time) / 1000U;
if (secs) {
@@ -444,10 +605,74 @@
if (status)
pr_err("%s: stats mbox failed with status = %d\n",
__func__, status);
+ /* Update PD counters from PD resource manager */
+ if (dev->pd_mgr->pd_prealloc_valid) {
+ rsrc_stats->dpp_pds = dev->pd_mgr->pd_dpp_count;
+ rsrc_stats->non_dpp_pds = dev->pd_mgr->pd_norm_count;
+ /* Threshold stata*/
+ rsrc_stats = &rdma_stats->th_rsrc_stats;
+ rsrc_stats->dpp_pds = dev->pd_mgr->pd_dpp_thrsh;
+ rsrc_stats->non_dpp_pds = dev->pd_mgr->pd_norm_thrsh;
+ }
dev->last_stats_time = jiffies;
}
}
+static ssize_t ocrdma_dbgfs_ops_write(struct file *filp,
+ const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ char tmp_str[32];
+ long reset;
+ int status = 0;
+ struct ocrdma_stats *pstats = filp->private_data;
+ struct ocrdma_dev *dev = pstats->dev;
+
+ if (count > 32)
+ goto err;
+
+ if (copy_from_user(tmp_str, buffer, count))
+ goto err;
+
+ tmp_str[count-1] = '\0';
+ if (kstrtol(tmp_str, 10, &reset))
+ goto err;
+
+ switch (pstats->type) {
+ case OCRDMA_RESET_STATS:
+ if (reset) {
+ status = ocrdma_mbx_rdma_stats(dev, true);
+ if (status) {
+ pr_err("Failed to reset stats = %d", status);
+ goto err;
+ }
+ }
+ break;
+ default:
+ goto err;
+ }
+
+ return count;
+err:
+ return -EFAULT;
+}
+
+int ocrdma_pma_counters(struct ocrdma_dev *dev,
+ struct ib_mad *out_mad)
+{
+ struct ib_pma_portcounters *pma_cnt;
+
+ memset(out_mad->data, 0, sizeof out_mad->data);
+ pma_cnt = (void *)(out_mad->data + 40);
+ ocrdma_update_stats(dev);
+
+ pma_cnt->port_xmit_data = cpu_to_be32(ocrdma_sysfs_xmit_data(dev));
+ pma_cnt->port_rcv_data = cpu_to_be32(ocrdma_sysfs_rcv_data(dev));
+ pma_cnt->port_xmit_packets = cpu_to_be32(ocrdma_sysfs_xmit_pkts(dev));
+ pma_cnt->port_rcv_packets = cpu_to_be32(ocrdma_sysfs_rcv_pkts(dev));
+ return 0;
+}
+
static ssize_t ocrdma_dbgfs_ops_read(struct file *filp, char __user *buffer,
size_t usr_buf_len, loff_t *ppos)
{
@@ -492,6 +717,9 @@
case OCRDMA_RX_DBG_STATS:
data = ocrdma_rx_dbg_stats(dev);
break;
+ case OCRDMA_DRV_STATS:
+ data = ocrdma_driver_dbg_stats(dev);
+ break;
default:
status = -EFAULT;
@@ -514,6 +742,7 @@
.owner = THIS_MODULE,
.open = simple_open,
.read = ocrdma_dbgfs_ops_read,
+ .write = ocrdma_dbgfs_ops_write,
};
void ocrdma_add_port_stats(struct ocrdma_dev *dev)
@@ -582,6 +811,18 @@
&dev->rx_dbg_stats, &ocrdma_dbg_ops))
goto err;
+ dev->driver_stats.type = OCRDMA_DRV_STATS;
+ dev->driver_stats.dev = dev;
+ if (!debugfs_create_file("driver_dbg_stats", S_IRUSR, dev->dir,
+ &dev->driver_stats, &ocrdma_dbg_ops))
+ goto err;
+
+ dev->reset_stats.type = OCRDMA_RESET_STATS;
+ dev->reset_stats.dev = dev;
+ if (!debugfs_create_file("reset_stats", S_IRUSR, dev->dir,
+ &dev->reset_stats, &ocrdma_dbg_ops))
+ goto err;
+
/* Now create dma_mem for stats mbx command */
if (!ocrdma_alloc_stats_mem(dev))
goto err;
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_stats.h b/drivers/infiniband/hw/ocrdma/ocrdma_stats.h
index 5f5e20c..091edd6 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_stats.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_stats.h
@@ -43,12 +43,16 @@
OCRDMA_RXQP_ERRSTATS,
OCRDMA_TXQP_ERRSTATS,
OCRDMA_TX_DBG_STATS,
- OCRDMA_RX_DBG_STATS
+ OCRDMA_RX_DBG_STATS,
+ OCRDMA_DRV_STATS,
+ OCRDMA_RESET_STATS
};
void ocrdma_rem_debugfs(void);
void ocrdma_init_debugfs(void);
void ocrdma_rem_port_stats(struct ocrdma_dev *dev);
void ocrdma_add_port_stats(struct ocrdma_dev *dev);
+int ocrdma_pma_counters(struct ocrdma_dev *dev,
+ struct ib_mad *out_mad);
#endif /* __OCRDMA_STATS_H__ */
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
index fb8d8c4..8771755 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
@@ -53,7 +53,7 @@
dev = get_ocrdma_dev(ibdev);
memset(sgid, 0, sizeof(*sgid));
- if (index > OCRDMA_MAX_SGID)
+ if (index >= OCRDMA_MAX_SGID)
return -EINVAL;
memcpy(sgid, &dev->sgid_tbl[index], sizeof(*sgid));
@@ -253,6 +253,107 @@
return found;
}
+
+static u16 _ocrdma_pd_mgr_get_bitmap(struct ocrdma_dev *dev, bool dpp_pool)
+{
+ u16 pd_bitmap_idx = 0;
+ const unsigned long *pd_bitmap;
+
+ if (dpp_pool) {
+ pd_bitmap = dev->pd_mgr->pd_dpp_bitmap;
+ pd_bitmap_idx = find_first_zero_bit(pd_bitmap,
+ dev->pd_mgr->max_dpp_pd);
+ __set_bit(pd_bitmap_idx, dev->pd_mgr->pd_dpp_bitmap);
+ dev->pd_mgr->pd_dpp_count++;
+ if (dev->pd_mgr->pd_dpp_count > dev->pd_mgr->pd_dpp_thrsh)
+ dev->pd_mgr->pd_dpp_thrsh = dev->pd_mgr->pd_dpp_count;
+ } else {
+ pd_bitmap = dev->pd_mgr->pd_norm_bitmap;
+ pd_bitmap_idx = find_first_zero_bit(pd_bitmap,
+ dev->pd_mgr->max_normal_pd);
+ __set_bit(pd_bitmap_idx, dev->pd_mgr->pd_norm_bitmap);
+ dev->pd_mgr->pd_norm_count++;
+ if (dev->pd_mgr->pd_norm_count > dev->pd_mgr->pd_norm_thrsh)
+ dev->pd_mgr->pd_norm_thrsh = dev->pd_mgr->pd_norm_count;
+ }
+ return pd_bitmap_idx;
+}
+
+static int _ocrdma_pd_mgr_put_bitmap(struct ocrdma_dev *dev, u16 pd_id,
+ bool dpp_pool)
+{
+ u16 pd_count;
+ u16 pd_bit_index;
+
+ pd_count = dpp_pool ? dev->pd_mgr->pd_dpp_count :
+ dev->pd_mgr->pd_norm_count;
+ if (pd_count == 0)
+ return -EINVAL;
+
+ if (dpp_pool) {
+ pd_bit_index = pd_id - dev->pd_mgr->pd_dpp_start;
+ if (pd_bit_index >= dev->pd_mgr->max_dpp_pd) {
+ return -EINVAL;
+ } else {
+ __clear_bit(pd_bit_index, dev->pd_mgr->pd_dpp_bitmap);
+ dev->pd_mgr->pd_dpp_count--;
+ }
+ } else {
+ pd_bit_index = pd_id - dev->pd_mgr->pd_norm_start;
+ if (pd_bit_index >= dev->pd_mgr->max_normal_pd) {
+ return -EINVAL;
+ } else {
+ __clear_bit(pd_bit_index, dev->pd_mgr->pd_norm_bitmap);
+ dev->pd_mgr->pd_norm_count--;
+ }
+ }
+
+ return 0;
+}
+
+static u8 ocrdma_put_pd_num(struct ocrdma_dev *dev, u16 pd_id,
+ bool dpp_pool)
+{
+ int status;
+
+ mutex_lock(&dev->dev_lock);
+ status = _ocrdma_pd_mgr_put_bitmap(dev, pd_id, dpp_pool);
+ mutex_unlock(&dev->dev_lock);
+ return status;
+}
+
+static int ocrdma_get_pd_num(struct ocrdma_dev *dev, struct ocrdma_pd *pd)
+{
+ u16 pd_idx = 0;
+ int status = 0;
+
+ mutex_lock(&dev->dev_lock);
+ if (pd->dpp_enabled) {
+ /* try allocating DPP PD, if not available then normal PD */
+ if (dev->pd_mgr->pd_dpp_count < dev->pd_mgr->max_dpp_pd) {
+ pd_idx = _ocrdma_pd_mgr_get_bitmap(dev, true);
+ pd->id = dev->pd_mgr->pd_dpp_start + pd_idx;
+ pd->dpp_page = dev->pd_mgr->dpp_page_index + pd_idx;
+ } else if (dev->pd_mgr->pd_norm_count <
+ dev->pd_mgr->max_normal_pd) {
+ pd_idx = _ocrdma_pd_mgr_get_bitmap(dev, false);
+ pd->id = dev->pd_mgr->pd_norm_start + pd_idx;
+ pd->dpp_enabled = false;
+ } else {
+ status = -EINVAL;
+ }
+ } else {
+ if (dev->pd_mgr->pd_norm_count < dev->pd_mgr->max_normal_pd) {
+ pd_idx = _ocrdma_pd_mgr_get_bitmap(dev, false);
+ pd->id = dev->pd_mgr->pd_norm_start + pd_idx;
+ } else {
+ status = -EINVAL;
+ }
+ }
+ mutex_unlock(&dev->dev_lock);
+ return status;
+}
+
static struct ocrdma_pd *_ocrdma_alloc_pd(struct ocrdma_dev *dev,
struct ocrdma_ucontext *uctx,
struct ib_udata *udata)
@@ -272,6 +373,11 @@
dev->attr.wqe_size) : 0;
}
+ if (dev->pd_mgr->pd_prealloc_valid) {
+ status = ocrdma_get_pd_num(dev, pd);
+ return (status == 0) ? pd : ERR_PTR(status);
+ }
+
retry:
status = ocrdma_mbx_alloc_pd(dev, pd);
if (status) {
@@ -299,7 +405,11 @@
{
int status = 0;
- status = ocrdma_mbx_dealloc_pd(dev, pd);
+ if (dev->pd_mgr->pd_prealloc_valid)
+ status = ocrdma_put_pd_num(dev, pd->id, pd->dpp_enabled);
+ else
+ status = ocrdma_mbx_dealloc_pd(dev, pd);
+
kfree(pd);
return status;
}
@@ -325,7 +435,6 @@
static int ocrdma_dealloc_ucontext_pd(struct ocrdma_ucontext *uctx)
{
- int status = 0;
struct ocrdma_pd *pd = uctx->cntxt_pd;
struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
@@ -334,8 +443,8 @@
__func__, dev->id, pd->id);
}
uctx->cntxt_pd = NULL;
- status = _ocrdma_dealloc_pd(dev, pd);
- return status;
+ (void)_ocrdma_dealloc_pd(dev, pd);
+ return 0;
}
static struct ocrdma_pd *ocrdma_get_ucontext_pd(struct ocrdma_ucontext *uctx)
@@ -569,7 +678,7 @@
if (is_uctx_pd) {
ocrdma_release_ucontext_pd(uctx);
} else {
- status = ocrdma_mbx_dealloc_pd(dev, pd);
+ status = _ocrdma_dealloc_pd(dev, pd);
kfree(pd);
}
exit:
@@ -837,9 +946,8 @@
{
struct ocrdma_mr *mr = get_ocrdma_mr(ib_mr);
struct ocrdma_dev *dev = get_ocrdma_dev(ib_mr->device);
- int status;
- status = ocrdma_mbx_dealloc_lkey(dev, mr->hwmr.fr_mr, mr->hwmr.lkey);
+ (void) ocrdma_mbx_dealloc_lkey(dev, mr->hwmr.fr_mr, mr->hwmr.lkey);
ocrdma_free_mr_pbl_tbl(dev, &mr->hwmr);
@@ -850,11 +958,10 @@
/* Don't stop cleanup, in case FW is unresponsive */
if (dev->mqe_ctx.fw_error_state) {
- status = 0;
pr_err("%s(%d) fw not responding.\n",
__func__, dev->id);
}
- return status;
+ return 0;
}
static int ocrdma_copy_cq_uresp(struct ocrdma_dev *dev, struct ocrdma_cq *cq,
@@ -986,7 +1093,6 @@
int ocrdma_destroy_cq(struct ib_cq *ibcq)
{
- int status;
struct ocrdma_cq *cq = get_ocrdma_cq(ibcq);
struct ocrdma_eq *eq = NULL;
struct ocrdma_dev *dev = get_ocrdma_dev(ibcq->device);
@@ -1003,7 +1109,7 @@
synchronize_irq(irq);
ocrdma_flush_cq(cq);
- status = ocrdma_mbx_destroy_cq(dev, cq);
+ (void)ocrdma_mbx_destroy_cq(dev, cq);
if (cq->ucontext) {
pdid = cq->ucontext->cntxt_pd->id;
ocrdma_del_mmap(cq->ucontext, (u64) cq->pa,
@@ -1014,7 +1120,7 @@
}
kfree(cq);
- return status;
+ return 0;
}
static int ocrdma_add_qpn_map(struct ocrdma_dev *dev, struct ocrdma_qp *qp)
@@ -1113,8 +1219,8 @@
int status = 0;
u64 usr_db;
struct ocrdma_create_qp_uresp uresp;
- struct ocrdma_dev *dev = qp->dev;
struct ocrdma_pd *pd = qp->pd;
+ struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
memset(&uresp, 0, sizeof(uresp));
usr_db = dev->nic_info.unmapped_db +
@@ -1253,7 +1359,6 @@
status = -ENOMEM;
goto gen_err;
}
- qp->dev = dev;
ocrdma_set_qp_init_params(qp, pd, attrs);
if (udata == NULL)
qp->cap_flags |= (OCRDMA_QP_MW_BIND | OCRDMA_QP_LKEY0 |
@@ -1312,7 +1417,7 @@
enum ib_qp_state old_qps;
qp = get_ocrdma_qp(ibqp);
- dev = qp->dev;
+ dev = get_ocrdma_dev(ibqp->device);
if (attr_mask & IB_QP_STATE)
status = ocrdma_qp_state_change(qp, attr->qp_state, &old_qps);
/* if new and previous states are same hw doesn't need to
@@ -1335,7 +1440,7 @@
enum ib_qp_state old_qps, new_qps;
qp = get_ocrdma_qp(ibqp);
- dev = qp->dev;
+ dev = get_ocrdma_dev(ibqp->device);
/* syncronize with multiple context trying to change, retrive qps */
mutex_lock(&dev->dev_lock);
@@ -1402,7 +1507,7 @@
u32 qp_state;
struct ocrdma_qp_params params;
struct ocrdma_qp *qp = get_ocrdma_qp(ibqp);
- struct ocrdma_dev *dev = qp->dev;
+ struct ocrdma_dev *dev = get_ocrdma_dev(ibqp->device);
memset(¶ms, 0, sizeof(params));
mutex_lock(&dev->dev_lock);
@@ -1412,8 +1517,6 @@
goto mbx_err;
if (qp->qp_type == IB_QPT_UD)
qp_attr->qkey = params.qkey;
- qp_attr->qp_state = get_ibqp_state(IB_QPS_INIT);
- qp_attr->cur_qp_state = get_ibqp_state(IB_QPS_INIT);
qp_attr->path_mtu =
ocrdma_mtu_int_to_enum(params.path_mtu_pkey_indx &
OCRDMA_QP_PARAMS_PATH_MTU_MASK) >>
@@ -1468,6 +1571,8 @@
memset(&qp_attr->alt_ah_attr, 0, sizeof(qp_attr->alt_ah_attr));
qp_state = (params.max_sge_recv_flags & OCRDMA_QP_PARAMS_STATE_MASK) >>
OCRDMA_QP_PARAMS_STATE_SHIFT;
+ qp_attr->qp_state = get_ibqp_state(qp_state);
+ qp_attr->cur_qp_state = qp_attr->qp_state;
qp_attr->sq_draining = (qp_state == OCRDMA_QPS_SQ_DRAINING) ? 1 : 0;
qp_attr->max_dest_rd_atomic =
params.max_ord_ird >> OCRDMA_QP_PARAMS_MAX_ORD_SHIFT;
@@ -1475,19 +1580,18 @@
params.max_ord_ird & OCRDMA_QP_PARAMS_MAX_IRD_MASK;
qp_attr->en_sqd_async_notify = (params.max_sge_recv_flags &
OCRDMA_QP_PARAMS_FLAGS_SQD_ASYNC) ? 1 : 0;
+ /* Sync driver QP state with FW */
+ ocrdma_qp_state_change(qp, qp_attr->qp_state, NULL);
mbx_err:
return status;
}
-static void ocrdma_srq_toggle_bit(struct ocrdma_srq *srq, int idx)
+static void ocrdma_srq_toggle_bit(struct ocrdma_srq *srq, unsigned int idx)
{
- int i = idx / 32;
- unsigned int mask = (1 << (idx % 32));
+ unsigned int i = idx / 32;
+ u32 mask = (1U << (idx % 32));
- if (srq->idx_bit_fields[i] & mask)
- srq->idx_bit_fields[i] &= ~mask;
- else
- srq->idx_bit_fields[i] |= mask;
+ srq->idx_bit_fields[i] ^= mask;
}
static int ocrdma_hwq_free_cnt(struct ocrdma_qp_hwq_info *q)
@@ -1596,7 +1700,7 @@
{
int found = false;
unsigned long flags;
- struct ocrdma_dev *dev = qp->dev;
+ struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
/* sync with any active CQ poll */
spin_lock_irqsave(&dev->flush_q_lock, flags);
@@ -1613,7 +1717,6 @@
int ocrdma_destroy_qp(struct ib_qp *ibqp)
{
- int status;
struct ocrdma_pd *pd;
struct ocrdma_qp *qp;
struct ocrdma_dev *dev;
@@ -1622,7 +1725,7 @@
unsigned long flags;
qp = get_ocrdma_qp(ibqp);
- dev = qp->dev;
+ dev = get_ocrdma_dev(ibqp->device);
attrs.qp_state = IB_QPS_ERR;
pd = qp->pd;
@@ -1635,7 +1738,7 @@
* discarded until the old CQEs are discarded.
*/
mutex_lock(&dev->dev_lock);
- status = ocrdma_mbx_destroy_qp(dev, qp);
+ (void) ocrdma_mbx_destroy_qp(dev, qp);
/*
* acquire CQ lock while destroy is in progress, in order to
@@ -1670,7 +1773,7 @@
kfree(qp->wqe_wr_id_tbl);
kfree(qp->rqe_wr_id_tbl);
kfree(qp);
- return status;
+ return 0;
}
static int ocrdma_copy_srq_uresp(struct ocrdma_dev *dev, struct ocrdma_srq *srq,
@@ -1831,6 +1934,8 @@
else
ud_hdr->qkey = wr->wr.ud.remote_qkey;
ud_hdr->rsvd_ahid = ah->id;
+ if (ah->av->valid & OCRDMA_AV_VLAN_VALID)
+ hdr->cw |= (OCRDMA_FLAG_AH_VLAN_PR << OCRDMA_WQE_FLAGS_SHIFT);
}
static void ocrdma_build_sges(struct ocrdma_hdr_wqe *hdr,
@@ -2007,11 +2112,12 @@
u64 fbo;
struct ocrdma_ewqe_fr *fast_reg = (struct ocrdma_ewqe_fr *)(hdr + 1);
struct ocrdma_mr *mr;
+ struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
u32 wqe_size = sizeof(*fast_reg) + sizeof(*hdr);
wqe_size = roundup(wqe_size, OCRDMA_WQE_ALIGN_BYTES);
- if (wr->wr.fast_reg.page_list_len > qp->dev->attr.max_pages_per_frmr)
+ if (wr->wr.fast_reg.page_list_len > dev->attr.max_pages_per_frmr)
return -EINVAL;
hdr->cw |= (OCRDMA_FR_MR << OCRDMA_WQE_OPCODE_SHIFT);
@@ -2039,7 +2145,7 @@
fast_reg->size_sge =
get_encoded_page_size(1 << wr->wr.fast_reg.page_shift);
mr = (struct ocrdma_mr *) (unsigned long)
- qp->dev->stag_arr[(hdr->lkey >> 8) & (OCRDMA_MAX_STAG - 1)];
+ dev->stag_arr[(hdr->lkey >> 8) & (OCRDMA_MAX_STAG - 1)];
build_frmr_pbes(wr, mr->hwmr.pbl_table, &mr->hwmr);
return 0;
}
@@ -2112,8 +2218,6 @@
hdr->cw |= (OCRDMA_WRITE << OCRDMA_WQE_OPCODE_SHIFT);
status = ocrdma_build_write(qp, hdr, wr);
break;
- case IB_WR_RDMA_READ_WITH_INV:
- hdr->cw |= (OCRDMA_FLAG_INV << OCRDMA_WQE_FLAGS_SHIFT);
case IB_WR_RDMA_READ:
ocrdma_build_read(qp, hdr, wr);
break;
@@ -2484,8 +2588,11 @@
bool *polled, bool *stop)
{
bool expand;
+ struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
int status = (le32_to_cpu(cqe->flags_status_srcqpn) &
OCRDMA_CQE_STATUS_MASK) >> OCRDMA_CQE_STATUS_SHIFT;
+ if (status < OCRDMA_MAX_CQE_ERR)
+ atomic_inc(&dev->cqe_err_stats[status]);
/* when hw sq is empty, but rq is not empty, so we continue
* to keep the cqe in order to get the cq event again.
@@ -2604,6 +2711,10 @@
int status)
{
bool expand;
+ struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
+
+ if (status < OCRDMA_MAX_CQE_ERR)
+ atomic_inc(&dev->cqe_err_stats[status]);
/* when hw_rq is empty, but wq is not empty, so continue
* to keep the cqe to get the cq event again.
diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h
index c00ae09..ffd48bf 100644
--- a/drivers/infiniband/hw/qib/qib.h
+++ b/drivers/infiniband/hw/qib/qib.h
@@ -1082,12 +1082,6 @@
/* control high-level access to EEPROM */
struct mutex eep_lock;
uint64_t traffic_wds;
- /* active time is kept in seconds, but logged in hours */
- atomic_t active_time;
- /* Below are nominal shadow of EEPROM, new since last EEPROM update */
- uint8_t eep_st_errs[QIB_EEP_LOG_CNT];
- uint8_t eep_st_new_errs[QIB_EEP_LOG_CNT];
- uint16_t eep_hrs;
/*
* masks for which bits of errs, hwerrs that cause
* each of the counters to increment.
@@ -1309,8 +1303,7 @@
int qib_twsi_blk_wr(struct qib_devdata *dd, int dev, int addr,
const void *buffer, int len);
void qib_get_eeprom_info(struct qib_devdata *);
-int qib_update_eeprom_log(struct qib_devdata *dd);
-void qib_inc_eeprom_err(struct qib_devdata *dd, u32 eidx, u32 incr);
+#define qib_inc_eeprom_err(dd, eidx, incr)
void qib_dump_lookup_output_queue(struct qib_devdata *);
void qib_force_pio_avail_update(struct qib_devdata *);
void qib_clear_symerror_on_linkup(unsigned long opaque);
@@ -1467,11 +1460,14 @@
* Flush write combining store buffers (if present) and perform a write
* barrier.
*/
+static inline void qib_flush_wc(void)
+{
#if defined(CONFIG_X86_64)
-#define qib_flush_wc() asm volatile("sfence" : : : "memory")
+ asm volatile("sfence" : : : "memory");
#else
-#define qib_flush_wc() wmb() /* no reorder around wc flush */
+ wmb(); /* no reorder around wc flush */
#endif
+}
/* global module parameter variables */
extern unsigned qib_ibmtu;
diff --git a/drivers/infiniband/hw/qib/qib_common.h b/drivers/infiniband/hw/qib/qib_common.h
index 5670ace..4fb78ab 100644
--- a/drivers/infiniband/hw/qib/qib_common.h
+++ b/drivers/infiniband/hw/qib/qib_common.h
@@ -257,7 +257,7 @@
/* shared memory page for send buffer disarm status */
__u64 spi_sendbuf_status;
-} __attribute__ ((aligned(8)));
+} __aligned(8);
/*
* This version number is given to the driver by the user code during
@@ -361,7 +361,7 @@
*/
__u64 spu_base_info;
-} __attribute__ ((aligned(8)));
+} __aligned(8);
/* User commands. */
diff --git a/drivers/infiniband/hw/qib/qib_debugfs.c b/drivers/infiniband/hw/qib/qib_debugfs.c
index 6abd3ed..5e75b43 100644
--- a/drivers/infiniband/hw/qib/qib_debugfs.c
+++ b/drivers/infiniband/hw/qib/qib_debugfs.c
@@ -255,7 +255,6 @@
DEBUGFS_FILE_CREATE(opcode_stats);
DEBUGFS_FILE_CREATE(ctx_stats);
DEBUGFS_FILE_CREATE(qp_stats);
- return;
}
void qib_dbg_ibdev_exit(struct qib_ibdev *ibd)
diff --git a/drivers/infiniband/hw/qib/qib_diag.c b/drivers/infiniband/hw/qib/qib_diag.c
index 5dfda4c..8c34b23 100644
--- a/drivers/infiniband/hw/qib/qib_diag.c
+++ b/drivers/infiniband/hw/qib/qib_diag.c
@@ -85,7 +85,7 @@
client_pool = dc->next;
else
/* None in pool, alloc and init */
- dc = kmalloc(sizeof *dc, GFP_KERNEL);
+ dc = kmalloc(sizeof(*dc), GFP_KERNEL);
if (dc) {
dc->next = NULL;
@@ -257,6 +257,7 @@
if (dd->userbase) {
/* If user regs mapped, they are after send, so set limit. */
u32 ulim = (dd->cfgctxts * dd->ureg_align) + dd->uregbase;
+
if (!dd->piovl15base)
snd_lim = dd->uregbase;
krb32 = (u32 __iomem *)dd->userbase;
@@ -280,6 +281,7 @@
snd_bottom = dd->pio2k_bufbase;
if (snd_lim == 0) {
u32 tot2k = dd->piobcnt2k * ALIGN(dd->piosize2k, dd->palign);
+
snd_lim = snd_bottom + tot2k;
}
/* If 4k buffers exist, account for them by bumping
@@ -398,6 +400,7 @@
/* not very efficient, but it works for now */
while (reg_addr < reg_end) {
u64 data;
+
if (copy_from_user(&data, uaddr, sizeof(data))) {
ret = -EFAULT;
goto bail;
@@ -698,7 +701,7 @@
if (!dd || !op)
return -EINVAL;
- olp = vmalloc(sizeof *olp);
+ olp = vmalloc(sizeof(*olp));
if (!olp) {
pr_err("vmalloc for observer failed\n");
return -ENOMEM;
@@ -796,6 +799,7 @@
op = diag_get_observer(dd, *off);
if (op) {
u32 offset = *off;
+
ret = op->hook(dd, op, offset, &data64, 0, use_32);
}
/*
@@ -873,6 +877,7 @@
if (count == 4 || count == 8) {
u64 data64;
u32 offset = *off;
+
ret = copy_from_user(&data64, data, count);
if (ret) {
ret = -EFAULT;
diff --git a/drivers/infiniband/hw/qib/qib_driver.c b/drivers/infiniband/hw/qib/qib_driver.c
index 5bee08f..f58fdc3 100644
--- a/drivers/infiniband/hw/qib/qib_driver.c
+++ b/drivers/infiniband/hw/qib/qib_driver.c
@@ -86,7 +86,7 @@
{
static char iname[16];
- snprintf(iname, sizeof iname, "infinipath%u", unit);
+ snprintf(iname, sizeof(iname), "infinipath%u", unit);
return iname;
}
@@ -349,6 +349,7 @@
qp_num = be32_to_cpu(ohdr->bth[1]) & QIB_QPN_MASK;
if (qp_num != QIB_MULTICAST_QPN) {
int ruc_res;
+
qp = qib_lookup_qpn(ibp, qp_num);
if (!qp)
goto drop;
@@ -461,6 +462,7 @@
rhf_addr = (__le32 *) rcd->rcvhdrq + l + dd->rhf_offset;
if (dd->flags & QIB_NODMA_RTAIL) {
u32 seq = qib_hdrget_seq(rhf_addr);
+
if (seq != rcd->seq_cnt)
goto bail;
hdrqtail = 0;
@@ -651,6 +653,7 @@
int qib_set_lid(struct qib_pportdata *ppd, u32 lid, u8 lmc)
{
struct qib_devdata *dd = ppd->dd;
+
ppd->lid = lid;
ppd->lmc = lmc;
diff --git a/drivers/infiniband/hw/qib/qib_eeprom.c b/drivers/infiniband/hw/qib/qib_eeprom.c
index 4d5d71a..311ee6c 100644
--- a/drivers/infiniband/hw/qib/qib_eeprom.c
+++ b/drivers/infiniband/hw/qib/qib_eeprom.c
@@ -153,6 +153,7 @@
if (t && dd0->nguid > 1 && t <= dd0->nguid) {
u8 oguid;
+
dd->base_guid = dd0->base_guid;
bguid = (u8 *) &dd->base_guid;
@@ -251,206 +252,25 @@
* This board has a Serial-prefix, which is stored
* elsewhere for backward-compatibility.
*/
- memcpy(snp, ifp->if_sprefix, sizeof ifp->if_sprefix);
- snp[sizeof ifp->if_sprefix] = '\0';
+ memcpy(snp, ifp->if_sprefix, sizeof(ifp->if_sprefix));
+ snp[sizeof(ifp->if_sprefix)] = '\0';
len = strlen(snp);
snp += len;
- len = (sizeof dd->serial) - len;
- if (len > sizeof ifp->if_serial)
- len = sizeof ifp->if_serial;
+ len = sizeof(dd->serial) - len;
+ if (len > sizeof(ifp->if_serial))
+ len = sizeof(ifp->if_serial);
memcpy(snp, ifp->if_serial, len);
- } else
- memcpy(dd->serial, ifp->if_serial,
- sizeof ifp->if_serial);
+ } else {
+ memcpy(dd->serial, ifp->if_serial, sizeof(ifp->if_serial));
+ }
if (!strstr(ifp->if_comment, "Tested successfully"))
qib_dev_err(dd,
"Board SN %s did not pass functional test: %s\n",
dd->serial, ifp->if_comment);
- memcpy(&dd->eep_st_errs, &ifp->if_errcntp, QIB_EEP_LOG_CNT);
- /*
- * Power-on (actually "active") hours are kept as little-endian value
- * in EEPROM, but as seconds in a (possibly as small as 24-bit)
- * atomic_t while running.
- */
- atomic_set(&dd->active_time, 0);
- dd->eep_hrs = ifp->if_powerhour[0] | (ifp->if_powerhour[1] << 8);
-
done:
vfree(buf);
bail:;
}
-/**
- * qib_update_eeprom_log - copy active-time and error counters to eeprom
- * @dd: the qlogic_ib device
- *
- * Although the time is kept as seconds in the qib_devdata struct, it is
- * rounded to hours for re-write, as we have only 16 bits in EEPROM.
- * First-cut code reads whole (expected) struct qib_flash, modifies,
- * re-writes. Future direction: read/write only what we need, assuming
- * that the EEPROM had to have been "good enough" for driver init, and
- * if not, we aren't making it worse.
- *
- */
-int qib_update_eeprom_log(struct qib_devdata *dd)
-{
- void *buf;
- struct qib_flash *ifp;
- int len, hi_water;
- uint32_t new_time, new_hrs;
- u8 csum;
- int ret, idx;
- unsigned long flags;
-
- /* first, check if we actually need to do anything. */
- ret = 0;
- for (idx = 0; idx < QIB_EEP_LOG_CNT; ++idx) {
- if (dd->eep_st_new_errs[idx]) {
- ret = 1;
- break;
- }
- }
- new_time = atomic_read(&dd->active_time);
-
- if (ret == 0 && new_time < 3600)
- goto bail;
-
- /*
- * The quick-check above determined that there is something worthy
- * of logging, so get current contents and do a more detailed idea.
- * read full flash, not just currently used part, since it may have
- * been written with a newer definition
- */
- len = sizeof(struct qib_flash);
- buf = vmalloc(len);
- ret = 1;
- if (!buf) {
- qib_dev_err(dd,
- "Couldn't allocate memory to read %u bytes from eeprom for logging\n",
- len);
- goto bail;
- }
-
- /* Grab semaphore and read current EEPROM. If we get an
- * error, let go, but if not, keep it until we finish write.
- */
- ret = mutex_lock_interruptible(&dd->eep_lock);
- if (ret) {
- qib_dev_err(dd, "Unable to acquire EEPROM for logging\n");
- goto free_bail;
- }
- ret = qib_twsi_blk_rd(dd, dd->twsi_eeprom_dev, 0, buf, len);
- if (ret) {
- mutex_unlock(&dd->eep_lock);
- qib_dev_err(dd, "Unable read EEPROM for logging\n");
- goto free_bail;
- }
- ifp = (struct qib_flash *)buf;
-
- csum = flash_csum(ifp, 0);
- if (csum != ifp->if_csum) {
- mutex_unlock(&dd->eep_lock);
- qib_dev_err(dd, "EEPROM cks err (0x%02X, S/B 0x%02X)\n",
- csum, ifp->if_csum);
- ret = 1;
- goto free_bail;
- }
- hi_water = 0;
- spin_lock_irqsave(&dd->eep_st_lock, flags);
- for (idx = 0; idx < QIB_EEP_LOG_CNT; ++idx) {
- int new_val = dd->eep_st_new_errs[idx];
- if (new_val) {
- /*
- * If we have seen any errors, add to EEPROM values
- * We need to saturate at 0xFF (255) and we also
- * would need to adjust the checksum if we were
- * trying to minimize EEPROM traffic
- * Note that we add to actual current count in EEPROM,
- * in case it was altered while we were running.
- */
- new_val += ifp->if_errcntp[idx];
- if (new_val > 0xFF)
- new_val = 0xFF;
- if (ifp->if_errcntp[idx] != new_val) {
- ifp->if_errcntp[idx] = new_val;
- hi_water = offsetof(struct qib_flash,
- if_errcntp) + idx;
- }
- /*
- * update our shadow (used to minimize EEPROM
- * traffic), to match what we are about to write.
- */
- dd->eep_st_errs[idx] = new_val;
- dd->eep_st_new_errs[idx] = 0;
- }
- }
- /*
- * Now update active-time. We would like to round to the nearest hour
- * but unless atomic_t are sure to be proper signed ints we cannot,
- * because we need to account for what we "transfer" to EEPROM and
- * if we log an hour at 31 minutes, then we would need to set
- * active_time to -29 to accurately count the _next_ hour.
- */
- if (new_time >= 3600) {
- new_hrs = new_time / 3600;
- atomic_sub((new_hrs * 3600), &dd->active_time);
- new_hrs += dd->eep_hrs;
- if (new_hrs > 0xFFFF)
- new_hrs = 0xFFFF;
- dd->eep_hrs = new_hrs;
- if ((new_hrs & 0xFF) != ifp->if_powerhour[0]) {
- ifp->if_powerhour[0] = new_hrs & 0xFF;
- hi_water = offsetof(struct qib_flash, if_powerhour);
- }
- if ((new_hrs >> 8) != ifp->if_powerhour[1]) {
- ifp->if_powerhour[1] = new_hrs >> 8;
- hi_water = offsetof(struct qib_flash, if_powerhour) + 1;
- }
- }
- /*
- * There is a tiny possibility that we could somehow fail to write
- * the EEPROM after updating our shadows, but problems from holding
- * the spinlock too long are a much bigger issue.
- */
- spin_unlock_irqrestore(&dd->eep_st_lock, flags);
- if (hi_water) {
- /* we made some change to the data, uopdate cksum and write */
- csum = flash_csum(ifp, 1);
- ret = eeprom_write_with_enable(dd, 0, buf, hi_water + 1);
- }
- mutex_unlock(&dd->eep_lock);
- if (ret)
- qib_dev_err(dd, "Failed updating EEPROM\n");
-
-free_bail:
- vfree(buf);
-bail:
- return ret;
-}
-
-/**
- * qib_inc_eeprom_err - increment one of the four error counters
- * that are logged to EEPROM.
- * @dd: the qlogic_ib device
- * @eidx: 0..3, the counter to increment
- * @incr: how much to add
- *
- * Each counter is 8-bits, and saturates at 255 (0xFF). They
- * are copied to the EEPROM (aka flash) whenever qib_update_eeprom_log()
- * is called, but it can only be called in a context that allows sleep.
- * This function can be called even at interrupt level.
- */
-void qib_inc_eeprom_err(struct qib_devdata *dd, u32 eidx, u32 incr)
-{
- uint new_val;
- unsigned long flags;
-
- spin_lock_irqsave(&dd->eep_st_lock, flags);
- new_val = dd->eep_st_new_errs[eidx] + incr;
- if (new_val > 255)
- new_val = 255;
- dd->eep_st_new_errs[eidx] = new_val;
- spin_unlock_irqrestore(&dd->eep_st_lock, flags);
-}
diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c
index b15e34e..41937c6 100644
--- a/drivers/infiniband/hw/qib/qib_file_ops.c
+++ b/drivers/infiniband/hw/qib/qib_file_ops.c
@@ -351,9 +351,10 @@
* unless perhaps the user has mpin'ed the pages
* themselves.
*/
- qib_devinfo(dd->pcidev,
- "Failed to lock addr %p, %u pages: "
- "errno %d\n", (void *) vaddr, cnt, -ret);
+ qib_devinfo(
+ dd->pcidev,
+ "Failed to lock addr %p, %u pages: errno %d\n",
+ (void *) vaddr, cnt, -ret);
goto done;
}
for (i = 0; i < cnt; i++, vaddr += PAGE_SIZE) {
@@ -437,7 +438,7 @@
goto cleanup;
}
if (copy_to_user((void __user *) (unsigned long) ti->tidmap,
- tidmap, sizeof tidmap)) {
+ tidmap, sizeof(tidmap))) {
ret = -EFAULT;
goto cleanup;
}
@@ -484,7 +485,7 @@
}
if (copy_from_user(tidmap, (void __user *)(unsigned long)ti->tidmap,
- sizeof tidmap)) {
+ sizeof(tidmap))) {
ret = -EFAULT;
goto done;
}
@@ -951,8 +952,8 @@
/* rcvegrbufs are read-only on the slave */
if (vma->vm_flags & VM_WRITE) {
qib_devinfo(dd->pcidev,
- "Can't map eager buffers as "
- "writable (flags=%lx)\n", vma->vm_flags);
+ "Can't map eager buffers as writable (flags=%lx)\n",
+ vma->vm_flags);
ret = -EPERM;
goto bail;
}
@@ -1185,6 +1186,7 @@
*/
if (weight >= qib_cpulist_count) {
int cpu;
+
cpu = find_first_zero_bit(qib_cpulist,
qib_cpulist_count);
if (cpu == qib_cpulist_count)
@@ -1247,10 +1249,7 @@
if (!qib_compatible_subctxts(uinfo->spu_userversion >> 16,
uinfo->spu_userversion & 0xffff)) {
qib_devinfo(dd->pcidev,
- "Mismatched user version (%d.%d) and driver "
- "version (%d.%d) while context sharing. Ensure "
- "that driver and library are from the same "
- "release.\n",
+ "Mismatched user version (%d.%d) and driver version (%d.%d) while context sharing. Ensure that driver and library are from the same release.\n",
(int) (uinfo->spu_userversion >> 16),
(int) (uinfo->spu_userversion & 0xffff),
QIB_USER_SWMAJOR, QIB_USER_SWMINOR);
@@ -1391,6 +1390,7 @@
}
if (!ppd) {
u32 pidx = ctxt % dd->num_pports;
+
if (usable(dd->pport + pidx))
ppd = dd->pport + pidx;
else {
@@ -1438,10 +1438,12 @@
if (alg == QIB_PORT_ALG_ACROSS) {
unsigned inuse = ~0U;
+
/* find device (with ACTIVE ports) with fewest ctxts in use */
for (ndev = 0; ndev < devmax; ndev++) {
struct qib_devdata *dd = qib_lookup(ndev);
unsigned cused = 0, cfree = 0, pusable = 0;
+
if (!dd)
continue;
if (port && port <= dd->num_pports &&
@@ -1471,6 +1473,7 @@
} else {
for (ndev = 0; ndev < devmax; ndev++) {
struct qib_devdata *dd = qib_lookup(ndev);
+
if (dd) {
ret = choose_port_ctxt(fp, dd, port, uinfo);
if (!ret)
@@ -1556,6 +1559,7 @@
}
for (ndev = 0; ndev < devmax; ndev++) {
struct qib_devdata *dd = qib_lookup(ndev);
+
if (dd) {
if (pcibus_to_node(dd->pcidev->bus) < 0) {
ret = -EINVAL;
diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c
index 8185458..55f240a3 100644
--- a/drivers/infiniband/hw/qib/qib_fs.c
+++ b/drivers/infiniband/hw/qib/qib_fs.c
@@ -106,7 +106,7 @@
{
qib_stats.sps_ints = qib_sps_ints();
return simple_read_from_buffer(buf, count, ppos, &qib_stats,
- sizeof qib_stats);
+ sizeof(qib_stats));
}
/*
@@ -133,7 +133,7 @@
size_t count, loff_t *ppos)
{
return simple_read_from_buffer(buf, count, ppos, qib_statnames,
- sizeof qib_statnames - 1); /* no null */
+ sizeof(qib_statnames) - 1); /* no null */
}
static const struct file_operations driver_ops[] = {
@@ -379,7 +379,7 @@
int ret, i;
/* create the per-unit directory */
- snprintf(unit, sizeof unit, "%u", dd->unit);
+ snprintf(unit, sizeof(unit), "%u", dd->unit);
ret = create_file(unit, S_IFDIR|S_IRUGO|S_IXUGO, sb->s_root, &dir,
&simple_dir_operations, dd);
if (ret) {
@@ -482,7 +482,7 @@
root = dget(sb->s_root);
mutex_lock(&root->d_inode->i_mutex);
- snprintf(unit, sizeof unit, "%u", dd->unit);
+ snprintf(unit, sizeof(unit), "%u", dd->unit);
dir = lookup_one_len(unit, root, strlen(unit));
if (IS_ERR(dir)) {
@@ -560,6 +560,7 @@
const char *dev_name, void *data)
{
struct dentry *ret;
+
ret = mount_single(fs_type, flags, data, qibfs_fill_super);
if (!IS_ERR(ret))
qib_super = ret->d_sb;
diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c
index d68266a..0d2ba59 100644
--- a/drivers/infiniband/hw/qib/qib_iba6120.c
+++ b/drivers/infiniband/hw/qib/qib_iba6120.c
@@ -333,6 +333,7 @@
enum qib_ureg regno, u64 value, int ctxt)
{
u64 __iomem *ubase;
+
if (dd->userbase)
ubase = (u64 __iomem *)
((char __iomem *) dd->userbase +
@@ -834,14 +835,14 @@
bits = (u32) ((hwerrs >>
QLOGIC_IB_HWE_PCIEMEMPARITYERR_SHIFT) &
QLOGIC_IB_HWE_PCIEMEMPARITYERR_MASK);
- snprintf(bitsmsg, sizeof dd->cspec->bitsmsgbuf,
+ snprintf(bitsmsg, sizeof(dd->cspec->bitsmsgbuf),
"[PCIe Mem Parity Errs %x] ", bits);
strlcat(msg, bitsmsg, msgl);
}
if (hwerrs & _QIB_PLL_FAIL) {
isfatal = 1;
- snprintf(bitsmsg, sizeof dd->cspec->bitsmsgbuf,
+ snprintf(bitsmsg, sizeof(dd->cspec->bitsmsgbuf),
"[PLL failed (%llx), InfiniPath hardware unusable]",
(unsigned long long) hwerrs & _QIB_PLL_FAIL);
strlcat(msg, bitsmsg, msgl);
@@ -1014,7 +1015,7 @@
/* do these first, they are most important */
if (errs & ERR_MASK(HardwareErr))
- qib_handle_6120_hwerrors(dd, msg, sizeof dd->cspec->emsgbuf);
+ qib_handle_6120_hwerrors(dd, msg, sizeof(dd->cspec->emsgbuf));
else
for (log_idx = 0; log_idx < QIB_EEP_LOG_CNT; ++log_idx)
if (errs & dd->eep_st_masks[log_idx].errs_to_log)
@@ -1062,7 +1063,7 @@
*/
mask = ERR_MASK(IBStatusChanged) | ERR_MASK(RcvEgrFullErr) |
ERR_MASK(RcvHdrFullErr) | ERR_MASK(HardwareErr);
- qib_decode_6120_err(dd, msg, sizeof dd->cspec->emsgbuf, errs & ~mask);
+ qib_decode_6120_err(dd, msg, sizeof(dd->cspec->emsgbuf), errs & ~mask);
if (errs & E_SUM_PKTERRS)
qib_stats.sps_rcverrs++;
@@ -1670,6 +1671,7 @@
}
if (crcs) {
u32 cntr = dd->cspec->lli_counter;
+
cntr += crcs;
if (cntr) {
if (cntr > dd->cspec->lli_thresh) {
@@ -1722,6 +1724,7 @@
"irq is 0, BIOS error? Interrupts won't work\n");
else {
int ret;
+
ret = request_irq(dd->cspec->irq, qib_6120intr, 0,
QIB_DRV_NAME, dd);
if (ret)
@@ -2681,8 +2684,6 @@
spin_lock_irqsave(&dd->eep_st_lock, flags);
traffic_wds -= dd->traffic_wds;
dd->traffic_wds += traffic_wds;
- if (traffic_wds >= QIB_TRAFFIC_ACTIVE_THRESHOLD)
- atomic_add(5, &dd->active_time); /* S/B #define */
spin_unlock_irqrestore(&dd->eep_st_lock, flags);
qib_chk_6120_errormask(dd);
@@ -2929,6 +2930,7 @@
static int qib_6120_set_loopback(struct qib_pportdata *ppd, const char *what)
{
int ret = 0;
+
if (!strncmp(what, "ibc", 3)) {
ppd->dd->cspec->ibcctrl |= SYM_MASK(IBCCtrl, Loopback);
qib_devinfo(ppd->dd->pcidev, "Enabling IB%u:%u IBC loopback\n",
@@ -3170,6 +3172,7 @@
static void set_6120_baseaddrs(struct qib_devdata *dd)
{
u32 cregbase;
+
cregbase = qib_read_kreg32(dd, kr_counterregbase);
dd->cspec->cregbase = (u64 __iomem *)
((char __iomem *) dd->kregbase + cregbase);
diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c
index 7dec89f..22affda 100644
--- a/drivers/infiniband/hw/qib/qib_iba7220.c
+++ b/drivers/infiniband/hw/qib/qib_iba7220.c
@@ -902,7 +902,8 @@
errs &= QLOGIC_IB_E_SDMAERRS;
msg = dd->cspec->sdmamsgbuf;
- qib_decode_7220_sdma_errs(ppd, errs, msg, sizeof dd->cspec->sdmamsgbuf);
+ qib_decode_7220_sdma_errs(ppd, errs, msg,
+ sizeof(dd->cspec->sdmamsgbuf));
spin_lock_irqsave(&ppd->sdma_lock, flags);
if (errs & ERR_MASK(SendBufMisuseErr)) {
@@ -1043,6 +1044,7 @@
static void reenable_7220_chase(unsigned long opaque)
{
struct qib_pportdata *ppd = (struct qib_pportdata *)opaque;
+
ppd->cpspec->chase_timer.expires = 0;
qib_set_ib_7220_lstate(ppd, QLOGIC_IB_IBCC_LINKCMD_DOWN,
QLOGIC_IB_IBCC_LINKINITCMD_POLL);
@@ -1101,7 +1103,7 @@
/* do these first, they are most important */
if (errs & ERR_MASK(HardwareErr))
- qib_7220_handle_hwerrors(dd, msg, sizeof dd->cspec->emsgbuf);
+ qib_7220_handle_hwerrors(dd, msg, sizeof(dd->cspec->emsgbuf));
else
for (log_idx = 0; log_idx < QIB_EEP_LOG_CNT; ++log_idx)
if (errs & dd->eep_st_masks[log_idx].errs_to_log)
@@ -1155,7 +1157,7 @@
ERR_MASK(RcvEgrFullErr) | ERR_MASK(RcvHdrFullErr) |
ERR_MASK(HardwareErr) | ERR_MASK(SDmaDisabledErr);
- qib_decode_7220_err(dd, msg, sizeof dd->cspec->emsgbuf, errs & ~mask);
+ qib_decode_7220_err(dd, msg, sizeof(dd->cspec->emsgbuf), errs & ~mask);
if (errs & E_SUM_PKTERRS)
qib_stats.sps_rcverrs++;
@@ -1380,7 +1382,7 @@
bits = (u32) ((hwerrs >>
QLOGIC_IB_HWE_PCIEMEMPARITYERR_SHIFT) &
QLOGIC_IB_HWE_PCIEMEMPARITYERR_MASK);
- snprintf(bitsmsg, sizeof dd->cspec->bitsmsgbuf,
+ snprintf(bitsmsg, sizeof(dd->cspec->bitsmsgbuf),
"[PCIe Mem Parity Errs %x] ", bits);
strlcat(msg, bitsmsg, msgl);
}
@@ -1390,7 +1392,7 @@
if (hwerrs & _QIB_PLL_FAIL) {
isfatal = 1;
- snprintf(bitsmsg, sizeof dd->cspec->bitsmsgbuf,
+ snprintf(bitsmsg, sizeof(dd->cspec->bitsmsgbuf),
"[PLL failed (%llx), InfiniPath hardware unusable]",
(unsigned long long) hwerrs & _QIB_PLL_FAIL);
strlcat(msg, bitsmsg, msgl);
@@ -3297,8 +3299,6 @@
spin_lock_irqsave(&dd->eep_st_lock, flags);
traffic_wds -= dd->traffic_wds;
dd->traffic_wds += traffic_wds;
- if (traffic_wds >= QIB_TRAFFIC_ACTIVE_THRESHOLD)
- atomic_add(5, &dd->active_time); /* S/B #define */
spin_unlock_irqrestore(&dd->eep_st_lock, flags);
done:
mod_timer(&dd->stats_timer, jiffies + HZ * ACTIVITY_TIMER);
diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c
index a7eb3251..ef97b71 100644
--- a/drivers/infiniband/hw/qib/qib_iba7322.c
+++ b/drivers/infiniband/hw/qib/qib_iba7322.c
@@ -117,7 +117,7 @@
static ushort qib_long_atten = 10; /* 10 dB ~= 5m length */
module_param_named(long_attenuation, qib_long_atten, ushort, S_IRUGO);
-MODULE_PARM_DESC(long_attenuation, \
+MODULE_PARM_DESC(long_attenuation,
"attenuation cutoff (dB) for long copper cable setup");
static ushort qib_singleport;
@@ -153,11 +153,12 @@
static int setup_txselect(const char *, struct kernel_param *);
module_param_call(txselect, setup_txselect, param_get_string,
&kp_txselect, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(txselect, \
+MODULE_PARM_DESC(txselect,
"Tx serdes indices (for no QSFP or invalid QSFP data)");
#define BOARD_QME7342 5
#define BOARD_QMH7342 6
+#define BOARD_QMH7360 9
#define IS_QMH(dd) (SYM_FIELD((dd)->revision, Revision, BoardID) == \
BOARD_QMH7342)
#define IS_QME(dd) (SYM_FIELD((dd)->revision, Revision, BoardID) == \
@@ -817,6 +818,7 @@
enum qib_ureg regno, u64 value, int ctxt)
{
u64 __iomem *ubase;
+
if (dd->userbase)
ubase = (u64 __iomem *)
((char __iomem *) dd->userbase +
@@ -1677,7 +1679,7 @@
/* do these first, they are most important */
if (errs & QIB_E_HARDWARE) {
*msg = '\0';
- qib_7322_handle_hwerrors(dd, msg, sizeof dd->cspec->emsgbuf);
+ qib_7322_handle_hwerrors(dd, msg, sizeof(dd->cspec->emsgbuf));
} else
for (log_idx = 0; log_idx < QIB_EEP_LOG_CNT; ++log_idx)
if (errs & dd->eep_st_masks[log_idx].errs_to_log)
@@ -1702,7 +1704,7 @@
mask = QIB_E_HARDWARE;
*msg = '\0';
- err_decode(msg, sizeof dd->cspec->emsgbuf, errs & ~mask,
+ err_decode(msg, sizeof(dd->cspec->emsgbuf), errs & ~mask,
qib_7322error_msgs);
/*
@@ -1889,10 +1891,10 @@
*msg = '\0';
if (errs & ~QIB_E_P_BITSEXTANT) {
- err_decode(msg, sizeof ppd->cpspec->epmsgbuf,
+ err_decode(msg, sizeof(ppd->cpspec->epmsgbuf),
errs & ~QIB_E_P_BITSEXTANT, qib_7322p_error_msgs);
if (!*msg)
- snprintf(msg, sizeof ppd->cpspec->epmsgbuf,
+ snprintf(msg, sizeof(ppd->cpspec->epmsgbuf),
"no others");
qib_dev_porterr(dd, ppd->port,
"error interrupt with unknown errors 0x%016Lx set (and %s)\n",
@@ -1906,7 +1908,7 @@
/* determine cause, then write to clear */
symptom = qib_read_kreg_port(ppd, krp_sendhdrsymptom);
qib_write_kreg_port(ppd, krp_sendhdrsymptom, 0);
- err_decode(msg, sizeof ppd->cpspec->epmsgbuf, symptom,
+ err_decode(msg, sizeof(ppd->cpspec->epmsgbuf), symptom,
hdrchk_msgs);
*msg = '\0';
/* senderrbuf cleared in SPKTERRS below */
@@ -1922,7 +1924,7 @@
* isn't valid. We don't want to confuse people, so
* we just don't print them, except at debug
*/
- err_decode(msg, sizeof ppd->cpspec->epmsgbuf,
+ err_decode(msg, sizeof(ppd->cpspec->epmsgbuf),
(errs & QIB_E_P_LINK_PKTERRS),
qib_7322p_error_msgs);
*msg = '\0';
@@ -1938,7 +1940,7 @@
* valid. We don't want to confuse people, so we just
* don't print them, except at debug
*/
- err_decode(msg, sizeof ppd->cpspec->epmsgbuf, errs,
+ err_decode(msg, sizeof(ppd->cpspec->epmsgbuf), errs,
qib_7322p_error_msgs);
ignore_this_time = errs & QIB_E_P_LINK_PKTERRS;
*msg = '\0';
@@ -2031,6 +2033,7 @@
if (dd->cspec->num_msix_entries) {
/* and same for MSIx */
u64 val = qib_read_kreg64(dd, kr_intgranted);
+
if (val)
qib_write_kreg(dd, kr_intgranted, val);
}
@@ -2176,6 +2179,7 @@
int err;
unsigned long flags;
struct qib_pportdata *ppd = dd->pport;
+
for (; pidx < dd->num_pports; ++pidx, ppd++) {
err = 0;
if (pidx == 0 && (hwerrs &
@@ -2801,9 +2805,11 @@
if (n->rcv) {
struct qib_ctxtdata *rcd = (struct qib_ctxtdata *)n->arg;
+
qib_update_rhdrq_dca(rcd, cpu);
} else {
struct qib_pportdata *ppd = (struct qib_pportdata *)n->arg;
+
qib_update_sdma_dca(ppd, cpu);
}
}
@@ -2816,9 +2822,11 @@
if (n->rcv) {
struct qib_ctxtdata *rcd = (struct qib_ctxtdata *)n->arg;
+
dd = rcd->dd;
} else {
struct qib_pportdata *ppd = (struct qib_pportdata *)n->arg;
+
dd = ppd->dd;
}
qib_devinfo(dd->pcidev,
@@ -2994,6 +3002,7 @@
struct qib_pportdata *ppd;
struct qib_qsfp_data *qd;
u32 mask;
+
if (!dd->pport[pidx].link_speed_supported)
continue;
mask = QSFP_GPIO_MOD_PRS_N;
@@ -3001,6 +3010,7 @@
mask <<= (QSFP_GPIO_PORT2_SHIFT * ppd->hw_pidx);
if (gpiostatus & dd->cspec->gpio_mask & mask) {
u64 pins;
+
qd = &ppd->cpspec->qsfp_data;
gpiostatus &= ~mask;
pins = qib_read_kreg64(dd, kr_extstatus);
@@ -3442,7 +3452,7 @@
}
/* Try to get MSIx interrupts */
- memset(redirect, 0, sizeof redirect);
+ memset(redirect, 0, sizeof(redirect));
mask = ~0ULL;
msixnum = 0;
local_mask = cpumask_of_pcibus(dd->pcidev->bus);
@@ -3617,6 +3627,10 @@
n = "InfiniPath_QME7362";
dd->flags |= QIB_HAS_QSFP;
break;
+ case BOARD_QMH7360:
+ n = "Intel IB QDR 1P FLR-QSFP Adptr";
+ dd->flags |= QIB_HAS_QSFP;
+ break;
case 15:
n = "InfiniPath_QLE7342_TEST";
dd->flags |= QIB_HAS_QSFP;
@@ -3694,6 +3708,7 @@
*/
for (i = 0; i < msix_entries; i++) {
u64 vecaddr, vecdata;
+
vecaddr = qib_read_kreg64(dd, 2 * i +
(QIB_7322_MsixTable_OFFS / sizeof(u64)));
vecdata = qib_read_kreg64(dd, 1 + 2 * i +
@@ -5178,8 +5193,6 @@
spin_lock_irqsave(&ppd->dd->eep_st_lock, flags);
traffic_wds -= ppd->dd->traffic_wds;
ppd->dd->traffic_wds += traffic_wds;
- if (traffic_wds >= QIB_TRAFFIC_ACTIVE_THRESHOLD)
- atomic_add(ACTIVITY_TIMER, &ppd->dd->active_time);
spin_unlock_irqrestore(&ppd->dd->eep_st_lock, flags);
if (ppd->cpspec->qdr_dfe_on && (ppd->link_speed_active &
QIB_IB_QDR) &&
@@ -5357,6 +5370,7 @@
static void set_7322_ibspeed_fast(struct qib_pportdata *ppd, u32 speed)
{
u64 newctrlb;
+
newctrlb = ppd->cpspec->ibcctrl_b & ~(IBA7322_IBC_SPEED_MASK |
IBA7322_IBC_IBTA_1_2_MASK |
IBA7322_IBC_MAX_SPEED_MASK);
@@ -5843,6 +5857,7 @@
static void qib_7322_set_baseaddrs(struct qib_devdata *dd)
{
u32 cregbase;
+
cregbase = qib_read_kreg32(dd, kr_counterregbase);
dd->cspec->cregbase = (u64 __iomem *)(cregbase +
@@ -6183,6 +6198,7 @@
struct qib_devdata *dd;
unsigned long val;
char *n;
+
if (strlen(str) >= MAX_ATTEN_LEN) {
pr_info("txselect_values string too long\n");
return -ENOSPC;
@@ -6393,6 +6409,7 @@
val = TIDFLOW_ERRBITS; /* these are W1C */
for (i = 0; i < dd->cfgctxts; i++) {
int flow;
+
for (flow = 0; flow < NUM_TIDFLOWS_CTXT; flow++)
qib_write_ureg(dd, ur_rcvflowtable+flow, val, i);
}
@@ -6503,6 +6520,7 @@
for (pidx = 0; pidx < NUM_IB_PORTS; ++pidx) {
struct qib_chippport_specific *cp = ppd->cpspec;
+
ppd->link_speed_supported = features & PORT_SPD_CAP;
features >>= PORT_SPD_CAP_SHIFT;
if (!ppd->link_speed_supported) {
@@ -6581,8 +6599,7 @@
ppd->vls_supported = IB_VL_VL0_7;
else {
qib_devinfo(dd->pcidev,
- "Invalid num_vls %u for MTU %d "
- ", using 4 VLs\n",
+ "Invalid num_vls %u for MTU %d , using 4 VLs\n",
qib_num_cfg_vls, mtu);
ppd->vls_supported = IB_VL_VL0_3;
qib_num_cfg_vls = 4;
@@ -7890,6 +7907,7 @@
static int serdes_7322_init(struct qib_pportdata *ppd)
{
int ret = 0;
+
if (ppd->dd->cspec->r1)
ret = serdes_7322_init_old(ppd);
else
@@ -8305,8 +8323,8 @@
static int qib_r_grab(struct qib_devdata *dd)
{
- u64 val;
- val = SJA_EN;
+ u64 val = SJA_EN;
+
qib_write_kreg(dd, kr_r_access, val);
qib_read_kreg32(dd, kr_scratch);
return 0;
@@ -8319,6 +8337,7 @@
{
u64 val;
int timeout;
+
for (timeout = 0; timeout < 100 ; ++timeout) {
val = qib_read_kreg32(dd, kr_r_access);
if (val & R_RDY)
@@ -8346,6 +8365,7 @@
}
if (inp) {
int tdi = inp[pos >> 3] >> (pos & 7);
+
val |= ((tdi & 1) << R_TDI_LSB);
}
qib_write_kreg(dd, kr_r_access, val);
diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c
index 729da39c..2ee3695 100644
--- a/drivers/infiniband/hw/qib/qib_init.c
+++ b/drivers/infiniband/hw/qib/qib_init.c
@@ -140,7 +140,7 @@
* Allocate full ctxtcnt array, rather than just cfgctxts, because
* cleanup iterates across all possible ctxts.
*/
- dd->rcd = kzalloc(sizeof(*dd->rcd) * dd->ctxtcnt, GFP_KERNEL);
+ dd->rcd = kcalloc(dd->ctxtcnt, sizeof(*dd->rcd), GFP_KERNEL);
if (!dd->rcd) {
qib_dev_err(dd,
"Unable to allocate ctxtdata array, failing\n");
@@ -234,6 +234,7 @@
u8 hw_pidx, u8 port)
{
int size;
+
ppd->dd = dd;
ppd->hw_pidx = hw_pidx;
ppd->port = port; /* IB port number, not index */
@@ -613,6 +614,7 @@
ppd = dd->pport + pidx;
if (!ppd->qib_wq) {
char wq_name[8]; /* 3 + 2 + 1 + 1 + 1 */
+
snprintf(wq_name, sizeof(wq_name), "qib%d_%d",
dd->unit, pidx);
ppd->qib_wq =
@@ -714,6 +716,7 @@
for (pidx = 0; pidx < dd->num_pports; ++pidx) {
int mtu;
+
if (lastfail)
ret = lastfail;
ppd = dd->pport + pidx;
@@ -931,7 +934,6 @@
qib_free_pportdata(ppd);
}
- qib_update_eeprom_log(dd);
}
/**
@@ -1026,8 +1028,7 @@
addr = vmalloc(cnt);
if (!addr) {
qib_devinfo(dd->pcidev,
- "Couldn't get memory for checking PIO perf,"
- " skipping\n");
+ "Couldn't get memory for checking PIO perf, skipping\n");
goto done;
}
@@ -1163,6 +1164,7 @@
if (!qib_cpulist_count) {
u32 count = num_online_cpus();
+
qib_cpulist = kzalloc(BITS_TO_LONGS(count) *
sizeof(long), GFP_KERNEL);
if (qib_cpulist)
@@ -1179,7 +1181,7 @@
if (!list_empty(&dd->list))
list_del_init(&dd->list);
ib_dealloc_device(&dd->verbs_dev.ibdev);
- return ERR_PTR(ret);;
+ return ERR_PTR(ret);
}
/*
diff --git a/drivers/infiniband/hw/qib/qib_intr.c b/drivers/infiniband/hw/qib/qib_intr.c
index f4918f2..086616d 100644
--- a/drivers/infiniband/hw/qib/qib_intr.c
+++ b/drivers/infiniband/hw/qib/qib_intr.c
@@ -168,7 +168,6 @@
ppd->lastibcstat = ibcs;
if (ev)
signal_ib_event(ppd, ev);
- return;
}
void qib_clear_symerror_on_linkup(unsigned long opaque)
diff --git a/drivers/infiniband/hw/qib/qib_keys.c b/drivers/infiniband/hw/qib/qib_keys.c
index 3b9afcc..ad843c7 100644
--- a/drivers/infiniband/hw/qib/qib_keys.c
+++ b/drivers/infiniband/hw/qib/qib_keys.c
@@ -122,10 +122,10 @@
if (!mr->lkey_published)
goto out;
if (lkey == 0)
- rcu_assign_pointer(dev->dma_mr, NULL);
+ RCU_INIT_POINTER(dev->dma_mr, NULL);
else {
r = lkey >> (32 - ib_qib_lkey_table_size);
- rcu_assign_pointer(rkt->table[r], NULL);
+ RCU_INIT_POINTER(rkt->table[r], NULL);
}
qib_put_mr(mr);
mr->lkey_published = 0;
diff --git a/drivers/infiniband/hw/qib/qib_mad.c b/drivers/infiniband/hw/qib/qib_mad.c
index 636be11..395f404 100644
--- a/drivers/infiniband/hw/qib/qib_mad.c
+++ b/drivers/infiniband/hw/qib/qib_mad.c
@@ -152,14 +152,14 @@
data.trap_num = trap_num;
data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid);
data.toggle_count = 0;
- memset(&data.details, 0, sizeof data.details);
+ memset(&data.details, 0, sizeof(data.details));
data.details.ntc_257_258.lid1 = lid1;
data.details.ntc_257_258.lid2 = lid2;
data.details.ntc_257_258.key = cpu_to_be32(key);
data.details.ntc_257_258.sl_qp1 = cpu_to_be32((sl << 28) | qp1);
data.details.ntc_257_258.qp2 = cpu_to_be32(qp2);
- qib_send_trap(ibp, &data, sizeof data);
+ qib_send_trap(ibp, &data, sizeof(data));
}
/*
@@ -176,7 +176,7 @@
data.trap_num = IB_NOTICE_TRAP_BAD_MKEY;
data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid);
data.toggle_count = 0;
- memset(&data.details, 0, sizeof data.details);
+ memset(&data.details, 0, sizeof(data.details));
data.details.ntc_256.lid = data.issuer_lid;
data.details.ntc_256.method = smp->method;
data.details.ntc_256.attr_id = smp->attr_id;
@@ -198,7 +198,7 @@
hop_cnt);
}
- qib_send_trap(ibp, &data, sizeof data);
+ qib_send_trap(ibp, &data, sizeof(data));
}
/*
@@ -214,11 +214,11 @@
data.trap_num = IB_NOTICE_TRAP_CAP_MASK_CHG;
data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid);
data.toggle_count = 0;
- memset(&data.details, 0, sizeof data.details);
+ memset(&data.details, 0, sizeof(data.details));
data.details.ntc_144.lid = data.issuer_lid;
data.details.ntc_144.new_cap_mask = cpu_to_be32(ibp->port_cap_flags);
- qib_send_trap(ibp, &data, sizeof data);
+ qib_send_trap(ibp, &data, sizeof(data));
}
/*
@@ -234,11 +234,11 @@
data.trap_num = IB_NOTICE_TRAP_SYS_GUID_CHG;
data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid);
data.toggle_count = 0;
- memset(&data.details, 0, sizeof data.details);
+ memset(&data.details, 0, sizeof(data.details));
data.details.ntc_145.lid = data.issuer_lid;
data.details.ntc_145.new_sys_guid = ib_qib_sys_image_guid;
- qib_send_trap(ibp, &data, sizeof data);
+ qib_send_trap(ibp, &data, sizeof(data));
}
/*
@@ -254,12 +254,12 @@
data.trap_num = IB_NOTICE_TRAP_CAP_MASK_CHG;
data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid);
data.toggle_count = 0;
- memset(&data.details, 0, sizeof data.details);
+ memset(&data.details, 0, sizeof(data.details));
data.details.ntc_144.lid = data.issuer_lid;
data.details.ntc_144.local_changes = 1;
data.details.ntc_144.change_flags = IB_NOTICE_TRAP_NODE_DESC_CHG;
- qib_send_trap(ibp, &data, sizeof data);
+ qib_send_trap(ibp, &data, sizeof(data));
}
static int subn_get_nodedescription(struct ib_smp *smp,
diff --git a/drivers/infiniband/hw/qib/qib_mmap.c b/drivers/infiniband/hw/qib/qib_mmap.c
index 8b73a11..146cf29 100644
--- a/drivers/infiniband/hw/qib/qib_mmap.c
+++ b/drivers/infiniband/hw/qib/qib_mmap.c
@@ -134,7 +134,7 @@
void *obj) {
struct qib_mmap_info *ip;
- ip = kmalloc(sizeof *ip, GFP_KERNEL);
+ ip = kmalloc(sizeof(*ip), GFP_KERNEL);
if (!ip)
goto bail;
diff --git a/drivers/infiniband/hw/qib/qib_mr.c b/drivers/infiniband/hw/qib/qib_mr.c
index a77fb4f..c4473db 100644
--- a/drivers/infiniband/hw/qib/qib_mr.c
+++ b/drivers/infiniband/hw/qib/qib_mr.c
@@ -55,7 +55,7 @@
m = (count + QIB_SEGSZ - 1) / QIB_SEGSZ;
for (; i < m; i++) {
- mr->map[i] = kzalloc(sizeof *mr->map[0], GFP_KERNEL);
+ mr->map[i] = kzalloc(sizeof(*mr->map[0]), GFP_KERNEL);
if (!mr->map[i])
goto bail;
}
@@ -104,7 +104,7 @@
goto bail;
}
- mr = kzalloc(sizeof *mr, GFP_KERNEL);
+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);
if (!mr) {
ret = ERR_PTR(-ENOMEM);
goto bail;
@@ -143,7 +143,7 @@
/* Allocate struct plus pointers to first level page tables. */
m = (count + QIB_SEGSZ - 1) / QIB_SEGSZ;
- mr = kzalloc(sizeof *mr + m * sizeof mr->mr.map[0], GFP_KERNEL);
+ mr = kzalloc(sizeof(*mr) + m * sizeof(mr->mr.map[0]), GFP_KERNEL);
if (!mr)
goto bail;
@@ -347,7 +347,7 @@
if (size > PAGE_SIZE)
return ERR_PTR(-EINVAL);
- pl = kzalloc(sizeof *pl, GFP_KERNEL);
+ pl = kzalloc(sizeof(*pl), GFP_KERNEL);
if (!pl)
return ERR_PTR(-ENOMEM);
@@ -386,7 +386,7 @@
/* Allocate struct plus pointers to first level page tables. */
m = (fmr_attr->max_pages + QIB_SEGSZ - 1) / QIB_SEGSZ;
- fmr = kzalloc(sizeof *fmr + m * sizeof fmr->mr.map[0], GFP_KERNEL);
+ fmr = kzalloc(sizeof(*fmr) + m * sizeof(fmr->mr.map[0]), GFP_KERNEL);
if (!fmr)
goto bail;
diff --git a/drivers/infiniband/hw/qib/qib_pcie.c b/drivers/infiniband/hw/qib/qib_pcie.c
index 61a0046..4758a38 100644
--- a/drivers/infiniband/hw/qib/qib_pcie.c
+++ b/drivers/infiniband/hw/qib/qib_pcie.c
@@ -210,7 +210,7 @@
/* We can't pass qib_msix_entry array to qib_msix_setup
* so use a dummy msix_entry array and copy the allocated
* irq back to the qib_msix_entry array. */
- msix_entry = kmalloc(nvec * sizeof(*msix_entry), GFP_KERNEL);
+ msix_entry = kcalloc(nvec, sizeof(*msix_entry), GFP_KERNEL);
if (!msix_entry)
goto do_intx;
@@ -234,8 +234,10 @@
kfree(msix_entry);
do_intx:
- qib_dev_err(dd, "pci_enable_msix_range %d vectors failed: %d, "
- "falling back to INTx\n", nvec, ret);
+ qib_dev_err(
+ dd,
+ "pci_enable_msix_range %d vectors failed: %d, falling back to INTx\n",
+ nvec, ret);
*msixcnt = 0;
qib_enable_intx(dd->pcidev);
}
@@ -459,6 +461,7 @@
void qib_pcie_reenable(struct qib_devdata *dd, u16 cmd, u8 iline, u8 cline)
{
int r;
+
r = pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_0,
dd->pcibar0);
if (r)
@@ -696,6 +699,7 @@
qib_pci_resume(struct pci_dev *pdev)
{
struct qib_devdata *dd = pci_get_drvdata(pdev);
+
qib_devinfo(pdev, "QIB resume function called\n");
pci_cleanup_aer_uncorrect_error_status(pdev);
/*
diff --git a/drivers/infiniband/hw/qib/qib_qp.c b/drivers/infiniband/hw/qib/qib_qp.c
index 6ddc026..4fa88ba 100644
--- a/drivers/infiniband/hw/qib/qib_qp.c
+++ b/drivers/infiniband/hw/qib/qib_qp.c
@@ -255,10 +255,10 @@
if (rcu_dereference_protected(ibp->qp0,
lockdep_is_held(&dev->qpt_lock)) == qp) {
- rcu_assign_pointer(ibp->qp0, NULL);
+ RCU_INIT_POINTER(ibp->qp0, NULL);
} else if (rcu_dereference_protected(ibp->qp1,
lockdep_is_held(&dev->qpt_lock)) == qp) {
- rcu_assign_pointer(ibp->qp1, NULL);
+ RCU_INIT_POINTER(ibp->qp1, NULL);
} else {
struct qib_qp *q;
struct qib_qp __rcu **qpp;
@@ -269,7 +269,7 @@
lockdep_is_held(&dev->qpt_lock))) != NULL;
qpp = &q->next)
if (q == qp) {
- rcu_assign_pointer(*qpp,
+ RCU_INIT_POINTER(*qpp,
rcu_dereference_protected(qp->next,
lockdep_is_held(&dev->qpt_lock)));
removed = 1;
@@ -315,7 +315,7 @@
for (n = 0; n < dev->qp_table_size; n++) {
qp = rcu_dereference_protected(dev->qp_table[n],
lockdep_is_held(&dev->qpt_lock));
- rcu_assign_pointer(dev->qp_table[n], NULL);
+ RCU_INIT_POINTER(dev->qp_table[n], NULL);
for (; qp; qp = rcu_dereference_protected(qp->next,
lockdep_is_held(&dev->qpt_lock)))
diff --git a/drivers/infiniband/hw/qib/qib_qsfp.c b/drivers/infiniband/hw/qib/qib_qsfp.c
index fa71b1e..5e27f76 100644
--- a/drivers/infiniband/hw/qib/qib_qsfp.c
+++ b/drivers/infiniband/hw/qib/qib_qsfp.c
@@ -81,7 +81,7 @@
* Module could take up to 2 Msec to respond to MOD_SEL, and there
* is no way to tell if it is ready, so we must wait.
*/
- msleep(2);
+ msleep(20);
/* Make sure TWSI bus is in sane state. */
ret = qib_twsi_reset(dd);
@@ -99,6 +99,7 @@
while (cnt < len) {
unsigned in_page;
int wlen = len - cnt;
+
in_page = addr % QSFP_PAGESIZE;
if ((in_page + wlen) > QSFP_PAGESIZE)
wlen = QSFP_PAGESIZE - in_page;
@@ -139,7 +140,7 @@
else if (pass)
qib_dev_porterr(dd, ppd->port, "QSFP retries: %d\n", pass);
- msleep(2);
+ msleep(20);
bail:
mutex_unlock(&dd->eep_lock);
@@ -189,7 +190,7 @@
* Module could take up to 2 Msec to respond to MOD_SEL,
* and there is no way to tell if it is ready, so we must wait.
*/
- msleep(2);
+ msleep(20);
/* Make sure TWSI bus is in sane state. */
ret = qib_twsi_reset(dd);
@@ -206,6 +207,7 @@
while (cnt < len) {
unsigned in_page;
int wlen = len - cnt;
+
in_page = addr % QSFP_PAGESIZE;
if ((in_page + wlen) > QSFP_PAGESIZE)
wlen = QSFP_PAGESIZE - in_page;
@@ -234,7 +236,7 @@
* going away, and there is no way to tell if it is ready.
* so we must wait.
*/
- msleep(2);
+ msleep(20);
bail:
mutex_unlock(&dd->eep_lock);
@@ -296,6 +298,7 @@
* set the page to zero, Even if it already appears to be zero.
*/
u8 poke = 0;
+
ret = qib_qsfp_write(ppd, 127, &poke, 1);
udelay(50);
if (ret != 1) {
@@ -480,7 +483,6 @@
udelay(20); /* Generous RST dwell */
dd->f_gpio_mod(dd, mask, mask, mask);
- return;
}
void qib_qsfp_deinit(struct qib_qsfp_data *qd)
@@ -540,6 +542,7 @@
while (bidx < QSFP_DEFAULT_HDR_CNT) {
int iidx;
+
ret = qsfp_read(ppd, bidx, bin_buff, QSFP_DUMP_CHUNK);
if (ret < 0)
goto bail;
diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c
index 2f25018..4544d6f 100644
--- a/drivers/infiniband/hw/qib/qib_rc.c
+++ b/drivers/infiniband/hw/qib/qib_rc.c
@@ -1017,7 +1017,7 @@
/* Post a send completion queue entry if requested. */
if (!(qp->s_flags & QIB_S_SIGNAL_REQ_WR) ||
(wqe->wr.send_flags & IB_SEND_SIGNALED)) {
- memset(&wc, 0, sizeof wc);
+ memset(&wc, 0, sizeof(wc));
wc.wr_id = wqe->wr.wr_id;
wc.status = IB_WC_SUCCESS;
wc.opcode = ib_qib_wc_opcode[wqe->wr.opcode];
@@ -1073,7 +1073,7 @@
/* Post a send completion queue entry if requested. */
if (!(qp->s_flags & QIB_S_SIGNAL_REQ_WR) ||
(wqe->wr.send_flags & IB_SEND_SIGNALED)) {
- memset(&wc, 0, sizeof wc);
+ memset(&wc, 0, sizeof(wc));
wc.wr_id = wqe->wr.wr_id;
wc.status = IB_WC_SUCCESS;
wc.opcode = ib_qib_wc_opcode[wqe->wr.opcode];
diff --git a/drivers/infiniband/hw/qib/qib_ruc.c b/drivers/infiniband/hw/qib/qib_ruc.c
index 4c07a8b..f42bd0f 100644
--- a/drivers/infiniband/hw/qib/qib_ruc.c
+++ b/drivers/infiniband/hw/qib/qib_ruc.c
@@ -247,8 +247,8 @@
struct qib_pportdata *ppd = ppd_from_ibp(ibp);
return ppd->guid;
- } else
- return ibp->guids[index - 1];
+ }
+ return ibp->guids[index - 1];
}
static int gid_ok(union ib_gid *gid, __be64 gid_prefix, __be64 id)
@@ -420,7 +420,7 @@
goto serr;
}
- memset(&wc, 0, sizeof wc);
+ memset(&wc, 0, sizeof(wc));
send_status = IB_WC_SUCCESS;
release = 1;
@@ -792,7 +792,7 @@
status != IB_WC_SUCCESS) {
struct ib_wc wc;
- memset(&wc, 0, sizeof wc);
+ memset(&wc, 0, sizeof(wc));
wc.wr_id = wqe->wr.wr_id;
wc.status = status;
wc.opcode = ib_qib_wc_opcode[wqe->wr.opcode];
diff --git a/drivers/infiniband/hw/qib/qib_sd7220.c b/drivers/infiniband/hw/qib/qib_sd7220.c
index 911205d..c72775f 100644
--- a/drivers/infiniband/hw/qib/qib_sd7220.c
+++ b/drivers/infiniband/hw/qib/qib_sd7220.c
@@ -259,6 +259,7 @@
* it again during startup.
*/
u64 val;
+
rst_val &= ~(1ULL);
qib_write_kreg(dd, kr_hwerrmask,
dd->cspec->hwerrmask &
@@ -590,6 +591,7 @@
* Both should be clear
*/
u64 newval = 0;
+
qib_write_kreg(dd, acc, newval);
/* First read after write is not trustworthy */
pollval = qib_read_kreg32(dd, acc);
@@ -601,6 +603,7 @@
/* Need to claim */
u64 pollval;
u64 newval = EPB_ACC_REQ | oct_sel;
+
qib_write_kreg(dd, acc, newval);
/* First read after write is not trustworthy */
pollval = qib_read_kreg32(dd, acc);
@@ -812,6 +815,7 @@
if (!sofar) {
/* Only set address at start of chunk */
int addrbyte = (addr + sofar) >> 8;
+
transval = csbit | EPB_MADDRH | addrbyte;
tries = epb_trans(dd, trans, transval,
&transval);
@@ -922,7 +926,7 @@
* IRQ not set up at this point in init, so we poll.
*/
#define IB_SERDES_TRIM_DONE (1ULL << 11)
-#define TRIM_TMO (30)
+#define TRIM_TMO (15)
static int qib_sd_trimdone_poll(struct qib_devdata *dd)
{
@@ -940,7 +944,7 @@
ret = 1;
break;
}
- msleep(10);
+ msleep(20);
}
if (trim_tmo >= TRIM_TMO) {
qib_dev_err(dd, "No TRIMDONE in %d tries\n", trim_tmo);
@@ -1071,6 +1075,7 @@
dds_reg_map >>= 4;
for (midx = 0; midx < DDS_ROWS; ++midx) {
u64 __iomem *daddr = taddr + ((midx << 4) + idx);
+
data = dds_init_vals[midx].reg_vals[idx];
writeq(data, daddr);
mmiowb();
diff --git a/drivers/infiniband/hw/qib/qib_sysfs.c b/drivers/infiniband/hw/qib/qib_sysfs.c
index 3c8e4e3..81f56cd 100644
--- a/drivers/infiniband/hw/qib/qib_sysfs.c
+++ b/drivers/infiniband/hw/qib/qib_sysfs.c
@@ -586,8 +586,8 @@
container_of(device, struct qib_ibdev, ibdev.dev);
struct qib_devdata *dd = dd_from_dev(dev);
- buf[sizeof dd->serial] = '\0';
- memcpy(buf, dd->serial, sizeof dd->serial);
+ buf[sizeof(dd->serial)] = '\0';
+ memcpy(buf, dd->serial, sizeof(dd->serial));
strcat(buf, "\n");
return strlen(buf);
}
@@ -611,28 +611,6 @@
return ret < 0 ? ret : count;
}
-static ssize_t show_logged_errs(struct device *device,
- struct device_attribute *attr, char *buf)
-{
- struct qib_ibdev *dev =
- container_of(device, struct qib_ibdev, ibdev.dev);
- struct qib_devdata *dd = dd_from_dev(dev);
- int idx, count;
-
- /* force consistency with actual EEPROM */
- if (qib_update_eeprom_log(dd) != 0)
- return -ENXIO;
-
- count = 0;
- for (idx = 0; idx < QIB_EEP_LOG_CNT; ++idx) {
- count += scnprintf(buf + count, PAGE_SIZE - count, "%d%c",
- dd->eep_st_errs[idx],
- idx == (QIB_EEP_LOG_CNT - 1) ? '\n' : ' ');
- }
-
- return count;
-}
-
/*
* Dump tempsense regs. in decimal, to ease shell-scripts.
*/
@@ -679,7 +657,6 @@
static DEVICE_ATTR(nfreectxts, S_IRUGO, show_nfreectxts, NULL);
static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL);
static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL);
-static DEVICE_ATTR(logged_errors, S_IRUGO, show_logged_errs, NULL);
static DEVICE_ATTR(tempsense, S_IRUGO, show_tempsense, NULL);
static DEVICE_ATTR(localbus_info, S_IRUGO, show_localbus_info, NULL);
static DEVICE_ATTR(chip_reset, S_IWUSR, NULL, store_chip_reset);
@@ -693,7 +670,6 @@
&dev_attr_nfreectxts,
&dev_attr_serial,
&dev_attr_boardversion,
- &dev_attr_logged_errors,
&dev_attr_tempsense,
&dev_attr_localbus_info,
&dev_attr_chip_reset,
diff --git a/drivers/infiniband/hw/qib/qib_twsi.c b/drivers/infiniband/hw/qib/qib_twsi.c
index 647f7be..f569866 100644
--- a/drivers/infiniband/hw/qib/qib_twsi.c
+++ b/drivers/infiniband/hw/qib/qib_twsi.c
@@ -105,6 +105,7 @@
udelay(2);
else {
int rise_usec;
+
for (rise_usec = SCL_WAIT_USEC; rise_usec > 0; rise_usec -= 2) {
if (mask & dd->f_gpio_mod(dd, 0, 0, 0))
break;
@@ -326,6 +327,7 @@
static int qib_twsi_wr(struct qib_devdata *dd, int data, int flags)
{
int ret = 1;
+
if (flags & QIB_TWSI_START)
start_seq(dd);
@@ -435,8 +437,7 @@
int sub_len;
const u8 *bp = buffer;
int max_wait_time, i;
- int ret;
- ret = 1;
+ int ret = 1;
while (len > 0) {
if (dev == QIB_TWSI_NO_DEV) {
diff --git a/drivers/infiniband/hw/qib/qib_tx.c b/drivers/infiniband/hw/qib/qib_tx.c
index 31d3561..eface3b 100644
--- a/drivers/infiniband/hw/qib/qib_tx.c
+++ b/drivers/infiniband/hw/qib/qib_tx.c
@@ -180,6 +180,7 @@
for (i = 0; i < cnt; i++) {
int which;
+
if (!test_bit(i, mask))
continue;
/*
diff --git a/drivers/infiniband/hw/qib/qib_ud.c b/drivers/infiniband/hw/qib/qib_ud.c
index aaf7039..26243b7 100644
--- a/drivers/infiniband/hw/qib/qib_ud.c
+++ b/drivers/infiniband/hw/qib/qib_ud.c
@@ -127,7 +127,7 @@
* present on the wire.
*/
length = swqe->length;
- memset(&wc, 0, sizeof wc);
+ memset(&wc, 0, sizeof(wc));
wc.byte_len = length + sizeof(struct ib_grh);
if (swqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
diff --git a/drivers/infiniband/hw/qib/qib_user_sdma.c b/drivers/infiniband/hw/qib/qib_user_sdma.c
index d2806ca..3e0677c 100644
--- a/drivers/infiniband/hw/qib/qib_user_sdma.c
+++ b/drivers/infiniband/hw/qib/qib_user_sdma.c
@@ -50,7 +50,7 @@
/* expected size of headers (for dma_pool) */
#define QIB_USER_SDMA_EXP_HEADER_LENGTH 64
/* attempt to drain the queue for 5secs */
-#define QIB_USER_SDMA_DRAIN_TIMEOUT 500
+#define QIB_USER_SDMA_DRAIN_TIMEOUT 250
/*
* track how many times a process open this driver.
@@ -226,6 +226,7 @@
sdma_rb_node->refcount++;
} else {
int ret;
+
sdma_rb_node = kmalloc(sizeof(
struct qib_user_sdma_rb_node), GFP_KERNEL);
if (!sdma_rb_node)
@@ -936,6 +937,7 @@
if (tiddma) {
char *tidsm = (char *)pkt + pktsize;
+
cfur = copy_from_user(tidsm,
iov[idx].iov_base, tidsmsize);
if (cfur) {
@@ -1142,7 +1144,7 @@
qib_user_sdma_hwqueue_clean(ppd);
qib_user_sdma_queue_clean(ppd, pq);
mutex_unlock(&pq->lock);
- msleep(10);
+ msleep(20);
}
if (pq->num_pending || pq->num_sending) {
@@ -1316,8 +1318,6 @@
if (nfree && !list_empty(pktlist))
goto retry;
-
- return;
}
/* pq->lock must be held, get packets on the wire... */
diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c
index 9bcfbd8..4a35998 100644
--- a/drivers/infiniband/hw/qib/qib_verbs.c
+++ b/drivers/infiniband/hw/qib/qib_verbs.c
@@ -1342,6 +1342,7 @@
done:
if (dd->flags & QIB_USE_SPCL_TRIG) {
u32 spcl_off = (pbufn >= dd->piobcnt2k) ? 2047 : 1023;
+
qib_flush_wc();
__raw_writel(0xaebecede, piobuf_orig + spcl_off);
}
@@ -1744,7 +1745,7 @@
* we allow allocations of more than we report for this value.
*/
- pd = kmalloc(sizeof *pd, GFP_KERNEL);
+ pd = kmalloc(sizeof(*pd), GFP_KERNEL);
if (!pd) {
ret = ERR_PTR(-ENOMEM);
goto bail;
@@ -1829,7 +1830,7 @@
goto bail;
}
- ah = kmalloc(sizeof *ah, GFP_ATOMIC);
+ ah = kmalloc(sizeof(*ah), GFP_ATOMIC);
if (!ah) {
ret = ERR_PTR(-ENOMEM);
goto bail;
@@ -1862,7 +1863,7 @@
struct ib_ah *ah = ERR_PTR(-EINVAL);
struct qib_qp *qp0;
- memset(&attr, 0, sizeof attr);
+ memset(&attr, 0, sizeof(attr));
attr.dlid = dlid;
attr.port_num = ppd_from_ibp(ibp)->port;
rcu_read_lock();
@@ -1977,7 +1978,7 @@
struct qib_ucontext *context;
struct ib_ucontext *ret;
- context = kmalloc(sizeof *context, GFP_KERNEL);
+ context = kmalloc(sizeof(*context), GFP_KERNEL);
if (!context) {
ret = ERR_PTR(-ENOMEM);
goto bail;
@@ -2054,7 +2055,9 @@
dev->qp_table_size = ib_qib_qp_table_size;
get_random_bytes(&dev->qp_rnd, sizeof(dev->qp_rnd));
- dev->qp_table = kmalloc(dev->qp_table_size * sizeof *dev->qp_table,
+ dev->qp_table = kmalloc_array(
+ dev->qp_table_size,
+ sizeof(*dev->qp_table),
GFP_KERNEL);
if (!dev->qp_table) {
ret = -ENOMEM;
@@ -2122,7 +2125,7 @@
for (i = 0; i < ppd->sdma_descq_cnt; i++) {
struct qib_verbs_txreq *tx;
- tx = kzalloc(sizeof *tx, GFP_KERNEL);
+ tx = kzalloc(sizeof(*tx), GFP_KERNEL);
if (!tx) {
ret = -ENOMEM;
goto err_tx;
diff --git a/drivers/infiniband/hw/qib/qib_verbs_mcast.c b/drivers/infiniband/hw/qib/qib_verbs_mcast.c
index dabb697..f8ea069 100644
--- a/drivers/infiniband/hw/qib/qib_verbs_mcast.c
+++ b/drivers/infiniband/hw/qib/qib_verbs_mcast.c
@@ -43,7 +43,7 @@
{
struct qib_mcast_qp *mqp;
- mqp = kmalloc(sizeof *mqp, GFP_KERNEL);
+ mqp = kmalloc(sizeof(*mqp), GFP_KERNEL);
if (!mqp)
goto bail;
@@ -75,7 +75,7 @@
{
struct qib_mcast *mcast;
- mcast = kmalloc(sizeof *mcast, GFP_KERNEL);
+ mcast = kmalloc(sizeof(*mcast), GFP_KERNEL);
if (!mcast)
goto bail;
diff --git a/drivers/infiniband/hw/qib/qib_wc_x86_64.c b/drivers/infiniband/hw/qib/qib_wc_x86_64.c
index 1d7281c..81b225f 100644
--- a/drivers/infiniband/hw/qib/qib_wc_x86_64.c
+++ b/drivers/infiniband/hw/qib/qib_wc_x86_64.c
@@ -72,6 +72,7 @@
if (dd->piobcnt2k && dd->piobcnt4k) {
/* 2 sizes for chip */
unsigned long pio2kbase, pio4kbase;
+
pio2kbase = dd->piobufbase & 0xffffffffUL;
pio4kbase = (dd->piobufbase >> 32) & 0xffffffffUL;
if (pio2kbase < pio4kbase) {
@@ -91,7 +92,7 @@
}
for (bits = 0; !(piolen & (1ULL << bits)); bits++)
- /* do nothing */ ;
+ ; /* do nothing */
if (piolen != (1ULL << bits)) {
piolen >>= bits;
@@ -100,8 +101,8 @@
piolen = 1ULL << (bits + 1);
}
if (pioaddr & (piolen - 1)) {
- u64 atmp;
- atmp = pioaddr & ~(piolen - 1);
+ u64 atmp = pioaddr & ~(piolen - 1);
+
if (atmp < addr || (atmp + piolen) > (addr + len)) {
qib_dev_err(dd,
"No way to align address/size (%llx/%llx), no WC mtrr\n",
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index 5ce2681..b47aea1 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -654,7 +654,9 @@
enum dma_data_direction dma_dir);
void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task,
- struct iser_data_buf *data);
+ struct iser_data_buf *data,
+ enum dma_data_direction dir);
+
int iser_initialize_task_headers(struct iscsi_task *task,
struct iser_tx_desc *tx_desc);
int iser_alloc_rx_descriptors(struct iser_conn *iser_conn,
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 3821633..20e859a 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -320,9 +320,6 @@
struct ib_conn *ib_conn = &iser_conn->ib_conn;
struct iser_device *device = ib_conn->device;
- if (!iser_conn->rx_descs)
- goto free_login_buf;
-
if (device->iser_free_rdma_reg_res)
device->iser_free_rdma_reg_res(ib_conn);
@@ -334,7 +331,6 @@
/* make sure we never redo any unmapping */
iser_conn->rx_descs = NULL;
-free_login_buf:
iser_free_login_buf(iser_conn);
}
@@ -714,19 +710,23 @@
device->iser_unreg_rdma_mem(iser_task, ISER_DIR_IN);
if (is_rdma_data_aligned)
iser_dma_unmap_task_data(iser_task,
- &iser_task->data[ISER_DIR_IN]);
+ &iser_task->data[ISER_DIR_IN],
+ DMA_FROM_DEVICE);
if (prot_count && is_rdma_prot_aligned)
iser_dma_unmap_task_data(iser_task,
- &iser_task->prot[ISER_DIR_IN]);
+ &iser_task->prot[ISER_DIR_IN],
+ DMA_FROM_DEVICE);
}
if (iser_task->dir[ISER_DIR_OUT]) {
device->iser_unreg_rdma_mem(iser_task, ISER_DIR_OUT);
if (is_rdma_data_aligned)
iser_dma_unmap_task_data(iser_task,
- &iser_task->data[ISER_DIR_OUT]);
+ &iser_task->data[ISER_DIR_OUT],
+ DMA_TO_DEVICE);
if (prot_count && is_rdma_prot_aligned)
iser_dma_unmap_task_data(iser_task,
- &iser_task->prot[ISER_DIR_OUT]);
+ &iser_task->prot[ISER_DIR_OUT],
+ DMA_TO_DEVICE);
}
}
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c
index abce933..341040b 100644
--- a/drivers/infiniband/ulp/iser/iser_memory.c
+++ b/drivers/infiniband/ulp/iser/iser_memory.c
@@ -332,12 +332,13 @@
}
void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task,
- struct iser_data_buf *data)
+ struct iser_data_buf *data,
+ enum dma_data_direction dir)
{
struct ib_device *dev;
dev = iser_task->iser_conn->ib_conn.device->ib_device;
- ib_dma_unmap_sg(dev, data->buf, data->size, DMA_FROM_DEVICE);
+ ib_dma_unmap_sg(dev, data->buf, data->size, dir);
}
static int fall_to_bounce_buf(struct iscsi_iser_task *iser_task,
@@ -357,7 +358,9 @@
iser_data_buf_dump(mem, ibdev);
/* unmap the command data before accessing it */
- iser_dma_unmap_task_data(iser_task, mem);
+ iser_dma_unmap_task_data(iser_task, mem,
+ (cmd_dir == ISER_DIR_OUT) ?
+ DMA_TO_DEVICE : DMA_FROM_DEVICE);
/* allocate copy buf, if we are writing, copy the */
/* unaligned scatterlist, dma map the copy */
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index 695a270..4065abe 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -600,16 +600,16 @@
/**
* iser_free_ib_conn_res - release IB related resources
* @iser_conn: iser connection struct
- * @destroy_device: indicator if we need to try to release
- * the iser device (only iscsi shutdown and DEVICE_REMOVAL
- * will use this.
+ * @destroy: indicator if we need to try to release the
+ * iser device and memory regoins pool (only iscsi
+ * shutdown and DEVICE_REMOVAL will use this).
*
* This routine is called with the iser state mutex held
* so the cm_id removal is out of here. It is Safe to
* be invoked multiple times.
*/
static void iser_free_ib_conn_res(struct iser_conn *iser_conn,
- bool destroy_device)
+ bool destroy)
{
struct ib_conn *ib_conn = &iser_conn->ib_conn;
struct iser_device *device = ib_conn->device;
@@ -617,17 +617,20 @@
iser_info("freeing conn %p cma_id %p qp %p\n",
iser_conn, ib_conn->cma_id, ib_conn->qp);
- iser_free_rx_descriptors(iser_conn);
-
if (ib_conn->qp != NULL) {
ib_conn->comp->active_qps--;
rdma_destroy_qp(ib_conn->cma_id);
ib_conn->qp = NULL;
}
- if (destroy_device && device != NULL) {
- iser_device_try_release(device);
- ib_conn->device = NULL;
+ if (destroy) {
+ if (iser_conn->rx_descs)
+ iser_free_rx_descriptors(iser_conn);
+
+ if (device != NULL) {
+ iser_device_try_release(device);
+ ib_conn->device = NULL;
+ }
}
}
@@ -643,9 +646,11 @@
mutex_unlock(&ig.connlist_mutex);
mutex_lock(&iser_conn->state_mutex);
+ /* In case we endup here without ep_disconnect being invoked. */
if (iser_conn->state != ISER_CONN_DOWN) {
iser_warn("iser conn %p state %d, expected state down.\n",
iser_conn, iser_conn->state);
+ iscsi_destroy_endpoint(iser_conn->ep);
iser_conn->state = ISER_CONN_DOWN;
}
/*
@@ -840,7 +845,7 @@
}
static void iser_cleanup_handler(struct rdma_cm_id *cma_id,
- bool destroy_device)
+ bool destroy)
{
struct iser_conn *iser_conn = (struct iser_conn *)cma_id->context;
@@ -850,7 +855,7 @@
* and flush errors.
*/
iser_disconnected_handler(cma_id);
- iser_free_ib_conn_res(iser_conn, destroy_device);
+ iser_free_ib_conn_res(iser_conn, destroy);
complete(&iser_conn->ib_completion);
};
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index dafb3c5..075b19c 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -38,7 +38,7 @@
#define ISER_MAX_CQ_LEN (ISER_MAX_RX_CQ_LEN + ISER_MAX_TX_CQ_LEN + \
ISERT_MAX_CONN)
-int isert_debug_level = 0;
+static int isert_debug_level;
module_param_named(debug_level, isert_debug_level, int, 0644);
MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0 (default:0)");
@@ -949,7 +949,7 @@
isert_err("ib_post_recv() failed with ret: %d\n", ret);
isert_conn->post_recv_buf_count -= count;
} else {
- isert_dbg("isert_post_recv(): Posted %d RX buffers\n", count);
+ isert_dbg("Posted %d RX buffers\n", count);
isert_conn->conn_rx_desc_head = rx_head;
}
return ret;
@@ -1351,17 +1351,19 @@
struct iscsi_conn *conn = isert_conn->conn;
u32 payload_length = ntoh24(hdr->dlength);
int rc;
- unsigned char *text_in;
+ unsigned char *text_in = NULL;
rc = iscsit_setup_text_cmd(conn, cmd, hdr);
if (rc < 0)
return rc;
- text_in = kzalloc(payload_length, GFP_KERNEL);
- if (!text_in) {
- isert_err("Unable to allocate text_in of payload_length: %u\n",
- payload_length);
- return -ENOMEM;
+ if (payload_length) {
+ text_in = kzalloc(payload_length, GFP_KERNEL);
+ if (!text_in) {
+ isert_err("Unable to allocate text_in of payload_length: %u\n",
+ payload_length);
+ return -ENOMEM;
+ }
}
cmd->text_in_ptr = text_in;
@@ -1434,9 +1436,15 @@
ret = iscsit_handle_logout_cmd(conn, cmd, (unsigned char *)hdr);
break;
case ISCSI_OP_TEXT:
- cmd = isert_allocate_cmd(conn);
- if (!cmd)
- break;
+ if (be32_to_cpu(hdr->ttt) != 0xFFFFFFFF) {
+ cmd = iscsit_find_cmd_from_itt(conn, hdr->itt);
+ if (!cmd)
+ break;
+ } else {
+ cmd = isert_allocate_cmd(conn);
+ if (!cmd)
+ break;
+ }
isert_cmd = iscsit_priv_cmd(cmd);
ret = isert_handle_text_cmd(isert_conn, isert_cmd, cmd,
@@ -1658,6 +1666,7 @@
struct isert_conn *isert_conn = isert_cmd->conn;
struct iscsi_conn *conn = isert_conn->conn;
struct isert_device *device = isert_conn->conn_device;
+ struct iscsi_text_rsp *hdr;
isert_dbg("Cmd %p\n", isert_cmd);
@@ -1698,6 +1707,11 @@
case ISCSI_OP_REJECT:
case ISCSI_OP_NOOP_OUT:
case ISCSI_OP_TEXT:
+ hdr = (struct iscsi_text_rsp *)&isert_cmd->tx_desc.iscsi_header;
+ /* If the continue bit is on, keep the command alive */
+ if (hdr->flags & ISCSI_FLAG_TEXT_CONTINUE)
+ break;
+
spin_lock_bh(&conn->cmd_lock);
if (!list_empty(&cmd->i_conn_node))
list_del_init(&cmd->i_conn_node);
@@ -1709,8 +1723,7 @@
* associated cmd->se_cmd needs to be released.
*/
if (cmd->se_cmd.se_tfo != NULL) {
- isert_dbg("Calling transport_generic_free_cmd from"
- " isert_put_cmd for 0x%02x\n",
+ isert_dbg("Calling transport_generic_free_cmd for 0x%02x\n",
cmd->iscsi_opcode);
transport_generic_free_cmd(&cmd->se_cmd, 0);
break;
@@ -2275,7 +2288,7 @@
}
isert_init_send_wr(isert_conn, isert_cmd, send_wr);
- isert_dbg("conn %p Text Reject\n", isert_conn);
+ isert_dbg("conn %p Text Response\n", isert_conn);
return isert_post_response(isert_conn, isert_cmd);
}
@@ -3136,7 +3149,7 @@
spin_lock_bh(&np->np_thread_lock);
if (np->np_thread_state >= ISCSI_NP_THREAD_RESET) {
spin_unlock_bh(&np->np_thread_lock);
- isert_dbg("np_thread_state %d for isert_accept_np\n",
+ isert_dbg("np_thread_state %d\n",
np->np_thread_state);
/**
* No point in stalling here when np_thread
@@ -3320,7 +3333,8 @@
{
int ret;
- isert_comp_wq = alloc_workqueue("isert_comp_wq", 0, 0);
+ isert_comp_wq = alloc_workqueue("isert_comp_wq",
+ WQ_UNBOUND | WQ_HIGHPRI, 0);
if (!isert_comp_wq) {
isert_err("Unable to allocate isert_comp_wq\n");
ret = -ENOMEM;
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index eb694dd..6e0a477 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -3518,7 +3518,7 @@
DECLARE_COMPLETION_ONSTACK(release_done);
struct srpt_rdma_ch *ch;
struct srpt_device *sdev;
- int res;
+ unsigned long res;
ch = se_sess->fabric_sess_ptr;
WARN_ON(ch->sess != se_sess);
@@ -3533,7 +3533,7 @@
spin_unlock_irq(&sdev->spinlock);
res = wait_for_completion_timeout(&release_done, 60 * HZ);
- WARN_ON(res <= 0);
+ WARN_ON(res == 0);
}
/**
diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
index b784257..d09cefa 100644
--- a/drivers/input/joystick/adi.c
+++ b/drivers/input/joystick/adi.c
@@ -535,8 +535,7 @@
}
}
fail2: for (i = 0; i < 2; i++)
- if (port->adi[i].dev)
- input_free_device(port->adi[i].dev);
+ input_free_device(port->adi[i].dev);
gameport_close(gameport);
fail1: gameport_set_drvdata(gameport, NULL);
kfree(port);
diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c
index a89488a..fcef5d1 100644
--- a/drivers/input/keyboard/pxa27x_keypad.c
+++ b/drivers/input/keyboard/pxa27x_keypad.c
@@ -345,13 +345,11 @@
{
const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
struct input_dev *input_dev = keypad->input_dev;
- const struct matrix_keymap_data *keymap_data =
- pdata ? pdata->matrix_keymap_data : NULL;
unsigned short keycode;
int i;
int error;
- error = matrix_keypad_build_keymap(keymap_data, NULL,
+ error = matrix_keypad_build_keymap(pdata->matrix_keymap_data, NULL,
pdata->matrix_key_rows,
pdata->matrix_key_cols,
keypad->keycodes, input_dev);
diff --git a/drivers/input/misc/bfin_rotary.c b/drivers/input/misc/bfin_rotary.c
index 3f43515..a0fc18f 100644
--- a/drivers/input/misc/bfin_rotary.c
+++ b/drivers/input/misc/bfin_rotary.c
@@ -7,29 +7,37 @@
#include <linux/module.h>
#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/irq.h>
#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/slab.h>
+#include <linux/platform_data/bfin_rotary.h>
#include <asm/portmux.h>
-#include <asm/bfin_rotary.h>
-static const u16 per_cnt[] = {
- P_CNT_CUD,
- P_CNT_CDG,
- P_CNT_CZM,
- 0
-};
+#define CNT_CONFIG_OFF 0 /* CNT Config Offset */
+#define CNT_IMASK_OFF 4 /* CNT Interrupt Mask Offset */
+#define CNT_STATUS_OFF 8 /* CNT Status Offset */
+#define CNT_COMMAND_OFF 12 /* CNT Command Offset */
+#define CNT_DEBOUNCE_OFF 16 /* CNT Debounce Offset */
+#define CNT_COUNTER_OFF 20 /* CNT Counter Offset */
+#define CNT_MAX_OFF 24 /* CNT Maximum Count Offset */
+#define CNT_MIN_OFF 28 /* CNT Minimum Count Offset */
struct bfin_rot {
struct input_dev *input;
+ void __iomem *base;
int irq;
unsigned int up_key;
unsigned int down_key;
unsigned int button_key;
unsigned int rel_code;
+
+ unsigned short mode;
+ unsigned short debounce;
+
unsigned short cnt_config;
unsigned short cnt_imask;
unsigned short cnt_debounce;
@@ -59,18 +67,17 @@
static irqreturn_t bfin_rotary_isr(int irq, void *dev_id)
{
- struct platform_device *pdev = dev_id;
- struct bfin_rot *rotary = platform_get_drvdata(pdev);
+ struct bfin_rot *rotary = dev_id;
int delta;
- switch (bfin_read_CNT_STATUS()) {
+ switch (readw(rotary->base + CNT_STATUS_OFF)) {
case ICII:
break;
case UCII:
case DCII:
- delta = bfin_read_CNT_COUNTER();
+ delta = readl(rotary->base + CNT_COUNTER_OFF);
if (delta)
report_rotary_event(rotary, delta);
break;
@@ -83,16 +90,52 @@
break;
}
- bfin_write_CNT_COMMAND(W1LCNT_ZERO); /* Clear COUNTER */
- bfin_write_CNT_STATUS(-1); /* Clear STATUS */
+ writew(W1LCNT_ZERO, rotary->base + CNT_COMMAND_OFF); /* Clear COUNTER */
+ writew(-1, rotary->base + CNT_STATUS_OFF); /* Clear STATUS */
return IRQ_HANDLED;
}
+static int bfin_rotary_open(struct input_dev *input)
+{
+ struct bfin_rot *rotary = input_get_drvdata(input);
+ unsigned short val;
+
+ if (rotary->mode & ROT_DEBE)
+ writew(rotary->debounce & DPRESCALE,
+ rotary->base + CNT_DEBOUNCE_OFF);
+
+ writew(rotary->mode & ~CNTE, rotary->base + CNT_CONFIG_OFF);
+
+ val = UCIE | DCIE;
+ if (rotary->button_key)
+ val |= CZMIE;
+ writew(val, rotary->base + CNT_IMASK_OFF);
+
+ writew(rotary->mode | CNTE, rotary->base + CNT_CONFIG_OFF);
+
+ return 0;
+}
+
+static void bfin_rotary_close(struct input_dev *input)
+{
+ struct bfin_rot *rotary = input_get_drvdata(input);
+
+ writew(0, rotary->base + CNT_CONFIG_OFF);
+ writew(0, rotary->base + CNT_IMASK_OFF);
+}
+
+static void bfin_rotary_free_action(void *data)
+{
+ peripheral_free_list(data);
+}
+
static int bfin_rotary_probe(struct platform_device *pdev)
{
- struct bfin_rotary_platform_data *pdata = dev_get_platdata(&pdev->dev);
+ struct device *dev = &pdev->dev;
+ const struct bfin_rotary_platform_data *pdata = dev_get_platdata(dev);
struct bfin_rot *rotary;
+ struct resource *res;
struct input_dev *input;
int error;
@@ -102,18 +145,37 @@
return -EINVAL;
}
- error = peripheral_request_list(per_cnt, dev_name(&pdev->dev));
- if (error) {
- dev_err(&pdev->dev, "requesting peripherals failed\n");
- return error;
+ if (pdata->pin_list) {
+ error = peripheral_request_list(pdata->pin_list,
+ dev_name(&pdev->dev));
+ if (error) {
+ dev_err(dev, "requesting peripherals failed: %d\n",
+ error);
+ return error;
+ }
+
+ error = devm_add_action(dev, bfin_rotary_free_action,
+ pdata->pin_list);
+ if (error) {
+ dev_err(dev, "setting cleanup action failed: %d\n",
+ error);
+ peripheral_free_list(pdata->pin_list);
+ return error;
+ }
}
- rotary = kzalloc(sizeof(struct bfin_rot), GFP_KERNEL);
- input = input_allocate_device();
- if (!rotary || !input) {
- error = -ENOMEM;
- goto out1;
- }
+ rotary = devm_kzalloc(dev, sizeof(struct bfin_rot), GFP_KERNEL);
+ if (!rotary)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ rotary->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(rotary->base))
+ return PTR_ERR(rotary->base);
+
+ input = devm_input_allocate_device(dev);
+ if (!input)
+ return -ENOMEM;
rotary->input = input;
@@ -122,9 +184,8 @@
rotary->button_key = pdata->rotary_button_key;
rotary->rel_code = pdata->rotary_rel_code;
- error = rotary->irq = platform_get_irq(pdev, 0);
- if (error < 0)
- goto out1;
+ rotary->mode = pdata->mode;
+ rotary->debounce = pdata->debounce;
input->name = pdev->name;
input->phys = "bfin-rotary/input0";
@@ -137,6 +198,9 @@
input->id.product = 0x0001;
input->id.version = 0x0100;
+ input->open = bfin_rotary_open;
+ input->close = bfin_rotary_close;
+
if (rotary->up_key) {
__set_bit(EV_KEY, input->evbit);
__set_bit(rotary->up_key, input->keybit);
@@ -151,75 +215,43 @@
__set_bit(rotary->button_key, input->keybit);
}
- error = request_irq(rotary->irq, bfin_rotary_isr,
- 0, dev_name(&pdev->dev), pdev);
+ /* Quiesce the device before requesting irq */
+ bfin_rotary_close(input);
+
+ rotary->irq = platform_get_irq(pdev, 0);
+ if (rotary->irq < 0) {
+ dev_err(dev, "No rotary IRQ specified\n");
+ return -ENOENT;
+ }
+
+ error = devm_request_irq(dev, rotary->irq, bfin_rotary_isr,
+ 0, dev_name(dev), rotary);
if (error) {
- dev_err(&pdev->dev,
- "unable to claim irq %d; error %d\n",
+ dev_err(dev, "unable to claim irq %d; error %d\n",
rotary->irq, error);
- goto out1;
+ return error;
}
error = input_register_device(input);
if (error) {
- dev_err(&pdev->dev,
- "unable to register input device (%d)\n", error);
- goto out2;
+ dev_err(dev, "unable to register input device (%d)\n", error);
+ return error;
}
- if (pdata->rotary_button_key)
- bfin_write_CNT_IMASK(CZMIE);
-
- if (pdata->mode & ROT_DEBE)
- bfin_write_CNT_DEBOUNCE(pdata->debounce & DPRESCALE);
-
- if (pdata->mode)
- bfin_write_CNT_CONFIG(bfin_read_CNT_CONFIG() |
- (pdata->mode & ~CNTE));
-
- bfin_write_CNT_IMASK(bfin_read_CNT_IMASK() | UCIE | DCIE);
- bfin_write_CNT_CONFIG(bfin_read_CNT_CONFIG() | CNTE);
-
platform_set_drvdata(pdev, rotary);
device_init_wakeup(&pdev->dev, 1);
return 0;
-
-out2:
- free_irq(rotary->irq, pdev);
-out1:
- input_free_device(input);
- kfree(rotary);
- peripheral_free_list(per_cnt);
-
- return error;
}
-static int bfin_rotary_remove(struct platform_device *pdev)
-{
- struct bfin_rot *rotary = platform_get_drvdata(pdev);
-
- bfin_write_CNT_CONFIG(0);
- bfin_write_CNT_IMASK(0);
-
- free_irq(rotary->irq, pdev);
- input_unregister_device(rotary->input);
- peripheral_free_list(per_cnt);
-
- kfree(rotary);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int bfin_rotary_suspend(struct device *dev)
+static int __maybe_unused bfin_rotary_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct bfin_rot *rotary = platform_get_drvdata(pdev);
- rotary->cnt_config = bfin_read_CNT_CONFIG();
- rotary->cnt_imask = bfin_read_CNT_IMASK();
- rotary->cnt_debounce = bfin_read_CNT_DEBOUNCE();
+ rotary->cnt_config = readw(rotary->base + CNT_CONFIG_OFF);
+ rotary->cnt_imask = readw(rotary->base + CNT_IMASK_OFF);
+ rotary->cnt_debounce = readw(rotary->base + CNT_DEBOUNCE_OFF);
if (device_may_wakeup(&pdev->dev))
enable_irq_wake(rotary->irq);
@@ -227,38 +259,32 @@
return 0;
}
-static int bfin_rotary_resume(struct device *dev)
+static int __maybe_unused bfin_rotary_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct bfin_rot *rotary = platform_get_drvdata(pdev);
- bfin_write_CNT_DEBOUNCE(rotary->cnt_debounce);
- bfin_write_CNT_IMASK(rotary->cnt_imask);
- bfin_write_CNT_CONFIG(rotary->cnt_config & ~CNTE);
+ writew(rotary->cnt_debounce, rotary->base + CNT_DEBOUNCE_OFF);
+ writew(rotary->cnt_imask, rotary->base + CNT_IMASK_OFF);
+ writew(rotary->cnt_config & ~CNTE, rotary->base + CNT_CONFIG_OFF);
if (device_may_wakeup(&pdev->dev))
disable_irq_wake(rotary->irq);
if (rotary->cnt_config & CNTE)
- bfin_write_CNT_CONFIG(rotary->cnt_config);
+ writew(rotary->cnt_config, rotary->base + CNT_CONFIG_OFF);
return 0;
}
-static const struct dev_pm_ops bfin_rotary_pm_ops = {
- .suspend = bfin_rotary_suspend,
- .resume = bfin_rotary_resume,
-};
-#endif
+static SIMPLE_DEV_PM_OPS(bfin_rotary_pm_ops,
+ bfin_rotary_suspend, bfin_rotary_resume);
static struct platform_driver bfin_rotary_device_driver = {
.probe = bfin_rotary_probe,
- .remove = bfin_rotary_remove,
.driver = {
.name = "bfin-rotary",
-#ifdef CONFIG_PM
.pm = &bfin_rotary_pm_ops,
-#endif
},
};
module_platform_driver(bfin_rotary_device_driver);
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
index 79cc0f7..e8e010a 100644
--- a/drivers/input/misc/soc_button_array.c
+++ b/drivers/input/misc/soc_button_array.c
@@ -195,7 +195,7 @@
static struct soc_button_info soc_button_PNP0C40[] = {
{ "power", 0, EV_KEY, KEY_POWER, false, true },
- { "home", 1, EV_KEY, KEY_HOME, false, true },
+ { "home", 1, EV_KEY, KEY_LEFTMETA, false, true },
{ "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
{ "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false },
{ "rotation_lock", 4, EV_SW, SW_ROTATE_LOCK, false, false },
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index f205b8b..d28726a 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -99,36 +99,58 @@
#define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */
#define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with
6-byte ALPS packet */
-#define ALPS_IS_RUSHMORE 0x100 /* device is a rushmore */
#define ALPS_BUTTONPAD 0x200 /* device is a clickpad */
static const struct alps_model_info alps_model_data[] = {
- { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
- { { 0x33, 0x02, 0x0a }, 0x00, ALPS_PROTO_V1, 0x88, 0xf8, 0 }, /* UMAX-530T */
- { { 0x53, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
- { { 0x53, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
- { { 0x60, 0x03, 0xc8 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, /* HP ze1115 */
- { { 0x63, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
- { { 0x63, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
- { { 0x63, 0x02, 0x28 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */
- { { 0x63, 0x02, 0x3c }, 0x00, ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */
- { { 0x63, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */
- { { 0x63, 0x02, 0x64 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
- { { 0x63, 0x03, 0xc8 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D800 */
- { { 0x73, 0x00, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */
- { { 0x73, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
- { { 0x73, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */
- { { 0x20, 0x02, 0x0e }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
- { { 0x22, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
- { { 0x22, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
+ { { 0x32, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Toshiba Salellite Pro M10 */
+ { { 0x33, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V1, 0x88, 0xf8, 0 } }, /* UMAX-530T */
+ { { 0x53, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } },
+ { { 0x53, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } },
+ { { 0x60, 0x03, 0xc8 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, /* HP ze1115 */
+ { { 0x63, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } },
+ { { 0x63, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } },
+ { { 0x63, 0x02, 0x28 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Fujitsu Siemens S6010 */
+ { { 0x63, 0x02, 0x3c }, 0x00, { ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL } }, /* Toshiba Satellite S2400-103 */
+ { { 0x63, 0x02, 0x50 }, 0x00, { ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 } }, /* NEC Versa L320 */
+ { { 0x63, 0x02, 0x64 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } },
+ { { 0x63, 0x03, 0xc8 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D800 */
+ { { 0x73, 0x00, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT } }, /* ThinkPad R61 8918-5QG */
+ { { 0x73, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } },
+ { { 0x73, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Ahtec Laptop */
+
+ /*
+ * XXX This entry is suspicious. First byte has zero lower nibble,
+ * which is what a normal mouse would report. Also, the value 0x0e
+ * isn't valid per PS/2 spec.
+ */
+ { { 0x20, 0x02, 0x0e }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } },
+
+ { { 0x22, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } },
+ { { 0x22, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D600 */
/* Dell Latitude E5500, E6400, E6500, Precision M4400 */
- { { 0x62, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf,
- ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },
- { { 0x73, 0x00, 0x14 }, 0x00, ALPS_PROTO_V6, 0xff, 0xff, ALPS_DUALPOINT }, /* Dell XT2 */
- { { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */
- { { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff,
- ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */
- { { 0x73, 0x02, 0x64 }, 0x8a, ALPS_PROTO_V4, 0x8f, 0x8f, 0 },
+ { { 0x62, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xcf, 0xcf,
+ ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED } },
+ { { 0x73, 0x00, 0x14 }, 0x00, { ALPS_PROTO_V6, 0xff, 0xff, ALPS_DUALPOINT } }, /* Dell XT2 */
+ { { 0x73, 0x02, 0x50 }, 0x00, { ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS } }, /* Dell Vostro 1400 */
+ { { 0x52, 0x01, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xff, 0xff,
+ ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED } }, /* Toshiba Tecra A11-11L */
+ { { 0x73, 0x02, 0x64 }, 0x8a, { ALPS_PROTO_V4, 0x8f, 0x8f, 0 } },
+};
+
+static const struct alps_protocol_info alps_v3_protocol_data = {
+ ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT
+};
+
+static const struct alps_protocol_info alps_v3_rushmore_data = {
+ ALPS_PROTO_V3_RUSHMORE, 0x8f, 0x8f, ALPS_DUALPOINT
+};
+
+static const struct alps_protocol_info alps_v5_protocol_data = {
+ ALPS_PROTO_V5, 0xc8, 0xd8, 0
+};
+
+static const struct alps_protocol_info alps_v7_protocol_data = {
+ ALPS_PROTO_V7, 0x48, 0x48, ALPS_DUALPOINT
};
static void alps_set_abs_params_st(struct alps_data *priv,
@@ -136,12 +158,6 @@
static void alps_set_abs_params_mt(struct alps_data *priv,
struct input_dev *dev1);
-/*
- * XXX - this entry is suspicious. First byte has zero lower nibble,
- * which is what a normal mouse would report. Also, the value 0x0e
- * isn't valid per PS/2 spec.
- */
-
/* Packet formats are described in Documentation/input/alps.txt */
static bool alps_is_valid_first_byte(struct alps_data *priv,
@@ -150,8 +166,7 @@
return (data & priv->mask0) == priv->byte0;
}
-static void alps_report_buttons(struct psmouse *psmouse,
- struct input_dev *dev1, struct input_dev *dev2,
+static void alps_report_buttons(struct input_dev *dev1, struct input_dev *dev2,
int left, int right, int middle)
{
struct input_dev *dev;
@@ -161,20 +176,21 @@
* other device (dev2) then this event should be also
* sent through that device.
*/
- dev = test_bit(BTN_LEFT, dev2->key) ? dev2 : dev1;
+ dev = (dev2 && test_bit(BTN_LEFT, dev2->key)) ? dev2 : dev1;
input_report_key(dev, BTN_LEFT, left);
- dev = test_bit(BTN_RIGHT, dev2->key) ? dev2 : dev1;
+ dev = (dev2 && test_bit(BTN_RIGHT, dev2->key)) ? dev2 : dev1;
input_report_key(dev, BTN_RIGHT, right);
- dev = test_bit(BTN_MIDDLE, dev2->key) ? dev2 : dev1;
+ dev = (dev2 && test_bit(BTN_MIDDLE, dev2->key)) ? dev2 : dev1;
input_report_key(dev, BTN_MIDDLE, middle);
/*
* Sync the _other_ device now, we'll do the first
* device later once we report the rest of the events.
*/
- input_sync(dev2);
+ if (dev2)
+ input_sync(dev2);
}
static void alps_process_packet_v1_v2(struct psmouse *psmouse)
@@ -221,13 +237,13 @@
input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x));
input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y));
- alps_report_buttons(psmouse, dev2, dev, left, right, middle);
+ alps_report_buttons(dev2, dev, left, right, middle);
input_sync(dev2);
return;
}
- alps_report_buttons(psmouse, dev, dev2, left, right, middle);
+ alps_report_buttons(dev, dev2, left, right, middle);
/* Convert hardware tap to a reasonable Z value */
if (ges && !fin)
@@ -412,7 +428,7 @@
(2 * (priv->y_bits - 1));
/* y-bitmap order is reversed, except on rushmore */
- if (!(priv->flags & ALPS_IS_RUSHMORE)) {
+ if (priv->proto_version != ALPS_PROTO_V3_RUSHMORE) {
fields->mt[0].y = priv->y_max - fields->mt[0].y;
fields->mt[1].y = priv->y_max - fields->mt[1].y;
}
@@ -648,7 +664,8 @@
*/
if (f->is_mp) {
fingers = f->fingers;
- if (priv->proto_version == ALPS_PROTO_V3) {
+ if (priv->proto_version == ALPS_PROTO_V3 ||
+ priv->proto_version == ALPS_PROTO_V3_RUSHMORE) {
if (alps_process_bitmap(priv, f) == 0)
fingers = 0; /* Use st data */
@@ -892,34 +909,6 @@
unsigned char *pkt,
unsigned char pkt_id)
{
- /*
- * packet-fmt b7 b6 b5 b4 b3 b2 b1 b0
- * Byte0 TWO & MULTI L 1 R M 1 Y0-2 Y0-1 Y0-0
- * Byte0 NEW L 1 X1-5 1 1 Y0-2 Y0-1 Y0-0
- * Byte1 Y0-10 Y0-9 Y0-8 Y0-7 Y0-6 Y0-5 Y0-4 Y0-3
- * Byte2 X0-11 1 X0-10 X0-9 X0-8 X0-7 X0-6 X0-5
- * Byte3 X1-11 1 X0-4 X0-3 1 X0-2 X0-1 X0-0
- * Byte4 TWO X1-10 TWO X1-9 X1-8 X1-7 X1-6 X1-5 X1-4
- * Byte4 MULTI X1-10 TWO X1-9 X1-8 X1-7 X1-6 Y1-5 1
- * Byte4 NEW X1-10 TWO X1-9 X1-8 X1-7 X1-6 0 0
- * Byte5 TWO & NEW Y1-10 0 Y1-9 Y1-8 Y1-7 Y1-6 Y1-5 Y1-4
- * Byte5 MULTI Y1-10 0 Y1-9 Y1-8 Y1-7 Y1-6 F-1 F-0
- * L: Left button
- * R / M: Non-clickpads: Right / Middle button
- * Clickpads: When > 2 fingers are down, and some fingers
- * are in the button area, then the 2 coordinates reported
- * are for fingers outside the button area and these report
- * extra fingers being present in the right / left button
- * area. Note these fingers are not added to the F field!
- * so if a TWO packet is received and R = 1 then there are
- * 3 fingers down, etc.
- * TWO: 1: Two touches present, byte 0/4/5 are in TWO fmt
- * 0: If byte 4 bit 0 is 1, then byte 0/4/5 are in MULTI fmt
- * otherwise byte 0 bit 4 must be set and byte 0/4/5 are
- * in NEW fmt
- * F: Number of fingers - 3, 0 means 3 fingers, 1 means 4 ...
- */
-
mt[0].x = ((pkt[2] & 0x80) << 4);
mt[0].x |= ((pkt[2] & 0x3F) << 5);
mt[0].x |= ((pkt[3] & 0x30) >> 1);
@@ -1044,17 +1033,6 @@
return;
}
- /*
- * b7 b6 b5 b4 b3 b2 b1 b0
- * Byte0 0 1 0 0 1 0 0 0
- * Byte1 1 1 * * 1 M R L
- * Byte2 X7 1 X5 X4 X3 X2 X1 X0
- * Byte3 Z6 1 Y6 X6 1 Y2 Y1 Y0
- * Byte4 Y7 0 Y5 Y4 Y3 1 1 0
- * Byte5 T&P 0 Z5 Z4 Z3 Z2 Z1 Z0
- * M / R / L: Middle / Right / Left button
- */
-
x = ((packet[2] & 0xbf)) | ((packet[3] & 0x10) << 2);
y = (packet[3] & 0x07) | (packet[4] & 0xb8) |
((packet[3] & 0x20) << 1);
@@ -1107,23 +1085,89 @@
alps_process_touchpad_packet_v7(psmouse);
}
-static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
+static DEFINE_MUTEX(alps_mutex);
+
+static void alps_register_bare_ps2_mouse(struct work_struct *work)
+{
+ struct alps_data *priv =
+ container_of(work, struct alps_data, dev3_register_work.work);
+ struct psmouse *psmouse = priv->psmouse;
+ struct input_dev *dev3;
+ int error = 0;
+
+ mutex_lock(&alps_mutex);
+
+ if (priv->dev3)
+ goto out;
+
+ dev3 = input_allocate_device();
+ if (!dev3) {
+ psmouse_err(psmouse, "failed to allocate secondary device\n");
+ error = -ENOMEM;
+ goto out;
+ }
+
+ snprintf(priv->phys3, sizeof(priv->phys3), "%s/%s",
+ psmouse->ps2dev.serio->phys,
+ (priv->dev2 ? "input2" : "input1"));
+ dev3->phys = priv->phys3;
+
+ /*
+ * format of input device name is: "protocol vendor name"
+ * see function psmouse_switch_protocol() in psmouse-base.c
+ */
+ dev3->name = "PS/2 ALPS Mouse";
+
+ dev3->id.bustype = BUS_I8042;
+ dev3->id.vendor = 0x0002;
+ dev3->id.product = PSMOUSE_PS2;
+ dev3->id.version = 0x0000;
+ dev3->dev.parent = &psmouse->ps2dev.serio->dev;
+
+ input_set_capability(dev3, EV_REL, REL_X);
+ input_set_capability(dev3, EV_REL, REL_Y);
+ input_set_capability(dev3, EV_KEY, BTN_LEFT);
+ input_set_capability(dev3, EV_KEY, BTN_RIGHT);
+ input_set_capability(dev3, EV_KEY, BTN_MIDDLE);
+
+ __set_bit(INPUT_PROP_POINTER, dev3->propbit);
+
+ error = input_register_device(dev3);
+ if (error) {
+ psmouse_err(psmouse,
+ "failed to register secondary device: %d\n",
+ error);
+ input_free_device(dev3);
+ goto out;
+ }
+
+ priv->dev3 = dev3;
+
+out:
+ /*
+ * Save the error code so that we can detect that we
+ * already tried to create the device.
+ */
+ if (error)
+ priv->dev3 = ERR_PTR(error);
+
+ mutex_unlock(&alps_mutex);
+}
+
+static void alps_report_bare_ps2_packet(struct input_dev *dev,
unsigned char packet[],
bool report_buttons)
{
- struct alps_data *priv = psmouse->private;
- struct input_dev *dev2 = priv->dev2;
-
if (report_buttons)
- alps_report_buttons(psmouse, dev2, psmouse->dev,
+ alps_report_buttons(dev, NULL,
packet[0] & 1, packet[0] & 2, packet[0] & 4);
- input_report_rel(dev2, REL_X,
+ input_report_rel(dev, REL_X,
packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0);
- input_report_rel(dev2, REL_Y,
+ input_report_rel(dev, REL_Y,
packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0);
- input_sync(dev2);
+ input_sync(dev);
}
static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
@@ -1188,8 +1232,8 @@
* de-synchronization.
*/
- alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3],
- false);
+ alps_report_bare_ps2_packet(priv->dev2,
+ &psmouse->packet[3], false);
/*
* Continue with the standard ALPS protocol handling,
@@ -1245,9 +1289,18 @@
* properly we only do this if the device is fully synchronized.
*/
if (!psmouse->out_of_sync_cnt && (psmouse->packet[0] & 0xc8) == 0x08) {
+
+ /* Register dev3 mouse if we received PS/2 packet first time */
+ if (unlikely(!priv->dev3))
+ psmouse_queue_work(psmouse,
+ &priv->dev3_register_work, 0);
+
if (psmouse->pktcnt == 3) {
- alps_report_bare_ps2_packet(psmouse, psmouse->packet,
- true);
+ /* Once dev3 mouse device is registered report data */
+ if (likely(!IS_ERR_OR_NULL(priv->dev3)))
+ alps_report_bare_ps2_packet(priv->dev3,
+ psmouse->packet,
+ true);
return PSMOUSE_FULL_PACKET;
}
return PSMOUSE_GOOD_DATA;
@@ -1275,7 +1328,7 @@
psmouse->pktcnt - 1,
psmouse->packet[psmouse->pktcnt - 1]);
- if (priv->proto_version == ALPS_PROTO_V3 &&
+ if (priv->proto_version == ALPS_PROTO_V3_RUSHMORE &&
psmouse->pktcnt == psmouse->pktsize) {
/*
* Some Dell boxes, such as Latitude E6440 or E7440
@@ -1780,7 +1833,7 @@
* all.
*/
if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_SETSCALE21, param)) {
- psmouse_warn(psmouse, "trackstick E7 report failed\n");
+ psmouse_warn(psmouse, "Failed to initialize trackstick (E7 report failed)\n");
ret = -ENODEV;
} else {
psmouse_dbg(psmouse, "trackstick E7 report: %3ph\n", param);
@@ -1945,8 +1998,6 @@
ALPS_REG_BASE_RUSHMORE);
if (reg_val == -EIO)
goto error;
- if (reg_val == -ENODEV)
- priv->flags &= ~ALPS_DUALPOINT;
}
if (alps_enter_command_mode(psmouse) ||
@@ -2162,11 +2213,18 @@
return ret;
}
-static void alps_set_defaults(struct alps_data *priv)
+static int alps_set_protocol(struct psmouse *psmouse,
+ struct alps_data *priv,
+ const struct alps_protocol_info *protocol)
{
- priv->byte0 = 0x8f;
- priv->mask0 = 0x8f;
- priv->flags = ALPS_DUALPOINT;
+ psmouse->private = priv;
+
+ setup_timer(&priv->timer, alps_flush_packet, (unsigned long)psmouse);
+
+ priv->proto_version = protocol->version;
+ priv->byte0 = protocol->byte0;
+ priv->mask0 = protocol->mask0;
+ priv->flags = protocol->flags;
priv->x_max = 2000;
priv->y_max = 1400;
@@ -2182,6 +2240,7 @@
priv->x_max = 1023;
priv->y_max = 767;
break;
+
case ALPS_PROTO_V3:
priv->hw_init = alps_hw_init_v3;
priv->process_packet = alps_process_packet_v3;
@@ -2190,6 +2249,23 @@
priv->nibble_commands = alps_v3_nibble_commands;
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
break;
+
+ case ALPS_PROTO_V3_RUSHMORE:
+ priv->hw_init = alps_hw_init_rushmore_v3;
+ priv->process_packet = alps_process_packet_v3;
+ priv->set_abs_params = alps_set_abs_params_mt;
+ priv->decode_fields = alps_decode_rushmore;
+ priv->nibble_commands = alps_v3_nibble_commands;
+ priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
+ priv->x_bits = 16;
+ priv->y_bits = 12;
+
+ if (alps_probe_trackstick_v3(psmouse,
+ ALPS_REG_BASE_RUSHMORE) < 0)
+ priv->flags &= ~ALPS_DUALPOINT;
+
+ break;
+
case ALPS_PROTO_V4:
priv->hw_init = alps_hw_init_v4;
priv->process_packet = alps_process_packet_v4;
@@ -2197,6 +2273,7 @@
priv->nibble_commands = alps_v4_nibble_commands;
priv->addr_command = PSMOUSE_CMD_DISABLE;
break;
+
case ALPS_PROTO_V5:
priv->hw_init = alps_hw_init_dolphin_v1;
priv->process_packet = alps_process_touchpad_packet_v3_v5;
@@ -2204,14 +2281,12 @@
priv->set_abs_params = alps_set_abs_params_mt;
priv->nibble_commands = alps_v3_nibble_commands;
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
- priv->byte0 = 0xc8;
- priv->mask0 = 0xd8;
- priv->flags = 0;
priv->x_max = 1360;
priv->y_max = 660;
priv->x_bits = 23;
priv->y_bits = 12;
break;
+
case ALPS_PROTO_V6:
priv->hw_init = alps_hw_init_v6;
priv->process_packet = alps_process_packet_v6;
@@ -2220,6 +2295,7 @@
priv->x_max = 2047;
priv->y_max = 1535;
break;
+
case ALPS_PROTO_V7:
priv->hw_init = alps_hw_init_v7;
priv->process_packet = alps_process_packet_v7;
@@ -2227,19 +2303,21 @@
priv->set_abs_params = alps_set_abs_params_mt;
priv->nibble_commands = alps_v3_nibble_commands;
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
- priv->x_max = 0xfff;
- priv->y_max = 0x7ff;
- priv->byte0 = 0x48;
- priv->mask0 = 0x48;
+
+ if (alps_dolphin_get_device_area(psmouse, priv))
+ return -EIO;
if (priv->fw_ver[1] != 0xba)
priv->flags |= ALPS_BUTTONPAD;
+
break;
}
+
+ return 0;
}
-static int alps_match_table(struct psmouse *psmouse, struct alps_data *priv,
- unsigned char *e7, unsigned char *ec)
+static const struct alps_protocol_info *alps_match_table(unsigned char *e7,
+ unsigned char *ec)
{
const struct alps_model_info *model;
int i;
@@ -2251,23 +2329,18 @@
(!model->command_mode_resp ||
model->command_mode_resp == ec[2])) {
- priv->proto_version = model->proto_version;
- alps_set_defaults(priv);
-
- priv->flags = model->flags;
- priv->byte0 = model->byte0;
- priv->mask0 = model->mask0;
-
- return 0;
+ return &model->protocol_info;
}
}
- return -EINVAL;
+ return NULL;
}
static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
{
+ const struct alps_protocol_info *protocol;
unsigned char e6[4], e7[4], ec[4];
+ int error;
/*
* First try "E6 report".
@@ -2293,54 +2366,35 @@
alps_exit_command_mode(psmouse))
return -EIO;
- /* Save the Firmware version */
- memcpy(priv->fw_ver, ec, 3);
-
- if (alps_match_table(psmouse, priv, e7, ec) == 0) {
- return 0;
- } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 &&
- ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) {
- priv->proto_version = ALPS_PROTO_V5;
- alps_set_defaults(priv);
- if (alps_dolphin_get_device_area(psmouse, priv))
- return -EIO;
- else
- return 0;
- } else if (ec[0] == 0x88 &&
- ((ec[1] & 0xf0) == 0xb0 || (ec[1] & 0xf0) == 0xc0)) {
- priv->proto_version = ALPS_PROTO_V7;
- alps_set_defaults(priv);
-
- return 0;
- } else if (ec[0] == 0x88 && ec[1] == 0x08) {
- priv->proto_version = ALPS_PROTO_V3;
- alps_set_defaults(priv);
-
- priv->hw_init = alps_hw_init_rushmore_v3;
- priv->decode_fields = alps_decode_rushmore;
- priv->x_bits = 16;
- priv->y_bits = 12;
- priv->flags |= ALPS_IS_RUSHMORE;
-
- /* hack to make addr_command, nibble_command available */
- psmouse->private = priv;
-
- if (alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_RUSHMORE))
- priv->flags &= ~ALPS_DUALPOINT;
-
- return 0;
- } else if (ec[0] == 0x88 && ec[1] == 0x07 &&
- ec[2] >= 0x90 && ec[2] <= 0x9d) {
- priv->proto_version = ALPS_PROTO_V3;
- alps_set_defaults(priv);
-
- return 0;
+ protocol = alps_match_table(e7, ec);
+ if (!protocol) {
+ if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 &&
+ ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) {
+ protocol = &alps_v5_protocol_data;
+ } else if (ec[0] == 0x88 &&
+ ((ec[1] & 0xf0) == 0xb0 || (ec[1] & 0xf0) == 0xc0)) {
+ protocol = &alps_v7_protocol_data;
+ } else if (ec[0] == 0x88 && ec[1] == 0x08) {
+ protocol = &alps_v3_rushmore_data;
+ } else if (ec[0] == 0x88 && ec[1] == 0x07 &&
+ ec[2] >= 0x90 && ec[2] <= 0x9d) {
+ protocol = &alps_v3_protocol_data;
+ } else {
+ psmouse_dbg(psmouse,
+ "Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec);
+ return -EINVAL;
+ }
}
- psmouse_dbg(psmouse,
- "Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec);
+ if (priv) {
+ /* Save the Firmware version */
+ memcpy(priv->fw_ver, ec, 3);
+ error = alps_set_protocol(psmouse, priv, protocol);
+ if (error)
+ return error;
+ }
- return -EINVAL;
+ return 0;
}
static int alps_reconnect(struct psmouse *psmouse)
@@ -2361,7 +2415,10 @@
psmouse_reset(psmouse);
del_timer_sync(&priv->timer);
- input_unregister_device(priv->dev2);
+ if (priv->dev2)
+ input_unregister_device(priv->dev2);
+ if (!IS_ERR_OR_NULL(priv->dev3))
+ input_unregister_device(priv->dev3);
kfree(priv);
}
@@ -2394,25 +2451,12 @@
int alps_init(struct psmouse *psmouse)
{
- struct alps_data *priv;
- struct input_dev *dev1 = psmouse->dev, *dev2;
+ struct alps_data *priv = psmouse->private;
+ struct input_dev *dev1 = psmouse->dev;
+ int error;
- priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL);
- dev2 = input_allocate_device();
- if (!priv || !dev2)
- goto init_fail;
-
- priv->dev2 = dev2;
- setup_timer(&priv->timer, alps_flush_packet, (unsigned long)psmouse);
-
- psmouse->private = priv;
-
- psmouse_reset(psmouse);
-
- if (alps_identify(psmouse, priv) < 0)
- goto init_fail;
-
- if (priv->hw_init(psmouse))
+ error = priv->hw_init(psmouse);
+ if (error)
goto init_fail;
/*
@@ -2462,36 +2506,57 @@
}
if (priv->flags & ALPS_DUALPOINT) {
+ struct input_dev *dev2;
+
+ dev2 = input_allocate_device();
+ if (!dev2) {
+ psmouse_err(psmouse,
+ "failed to allocate trackstick device\n");
+ error = -ENOMEM;
+ goto init_fail;
+ }
+
+ snprintf(priv->phys2, sizeof(priv->phys2), "%s/input1",
+ psmouse->ps2dev.serio->phys);
+ dev2->phys = priv->phys2;
+
/*
* format of input device name is: "protocol vendor name"
* see function psmouse_switch_protocol() in psmouse-base.c
*/
dev2->name = "AlpsPS/2 ALPS DualPoint Stick";
+
+ dev2->id.bustype = BUS_I8042;
+ dev2->id.vendor = 0x0002;
dev2->id.product = PSMOUSE_ALPS;
dev2->id.version = priv->proto_version;
- } else {
- dev2->name = "PS/2 ALPS Mouse";
- dev2->id.product = PSMOUSE_PS2;
- dev2->id.version = 0x0000;
- }
+ dev2->dev.parent = &psmouse->ps2dev.serio->dev;
- snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys);
- dev2->phys = priv->phys;
- dev2->id.bustype = BUS_I8042;
- dev2->id.vendor = 0x0002;
- dev2->dev.parent = &psmouse->ps2dev.serio->dev;
+ input_set_capability(dev2, EV_REL, REL_X);
+ input_set_capability(dev2, EV_REL, REL_Y);
+ input_set_capability(dev2, EV_KEY, BTN_LEFT);
+ input_set_capability(dev2, EV_KEY, BTN_RIGHT);
+ input_set_capability(dev2, EV_KEY, BTN_MIDDLE);
- dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
- dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
- dev2->keybit[BIT_WORD(BTN_LEFT)] =
- BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
-
- __set_bit(INPUT_PROP_POINTER, dev2->propbit);
- if (priv->flags & ALPS_DUALPOINT)
+ __set_bit(INPUT_PROP_POINTER, dev2->propbit);
__set_bit(INPUT_PROP_POINTING_STICK, dev2->propbit);
- if (input_register_device(priv->dev2))
- goto init_fail;
+ error = input_register_device(dev2);
+ if (error) {
+ psmouse_err(psmouse,
+ "failed to register trackstick device: %d\n",
+ error);
+ input_free_device(dev2);
+ goto init_fail;
+ }
+
+ priv->dev2 = dev2;
+ }
+
+ priv->psmouse = psmouse;
+
+ INIT_DELAYED_WORK(&priv->dev3_register_work,
+ alps_register_bare_ps2_mouse);
psmouse->protocol_handler = alps_process_byte;
psmouse->poll = alps_poll;
@@ -2509,25 +2574,56 @@
init_fail:
psmouse_reset(psmouse);
- input_free_device(dev2);
- kfree(priv);
+ /*
+ * Even though we did not allocate psmouse->private we do free
+ * it here.
+ */
+ kfree(psmouse->private);
psmouse->private = NULL;
- return -1;
+ return error;
}
int alps_detect(struct psmouse *psmouse, bool set_properties)
{
- struct alps_data dummy;
+ struct alps_data *priv;
+ int error;
- if (alps_identify(psmouse, &dummy) < 0)
- return -1;
+ error = alps_identify(psmouse, NULL);
+ if (error)
+ return error;
+
+ /*
+ * Reset the device to make sure it is fully operational:
+ * on some laptops, like certain Dell Latitudes, we may
+ * fail to properly detect presence of trackstick if device
+ * has not been reset.
+ */
+ psmouse_reset(psmouse);
+
+ priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ error = alps_identify(psmouse, priv);
+ if (error)
+ return error;
if (set_properties) {
psmouse->vendor = "ALPS";
- psmouse->name = dummy.flags & ALPS_DUALPOINT ?
+ psmouse->name = priv->flags & ALPS_DUALPOINT ?
"DualPoint TouchPad" : "GlidePoint";
- psmouse->model = dummy.proto_version << 8;
+ psmouse->model = priv->proto_version;
+ } else {
+ /*
+ * Destroy alps_data structure we allocated earlier since
+ * this was just a "trial run". Otherwise we'll keep it
+ * to be used by alps_init() which has to be called if
+ * we succeed and set_properties is true.
+ */
+ kfree(priv);
+ psmouse->private = NULL;
}
+
return 0;
}
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index 66240b4..02513c0 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -14,13 +14,14 @@
#include <linux/input/mt.h>
-#define ALPS_PROTO_V1 1
-#define ALPS_PROTO_V2 2
-#define ALPS_PROTO_V3 3
-#define ALPS_PROTO_V4 4
-#define ALPS_PROTO_V5 5
-#define ALPS_PROTO_V6 6
-#define ALPS_PROTO_V7 7 /* t3btl t4s */
+#define ALPS_PROTO_V1 0x100
+#define ALPS_PROTO_V2 0x200
+#define ALPS_PROTO_V3 0x300
+#define ALPS_PROTO_V3_RUSHMORE 0x310
+#define ALPS_PROTO_V4 0x400
+#define ALPS_PROTO_V5 0x500
+#define ALPS_PROTO_V6 0x600
+#define ALPS_PROTO_V7 0x700 /* t3btl t4s */
#define MAX_TOUCHES 2
@@ -46,29 +47,37 @@
};
/**
+ * struct alps_protocol_info - information about protocol used by a device
+ * @version: Indicates V1/V2/V3/...
+ * @byte0: Helps figure out whether a position report packet matches the
+ * known format for this model. The first byte of the report, ANDed with
+ * mask0, should match byte0.
+ * @mask0: The mask used to check the first byte of the report.
+ * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
+ */
+struct alps_protocol_info {
+ u16 version;
+ u8 byte0, mask0;
+ unsigned int flags;
+};
+
+/**
* struct alps_model_info - touchpad ID table
* @signature: E7 response string to match.
* @command_mode_resp: For V3/V4 touchpads, the final byte of the EC response
* (aka command mode response) identifies the firmware minor version. This
* can be used to distinguish different hardware models which are not
* uniquely identifiable through their E7 responses.
- * @proto_version: Indicates V1/V2/V3/...
- * @byte0: Helps figure out whether a position report packet matches the
- * known format for this model. The first byte of the report, ANDed with
- * mask0, should match byte0.
- * @mask0: The mask used to check the first byte of the report.
- * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
+ * @protocol_info: information about protcol used by the device.
*
* Many (but not all) ALPS touchpads can be identified by looking at the
* values returned in the "E7 report" and/or the "EC report." This table
* lists a number of such touchpads.
*/
struct alps_model_info {
- unsigned char signature[3];
- unsigned char command_mode_resp;
- unsigned char proto_version;
- unsigned char byte0, mask0;
- int flags;
+ u8 signature[3];
+ u8 command_mode_resp;
+ struct alps_protocol_info protocol_info;
};
/**
@@ -132,8 +141,12 @@
/**
* struct alps_data - private data structure for the ALPS driver
- * @dev2: "Relative" device used to report trackstick or mouse activity.
- * @phys: Physical path for the relative device.
+ * @psmouse: Pointer to parent psmouse device
+ * @dev2: Trackstick device (can be NULL).
+ * @dev3: Generic PS/2 mouse (can be NULL, delayed registering).
+ * @phys2: Physical path for the trackstick device.
+ * @phys3: Physical path for the generic PS/2 mouse.
+ * @dev3_register_work: Delayed work for registering PS/2 mouse.
* @nibble_commands: Command mapping used for touchpad register accesses.
* @addr_command: Command used to tell the touchpad that a register address
* follows.
@@ -160,15 +173,19 @@
* @timer: Timer for flushing out the final report packet in the stream.
*/
struct alps_data {
+ struct psmouse *psmouse;
struct input_dev *dev2;
- char phys[32];
+ struct input_dev *dev3;
+ char phys2[32];
+ char phys3[32];
+ struct delayed_work dev3_register_work;
/* these are autodetected when the device is identified */
const struct alps_nibble_commands *nibble_commands;
int addr_command;
- unsigned char proto_version;
- unsigned char byte0, mask0;
- unsigned char fw_ver[3];
+ u16 proto_version;
+ u8 byte0, mask0;
+ u8 fw_ver[3];
int flags;
int x_max;
int y_max;
diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c
index 9118a18..28dcfc8 100644
--- a/drivers/input/mouse/cypress_ps2.c
+++ b/drivers/input/mouse/cypress_ps2.c
@@ -710,8 +710,3 @@
return -1;
}
-
-bool cypress_supported(void)
-{
- return true;
-}
diff --git a/drivers/input/mouse/cypress_ps2.h b/drivers/input/mouse/cypress_ps2.h
index 4720f21..81f68aa 100644
--- a/drivers/input/mouse/cypress_ps2.h
+++ b/drivers/input/mouse/cypress_ps2.h
@@ -172,7 +172,6 @@
#ifdef CONFIG_MOUSE_PS2_CYPRESS
int cypress_detect(struct psmouse *psmouse, bool set_properties);
int cypress_init(struct psmouse *psmouse);
-bool cypress_supported(void);
#else
inline int cypress_detect(struct psmouse *psmouse, bool set_properties)
{
@@ -182,10 +181,6 @@
{
return -ENOSYS;
}
-inline bool cypress_supported(void)
-{
- return 0;
-}
#endif /* CONFIG_MOUSE_PS2_CYPRESS */
#endif /* _CYPRESS_PS2_H */
diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c
index fca38ba..757f78a 100644
--- a/drivers/input/mouse/focaltech.c
+++ b/drivers/input/mouse/focaltech.c
@@ -424,11 +424,6 @@
return error;
}
-bool focaltech_supported(void)
-{
- return true;
-}
-
#else /* CONFIG_MOUSE_PS2_FOCALTECH */
int focaltech_init(struct psmouse *psmouse)
@@ -438,9 +433,4 @@
return 0;
}
-bool focaltech_supported(void)
-{
- return false;
-}
-
#endif /* CONFIG_MOUSE_PS2_FOCALTECH */
diff --git a/drivers/input/mouse/focaltech.h b/drivers/input/mouse/focaltech.h
index 71870a9..ca61ebf 100644
--- a/drivers/input/mouse/focaltech.h
+++ b/drivers/input/mouse/focaltech.h
@@ -19,6 +19,5 @@
int focaltech_detect(struct psmouse *psmouse, bool set_properties);
int focaltech_init(struct psmouse *psmouse);
-bool focaltech_supported(void);
#endif
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 68469fe..4ccd01d 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -727,7 +727,7 @@
if (psmouse_do_detect(focaltech_detect, psmouse, set_properties) == 0) {
if (max_proto > PSMOUSE_IMEX) {
if (!set_properties || focaltech_init(psmouse) == 0) {
- if (focaltech_supported())
+ if (IS_ENABLED(CONFIG_MOUSE_PS2_FOCALTECH))
return PSMOUSE_FOCALTECH;
/*
* Note that we need to also restrict
@@ -776,7 +776,7 @@
* Try activating protocol, but check if support is enabled first, since
* we try detecting Synaptics even when protocol is disabled.
*/
- if (synaptics_supported() &&
+ if (IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS) &&
(!set_properties || synaptics_init(psmouse) == 0)) {
return PSMOUSE_SYNAPTICS;
}
@@ -801,7 +801,7 @@
*/
if (max_proto > PSMOUSE_IMEX &&
cypress_detect(psmouse, set_properties) == 0) {
- if (cypress_supported()) {
+ if (IS_ENABLED(CONFIG_MOUSE_PS2_CYPRESS)) {
if (cypress_init(psmouse) == 0)
return PSMOUSE_CYPRESS;
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 7e705ee..f2cceb6 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -1454,11 +1454,6 @@
return __synaptics_init(psmouse, false);
}
-bool synaptics_supported(void)
-{
- return true;
-}
-
#else /* CONFIG_MOUSE_PS2_SYNAPTICS */
void __init synaptics_module_init(void)
@@ -1470,9 +1465,4 @@
return -ENOSYS;
}
-bool synaptics_supported(void)
-{
- return false;
-}
-
#endif /* CONFIG_MOUSE_PS2_SYNAPTICS */
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index 6faf9bb..aedc329 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -175,6 +175,5 @@
int synaptics_init(struct psmouse *psmouse);
int synaptics_init_relative(struct psmouse *psmouse);
void synaptics_reset(struct psmouse *psmouse);
-bool synaptics_supported(void);
#endif /* _SYNAPTICS_H */
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 08981be..713a962 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -18,9 +18,11 @@
#include <linux/slab.h>
#include <linux/crypto.h>
#include <linux/workqueue.h>
+#include <linux/kthread.h>
#include <linux/backing-dev.h>
#include <linux/atomic.h>
#include <linux/scatterlist.h>
+#include <linux/rbtree.h>
#include <asm/page.h>
#include <asm/unaligned.h>
#include <crypto/hash.h>
@@ -58,7 +60,8 @@
atomic_t io_pending;
int error;
sector_t sector;
- struct dm_crypt_io *base_io;
+
+ struct rb_node rb_node;
} CRYPTO_MINALIGN_ATTR;
struct dm_crypt_request {
@@ -108,7 +111,8 @@
* Crypt: maps a linear range of a block device
* and encrypts / decrypts at the same time.
*/
-enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID };
+enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID,
+ DM_CRYPT_SAME_CPU, DM_CRYPT_NO_OFFLOAD };
/*
* The fields in here must be read only after initialization.
@@ -121,14 +125,18 @@
* pool for per bio private data, crypto requests and
* encryption requeusts/buffer pages
*/
- mempool_t *io_pool;
mempool_t *req_pool;
mempool_t *page_pool;
struct bio_set *bs;
+ struct mutex bio_alloc_lock;
struct workqueue_struct *io_queue;
struct workqueue_struct *crypt_queue;
+ struct task_struct *write_thread;
+ wait_queue_head_t write_thread_wait;
+ struct rb_root write_tree;
+
char *cipher;
char *cipher_string;
@@ -172,9 +180,6 @@
};
#define MIN_IOS 16
-#define MIN_POOL_PAGES 32
-
-static struct kmem_cache *_crypt_io_pool;
static void clone_init(struct dm_crypt_io *, struct bio *);
static void kcryptd_queue_crypt(struct dm_crypt_io *io);
@@ -946,57 +951,70 @@
return 0;
}
+static void crypt_free_buffer_pages(struct crypt_config *cc, struct bio *clone);
+
/*
* Generate a new unfragmented bio with the given size
* This should never violate the device limitations
- * May return a smaller bio when running out of pages, indicated by
- * *out_of_pages set to 1.
+ *
+ * This function may be called concurrently. If we allocate from the mempool
+ * concurrently, there is a possibility of deadlock. For example, if we have
+ * mempool of 256 pages, two processes, each wanting 256, pages allocate from
+ * the mempool concurrently, it may deadlock in a situation where both processes
+ * have allocated 128 pages and the mempool is exhausted.
+ *
+ * In order to avoid this scenario we allocate the pages under a mutex.
+ *
+ * In order to not degrade performance with excessive locking, we try
+ * non-blocking allocations without a mutex first but on failure we fallback
+ * to blocking allocations with a mutex.
*/
-static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size,
- unsigned *out_of_pages)
+static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size)
{
struct crypt_config *cc = io->cc;
struct bio *clone;
unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
- gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
- unsigned i, len;
+ gfp_t gfp_mask = GFP_NOWAIT | __GFP_HIGHMEM;
+ unsigned i, len, remaining_size;
struct page *page;
+ struct bio_vec *bvec;
+
+retry:
+ if (unlikely(gfp_mask & __GFP_WAIT))
+ mutex_lock(&cc->bio_alloc_lock);
clone = bio_alloc_bioset(GFP_NOIO, nr_iovecs, cc->bs);
if (!clone)
- return NULL;
+ goto return_clone;
clone_init(io, clone);
- *out_of_pages = 0;
+
+ remaining_size = size;
for (i = 0; i < nr_iovecs; i++) {
page = mempool_alloc(cc->page_pool, gfp_mask);
if (!page) {
- *out_of_pages = 1;
- break;
+ crypt_free_buffer_pages(cc, clone);
+ bio_put(clone);
+ gfp_mask |= __GFP_WAIT;
+ goto retry;
}
- /*
- * If additional pages cannot be allocated without waiting,
- * return a partially-allocated bio. The caller will then try
- * to allocate more bios while submitting this partial bio.
- */
- gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT;
+ len = (remaining_size > PAGE_SIZE) ? PAGE_SIZE : remaining_size;
- len = (size > PAGE_SIZE) ? PAGE_SIZE : size;
+ bvec = &clone->bi_io_vec[clone->bi_vcnt++];
+ bvec->bv_page = page;
+ bvec->bv_len = len;
+ bvec->bv_offset = 0;
- if (!bio_add_page(clone, page, len, 0)) {
- mempool_free(page, cc->page_pool);
- break;
- }
+ clone->bi_iter.bi_size += len;
- size -= len;
+ remaining_size -= len;
}
- if (!clone->bi_iter.bi_size) {
- bio_put(clone);
- return NULL;
- }
+return_clone:
+ if (unlikely(gfp_mask & __GFP_WAIT))
+ mutex_unlock(&cc->bio_alloc_lock);
return clone;
}
@@ -1020,7 +1038,6 @@
io->base_bio = bio;
io->sector = sector;
io->error = 0;
- io->base_io = NULL;
io->ctx.req = NULL;
atomic_set(&io->io_pending, 0);
}
@@ -1033,13 +1050,11 @@
/*
* One of the bios was finished. Check for completion of
* the whole request and correctly clean up the buffer.
- * If base_io is set, wait for the last fragment to complete.
*/
static void crypt_dec_pending(struct dm_crypt_io *io)
{
struct crypt_config *cc = io->cc;
struct bio *base_bio = io->base_bio;
- struct dm_crypt_io *base_io = io->base_io;
int error = io->error;
if (!atomic_dec_and_test(&io->io_pending))
@@ -1047,16 +1062,8 @@
if (io->ctx.req)
crypt_free_req(cc, io->ctx.req, base_bio);
- if (io != dm_per_bio_data(base_bio, cc->per_bio_data_size))
- mempool_free(io, cc->io_pool);
- if (likely(!base_io))
- bio_endio(base_bio, error);
- else {
- if (error && !base_io->error)
- base_io->error = error;
- crypt_dec_pending(base_io);
- }
+ bio_endio(base_bio, error);
}
/*
@@ -1138,37 +1145,97 @@
return 0;
}
-static void kcryptd_io_write(struct dm_crypt_io *io)
-{
- struct bio *clone = io->ctx.bio_out;
- generic_make_request(clone);
-}
-
-static void kcryptd_io(struct work_struct *work)
+static void kcryptd_io_read_work(struct work_struct *work)
{
struct dm_crypt_io *io = container_of(work, struct dm_crypt_io, work);
- if (bio_data_dir(io->base_bio) == READ) {
- crypt_inc_pending(io);
- if (kcryptd_io_read(io, GFP_NOIO))
- io->error = -ENOMEM;
- crypt_dec_pending(io);
- } else
- kcryptd_io_write(io);
+ crypt_inc_pending(io);
+ if (kcryptd_io_read(io, GFP_NOIO))
+ io->error = -ENOMEM;
+ crypt_dec_pending(io);
}
-static void kcryptd_queue_io(struct dm_crypt_io *io)
+static void kcryptd_queue_read(struct dm_crypt_io *io)
{
struct crypt_config *cc = io->cc;
- INIT_WORK(&io->work, kcryptd_io);
+ INIT_WORK(&io->work, kcryptd_io_read_work);
queue_work(cc->io_queue, &io->work);
}
+static void kcryptd_io_write(struct dm_crypt_io *io)
+{
+ struct bio *clone = io->ctx.bio_out;
+
+ generic_make_request(clone);
+}
+
+#define crypt_io_from_node(node) rb_entry((node), struct dm_crypt_io, rb_node)
+
+static int dmcrypt_write(void *data)
+{
+ struct crypt_config *cc = data;
+ struct dm_crypt_io *io;
+
+ while (1) {
+ struct rb_root write_tree;
+ struct blk_plug plug;
+
+ DECLARE_WAITQUEUE(wait, current);
+
+ spin_lock_irq(&cc->write_thread_wait.lock);
+continue_locked:
+
+ if (!RB_EMPTY_ROOT(&cc->write_tree))
+ goto pop_from_list;
+
+ __set_current_state(TASK_INTERRUPTIBLE);
+ __add_wait_queue(&cc->write_thread_wait, &wait);
+
+ spin_unlock_irq(&cc->write_thread_wait.lock);
+
+ if (unlikely(kthread_should_stop())) {
+ set_task_state(current, TASK_RUNNING);
+ remove_wait_queue(&cc->write_thread_wait, &wait);
+ break;
+ }
+
+ schedule();
+
+ set_task_state(current, TASK_RUNNING);
+ spin_lock_irq(&cc->write_thread_wait.lock);
+ __remove_wait_queue(&cc->write_thread_wait, &wait);
+ goto continue_locked;
+
+pop_from_list:
+ write_tree = cc->write_tree;
+ cc->write_tree = RB_ROOT;
+ spin_unlock_irq(&cc->write_thread_wait.lock);
+
+ BUG_ON(rb_parent(write_tree.rb_node));
+
+ /*
+ * Note: we cannot walk the tree here with rb_next because
+ * the structures may be freed when kcryptd_io_write is called.
+ */
+ blk_start_plug(&plug);
+ do {
+ io = crypt_io_from_node(rb_first(&write_tree));
+ rb_erase(&io->rb_node, &write_tree);
+ kcryptd_io_write(io);
+ } while (!RB_EMPTY_ROOT(&write_tree));
+ blk_finish_plug(&plug);
+ }
+ return 0;
+}
+
static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io, int async)
{
struct bio *clone = io->ctx.bio_out;
struct crypt_config *cc = io->cc;
+ unsigned long flags;
+ sector_t sector;
+ struct rb_node **rbp, *parent;
if (unlikely(io->error < 0)) {
crypt_free_buffer_pages(cc, clone);
@@ -1182,20 +1249,34 @@
clone->bi_iter.bi_sector = cc->start + io->sector;
- if (async)
- kcryptd_queue_io(io);
- else
+ if (likely(!async) && test_bit(DM_CRYPT_NO_OFFLOAD, &cc->flags)) {
generic_make_request(clone);
+ return;
+ }
+
+ spin_lock_irqsave(&cc->write_thread_wait.lock, flags);
+ rbp = &cc->write_tree.rb_node;
+ parent = NULL;
+ sector = io->sector;
+ while (*rbp) {
+ parent = *rbp;
+ if (sector < crypt_io_from_node(parent)->sector)
+ rbp = &(*rbp)->rb_left;
+ else
+ rbp = &(*rbp)->rb_right;
+ }
+ rb_link_node(&io->rb_node, parent, rbp);
+ rb_insert_color(&io->rb_node, &cc->write_tree);
+
+ wake_up_locked(&cc->write_thread_wait);
+ spin_unlock_irqrestore(&cc->write_thread_wait.lock, flags);
}
static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
{
struct crypt_config *cc = io->cc;
struct bio *clone;
- struct dm_crypt_io *new_io;
int crypt_finished;
- unsigned out_of_pages = 0;
- unsigned remaining = io->base_bio->bi_iter.bi_size;
sector_t sector = io->sector;
int r;
@@ -1205,80 +1286,30 @@
crypt_inc_pending(io);
crypt_convert_init(cc, &io->ctx, NULL, io->base_bio, sector);
- /*
- * The allocated buffers can be smaller than the whole bio,
- * so repeat the whole process until all the data can be handled.
- */
- while (remaining) {
- clone = crypt_alloc_buffer(io, remaining, &out_of_pages);
- if (unlikely(!clone)) {
- io->error = -ENOMEM;
- break;
- }
-
- io->ctx.bio_out = clone;
- io->ctx.iter_out = clone->bi_iter;
-
- remaining -= clone->bi_iter.bi_size;
- sector += bio_sectors(clone);
-
- crypt_inc_pending(io);
-
- r = crypt_convert(cc, &io->ctx);
- if (r < 0)
- io->error = -EIO;
-
- crypt_finished = atomic_dec_and_test(&io->ctx.cc_pending);
-
- /* Encryption was already finished, submit io now */
- if (crypt_finished) {
- kcryptd_crypt_write_io_submit(io, 0);
-
- /*
- * If there was an error, do not try next fragments.
- * For async, error is processed in async handler.
- */
- if (unlikely(r < 0))
- break;
-
- io->sector = sector;
- }
-
- /*
- * Out of memory -> run queues
- * But don't wait if split was due to the io size restriction
- */
- if (unlikely(out_of_pages))
- congestion_wait(BLK_RW_ASYNC, HZ/100);
-
- /*
- * With async crypto it is unsafe to share the crypto context
- * between fragments, so switch to a new dm_crypt_io structure.
- */
- if (unlikely(!crypt_finished && remaining)) {
- new_io = mempool_alloc(cc->io_pool, GFP_NOIO);
- crypt_io_init(new_io, io->cc, io->base_bio, sector);
- crypt_inc_pending(new_io);
- crypt_convert_init(cc, &new_io->ctx, NULL,
- io->base_bio, sector);
- new_io->ctx.iter_in = io->ctx.iter_in;
-
- /*
- * Fragments after the first use the base_io
- * pending count.
- */
- if (!io->base_io)
- new_io->base_io = io;
- else {
- new_io->base_io = io->base_io;
- crypt_inc_pending(io->base_io);
- crypt_dec_pending(io);
- }
-
- io = new_io;
- }
+ clone = crypt_alloc_buffer(io, io->base_bio->bi_iter.bi_size);
+ if (unlikely(!clone)) {
+ io->error = -EIO;
+ goto dec;
}
+ io->ctx.bio_out = clone;
+ io->ctx.iter_out = clone->bi_iter;
+
+ sector += bio_sectors(clone);
+
+ crypt_inc_pending(io);
+ r = crypt_convert(cc, &io->ctx);
+ if (r)
+ io->error = -EIO;
+ crypt_finished = atomic_dec_and_test(&io->ctx.cc_pending);
+
+ /* Encryption was already finished, submit io now */
+ if (crypt_finished) {
+ kcryptd_crypt_write_io_submit(io, 0);
+ io->sector = sector;
+ }
+
+dec:
crypt_dec_pending(io);
}
@@ -1481,6 +1512,9 @@
if (!cc)
return;
+ if (cc->write_thread)
+ kthread_stop(cc->write_thread);
+
if (cc->io_queue)
destroy_workqueue(cc->io_queue);
if (cc->crypt_queue)
@@ -1495,8 +1529,6 @@
mempool_destroy(cc->page_pool);
if (cc->req_pool)
mempool_destroy(cc->req_pool);
- if (cc->io_pool)
- mempool_destroy(cc->io_pool);
if (cc->iv_gen_ops && cc->iv_gen_ops->dtr)
cc->iv_gen_ops->dtr(cc);
@@ -1688,7 +1720,7 @@
char dummy;
static struct dm_arg _args[] = {
- {0, 1, "Invalid number of feature args"},
+ {0, 3, "Invalid number of feature args"},
};
if (argc < 5) {
@@ -1710,13 +1742,6 @@
if (ret < 0)
goto bad;
- ret = -ENOMEM;
- cc->io_pool = mempool_create_slab_pool(MIN_IOS, _crypt_io_pool);
- if (!cc->io_pool) {
- ti->error = "Cannot allocate crypt io mempool";
- goto bad;
- }
-
cc->dmreq_start = sizeof(struct ablkcipher_request);
cc->dmreq_start += crypto_ablkcipher_reqsize(any_tfm(cc));
cc->dmreq_start = ALIGN(cc->dmreq_start, __alignof__(struct dm_crypt_request));
@@ -1734,6 +1759,7 @@
iv_size_padding = crypto_ablkcipher_alignmask(any_tfm(cc));
}
+ ret = -ENOMEM;
cc->req_pool = mempool_create_kmalloc_pool(MIN_IOS, cc->dmreq_start +
sizeof(struct dm_crypt_request) + iv_size_padding + cc->iv_size);
if (!cc->req_pool) {
@@ -1746,7 +1772,7 @@
sizeof(struct dm_crypt_request) + iv_size_padding + cc->iv_size,
ARCH_KMALLOC_MINALIGN);
- cc->page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0);
+ cc->page_pool = mempool_create_page_pool(BIO_MAX_PAGES, 0);
if (!cc->page_pool) {
ti->error = "Cannot allocate page mempool";
goto bad;
@@ -1758,6 +1784,8 @@
goto bad;
}
+ mutex_init(&cc->bio_alloc_lock);
+
ret = -EINVAL;
if (sscanf(argv[2], "%llu%c", &tmpll, &dummy) != 1) {
ti->error = "Invalid iv_offset sector";
@@ -1788,15 +1816,26 @@
if (ret)
goto bad;
- opt_string = dm_shift_arg(&as);
+ while (opt_params--) {
+ opt_string = dm_shift_arg(&as);
+ if (!opt_string) {
+ ti->error = "Not enough feature arguments";
+ goto bad;
+ }
- if (opt_params == 1 && opt_string &&
- !strcasecmp(opt_string, "allow_discards"))
- ti->num_discard_bios = 1;
- else if (opt_params) {
- ret = -EINVAL;
- ti->error = "Invalid feature arguments";
- goto bad;
+ if (!strcasecmp(opt_string, "allow_discards"))
+ ti->num_discard_bios = 1;
+
+ else if (!strcasecmp(opt_string, "same_cpu_crypt"))
+ set_bit(DM_CRYPT_SAME_CPU, &cc->flags);
+
+ else if (!strcasecmp(opt_string, "submit_from_crypt_cpus"))
+ set_bit(DM_CRYPT_NO_OFFLOAD, &cc->flags);
+
+ else {
+ ti->error = "Invalid feature arguments";
+ goto bad;
+ }
}
}
@@ -1807,13 +1846,28 @@
goto bad;
}
- cc->crypt_queue = alloc_workqueue("kcryptd",
- WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 1);
+ if (test_bit(DM_CRYPT_SAME_CPU, &cc->flags))
+ cc->crypt_queue = alloc_workqueue("kcryptd", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 1);
+ else
+ cc->crypt_queue = alloc_workqueue("kcryptd", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_UNBOUND,
+ num_online_cpus());
if (!cc->crypt_queue) {
ti->error = "Couldn't create kcryptd queue";
goto bad;
}
+ init_waitqueue_head(&cc->write_thread_wait);
+ cc->write_tree = RB_ROOT;
+
+ cc->write_thread = kthread_create(dmcrypt_write, cc, "dmcrypt_write");
+ if (IS_ERR(cc->write_thread)) {
+ ret = PTR_ERR(cc->write_thread);
+ cc->write_thread = NULL;
+ ti->error = "Couldn't spawn write thread";
+ goto bad;
+ }
+ wake_up_process(cc->write_thread);
+
ti->num_flush_bios = 1;
ti->discard_zeroes_data_unsupported = true;
@@ -1848,7 +1902,7 @@
if (bio_data_dir(io->base_bio) == READ) {
if (kcryptd_io_read(io, GFP_NOWAIT))
- kcryptd_queue_io(io);
+ kcryptd_queue_read(io);
} else
kcryptd_queue_crypt(io);
@@ -1860,6 +1914,7 @@
{
struct crypt_config *cc = ti->private;
unsigned i, sz = 0;
+ int num_feature_args = 0;
switch (type) {
case STATUSTYPE_INFO:
@@ -1878,8 +1933,18 @@
DMEMIT(" %llu %s %llu", (unsigned long long)cc->iv_offset,
cc->dev->name, (unsigned long long)cc->start);
- if (ti->num_discard_bios)
- DMEMIT(" 1 allow_discards");
+ num_feature_args += !!ti->num_discard_bios;
+ num_feature_args += test_bit(DM_CRYPT_SAME_CPU, &cc->flags);
+ num_feature_args += test_bit(DM_CRYPT_NO_OFFLOAD, &cc->flags);
+ if (num_feature_args) {
+ DMEMIT(" %d", num_feature_args);
+ if (ti->num_discard_bios)
+ DMEMIT(" allow_discards");
+ if (test_bit(DM_CRYPT_SAME_CPU, &cc->flags))
+ DMEMIT(" same_cpu_crypt");
+ if (test_bit(DM_CRYPT_NO_OFFLOAD, &cc->flags))
+ DMEMIT(" submit_from_crypt_cpus");
+ }
break;
}
@@ -1976,7 +2041,7 @@
static struct target_type crypt_target = {
.name = "crypt",
- .version = {1, 13, 0},
+ .version = {1, 14, 0},
.module = THIS_MODULE,
.ctr = crypt_ctr,
.dtr = crypt_dtr,
@@ -1994,15 +2059,9 @@
{
int r;
- _crypt_io_pool = KMEM_CACHE(dm_crypt_io, 0);
- if (!_crypt_io_pool)
- return -ENOMEM;
-
r = dm_register_target(&crypt_target);
- if (r < 0) {
+ if (r < 0)
DMERR("register failed %d", r);
- kmem_cache_destroy(_crypt_io_pool);
- }
return r;
}
@@ -2010,7 +2069,6 @@
static void __exit dm_crypt_exit(void)
{
dm_unregister_target(&crypt_target);
- kmem_cache_destroy(_crypt_io_pool);
}
module_init(dm_crypt_init);
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index c09359d..37de017 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -290,6 +290,12 @@
unsigned short logical_block_size = queue_logical_block_size(q);
sector_t num_sectors;
+ /* Reject unsupported discard requests */
+ if ((rw & REQ_DISCARD) && !blk_queue_discard(q)) {
+ dec_count(io, region, -EOPNOTSUPP);
+ return;
+ }
+
/*
* where->count may be zero if rw holds a flush and we need to
* send a zero-sized flush.
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 7dfdb5c..089d627 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -604,6 +604,15 @@
return;
}
+ /*
+ * If the bio is discard, return an error, but do not
+ * degrade the array.
+ */
+ if (bio->bi_rw & REQ_DISCARD) {
+ bio_endio(bio, -EOPNOTSUPP);
+ return;
+ }
+
for (i = 0; i < ms->nr_mirrors; i++)
if (test_bit(i, &error))
fail_mirror(ms->mirror + i, DM_RAID1_WRITE_ERROR);
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 864b03f..8b204ae2 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -1432,8 +1432,6 @@
full_bio->bi_private = pe->full_bio_private;
atomic_inc(&full_bio->bi_remaining);
}
- free_pending_exception(pe);
-
increment_pending_exceptions_done_count();
up_write(&s->lock);
@@ -1450,6 +1448,8 @@
}
retry_origin_bios(s, origin_bios);
+
+ free_pending_exception(pe);
}
static void commit_callback(void *context, int success)
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index ec1444f..73f2880 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -2571,7 +2571,7 @@
return 0;
}
-static struct mapped_device *dm_find_md(dev_t dev)
+struct mapped_device *dm_get_md(dev_t dev)
{
struct mapped_device *md;
unsigned minor = MINOR(dev);
@@ -2582,12 +2582,15 @@
spin_lock(&_minor_lock);
md = idr_find(&_minor_idr, minor);
- if (md && (md == MINOR_ALLOCED ||
- (MINOR(disk_devt(dm_disk(md))) != minor) ||
- dm_deleting_md(md) ||
- test_bit(DMF_FREEING, &md->flags))) {
- md = NULL;
- goto out;
+ if (md) {
+ if ((md == MINOR_ALLOCED ||
+ (MINOR(disk_devt(dm_disk(md))) != minor) ||
+ dm_deleting_md(md) ||
+ test_bit(DMF_FREEING, &md->flags))) {
+ md = NULL;
+ goto out;
+ }
+ dm_get(md);
}
out:
@@ -2595,16 +2598,6 @@
return md;
}
-
-struct mapped_device *dm_get_md(dev_t dev)
-{
- struct mapped_device *md = dm_find_md(dev);
-
- if (md)
- dm_get(md);
-
- return md;
-}
EXPORT_SYMBOL_GPL(dm_get_md);
void *dm_get_mdptr(struct mapped_device *md)
diff --git a/drivers/md/persistent-data/dm-space-map-disk.c b/drivers/md/persistent-data/dm-space-map-disk.c
index cfbf961..ebb280a 100644
--- a/drivers/md/persistent-data/dm-space-map-disk.c
+++ b/drivers/md/persistent-data/dm-space-map-disk.c
@@ -78,7 +78,9 @@
if (r)
return r;
- return count > 1;
+ *result = count > 1;
+
+ return 0;
}
static int sm_disk_set_count(struct dm_space_map *sm, dm_block_t b,
diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
index 6af0a28..e8a4218 100644
--- a/drivers/mmc/host/sunxi-mmc.c
+++ b/drivers/mmc/host/sunxi-mmc.c
@@ -21,8 +21,6 @@
#include <linux/err.h>
#include <linux/clk.h>
-#include <linux/clk/sunxi.h>
-
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
@@ -229,6 +227,8 @@
/* clock management */
struct clk *clk_ahb;
struct clk *clk_mmc;
+ struct clk *clk_sample;
+ struct clk *clk_output;
/* irq */
spinlock_t lock;
@@ -653,26 +653,31 @@
/* determine delays */
if (rate <= 400000) {
- oclk_dly = 0;
- sclk_dly = 7;
+ oclk_dly = 180;
+ sclk_dly = 42;
} else if (rate <= 25000000) {
- oclk_dly = 0;
- sclk_dly = 5;
+ oclk_dly = 180;
+ sclk_dly = 75;
} else if (rate <= 50000000) {
if (ios->timing == MMC_TIMING_UHS_DDR50) {
- oclk_dly = 2;
- sclk_dly = 4;
+ oclk_dly = 60;
+ sclk_dly = 120;
} else {
- oclk_dly = 3;
- sclk_dly = 5;
+ oclk_dly = 90;
+ sclk_dly = 150;
}
+ } else if (rate <= 100000000) {
+ oclk_dly = 6;
+ sclk_dly = 24;
+ } else if (rate <= 200000000) {
+ oclk_dly = 3;
+ sclk_dly = 12;
} else {
- /* rate > 50000000 */
- oclk_dly = 2;
- sclk_dly = 4;
+ return -EINVAL;
}
- clk_sunxi_mmc_phase_control(host->clk_mmc, sclk_dly, oclk_dly);
+ clk_set_phase(host->clk_sample, sclk_dly);
+ clk_set_phase(host->clk_output, oclk_dly);
return sunxi_mmc_oclk_onoff(host, 1);
}
@@ -913,6 +918,18 @@
return PTR_ERR(host->clk_mmc);
}
+ host->clk_output = devm_clk_get(&pdev->dev, "output");
+ if (IS_ERR(host->clk_output)) {
+ dev_err(&pdev->dev, "Could not get output clock\n");
+ return PTR_ERR(host->clk_output);
+ }
+
+ host->clk_sample = devm_clk_get(&pdev->dev, "sample");
+ if (IS_ERR(host->clk_sample)) {
+ dev_err(&pdev->dev, "Could not get sample clock\n");
+ return PTR_ERR(host->clk_sample);
+ }
+
host->reset = devm_reset_control_get(&pdev->dev, "ahb");
ret = clk_prepare_enable(host->clk_ahb);
@@ -927,11 +944,23 @@
goto error_disable_clk_ahb;
}
+ ret = clk_prepare_enable(host->clk_output);
+ if (ret) {
+ dev_err(&pdev->dev, "Enable output clk err %d\n", ret);
+ goto error_disable_clk_mmc;
+ }
+
+ ret = clk_prepare_enable(host->clk_sample);
+ if (ret) {
+ dev_err(&pdev->dev, "Enable sample clk err %d\n", ret);
+ goto error_disable_clk_output;
+ }
+
if (!IS_ERR(host->reset)) {
ret = reset_control_deassert(host->reset);
if (ret) {
dev_err(&pdev->dev, "reset err %d\n", ret);
- goto error_disable_clk_mmc;
+ goto error_disable_clk_sample;
}
}
@@ -950,6 +979,10 @@
error_assert_reset:
if (!IS_ERR(host->reset))
reset_control_assert(host->reset);
+error_disable_clk_sample:
+ clk_disable_unprepare(host->clk_sample);
+error_disable_clk_output:
+ clk_disable_unprepare(host->clk_output);
error_disable_clk_mmc:
clk_disable_unprepare(host->clk_mmc);
error_disable_clk_ahb:
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 638e7970..9752761 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -735,6 +735,31 @@
functionality. If in doubt, say Y here; it will only load on
supported platforms.
+config INTEL_IMR
+ bool "Intel Isolated Memory Region support"
+ default n
+ depends on X86_INTEL_QUARK && IOSF_MBI
+ ---help---
+ This option provides a means to manipulate Isolated Memory Regions.
+ IMRs are a set of registers that define read and write access masks
+ to prohibit certain system agents from accessing memory with 1 KiB
+ granularity.
+
+ IMRs make it possible to control read/write access to an address
+ by hardware agents inside the SoC. Read and write masks can be
+ defined for:
+ - eSRAM flush
+ - Dirty CPU snoop (write only)
+ - RMU access
+ - PCI Virtual Channel 0/Virtual Channel 1
+ - SMM mode
+ - Non SMM mode
+
+ Quark contains a set of eight IMR registers and makes use of those
+ registers during its bootup process.
+
+ If you are running on a Galileo/Quark say Y here.
+
config IBM_RTL
tristate "Device driver to enable PRTL support"
depends on X86 && PCI
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 73f9fee..99f43b7 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -1570,9 +1570,7 @@
* match the format by tcm_qla2xxx explict ConfigFS NodeACLs.
*/
memset(&port_name, 0, 36);
- snprintf(port_name, 36, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
- fc_wwpn[0], fc_wwpn[1], fc_wwpn[2], fc_wwpn[3], fc_wwpn[4],
- fc_wwpn[5], fc_wwpn[6], fc_wwpn[7]);
+ snprintf(port_name, sizeof(port_name), "%8phC", fc_wwpn);
/*
* Locate our struct se_node_acl either from an explict NodeACL created
* via ConfigFS, or via running in TPG demo mode.
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index aebde32..50bad55 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -30,7 +30,7 @@
#include <target/target_core_fabric.h>
#include <target/target_core_configfs.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_parameters.h"
#include "iscsi_target_seq_pdu_list.h"
#include "iscsi_target_tq.h"
@@ -45,7 +45,7 @@
#include "iscsi_target_util.h"
#include "iscsi_target.h"
#include "iscsi_target_device.h"
-#include "iscsi_target_stat.h"
+#include <target/iscsi/iscsi_target_stat.h>
#include <target/iscsi/iscsi_transport.h>
@@ -968,11 +968,7 @@
conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt;
if (hdr->flags & ISCSI_FLAG_CMD_READ) {
- spin_lock_bh(&conn->sess->ttt_lock);
- cmd->targ_xfer_tag = conn->sess->targ_xfer_tag++;
- if (cmd->targ_xfer_tag == 0xFFFFFFFF)
- cmd->targ_xfer_tag = conn->sess->targ_xfer_tag++;
- spin_unlock_bh(&conn->sess->ttt_lock);
+ cmd->targ_xfer_tag = session_get_next_ttt(conn->sess);
} else if (hdr->flags & ISCSI_FLAG_CMD_WRITE)
cmd->targ_xfer_tag = 0xFFFFFFFF;
cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
@@ -1998,6 +1994,7 @@
cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
cmd->data_direction = DMA_NONE;
+ cmd->text_in_ptr = NULL;
return 0;
}
@@ -2011,9 +2008,13 @@
int cmdsn_ret;
if (!text_in) {
- pr_err("Unable to locate text_in buffer for sendtargets"
- " discovery\n");
- goto reject;
+ cmd->targ_xfer_tag = be32_to_cpu(hdr->ttt);
+ if (cmd->targ_xfer_tag == 0xFFFFFFFF) {
+ pr_err("Unable to locate text_in buffer for sendtargets"
+ " discovery\n");
+ goto reject;
+ }
+ goto empty_sendtargets;
}
if (strncmp("SendTargets", text_in, 11) != 0) {
pr_err("Received Text Data that is not"
@@ -2040,6 +2041,7 @@
list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
spin_unlock_bh(&conn->cmd_lock);
+empty_sendtargets:
iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
@@ -3047,11 +3049,7 @@
int_to_scsilun(cmd->se_cmd.orig_fe_lun,
(struct scsi_lun *)&hdr->lun);
hdr->itt = cmd->init_task_tag;
- spin_lock_bh(&conn->sess->ttt_lock);
- r2t->targ_xfer_tag = conn->sess->targ_xfer_tag++;
- if (r2t->targ_xfer_tag == 0xFFFFFFFF)
- r2t->targ_xfer_tag = conn->sess->targ_xfer_tag++;
- spin_unlock_bh(&conn->sess->ttt_lock);
+ r2t->targ_xfer_tag = session_get_next_ttt(conn->sess);
hdr->ttt = cpu_to_be32(r2t->targ_xfer_tag);
hdr->statsn = cpu_to_be32(conn->stat_sn);
hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
@@ -3393,7 +3391,8 @@
static int
iscsit_build_sendtargets_response(struct iscsi_cmd *cmd,
- enum iscsit_transport_type network_transport)
+ enum iscsit_transport_type network_transport,
+ int skip_bytes, bool *completed)
{
char *payload = NULL;
struct iscsi_conn *conn = cmd->conn;
@@ -3405,7 +3404,7 @@
unsigned char buf[ISCSI_IQN_LEN+12]; /* iqn + "TargetName=" + \0 */
unsigned char *text_in = cmd->text_in_ptr, *text_ptr = NULL;
- buffer_len = max(conn->conn_ops->MaxRecvDataSegmentLength,
+ buffer_len = min(conn->conn_ops->MaxRecvDataSegmentLength,
SENDTARGETS_BUF_LIMIT);
payload = kzalloc(buffer_len, GFP_KERNEL);
@@ -3484,9 +3483,16 @@
end_of_buf = 1;
goto eob;
}
- memcpy(payload + payload_len, buf, len);
- payload_len += len;
- target_name_printed = 1;
+
+ if (skip_bytes && len <= skip_bytes) {
+ skip_bytes -= len;
+ } else {
+ memcpy(payload + payload_len, buf, len);
+ payload_len += len;
+ target_name_printed = 1;
+ if (len > skip_bytes)
+ skip_bytes = 0;
+ }
}
len = sprintf(buf, "TargetAddress="
@@ -3502,15 +3508,24 @@
end_of_buf = 1;
goto eob;
}
- memcpy(payload + payload_len, buf, len);
- payload_len += len;
+
+ if (skip_bytes && len <= skip_bytes) {
+ skip_bytes -= len;
+ } else {
+ memcpy(payload + payload_len, buf, len);
+ payload_len += len;
+ if (len > skip_bytes)
+ skip_bytes = 0;
+ }
}
spin_unlock(&tpg->tpg_np_lock);
}
spin_unlock(&tiqn->tiqn_tpg_lock);
eob:
- if (end_of_buf)
+ if (end_of_buf) {
+ *completed = false;
break;
+ }
if (cmd->cmd_flags & ICF_SENDTARGETS_SINGLE)
break;
@@ -3528,13 +3543,23 @@
enum iscsit_transport_type network_transport)
{
int text_length, padding;
+ bool completed = true;
- text_length = iscsit_build_sendtargets_response(cmd, network_transport);
+ text_length = iscsit_build_sendtargets_response(cmd, network_transport,
+ cmd->read_data_done,
+ &completed);
if (text_length < 0)
return text_length;
+ if (completed) {
+ hdr->flags |= ISCSI_FLAG_CMD_FINAL;
+ } else {
+ hdr->flags |= ISCSI_FLAG_TEXT_CONTINUE;
+ cmd->read_data_done += text_length;
+ if (cmd->targ_xfer_tag == 0xFFFFFFFF)
+ cmd->targ_xfer_tag = session_get_next_ttt(conn->sess);
+ }
hdr->opcode = ISCSI_OP_TEXT_RSP;
- hdr->flags |= ISCSI_FLAG_CMD_FINAL;
padding = ((-text_length) & 3);
hton24(hdr->dlength, text_length);
hdr->itt = cmd->init_task_tag;
@@ -3543,21 +3568,25 @@
hdr->statsn = cpu_to_be32(cmd->stat_sn);
iscsit_increment_maxcmdsn(cmd, conn->sess);
+ /*
+ * Reset maxcmdsn_inc in multi-part text payload exchanges to
+ * correctly increment MaxCmdSN for each response answering a
+ * non immediate text request with a valid CmdSN.
+ */
+ cmd->maxcmdsn_inc = 0;
hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
- pr_debug("Built Text Response: ITT: 0x%08x, StatSN: 0x%08x,"
- " Length: %u, CID: %hu\n", cmd->init_task_tag, cmd->stat_sn,
- text_length, conn->cid);
+ pr_debug("Built Text Response: ITT: 0x%08x, TTT: 0x%08x, StatSN: 0x%08x,"
+ " Length: %u, CID: %hu F: %d C: %d\n", cmd->init_task_tag,
+ cmd->targ_xfer_tag, cmd->stat_sn, text_length, conn->cid,
+ !!(hdr->flags & ISCSI_FLAG_CMD_FINAL),
+ !!(hdr->flags & ISCSI_FLAG_TEXT_CONTINUE));
return text_length + padding;
}
EXPORT_SYMBOL(iscsit_build_text_rsp);
-/*
- * FIXME: Add support for F_BIT and C_BIT when the length is longer than
- * MaxRecvDataSegmentLength.
- */
static int iscsit_send_text_rsp(
struct iscsi_cmd *cmd,
struct iscsi_conn *conn)
@@ -4021,9 +4050,15 @@
ret = iscsit_handle_task_mgt_cmd(conn, cmd, buf);
break;
case ISCSI_OP_TEXT:
- cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
- if (!cmd)
- goto reject;
+ if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) {
+ cmd = iscsit_find_cmd_from_itt(conn, hdr->itt);
+ if (!cmd)
+ goto reject;
+ } else {
+ cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
+ if (!cmd)
+ goto reject;
+ }
ret = iscsit_handle_text_cmd(conn, cmd, buf);
break;
diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c
index ab4915c..47e249d 100644
--- a/drivers/target/iscsi/iscsi_target_auth.c
+++ b/drivers/target/iscsi/iscsi_target_auth.c
@@ -22,7 +22,7 @@
#include <linux/err.h>
#include <linux/scatterlist.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_nego.h"
#include "iscsi_target_auth.h"
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index 9059c1e..48384b6 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -28,7 +28,7 @@
#include <target/configfs_macros.h>
#include <target/iscsi/iscsi_transport.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_parameters.h"
#include "iscsi_target_device.h"
#include "iscsi_target_erl0.h"
@@ -36,7 +36,7 @@
#include "iscsi_target_tpg.h"
#include "iscsi_target_util.h"
#include "iscsi_target.h"
-#include "iscsi_target_stat.h"
+#include <target/iscsi/iscsi_target_stat.h>
#include "iscsi_target_configfs.h"
struct target_fabric_configfs *lio_target_fabric_configfs;
@@ -674,12 +674,9 @@
rb += sprintf(page+rb, "InitiatorAlias: %s\n",
sess->sess_ops->InitiatorAlias);
- rb += sprintf(page+rb, "LIO Session ID: %u "
- "ISID: 0x%02x %02x %02x %02x %02x %02x "
- "TSIH: %hu ", sess->sid,
- sess->isid[0], sess->isid[1], sess->isid[2],
- sess->isid[3], sess->isid[4], sess->isid[5],
- sess->tsih);
+ rb += sprintf(page+rb,
+ "LIO Session ID: %u ISID: 0x%6ph TSIH: %hu ",
+ sess->sid, sess->isid, sess->tsih);
rb += sprintf(page+rb, "SessionType: %s\n",
(sess->sess_ops->SessionType) ?
"Discovery" : "Normal");
@@ -1758,9 +1755,7 @@
/*
* iSCSI Initiator Session Identifier from RFC-3720.
*/
- return snprintf(buf, size, "%02x%02x%02x%02x%02x%02x",
- sess->isid[0], sess->isid[1], sess->isid[2],
- sess->isid[3], sess->isid[4], sess->isid[5]);
+ return snprintf(buf, size, "%6phN", sess->isid);
}
static int lio_queue_data_in(struct se_cmd *se_cmd)
diff --git a/drivers/target/iscsi/iscsi_target_datain_values.c b/drivers/target/iscsi/iscsi_target_datain_values.c
index e93d5a7..fb3b52b 100644
--- a/drivers/target/iscsi/iscsi_target_datain_values.c
+++ b/drivers/target/iscsi/iscsi_target_datain_values.c
@@ -18,7 +18,7 @@
#include <scsi/iscsi_proto.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_seq_pdu_list.h"
#include "iscsi_target_erl1.h"
#include "iscsi_target_util.h"
diff --git a/drivers/target/iscsi/iscsi_target_device.c b/drivers/target/iscsi/iscsi_target_device.c
index 7087c73..34c3cd1 100644
--- a/drivers/target/iscsi/iscsi_target_device.c
+++ b/drivers/target/iscsi/iscsi_target_device.c
@@ -21,7 +21,7 @@
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_device.h"
#include "iscsi_target_tpg.h"
#include "iscsi_target_util.h"
diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c
index a0ae5fc..1c197ba 100644
--- a/drivers/target/iscsi/iscsi_target_erl0.c
+++ b/drivers/target/iscsi/iscsi_target_erl0.c
@@ -21,7 +21,8 @@
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
+#include <target/iscsi/iscsi_transport.h>
#include "iscsi_target_seq_pdu_list.h"
#include "iscsi_target_tq.h"
#include "iscsi_target_erl0.h"
@@ -939,7 +940,8 @@
if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) {
spin_unlock_bh(&conn->state_lock);
- iscsit_close_connection(conn);
+ if (conn->conn_transport->transport_type == ISCSI_TCP)
+ iscsit_close_connection(conn);
return;
}
diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c
index cda4d80..2e561de 100644
--- a/drivers/target/iscsi/iscsi_target_erl1.c
+++ b/drivers/target/iscsi/iscsi_target_erl1.c
@@ -22,7 +22,7 @@
#include <target/target_core_fabric.h>
#include <target/iscsi/iscsi_transport.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_seq_pdu_list.h"
#include "iscsi_target_datain_values.h"
#include "iscsi_target_device.h"
diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c
index 4ca8fd2..e24f1c7 100644
--- a/drivers/target/iscsi/iscsi_target_erl2.c
+++ b/drivers/target/iscsi/iscsi_target_erl2.c
@@ -21,7 +21,7 @@
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_datain_values.h"
#include "iscsi_target_util.h"
#include "iscsi_target_erl0.h"
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index 713c0c1..153fb66 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -24,14 +24,14 @@
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
+#include <target/iscsi/iscsi_target_stat.h>
#include "iscsi_target_tq.h"
#include "iscsi_target_device.h"
#include "iscsi_target_nego.h"
#include "iscsi_target_erl0.h"
#include "iscsi_target_erl2.h"
#include "iscsi_target_login.h"
-#include "iscsi_target_stat.h"
#include "iscsi_target_tpg.h"
#include "iscsi_target_util.h"
#include "iscsi_target.h"
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
index 62a095f..8c02fa3 100644
--- a/drivers/target/iscsi/iscsi_target_nego.c
+++ b/drivers/target/iscsi/iscsi_target_nego.c
@@ -22,7 +22,7 @@
#include <target/target_core_fabric.h>
#include <target/iscsi/iscsi_transport.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_parameters.h"
#include "iscsi_target_login.h"
#include "iscsi_target_nego.h"
diff --git a/drivers/target/iscsi/iscsi_target_nodeattrib.c b/drivers/target/iscsi/iscsi_target_nodeattrib.c
index 16454a9..208cca8 100644
--- a/drivers/target/iscsi/iscsi_target_nodeattrib.c
+++ b/drivers/target/iscsi/iscsi_target_nodeattrib.c
@@ -18,7 +18,7 @@
#include <target/target_core_base.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_device.h"
#include "iscsi_target_tpg.h"
#include "iscsi_target_util.h"
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index 18c2926..d4f9e96 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -18,7 +18,7 @@
#include <linux/slab.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_util.h"
#include "iscsi_target_parameters.h"
diff --git a/drivers/target/iscsi/iscsi_target_seq_pdu_list.c b/drivers/target/iscsi/iscsi_target_seq_pdu_list.c
index ca41b58..e446a09 100644
--- a/drivers/target/iscsi/iscsi_target_seq_pdu_list.c
+++ b/drivers/target/iscsi/iscsi_target_seq_pdu_list.c
@@ -20,7 +20,7 @@
#include <linux/slab.h>
#include <linux/random.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_util.h"
#include "iscsi_target_tpg.h"
#include "iscsi_target_seq_pdu_list.h"
diff --git a/drivers/target/iscsi/iscsi_target_stat.c b/drivers/target/iscsi/iscsi_target_stat.c
index 1033955..5e1349a 100644
--- a/drivers/target/iscsi/iscsi_target_stat.c
+++ b/drivers/target/iscsi/iscsi_target_stat.c
@@ -23,12 +23,12 @@
#include <target/target_core_base.h>
#include <target/configfs_macros.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_parameters.h"
#include "iscsi_target_device.h"
#include "iscsi_target_tpg.h"
#include "iscsi_target_util.h"
-#include "iscsi_target_stat.h"
+#include <target/iscsi/iscsi_target_stat.h>
#ifndef INITIAL_JIFFIES
#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ))
diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c
index 78404b1..b0224a7 100644
--- a/drivers/target/iscsi/iscsi_target_tmr.c
+++ b/drivers/target/iscsi/iscsi_target_tmr.c
@@ -23,7 +23,7 @@
#include <target/target_core_fabric.h>
#include <target/iscsi/iscsi_transport.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_seq_pdu_list.h"
#include "iscsi_target_datain_values.h"
#include "iscsi_target_device.h"
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c
index 9053a3c..bdd127c 100644
--- a/drivers/target/iscsi/iscsi_target_tpg.c
+++ b/drivers/target/iscsi/iscsi_target_tpg.c
@@ -20,7 +20,7 @@
#include <target/target_core_fabric.h>
#include <target/target_core_configfs.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_erl0.h"
#include "iscsi_target_login.h"
#include "iscsi_target_nodeattrib.h"
diff --git a/drivers/target/iscsi/iscsi_target_tq.c b/drivers/target/iscsi/iscsi_target_tq.c
index 601e9cc..26aa509 100644
--- a/drivers/target/iscsi/iscsi_target_tq.c
+++ b/drivers/target/iscsi/iscsi_target_tq.c
@@ -20,40 +20,26 @@
#include <linux/list.h>
#include <linux/bitmap.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_tq.h"
#include "iscsi_target.h"
-static LIST_HEAD(active_ts_list);
static LIST_HEAD(inactive_ts_list);
-static DEFINE_SPINLOCK(active_ts_lock);
static DEFINE_SPINLOCK(inactive_ts_lock);
static DEFINE_SPINLOCK(ts_bitmap_lock);
-static void iscsi_add_ts_to_active_list(struct iscsi_thread_set *ts)
-{
- spin_lock(&active_ts_lock);
- list_add_tail(&ts->ts_list, &active_ts_list);
- iscsit_global->active_ts++;
- spin_unlock(&active_ts_lock);
-}
-
static void iscsi_add_ts_to_inactive_list(struct iscsi_thread_set *ts)
{
+ if (!list_empty(&ts->ts_list)) {
+ WARN_ON(1);
+ return;
+ }
spin_lock(&inactive_ts_lock);
list_add_tail(&ts->ts_list, &inactive_ts_list);
iscsit_global->inactive_ts++;
spin_unlock(&inactive_ts_lock);
}
-static void iscsi_del_ts_from_active_list(struct iscsi_thread_set *ts)
-{
- spin_lock(&active_ts_lock);
- list_del(&ts->ts_list);
- iscsit_global->active_ts--;
- spin_unlock(&active_ts_lock);
-}
-
static struct iscsi_thread_set *iscsi_get_ts_from_inactive_list(void)
{
struct iscsi_thread_set *ts;
@@ -66,7 +52,7 @@
ts = list_first_entry(&inactive_ts_list, struct iscsi_thread_set, ts_list);
- list_del(&ts->ts_list);
+ list_del_init(&ts->ts_list);
iscsit_global->inactive_ts--;
spin_unlock(&inactive_ts_lock);
@@ -204,8 +190,6 @@
void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set *ts)
{
- iscsi_add_ts_to_active_list(ts);
-
spin_lock_bh(&ts->ts_state_lock);
conn->thread_set = ts;
ts->conn = conn;
@@ -397,7 +381,6 @@
if (ts->delay_inactive && (--ts->thread_count == 0)) {
spin_unlock_bh(&ts->ts_state_lock);
- iscsi_del_ts_from_active_list(ts);
if (!iscsit_global->in_shutdown)
iscsi_deallocate_extra_thread_sets();
@@ -452,7 +435,6 @@
if (ts->delay_inactive && (--ts->thread_count == 0)) {
spin_unlock_bh(&ts->ts_state_lock);
- iscsi_del_ts_from_active_list(ts);
if (!iscsit_global->in_shutdown)
iscsi_deallocate_extra_thread_sets();
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index bcd88ec..390df8e 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -25,7 +25,7 @@
#include <target/target_core_configfs.h>
#include <target/iscsi/iscsi_transport.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_parameters.h"
#include "iscsi_target_seq_pdu_list.h"
#include "iscsi_target_datain_values.h"
@@ -390,6 +390,7 @@
init_task_tag, conn->cid);
return NULL;
}
+EXPORT_SYMBOL(iscsit_find_cmd_from_itt);
struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(
struct iscsi_conn *conn,
@@ -939,13 +940,8 @@
state = (want_response) ? ISTATE_SEND_NOPIN_WANT_RESPONSE :
ISTATE_SEND_NOPIN_NO_RESPONSE;
cmd->init_task_tag = RESERVED_ITT;
- spin_lock_bh(&conn->sess->ttt_lock);
- cmd->targ_xfer_tag = (want_response) ? conn->sess->targ_xfer_tag++ :
- 0xFFFFFFFF;
- if (want_response && (cmd->targ_xfer_tag == 0xFFFFFFFF))
- cmd->targ_xfer_tag = conn->sess->targ_xfer_tag++;
- spin_unlock_bh(&conn->sess->ttt_lock);
-
+ cmd->targ_xfer_tag = (want_response) ?
+ session_get_next_ttt(conn->sess) : 0xFFFFFFFF;
spin_lock_bh(&conn->cmd_lock);
list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
spin_unlock_bh(&conn->cmd_lock);
diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h
index a68508c..1ab754a 100644
--- a/drivers/target/iscsi/iscsi_target_util.h
+++ b/drivers/target/iscsi/iscsi_target_util.h
@@ -16,7 +16,6 @@
extern int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
unsigned char * ,__be32 cmdsn);
extern int iscsit_check_unsolicited_dataout(struct iscsi_cmd *, unsigned char *);
-extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, itt_t);
extern struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(struct iscsi_conn *,
itt_t, u32);
extern struct iscsi_cmd *iscsit_find_cmd_from_ttt(struct iscsi_conn *, u32);
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index d836de2..44620fb 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -494,6 +494,11 @@
target_complete_cmd(cmd, SAM_STAT_GOOD);
return 0;
}
+ if (cmd->prot_op) {
+ pr_err("WRITE_SAME: Protection information with FILEIO"
+ " backends not supported\n");
+ return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ }
sg = &cmd->t_data_sg[0];
if (cmd->t_data_nents > 1 ||
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index 78346b8..d4a4b0f 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -464,6 +464,11 @@
sector_t block_lba = cmd->t_task_lba;
sector_t sectors = sbc_get_write_same_sectors(cmd);
+ if (cmd->prot_op) {
+ pr_err("WRITE_SAME: Protection information with IBLOCK"
+ " backends not supported\n");
+ return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ }
sg = &cmd->t_data_sg[0];
if (cmd->t_data_nents > 1 ||
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 283cf78..2de6fb8 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -1874,8 +1874,8 @@
}
if ((len + strlen(tmp) >= pr_aptpl_buf_len)) {
- pr_err("Unable to update renaming"
- " APTPL metadata\n");
+ pr_err("Unable to update renaming APTPL metadata,"
+ " reallocating larger buffer\n");
ret = -EMSGSIZE;
goto out;
}
@@ -1892,8 +1892,8 @@
lun->lun_sep->sep_rtpi, lun->unpacked_lun, reg_count);
if ((len + strlen(tmp) >= pr_aptpl_buf_len)) {
- pr_err("Unable to update renaming"
- " APTPL metadata\n");
+ pr_err("Unable to update renaming APTPL metadata,"
+ " reallocating larger buffer\n");
ret = -EMSGSIZE;
goto out;
}
@@ -1956,7 +1956,7 @@
static sense_reason_t core_scsi3_update_and_write_aptpl(struct se_device *dev, bool aptpl)
{
unsigned char *buf;
- int rc;
+ int rc, len = PR_APTPL_BUF_LEN;
if (!aptpl) {
char *null_buf = "No Registrations or Reservations\n";
@@ -1970,25 +1970,26 @@
return 0;
}
-
- buf = kzalloc(PR_APTPL_BUF_LEN, GFP_KERNEL);
+retry:
+ buf = vzalloc(len);
if (!buf)
return TCM_OUT_OF_RESOURCES;
- rc = core_scsi3_update_aptpl_buf(dev, buf, PR_APTPL_BUF_LEN);
+ rc = core_scsi3_update_aptpl_buf(dev, buf, len);
if (rc < 0) {
- kfree(buf);
- return TCM_OUT_OF_RESOURCES;
+ vfree(buf);
+ len *= 2;
+ goto retry;
}
rc = __core_scsi3_write_aptpl_to_file(dev, buf);
if (rc != 0) {
pr_err("SPC-3 PR: Could not update APTPL\n");
- kfree(buf);
+ vfree(buf);
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
dev->t10_pr.pr_aptpl_active = 1;
- kfree(buf);
+ vfree(buf);
pr_debug("SPC-3 PR: Set APTPL Bit Activated\n");
return 0;
}
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index cd4bed7..9a2f9d3 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -37,6 +37,9 @@
#include "target_core_alua.h"
static sense_reason_t
+sbc_check_prot(struct se_device *, struct se_cmd *, unsigned char *, u32, bool);
+
+static sense_reason_t
sbc_emulate_readcapacity(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
@@ -251,7 +254,10 @@
static sense_reason_t
sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *ops)
{
+ struct se_device *dev = cmd->se_dev;
+ sector_t end_lba = dev->transport->get_blocks(dev) + 1;
unsigned int sectors = sbc_get_write_same_sectors(cmd);
+ sense_reason_t ret;
if ((flags[0] & 0x04) || (flags[0] & 0x02)) {
pr_err("WRITE_SAME PBDATA and LBDATA"
@@ -264,6 +270,16 @@
sectors, cmd->se_dev->dev_attrib.max_write_same_len);
return TCM_INVALID_CDB_FIELD;
}
+ /*
+ * Sanity check for LBA wrap and request past end of device.
+ */
+ if (((cmd->t_task_lba + sectors) < cmd->t_task_lba) ||
+ ((cmd->t_task_lba + sectors) > end_lba)) {
+ pr_err("WRITE_SAME exceeds last lba %llu (lba %llu, sectors %u)\n",
+ (unsigned long long)end_lba, cmd->t_task_lba, sectors);
+ return TCM_ADDRESS_OUT_OF_RANGE;
+ }
+
/* We always have ANC_SUP == 0 so setting ANCHOR is always an error */
if (flags[0] & 0x10) {
pr_warn("WRITE SAME with ANCHOR not supported\n");
@@ -277,12 +293,21 @@
if (!ops->execute_write_same_unmap)
return TCM_UNSUPPORTED_SCSI_OPCODE;
+ if (!dev->dev_attrib.emulate_tpws) {
+ pr_err("Got WRITE_SAME w/ UNMAP=1, but backend device"
+ " has emulate_tpws disabled\n");
+ return TCM_UNSUPPORTED_SCSI_OPCODE;
+ }
cmd->execute_cmd = ops->execute_write_same_unmap;
return 0;
}
if (!ops->execute_write_same)
return TCM_UNSUPPORTED_SCSI_OPCODE;
+ ret = sbc_check_prot(dev, cmd, &cmd->t_task_cdb[0], sectors, true);
+ if (ret)
+ return ret;
+
cmd->execute_cmd = ops->execute_write_same;
return 0;
}
@@ -614,14 +639,21 @@
return 0;
}
-static bool
+static sense_reason_t
sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb,
u32 sectors, bool is_write)
{
u8 protect = cdb[1] >> 5;
- if ((!cmd->t_prot_sg || !cmd->t_prot_nents) && cmd->prot_pto)
- return true;
+ if (!cmd->t_prot_sg || !cmd->t_prot_nents) {
+ if (protect && !dev->dev_attrib.pi_prot_type) {
+ pr_err("CDB contains protect bit, but device does not"
+ " advertise PROTECT=1 feature bit\n");
+ return TCM_INVALID_CDB_FIELD;
+ }
+ if (cmd->prot_pto)
+ return TCM_NO_SENSE;
+ }
switch (dev->dev_attrib.pi_prot_type) {
case TARGET_DIF_TYPE3_PROT:
@@ -629,7 +661,7 @@
break;
case TARGET_DIF_TYPE2_PROT:
if (protect)
- return false;
+ return TCM_INVALID_CDB_FIELD;
cmd->reftag_seed = cmd->t_task_lba;
break;
@@ -638,12 +670,12 @@
break;
case TARGET_DIF_TYPE0_PROT:
default:
- return true;
+ return TCM_NO_SENSE;
}
if (sbc_set_prot_op_checks(protect, dev->dev_attrib.pi_prot_type,
is_write, cmd))
- return false;
+ return TCM_INVALID_CDB_FIELD;
cmd->prot_type = dev->dev_attrib.pi_prot_type;
cmd->prot_length = dev->prot_length * sectors;
@@ -662,7 +694,30 @@
__func__, cmd->prot_type, cmd->data_length, cmd->prot_length,
cmd->prot_op, cmd->prot_checks);
- return true;
+ return TCM_NO_SENSE;
+}
+
+static int
+sbc_check_dpofua(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb)
+{
+ if (cdb[1] & 0x10) {
+ if (!dev->dev_attrib.emulate_dpo) {
+ pr_err("Got CDB: 0x%02x with DPO bit set, but device"
+ " does not advertise support for DPO\n", cdb[0]);
+ return -EINVAL;
+ }
+ }
+ if (cdb[1] & 0x8) {
+ if (!dev->dev_attrib.emulate_fua_write ||
+ !dev->dev_attrib.emulate_write_cache) {
+ pr_err("Got CDB: 0x%02x with FUA bit set, but device"
+ " does not advertise support for FUA write\n",
+ cdb[0]);
+ return -EINVAL;
+ }
+ cmd->se_cmd_flags |= SCF_FUA;
+ }
+ return 0;
}
sense_reason_t
@@ -686,8 +741,12 @@
sectors = transport_get_sectors_10(cdb);
cmd->t_task_lba = transport_lba_32(cdb);
- if (!sbc_check_prot(dev, cmd, cdb, sectors, false))
- return TCM_UNSUPPORTED_SCSI_OPCODE;
+ if (sbc_check_dpofua(dev, cmd, cdb))
+ return TCM_INVALID_CDB_FIELD;
+
+ ret = sbc_check_prot(dev, cmd, cdb, sectors, false);
+ if (ret)
+ return ret;
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
cmd->execute_rw = ops->execute_rw;
@@ -697,8 +756,12 @@
sectors = transport_get_sectors_12(cdb);
cmd->t_task_lba = transport_lba_32(cdb);
- if (!sbc_check_prot(dev, cmd, cdb, sectors, false))
- return TCM_UNSUPPORTED_SCSI_OPCODE;
+ if (sbc_check_dpofua(dev, cmd, cdb))
+ return TCM_INVALID_CDB_FIELD;
+
+ ret = sbc_check_prot(dev, cmd, cdb, sectors, false);
+ if (ret)
+ return ret;
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
cmd->execute_rw = ops->execute_rw;
@@ -708,8 +771,12 @@
sectors = transport_get_sectors_16(cdb);
cmd->t_task_lba = transport_lba_64(cdb);
- if (!sbc_check_prot(dev, cmd, cdb, sectors, false))
- return TCM_UNSUPPORTED_SCSI_OPCODE;
+ if (sbc_check_dpofua(dev, cmd, cdb))
+ return TCM_INVALID_CDB_FIELD;
+
+ ret = sbc_check_prot(dev, cmd, cdb, sectors, false);
+ if (ret)
+ return ret;
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
cmd->execute_rw = ops->execute_rw;
@@ -727,11 +794,13 @@
sectors = transport_get_sectors_10(cdb);
cmd->t_task_lba = transport_lba_32(cdb);
- if (!sbc_check_prot(dev, cmd, cdb, sectors, true))
- return TCM_UNSUPPORTED_SCSI_OPCODE;
+ if (sbc_check_dpofua(dev, cmd, cdb))
+ return TCM_INVALID_CDB_FIELD;
- if (cdb[1] & 0x8)
- cmd->se_cmd_flags |= SCF_FUA;
+ ret = sbc_check_prot(dev, cmd, cdb, sectors, true);
+ if (ret)
+ return ret;
+
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
cmd->execute_rw = ops->execute_rw;
cmd->execute_cmd = sbc_execute_rw;
@@ -740,11 +809,13 @@
sectors = transport_get_sectors_12(cdb);
cmd->t_task_lba = transport_lba_32(cdb);
- if (!sbc_check_prot(dev, cmd, cdb, sectors, true))
- return TCM_UNSUPPORTED_SCSI_OPCODE;
+ if (sbc_check_dpofua(dev, cmd, cdb))
+ return TCM_INVALID_CDB_FIELD;
- if (cdb[1] & 0x8)
- cmd->se_cmd_flags |= SCF_FUA;
+ ret = sbc_check_prot(dev, cmd, cdb, sectors, true);
+ if (ret)
+ return ret;
+
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
cmd->execute_rw = ops->execute_rw;
cmd->execute_cmd = sbc_execute_rw;
@@ -753,11 +824,13 @@
sectors = transport_get_sectors_16(cdb);
cmd->t_task_lba = transport_lba_64(cdb);
- if (!sbc_check_prot(dev, cmd, cdb, sectors, true))
- return TCM_UNSUPPORTED_SCSI_OPCODE;
+ if (sbc_check_dpofua(dev, cmd, cdb))
+ return TCM_INVALID_CDB_FIELD;
- if (cdb[1] & 0x8)
- cmd->se_cmd_flags |= SCF_FUA;
+ ret = sbc_check_prot(dev, cmd, cdb, sectors, true);
+ if (ret)
+ return ret;
+
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
cmd->execute_rw = ops->execute_rw;
cmd->execute_cmd = sbc_execute_rw;
@@ -768,6 +841,9 @@
return TCM_INVALID_CDB_FIELD;
sectors = transport_get_sectors_10(cdb);
+ if (sbc_check_dpofua(dev, cmd, cdb))
+ return TCM_INVALID_CDB_FIELD;
+
cmd->t_task_lba = transport_lba_32(cdb);
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
@@ -777,8 +853,6 @@
cmd->execute_rw = ops->execute_rw;
cmd->execute_cmd = sbc_execute_rw;
cmd->transport_complete_callback = &xdreadwrite_callback;
- if (cdb[1] & 0x8)
- cmd->se_cmd_flags |= SCF_FUA;
break;
case VARIABLE_LENGTH_CMD:
{
@@ -787,6 +861,8 @@
case XDWRITEREAD_32:
sectors = transport_get_sectors_32(cdb);
+ if (sbc_check_dpofua(dev, cmd, cdb))
+ return TCM_INVALID_CDB_FIELD;
/*
* Use WRITE_32 and READ_32 opcodes for the emulated
* XDWRITE_READ_32 logic.
@@ -801,8 +877,6 @@
cmd->execute_rw = ops->execute_rw;
cmd->execute_cmd = sbc_execute_rw;
cmd->transport_complete_callback = &xdreadwrite_callback;
- if (cdb[1] & 0x8)
- cmd->se_cmd_flags |= SCF_FUA;
break;
case WRITE_SAME_32:
sectors = transport_get_sectors_32(cdb);
@@ -888,6 +962,11 @@
if (!ops->execute_unmap)
return TCM_UNSUPPORTED_SCSI_OPCODE;
+ if (!dev->dev_attrib.emulate_tpu) {
+ pr_err("Got UNMAP, but backend device has"
+ " emulate_tpu disabled\n");
+ return TCM_UNSUPPORTED_SCSI_OPCODE;
+ }
size = get_unaligned_be16(&cdb[7]);
cmd->execute_cmd = ops->execute_unmap;
break;
@@ -955,7 +1034,8 @@
unsigned long long end_lba;
check_lba:
end_lba = dev->transport->get_blocks(dev) + 1;
- if (cmd->t_task_lba + sectors > end_lba) {
+ if (((cmd->t_task_lba + sectors) < cmd->t_task_lba) ||
+ ((cmd->t_task_lba + sectors) > end_lba)) {
pr_err("cmd exceeds last lba %llu "
"(lba %llu, sectors %u)\n",
end_lba, cmd->t_task_lba, sectors);
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
index 4c71657..460e931 100644
--- a/drivers/target/target_core_spc.c
+++ b/drivers/target/target_core_spc.c
@@ -647,7 +647,7 @@
* support the use of the WRITE SAME (16) command to unmap LBAs.
*/
if (dev->dev_attrib.emulate_tpws != 0)
- buf[5] |= 0x40;
+ buf[5] |= 0x40 | 0x20;
return 0;
}
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index fbeedc0..933cd80 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -716,7 +716,7 @@
{
struct exynos_tmu_data *data = p;
- if (!data)
+ if (!data || !data->tmu_read)
return -EINVAL;
mutex_lock(&data->lock);
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 7cc0122..f8a1863 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -239,9 +239,12 @@
return (flags & PCI_MSIX_FLAGS_QSIZE) + 1;
}
- } else if (irq_type == VFIO_PCI_ERR_IRQ_INDEX)
+ } else if (irq_type == VFIO_PCI_ERR_IRQ_INDEX) {
if (pci_is_pcie(vdev->pdev))
return 1;
+ } else if (irq_type == VFIO_PCI_REQ_IRQ_INDEX) {
+ return 1;
+ }
return 0;
}
@@ -464,6 +467,7 @@
switch (info.index) {
case VFIO_PCI_INTX_IRQ_INDEX ... VFIO_PCI_MSIX_IRQ_INDEX:
+ case VFIO_PCI_REQ_IRQ_INDEX:
break;
case VFIO_PCI_ERR_IRQ_INDEX:
if (pci_is_pcie(vdev->pdev))
@@ -828,6 +832,20 @@
req_len, vma->vm_page_prot);
}
+static void vfio_pci_request(void *device_data, unsigned int count)
+{
+ struct vfio_pci_device *vdev = device_data;
+
+ mutex_lock(&vdev->igate);
+
+ if (vdev->req_trigger) {
+ dev_dbg(&vdev->pdev->dev, "Requesting device from user\n");
+ eventfd_signal(vdev->req_trigger, 1);
+ }
+
+ mutex_unlock(&vdev->igate);
+}
+
static const struct vfio_device_ops vfio_pci_ops = {
.name = "vfio-pci",
.open = vfio_pci_open,
@@ -836,6 +854,7 @@
.read = vfio_pci_read,
.write = vfio_pci_write,
.mmap = vfio_pci_mmap,
+ .request = vfio_pci_request,
};
static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c
index e8d695b..f88bfdf 100644
--- a/drivers/vfio/pci/vfio_pci_intrs.c
+++ b/drivers/vfio/pci/vfio_pci_intrs.c
@@ -763,46 +763,70 @@
return 0;
}
-static int vfio_pci_set_err_trigger(struct vfio_pci_device *vdev,
- unsigned index, unsigned start,
- unsigned count, uint32_t flags, void *data)
+static int vfio_pci_set_ctx_trigger_single(struct eventfd_ctx **ctx,
+ uint32_t flags, void *data)
{
int32_t fd = *(int32_t *)data;
- if ((index != VFIO_PCI_ERR_IRQ_INDEX) ||
- !(flags & VFIO_IRQ_SET_DATA_TYPE_MASK))
+ if (!(flags & VFIO_IRQ_SET_DATA_TYPE_MASK))
return -EINVAL;
/* DATA_NONE/DATA_BOOL enables loopback testing */
if (flags & VFIO_IRQ_SET_DATA_NONE) {
- if (vdev->err_trigger)
- eventfd_signal(vdev->err_trigger, 1);
+ if (*ctx)
+ eventfd_signal(*ctx, 1);
return 0;
} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
uint8_t trigger = *(uint8_t *)data;
- if (trigger && vdev->err_trigger)
- eventfd_signal(vdev->err_trigger, 1);
+ if (trigger && *ctx)
+ eventfd_signal(*ctx, 1);
return 0;
}
/* Handle SET_DATA_EVENTFD */
if (fd == -1) {
- if (vdev->err_trigger)
- eventfd_ctx_put(vdev->err_trigger);
- vdev->err_trigger = NULL;
+ if (*ctx)
+ eventfd_ctx_put(*ctx);
+ *ctx = NULL;
return 0;
} else if (fd >= 0) {
struct eventfd_ctx *efdctx;
efdctx = eventfd_ctx_fdget(fd);
if (IS_ERR(efdctx))
return PTR_ERR(efdctx);
- if (vdev->err_trigger)
- eventfd_ctx_put(vdev->err_trigger);
- vdev->err_trigger = efdctx;
+ if (*ctx)
+ eventfd_ctx_put(*ctx);
+ *ctx = efdctx;
return 0;
} else
return -EINVAL;
}
+
+static int vfio_pci_set_err_trigger(struct vfio_pci_device *vdev,
+ unsigned index, unsigned start,
+ unsigned count, uint32_t flags, void *data)
+{
+ if (index != VFIO_PCI_ERR_IRQ_INDEX)
+ return -EINVAL;
+
+ /*
+ * We should sanitize start & count, but that wasn't caught
+ * originally, so this IRQ index must forever ignore them :-(
+ */
+
+ return vfio_pci_set_ctx_trigger_single(&vdev->err_trigger, flags, data);
+}
+
+static int vfio_pci_set_req_trigger(struct vfio_pci_device *vdev,
+ unsigned index, unsigned start,
+ unsigned count, uint32_t flags, void *data)
+{
+ if (index != VFIO_PCI_REQ_IRQ_INDEX || start != 0 || count != 1)
+ return -EINVAL;
+
+ return vfio_pci_set_ctx_trigger_single(&vdev->req_trigger, flags, data);
+}
+
int vfio_pci_set_irqs_ioctl(struct vfio_pci_device *vdev, uint32_t flags,
unsigned index, unsigned start, unsigned count,
void *data)
@@ -844,6 +868,12 @@
func = vfio_pci_set_err_trigger;
break;
}
+ case VFIO_PCI_REQ_IRQ_INDEX:
+ switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
+ case VFIO_IRQ_SET_ACTION_TRIGGER:
+ func = vfio_pci_set_req_trigger;
+ break;
+ }
}
if (!func)
diff --git a/drivers/vfio/pci/vfio_pci_private.h b/drivers/vfio/pci/vfio_pci_private.h
index 671c17a..c9f9b32 100644
--- a/drivers/vfio/pci/vfio_pci_private.h
+++ b/drivers/vfio/pci/vfio_pci_private.h
@@ -58,6 +58,7 @@
struct pci_saved_state *pci_saved_state;
int refcnt;
struct eventfd_ctx *err_trigger;
+ struct eventfd_ctx *req_trigger;
};
#define is_intx(vdev) (vdev->irq_type == VFIO_PCI_INTX_IRQ_INDEX)
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
index f018d8d..4cde855 100644
--- a/drivers/vfio/vfio.c
+++ b/drivers/vfio/vfio.c
@@ -63,6 +63,11 @@
void *iommu_data;
};
+struct vfio_unbound_dev {
+ struct device *dev;
+ struct list_head unbound_next;
+};
+
struct vfio_group {
struct kref kref;
int minor;
@@ -75,6 +80,8 @@
struct notifier_block nb;
struct list_head vfio_next;
struct list_head container_next;
+ struct list_head unbound_list;
+ struct mutex unbound_lock;
atomic_t opened;
};
@@ -204,6 +211,8 @@
kref_init(&group->kref);
INIT_LIST_HEAD(&group->device_list);
mutex_init(&group->device_lock);
+ INIT_LIST_HEAD(&group->unbound_list);
+ mutex_init(&group->unbound_lock);
atomic_set(&group->container_users, 0);
atomic_set(&group->opened, 0);
group->iommu_group = iommu_group;
@@ -264,13 +273,22 @@
static void vfio_group_release(struct kref *kref)
{
struct vfio_group *group = container_of(kref, struct vfio_group, kref);
+ struct vfio_unbound_dev *unbound, *tmp;
+ struct iommu_group *iommu_group = group->iommu_group;
WARN_ON(!list_empty(&group->device_list));
+ list_for_each_entry_safe(unbound, tmp,
+ &group->unbound_list, unbound_next) {
+ list_del(&unbound->unbound_next);
+ kfree(unbound);
+ }
+
device_destroy(vfio.class, MKDEV(MAJOR(vfio.group_devt), group->minor));
list_del(&group->vfio_next);
vfio_free_group_minor(group->minor);
vfio_group_unlock_and_free(group);
+ iommu_group_put(iommu_group);
}
static void vfio_group_put(struct vfio_group *group)
@@ -440,17 +458,36 @@
}
/*
- * A vfio group is viable for use by userspace if all devices are either
- * driver-less or bound to a vfio or whitelisted driver. We test the
- * latter by the existence of a struct vfio_device matching the dev.
+ * A vfio group is viable for use by userspace if all devices are in
+ * one of the following states:
+ * - driver-less
+ * - bound to a vfio driver
+ * - bound to a whitelisted driver
+ *
+ * We use two methods to determine whether a device is bound to a vfio
+ * driver. The first is to test whether the device exists in the vfio
+ * group. The second is to test if the device exists on the group
+ * unbound_list, indicating it's in the middle of transitioning from
+ * a vfio driver to driver-less.
*/
static int vfio_dev_viable(struct device *dev, void *data)
{
struct vfio_group *group = data;
struct vfio_device *device;
struct device_driver *drv = ACCESS_ONCE(dev->driver);
+ struct vfio_unbound_dev *unbound;
+ int ret = -EINVAL;
- if (!drv || vfio_whitelisted_driver(drv))
+ mutex_lock(&group->unbound_lock);
+ list_for_each_entry(unbound, &group->unbound_list, unbound_next) {
+ if (dev == unbound->dev) {
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&group->unbound_lock);
+
+ if (!ret || !drv || vfio_whitelisted_driver(drv))
return 0;
device = vfio_group_get_device(group, dev);
@@ -459,7 +496,7 @@
return 0;
}
- return -EINVAL;
+ return ret;
}
/**
@@ -501,6 +538,7 @@
{
struct vfio_group *group = container_of(nb, struct vfio_group, nb);
struct device *dev = data;
+ struct vfio_unbound_dev *unbound;
/*
* Need to go through a group_lock lookup to get a reference or we
@@ -550,6 +588,17 @@
* stop the system to maintain isolation. At a minimum, we'd
* want a toggle to disable driver auto probe for this device.
*/
+
+ mutex_lock(&group->unbound_lock);
+ list_for_each_entry(unbound,
+ &group->unbound_list, unbound_next) {
+ if (dev == unbound->dev) {
+ list_del(&unbound->unbound_next);
+ kfree(unbound);
+ break;
+ }
+ }
+ mutex_unlock(&group->unbound_lock);
break;
}
@@ -578,6 +627,12 @@
iommu_group_put(iommu_group);
return PTR_ERR(group);
}
+ } else {
+ /*
+ * A found vfio_group already holds a reference to the
+ * iommu_group. A created vfio_group keeps the reference.
+ */
+ iommu_group_put(iommu_group);
}
device = vfio_group_get_device(group, dev);
@@ -586,21 +641,19 @@
dev_name(dev), iommu_group_id(iommu_group));
vfio_device_put(device);
vfio_group_put(group);
- iommu_group_put(iommu_group);
return -EBUSY;
}
device = vfio_group_create_device(group, dev, ops, device_data);
if (IS_ERR(device)) {
vfio_group_put(group);
- iommu_group_put(iommu_group);
return PTR_ERR(device);
}
/*
- * Added device holds reference to iommu_group and vfio_device
- * (which in turn holds reference to vfio_group). Drop extra
- * group reference used while acquiring device.
+ * Drop all but the vfio_device reference. The vfio_device holds
+ * a reference to the vfio_group, which holds a reference to the
+ * iommu_group.
*/
vfio_group_put(group);
@@ -655,8 +708,9 @@
{
struct vfio_device *device = dev_get_drvdata(dev);
struct vfio_group *group = device->group;
- struct iommu_group *iommu_group = group->iommu_group;
void *device_data = device->device_data;
+ struct vfio_unbound_dev *unbound;
+ unsigned int i = 0;
/*
* The group exists so long as we have a device reference. Get
@@ -664,15 +718,50 @@
*/
vfio_group_get(group);
+ /*
+ * When the device is removed from the group, the group suddenly
+ * becomes non-viable; the device has a driver (until the unbind
+ * completes), but it's not present in the group. This is bad news
+ * for any external users that need to re-acquire a group reference
+ * in order to match and release their existing reference. To
+ * solve this, we track such devices on the unbound_list to bridge
+ * the gap until they're fully unbound.
+ */
+ unbound = kzalloc(sizeof(*unbound), GFP_KERNEL);
+ if (unbound) {
+ unbound->dev = dev;
+ mutex_lock(&group->unbound_lock);
+ list_add(&unbound->unbound_next, &group->unbound_list);
+ mutex_unlock(&group->unbound_lock);
+ }
+ WARN_ON(!unbound);
+
vfio_device_put(device);
- /* TODO send a signal to encourage this to be released */
- wait_event(vfio.release_q, !vfio_dev_present(group, dev));
+ /*
+ * If the device is still present in the group after the above
+ * 'put', then it is in use and we need to request it from the
+ * bus driver. The driver may in turn need to request the
+ * device from the user. We send the request on an arbitrary
+ * interval with counter to allow the driver to take escalating
+ * measures to release the device if it has the ability to do so.
+ */
+ do {
+ device = vfio_group_get_device(group, dev);
+ if (!device)
+ break;
+
+ if (device->ops->request)
+ device->ops->request(device_data, i++);
+
+ vfio_device_put(device);
+
+ } while (wait_event_interruptible_timeout(vfio.release_q,
+ !vfio_dev_present(group, dev),
+ HZ * 10) <= 0);
vfio_group_put(group);
- iommu_group_put(iommu_group);
-
return device_data;
}
EXPORT_SYMBOL_GPL(vfio_del_group_dev);
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 4a9d666..57d8c37 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -66,6 +66,7 @@
struct list_head next;
struct list_head group_list;
int prot; /* IOMMU_CACHE */
+ bool fgsp; /* Fine-grained super pages */
};
struct vfio_dma {
@@ -264,6 +265,7 @@
unsigned long limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
bool lock_cap = capable(CAP_IPC_LOCK);
long ret, i;
+ bool rsvd;
if (!current->mm)
return -ENODEV;
@@ -272,10 +274,9 @@
if (ret)
return ret;
- if (is_invalid_reserved_pfn(*pfn_base))
- return 1;
+ rsvd = is_invalid_reserved_pfn(*pfn_base);
- if (!lock_cap && current->mm->locked_vm + 1 > limit) {
+ if (!rsvd && !lock_cap && current->mm->locked_vm + 1 > limit) {
put_pfn(*pfn_base, prot);
pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", __func__,
limit << PAGE_SHIFT);
@@ -283,7 +284,8 @@
}
if (unlikely(disable_hugepages)) {
- vfio_lock_acct(1);
+ if (!rsvd)
+ vfio_lock_acct(1);
return 1;
}
@@ -295,12 +297,14 @@
if (ret)
break;
- if (pfn != *pfn_base + i || is_invalid_reserved_pfn(pfn)) {
+ if (pfn != *pfn_base + i ||
+ rsvd != is_invalid_reserved_pfn(pfn)) {
put_pfn(pfn, prot);
break;
}
- if (!lock_cap && current->mm->locked_vm + i + 1 > limit) {
+ if (!rsvd && !lock_cap &&
+ current->mm->locked_vm + i + 1 > limit) {
put_pfn(pfn, prot);
pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n",
__func__, limit << PAGE_SHIFT);
@@ -308,7 +312,8 @@
}
}
- vfio_lock_acct(i);
+ if (!rsvd)
+ vfio_lock_acct(i);
return i;
}
@@ -346,12 +351,14 @@
domain = d = list_first_entry(&iommu->domain_list,
struct vfio_domain, next);
- list_for_each_entry_continue(d, &iommu->domain_list, next)
+ list_for_each_entry_continue(d, &iommu->domain_list, next) {
iommu_unmap(d->domain, dma->iova, dma->size);
+ cond_resched();
+ }
while (iova < end) {
- size_t unmapped;
- phys_addr_t phys;
+ size_t unmapped, len;
+ phys_addr_t phys, next;
phys = iommu_iova_to_phys(domain->domain, iova);
if (WARN_ON(!phys)) {
@@ -359,7 +366,19 @@
continue;
}
- unmapped = iommu_unmap(domain->domain, iova, PAGE_SIZE);
+ /*
+ * To optimize for fewer iommu_unmap() calls, each of which
+ * may require hardware cache flushing, try to find the
+ * largest contiguous physical memory chunk to unmap.
+ */
+ for (len = PAGE_SIZE;
+ !domain->fgsp && iova + len < end; len += PAGE_SIZE) {
+ next = iommu_iova_to_phys(domain->domain, iova + len);
+ if (next != phys + len)
+ break;
+ }
+
+ unmapped = iommu_unmap(domain->domain, iova, len);
if (WARN_ON(!unmapped))
break;
@@ -367,6 +386,8 @@
unmapped >> PAGE_SHIFT,
dma->prot, false);
iova += unmapped;
+
+ cond_resched();
}
vfio_lock_acct(-unlocked);
@@ -511,6 +532,8 @@
map_try_harder(d, iova, pfn, npage, prot))
goto unwind;
}
+
+ cond_resched();
}
return 0;
@@ -665,6 +688,39 @@
return 0;
}
+/*
+ * We change our unmap behavior slightly depending on whether the IOMMU
+ * supports fine-grained superpages. IOMMUs like AMD-Vi will use a superpage
+ * for practically any contiguous power-of-two mapping we give it. This means
+ * we don't need to look for contiguous chunks ourselves to make unmapping
+ * more efficient. On IOMMUs with coarse-grained super pages, like Intel VT-d
+ * with discrete 2M/1G/512G/1T superpages, identifying contiguous chunks
+ * significantly boosts non-hugetlbfs mappings and doesn't seem to hurt when
+ * hugetlbfs is in use.
+ */
+static void vfio_test_domain_fgsp(struct vfio_domain *domain)
+{
+ struct page *pages;
+ int ret, order = get_order(PAGE_SIZE * 2);
+
+ pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
+ if (!pages)
+ return;
+
+ ret = iommu_map(domain->domain, 0, page_to_phys(pages), PAGE_SIZE * 2,
+ IOMMU_READ | IOMMU_WRITE | domain->prot);
+ if (!ret) {
+ size_t unmapped = iommu_unmap(domain->domain, 0, PAGE_SIZE);
+
+ if (unmapped == PAGE_SIZE)
+ iommu_unmap(domain->domain, PAGE_SIZE, PAGE_SIZE);
+ else
+ domain->fgsp = true;
+ }
+
+ __free_pages(pages, order);
+}
+
static int vfio_iommu_type1_attach_group(void *iommu_data,
struct iommu_group *iommu_group)
{
@@ -758,6 +814,8 @@
}
}
+ vfio_test_domain_fgsp(domain);
+
/* replay mappings on new domains */
ret = vfio_iommu_replay(iommu, domain);
if (ret)
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
index dc78d87..8d4f3f1 100644
--- a/drivers/vhost/scsi.c
+++ b/drivers/vhost/scsi.c
@@ -38,7 +38,6 @@
#include <linux/miscdevice.h>
#include <asm/unaligned.h>
#include <scsi/scsi.h>
-#include <scsi/scsi_tcq.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
#include <target/target_core_fabric_configfs.h>
@@ -52,13 +51,13 @@
#include "vhost.h"
-#define TCM_VHOST_VERSION "v0.1"
-#define TCM_VHOST_NAMELEN 256
-#define TCM_VHOST_MAX_CDB_SIZE 32
-#define TCM_VHOST_DEFAULT_TAGS 256
-#define TCM_VHOST_PREALLOC_SGLS 2048
-#define TCM_VHOST_PREALLOC_UPAGES 2048
-#define TCM_VHOST_PREALLOC_PROT_SGLS 512
+#define VHOST_SCSI_VERSION "v0.1"
+#define VHOST_SCSI_NAMELEN 256
+#define VHOST_SCSI_MAX_CDB_SIZE 32
+#define VHOST_SCSI_DEFAULT_TAGS 256
+#define VHOST_SCSI_PREALLOC_SGLS 2048
+#define VHOST_SCSI_PREALLOC_UPAGES 2048
+#define VHOST_SCSI_PREALLOC_PROT_SGLS 512
struct vhost_scsi_inflight {
/* Wait for the flush operation to finish */
@@ -67,11 +66,13 @@
struct kref kref;
};
-struct tcm_vhost_cmd {
+struct vhost_scsi_cmd {
/* Descriptor from vhost_get_vq_desc() for virt_queue segment */
int tvc_vq_desc;
/* virtio-scsi initiator task attribute */
int tvc_task_attr;
+ /* virtio-scsi response incoming iovecs */
+ int tvc_in_iovs;
/* virtio-scsi initiator data direction */
enum dma_data_direction tvc_data_direction;
/* Expected data transfer length from virtio-scsi header */
@@ -81,26 +82,26 @@
/* The number of scatterlists associated with this cmd */
u32 tvc_sgl_count;
u32 tvc_prot_sgl_count;
- /* Saved unpacked SCSI LUN for tcm_vhost_submission_work() */
+ /* Saved unpacked SCSI LUN for vhost_scsi_submission_work() */
u32 tvc_lun;
/* Pointer to the SGL formatted memory from virtio-scsi */
struct scatterlist *tvc_sgl;
struct scatterlist *tvc_prot_sgl;
struct page **tvc_upages;
- /* Pointer to response */
- struct virtio_scsi_cmd_resp __user *tvc_resp;
+ /* Pointer to response header iovec */
+ struct iovec *tvc_resp_iov;
/* Pointer to vhost_scsi for our device */
struct vhost_scsi *tvc_vhost;
/* Pointer to vhost_virtqueue for the cmd */
struct vhost_virtqueue *tvc_vq;
/* Pointer to vhost nexus memory */
- struct tcm_vhost_nexus *tvc_nexus;
+ struct vhost_scsi_nexus *tvc_nexus;
/* The TCM I/O descriptor that is accessed via container_of() */
struct se_cmd tvc_se_cmd;
- /* work item used for cmwq dispatch to tcm_vhost_submission_work() */
+ /* work item used for cmwq dispatch to vhost_scsi_submission_work() */
struct work_struct work;
/* Copy of the incoming SCSI command descriptor block (CDB) */
- unsigned char tvc_cdb[TCM_VHOST_MAX_CDB_SIZE];
+ unsigned char tvc_cdb[VHOST_SCSI_MAX_CDB_SIZE];
/* Sense buffer that will be mapped into outgoing status */
unsigned char tvc_sense_buf[TRANSPORT_SENSE_BUFFER];
/* Completed commands list, serviced from vhost worker thread */
@@ -109,53 +110,53 @@
struct vhost_scsi_inflight *inflight;
};
-struct tcm_vhost_nexus {
+struct vhost_scsi_nexus {
/* Pointer to TCM session for I_T Nexus */
struct se_session *tvn_se_sess;
};
-struct tcm_vhost_nacl {
+struct vhost_scsi_nacl {
/* Binary World Wide unique Port Name for Vhost Initiator port */
u64 iport_wwpn;
/* ASCII formatted WWPN for Sas Initiator port */
- char iport_name[TCM_VHOST_NAMELEN];
- /* Returned by tcm_vhost_make_nodeacl() */
+ char iport_name[VHOST_SCSI_NAMELEN];
+ /* Returned by vhost_scsi_make_nodeacl() */
struct se_node_acl se_node_acl;
};
-struct tcm_vhost_tpg {
+struct vhost_scsi_tpg {
/* Vhost port target portal group tag for TCM */
u16 tport_tpgt;
/* Used to track number of TPG Port/Lun Links wrt to explict I_T Nexus shutdown */
int tv_tpg_port_count;
/* Used for vhost_scsi device reference to tpg_nexus, protected by tv_tpg_mutex */
int tv_tpg_vhost_count;
- /* list for tcm_vhost_list */
+ /* list for vhost_scsi_list */
struct list_head tv_tpg_list;
/* Used to protect access for tpg_nexus */
struct mutex tv_tpg_mutex;
/* Pointer to the TCM VHost I_T Nexus for this TPG endpoint */
- struct tcm_vhost_nexus *tpg_nexus;
- /* Pointer back to tcm_vhost_tport */
- struct tcm_vhost_tport *tport;
- /* Returned by tcm_vhost_make_tpg() */
+ struct vhost_scsi_nexus *tpg_nexus;
+ /* Pointer back to vhost_scsi_tport */
+ struct vhost_scsi_tport *tport;
+ /* Returned by vhost_scsi_make_tpg() */
struct se_portal_group se_tpg;
/* Pointer back to vhost_scsi, protected by tv_tpg_mutex */
struct vhost_scsi *vhost_scsi;
};
-struct tcm_vhost_tport {
+struct vhost_scsi_tport {
/* SCSI protocol the tport is providing */
u8 tport_proto_id;
/* Binary World Wide unique Port Name for Vhost Target port */
u64 tport_wwpn;
/* ASCII formatted WWPN for Vhost Target port */
- char tport_name[TCM_VHOST_NAMELEN];
- /* Returned by tcm_vhost_make_tport() */
+ char tport_name[VHOST_SCSI_NAMELEN];
+ /* Returned by vhost_scsi_make_tport() */
struct se_wwn tport_wwn;
};
-struct tcm_vhost_evt {
+struct vhost_scsi_evt {
/* event to be sent to guest */
struct virtio_scsi_event event;
/* event list, serviced from vhost worker thread */
@@ -171,7 +172,9 @@
/* Note: can't set VIRTIO_F_VERSION_1 yet, since that implies ANY_LAYOUT. */
enum {
VHOST_SCSI_FEATURES = VHOST_FEATURES | (1ULL << VIRTIO_SCSI_F_HOTPLUG) |
- (1ULL << VIRTIO_SCSI_F_T10_PI)
+ (1ULL << VIRTIO_SCSI_F_T10_PI) |
+ (1ULL << VIRTIO_F_ANY_LAYOUT) |
+ (1ULL << VIRTIO_F_VERSION_1)
};
#define VHOST_SCSI_MAX_TARGET 256
@@ -195,7 +198,7 @@
struct vhost_scsi {
/* Protected by vhost_scsi->dev.mutex */
- struct tcm_vhost_tpg **vs_tpg;
+ struct vhost_scsi_tpg **vs_tpg;
char vs_vhost_wwpn[TRANSPORT_IQN_LEN];
struct vhost_dev dev;
@@ -212,21 +215,21 @@
};
/* Local pointer to allocated TCM configfs fabric module */
-static struct target_fabric_configfs *tcm_vhost_fabric_configfs;
+static struct target_fabric_configfs *vhost_scsi_fabric_configfs;
-static struct workqueue_struct *tcm_vhost_workqueue;
+static struct workqueue_struct *vhost_scsi_workqueue;
-/* Global spinlock to protect tcm_vhost TPG list for vhost IOCTL access */
-static DEFINE_MUTEX(tcm_vhost_mutex);
-static LIST_HEAD(tcm_vhost_list);
+/* Global spinlock to protect vhost_scsi TPG list for vhost IOCTL access */
+static DEFINE_MUTEX(vhost_scsi_mutex);
+static LIST_HEAD(vhost_scsi_list);
-static int iov_num_pages(struct iovec *iov)
+static int iov_num_pages(void __user *iov_base, size_t iov_len)
{
- return (PAGE_ALIGN((unsigned long)iov->iov_base + iov->iov_len) -
- ((unsigned long)iov->iov_base & PAGE_MASK)) >> PAGE_SHIFT;
+ return (PAGE_ALIGN((unsigned long)iov_base + iov_len) -
+ ((unsigned long)iov_base & PAGE_MASK)) >> PAGE_SHIFT;
}
-static void tcm_vhost_done_inflight(struct kref *kref)
+static void vhost_scsi_done_inflight(struct kref *kref)
{
struct vhost_scsi_inflight *inflight;
@@ -234,7 +237,7 @@
complete(&inflight->comp);
}
-static void tcm_vhost_init_inflight(struct vhost_scsi *vs,
+static void vhost_scsi_init_inflight(struct vhost_scsi *vs,
struct vhost_scsi_inflight *old_inflight[])
{
struct vhost_scsi_inflight *new_inflight;
@@ -262,7 +265,7 @@
}
static struct vhost_scsi_inflight *
-tcm_vhost_get_inflight(struct vhost_virtqueue *vq)
+vhost_scsi_get_inflight(struct vhost_virtqueue *vq)
{
struct vhost_scsi_inflight *inflight;
struct vhost_scsi_virtqueue *svq;
@@ -274,31 +277,31 @@
return inflight;
}
-static void tcm_vhost_put_inflight(struct vhost_scsi_inflight *inflight)
+static void vhost_scsi_put_inflight(struct vhost_scsi_inflight *inflight)
{
- kref_put(&inflight->kref, tcm_vhost_done_inflight);
+ kref_put(&inflight->kref, vhost_scsi_done_inflight);
}
-static int tcm_vhost_check_true(struct se_portal_group *se_tpg)
+static int vhost_scsi_check_true(struct se_portal_group *se_tpg)
{
return 1;
}
-static int tcm_vhost_check_false(struct se_portal_group *se_tpg)
+static int vhost_scsi_check_false(struct se_portal_group *se_tpg)
{
return 0;
}
-static char *tcm_vhost_get_fabric_name(void)
+static char *vhost_scsi_get_fabric_name(void)
{
return "vhost";
}
-static u8 tcm_vhost_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+static u8 vhost_scsi_get_fabric_proto_ident(struct se_portal_group *se_tpg)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
- struct tcm_vhost_tport *tport = tpg->tport;
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
+ struct vhost_scsi_tport *tport = tpg->tport;
switch (tport->tport_proto_id) {
case SCSI_PROTOCOL_SAS:
@@ -316,37 +319,37 @@
return sas_get_fabric_proto_ident(se_tpg);
}
-static char *tcm_vhost_get_fabric_wwn(struct se_portal_group *se_tpg)
+static char *vhost_scsi_get_fabric_wwn(struct se_portal_group *se_tpg)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
- struct tcm_vhost_tport *tport = tpg->tport;
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
+ struct vhost_scsi_tport *tport = tpg->tport;
return &tport->tport_name[0];
}
-static u16 tcm_vhost_get_tag(struct se_portal_group *se_tpg)
+static u16 vhost_scsi_get_tpgt(struct se_portal_group *se_tpg)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
return tpg->tport_tpgt;
}
-static u32 tcm_vhost_get_default_depth(struct se_portal_group *se_tpg)
+static u32 vhost_scsi_get_default_depth(struct se_portal_group *se_tpg)
{
return 1;
}
static u32
-tcm_vhost_get_pr_transport_id(struct se_portal_group *se_tpg,
+vhost_scsi_get_pr_transport_id(struct se_portal_group *se_tpg,
struct se_node_acl *se_nacl,
struct t10_pr_registration *pr_reg,
int *format_code,
unsigned char *buf)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
- struct tcm_vhost_tport *tport = tpg->tport;
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
+ struct vhost_scsi_tport *tport = tpg->tport;
switch (tport->tport_proto_id) {
case SCSI_PROTOCOL_SAS:
@@ -369,14 +372,14 @@
}
static u32
-tcm_vhost_get_pr_transport_id_len(struct se_portal_group *se_tpg,
+vhost_scsi_get_pr_transport_id_len(struct se_portal_group *se_tpg,
struct se_node_acl *se_nacl,
struct t10_pr_registration *pr_reg,
int *format_code)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
- struct tcm_vhost_tport *tport = tpg->tport;
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
+ struct vhost_scsi_tport *tport = tpg->tport;
switch (tport->tport_proto_id) {
case SCSI_PROTOCOL_SAS:
@@ -399,14 +402,14 @@
}
static char *
-tcm_vhost_parse_pr_out_transport_id(struct se_portal_group *se_tpg,
+vhost_scsi_parse_pr_out_transport_id(struct se_portal_group *se_tpg,
const char *buf,
u32 *out_tid_len,
char **port_nexus_ptr)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
- struct tcm_vhost_tport *tport = tpg->tport;
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
+ struct vhost_scsi_tport *tport = tpg->tport;
switch (tport->tport_proto_id) {
case SCSI_PROTOCOL_SAS:
@@ -429,13 +432,13 @@
}
static struct se_node_acl *
-tcm_vhost_alloc_fabric_acl(struct se_portal_group *se_tpg)
+vhost_scsi_alloc_fabric_acl(struct se_portal_group *se_tpg)
{
- struct tcm_vhost_nacl *nacl;
+ struct vhost_scsi_nacl *nacl;
- nacl = kzalloc(sizeof(struct tcm_vhost_nacl), GFP_KERNEL);
+ nacl = kzalloc(sizeof(struct vhost_scsi_nacl), GFP_KERNEL);
if (!nacl) {
- pr_err("Unable to allocate struct tcm_vhost_nacl\n");
+ pr_err("Unable to allocate struct vhost_scsi_nacl\n");
return NULL;
}
@@ -443,24 +446,24 @@
}
static void
-tcm_vhost_release_fabric_acl(struct se_portal_group *se_tpg,
+vhost_scsi_release_fabric_acl(struct se_portal_group *se_tpg,
struct se_node_acl *se_nacl)
{
- struct tcm_vhost_nacl *nacl = container_of(se_nacl,
- struct tcm_vhost_nacl, se_node_acl);
+ struct vhost_scsi_nacl *nacl = container_of(se_nacl,
+ struct vhost_scsi_nacl, se_node_acl);
kfree(nacl);
}
-static u32 tcm_vhost_tpg_get_inst_index(struct se_portal_group *se_tpg)
+static u32 vhost_scsi_tpg_get_inst_index(struct se_portal_group *se_tpg)
{
return 1;
}
-static void tcm_vhost_release_cmd(struct se_cmd *se_cmd)
+static void vhost_scsi_release_cmd(struct se_cmd *se_cmd)
{
- struct tcm_vhost_cmd *tv_cmd = container_of(se_cmd,
- struct tcm_vhost_cmd, tvc_se_cmd);
- struct se_session *se_sess = se_cmd->se_sess;
+ struct vhost_scsi_cmd *tv_cmd = container_of(se_cmd,
+ struct vhost_scsi_cmd, tvc_se_cmd);
+ struct se_session *se_sess = tv_cmd->tvc_nexus->tvn_se_sess;
int i;
if (tv_cmd->tvc_sgl_count) {
@@ -472,53 +475,53 @@
put_page(sg_page(&tv_cmd->tvc_prot_sgl[i]));
}
- tcm_vhost_put_inflight(tv_cmd->inflight);
+ vhost_scsi_put_inflight(tv_cmd->inflight);
percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag);
}
-static int tcm_vhost_shutdown_session(struct se_session *se_sess)
+static int vhost_scsi_shutdown_session(struct se_session *se_sess)
{
return 0;
}
-static void tcm_vhost_close_session(struct se_session *se_sess)
+static void vhost_scsi_close_session(struct se_session *se_sess)
{
return;
}
-static u32 tcm_vhost_sess_get_index(struct se_session *se_sess)
+static u32 vhost_scsi_sess_get_index(struct se_session *se_sess)
{
return 0;
}
-static int tcm_vhost_write_pending(struct se_cmd *se_cmd)
+static int vhost_scsi_write_pending(struct se_cmd *se_cmd)
{
/* Go ahead and process the write immediately */
target_execute_cmd(se_cmd);
return 0;
}
-static int tcm_vhost_write_pending_status(struct se_cmd *se_cmd)
+static int vhost_scsi_write_pending_status(struct se_cmd *se_cmd)
{
return 0;
}
-static void tcm_vhost_set_default_node_attrs(struct se_node_acl *nacl)
+static void vhost_scsi_set_default_node_attrs(struct se_node_acl *nacl)
{
return;
}
-static u32 tcm_vhost_get_task_tag(struct se_cmd *se_cmd)
+static u32 vhost_scsi_get_task_tag(struct se_cmd *se_cmd)
{
return 0;
}
-static int tcm_vhost_get_cmd_state(struct se_cmd *se_cmd)
+static int vhost_scsi_get_cmd_state(struct se_cmd *se_cmd)
{
return 0;
}
-static void vhost_scsi_complete_cmd(struct tcm_vhost_cmd *cmd)
+static void vhost_scsi_complete_cmd(struct vhost_scsi_cmd *cmd)
{
struct vhost_scsi *vs = cmd->tvc_vhost;
@@ -527,44 +530,44 @@
vhost_work_queue(&vs->dev, &vs->vs_completion_work);
}
-static int tcm_vhost_queue_data_in(struct se_cmd *se_cmd)
+static int vhost_scsi_queue_data_in(struct se_cmd *se_cmd)
{
- struct tcm_vhost_cmd *cmd = container_of(se_cmd,
- struct tcm_vhost_cmd, tvc_se_cmd);
+ struct vhost_scsi_cmd *cmd = container_of(se_cmd,
+ struct vhost_scsi_cmd, tvc_se_cmd);
vhost_scsi_complete_cmd(cmd);
return 0;
}
-static int tcm_vhost_queue_status(struct se_cmd *se_cmd)
+static int vhost_scsi_queue_status(struct se_cmd *se_cmd)
{
- struct tcm_vhost_cmd *cmd = container_of(se_cmd,
- struct tcm_vhost_cmd, tvc_se_cmd);
+ struct vhost_scsi_cmd *cmd = container_of(se_cmd,
+ struct vhost_scsi_cmd, tvc_se_cmd);
vhost_scsi_complete_cmd(cmd);
return 0;
}
-static void tcm_vhost_queue_tm_rsp(struct se_cmd *se_cmd)
+static void vhost_scsi_queue_tm_rsp(struct se_cmd *se_cmd)
{
return;
}
-static void tcm_vhost_aborted_task(struct se_cmd *se_cmd)
+static void vhost_scsi_aborted_task(struct se_cmd *se_cmd)
{
return;
}
-static void tcm_vhost_free_evt(struct vhost_scsi *vs, struct tcm_vhost_evt *evt)
+static void vhost_scsi_free_evt(struct vhost_scsi *vs, struct vhost_scsi_evt *evt)
{
vs->vs_events_nr--;
kfree(evt);
}
-static struct tcm_vhost_evt *
-tcm_vhost_allocate_evt(struct vhost_scsi *vs,
+static struct vhost_scsi_evt *
+vhost_scsi_allocate_evt(struct vhost_scsi *vs,
u32 event, u32 reason)
{
struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
- struct tcm_vhost_evt *evt;
+ struct vhost_scsi_evt *evt;
if (vs->vs_events_nr > VHOST_SCSI_MAX_EVENT) {
vs->vs_events_missed = true;
@@ -573,7 +576,7 @@
evt = kzalloc(sizeof(*evt), GFP_KERNEL);
if (!evt) {
- vq_err(vq, "Failed to allocate tcm_vhost_evt\n");
+ vq_err(vq, "Failed to allocate vhost_scsi_evt\n");
vs->vs_events_missed = true;
return NULL;
}
@@ -585,7 +588,7 @@
return evt;
}
-static void vhost_scsi_free_cmd(struct tcm_vhost_cmd *cmd)
+static void vhost_scsi_free_cmd(struct vhost_scsi_cmd *cmd)
{
struct se_cmd *se_cmd = &cmd->tvc_se_cmd;
@@ -600,7 +603,7 @@
}
static void
-tcm_vhost_do_evt_work(struct vhost_scsi *vs, struct tcm_vhost_evt *evt)
+vhost_scsi_do_evt_work(struct vhost_scsi *vs, struct vhost_scsi_evt *evt)
{
struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
struct virtio_scsi_event *event = &evt->event;
@@ -646,24 +649,24 @@
if (!ret)
vhost_add_used_and_signal(&vs->dev, vq, head, 0);
else
- vq_err(vq, "Faulted on tcm_vhost_send_event\n");
+ vq_err(vq, "Faulted on vhost_scsi_send_event\n");
}
-static void tcm_vhost_evt_work(struct vhost_work *work)
+static void vhost_scsi_evt_work(struct vhost_work *work)
{
struct vhost_scsi *vs = container_of(work, struct vhost_scsi,
vs_event_work);
struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
- struct tcm_vhost_evt *evt;
+ struct vhost_scsi_evt *evt;
struct llist_node *llnode;
mutex_lock(&vq->mutex);
llnode = llist_del_all(&vs->vs_event_list);
while (llnode) {
- evt = llist_entry(llnode, struct tcm_vhost_evt, list);
+ evt = llist_entry(llnode, struct vhost_scsi_evt, list);
llnode = llist_next(llnode);
- tcm_vhost_do_evt_work(vs, evt);
- tcm_vhost_free_evt(vs, evt);
+ vhost_scsi_do_evt_work(vs, evt);
+ vhost_scsi_free_evt(vs, evt);
}
mutex_unlock(&vq->mutex);
}
@@ -679,15 +682,16 @@
vs_completion_work);
DECLARE_BITMAP(signal, VHOST_SCSI_MAX_VQ);
struct virtio_scsi_cmd_resp v_rsp;
- struct tcm_vhost_cmd *cmd;
+ struct vhost_scsi_cmd *cmd;
struct llist_node *llnode;
struct se_cmd *se_cmd;
+ struct iov_iter iov_iter;
int ret, vq;
bitmap_zero(signal, VHOST_SCSI_MAX_VQ);
llnode = llist_del_all(&vs->vs_completion_list);
while (llnode) {
- cmd = llist_entry(llnode, struct tcm_vhost_cmd,
+ cmd = llist_entry(llnode, struct vhost_scsi_cmd,
tvc_completion_list);
llnode = llist_next(llnode);
se_cmd = &cmd->tvc_se_cmd;
@@ -703,8 +707,11 @@
se_cmd->scsi_sense_length);
memcpy(v_rsp.sense, cmd->tvc_sense_buf,
se_cmd->scsi_sense_length);
- ret = copy_to_user(cmd->tvc_resp, &v_rsp, sizeof(v_rsp));
- if (likely(ret == 0)) {
+
+ iov_iter_init(&iov_iter, READ, cmd->tvc_resp_iov,
+ cmd->tvc_in_iovs, sizeof(v_rsp));
+ ret = copy_to_iter(&v_rsp, sizeof(v_rsp), &iov_iter);
+ if (likely(ret == sizeof(v_rsp))) {
struct vhost_scsi_virtqueue *q;
vhost_add_used(cmd->tvc_vq, cmd->tvc_vq_desc, 0);
q = container_of(cmd->tvc_vq, struct vhost_scsi_virtqueue, vq);
@@ -722,13 +729,13 @@
vhost_signal(&vs->dev, &vs->vqs[vq].vq);
}
-static struct tcm_vhost_cmd *
-vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct tcm_vhost_tpg *tpg,
+static struct vhost_scsi_cmd *
+vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg,
unsigned char *cdb, u64 scsi_tag, u16 lun, u8 task_attr,
u32 exp_data_len, int data_direction)
{
- struct tcm_vhost_cmd *cmd;
- struct tcm_vhost_nexus *tv_nexus;
+ struct vhost_scsi_cmd *cmd;
+ struct vhost_scsi_nexus *tv_nexus;
struct se_session *se_sess;
struct scatterlist *sg, *prot_sg;
struct page **pages;
@@ -736,22 +743,22 @@
tv_nexus = tpg->tpg_nexus;
if (!tv_nexus) {
- pr_err("Unable to locate active struct tcm_vhost_nexus\n");
+ pr_err("Unable to locate active struct vhost_scsi_nexus\n");
return ERR_PTR(-EIO);
}
se_sess = tv_nexus->tvn_se_sess;
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING);
if (tag < 0) {
- pr_err("Unable to obtain tag for tcm_vhost_cmd\n");
+ pr_err("Unable to obtain tag for vhost_scsi_cmd\n");
return ERR_PTR(-ENOMEM);
}
- cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[tag];
+ cmd = &((struct vhost_scsi_cmd *)se_sess->sess_cmd_map)[tag];
sg = cmd->tvc_sgl;
prot_sg = cmd->tvc_prot_sgl;
pages = cmd->tvc_upages;
- memset(cmd, 0, sizeof(struct tcm_vhost_cmd));
+ memset(cmd, 0, sizeof(struct vhost_scsi_cmd));
cmd->tvc_sgl = sg;
cmd->tvc_prot_sgl = prot_sg;
@@ -763,9 +770,9 @@
cmd->tvc_exp_data_len = exp_data_len;
cmd->tvc_data_direction = data_direction;
cmd->tvc_nexus = tv_nexus;
- cmd->inflight = tcm_vhost_get_inflight(vq);
+ cmd->inflight = vhost_scsi_get_inflight(vq);
- memcpy(cmd->tvc_cdb, cdb, TCM_VHOST_MAX_CDB_SIZE);
+ memcpy(cmd->tvc_cdb, cdb, VHOST_SCSI_MAX_CDB_SIZE);
return cmd;
}
@@ -776,29 +783,22 @@
* Returns the number of scatterlist entries used or -errno on error.
*/
static int
-vhost_scsi_map_to_sgl(struct tcm_vhost_cmd *tv_cmd,
+vhost_scsi_map_to_sgl(struct vhost_scsi_cmd *cmd,
+ void __user *ptr,
+ size_t len,
struct scatterlist *sgl,
- unsigned int sgl_count,
- struct iovec *iov,
- struct page **pages,
bool write)
{
- unsigned int npages = 0, pages_nr, offset, nbytes;
+ unsigned int npages = 0, offset, nbytes;
+ unsigned int pages_nr = iov_num_pages(ptr, len);
struct scatterlist *sg = sgl;
- void __user *ptr = iov->iov_base;
- size_t len = iov->iov_len;
+ struct page **pages = cmd->tvc_upages;
int ret, i;
- pages_nr = iov_num_pages(iov);
- if (pages_nr > sgl_count) {
+ if (pages_nr > VHOST_SCSI_PREALLOC_UPAGES) {
pr_err("vhost_scsi_map_to_sgl() pages_nr: %u greater than"
- " sgl_count: %u\n", pages_nr, sgl_count);
- return -ENOBUFS;
- }
- if (pages_nr > TCM_VHOST_PREALLOC_UPAGES) {
- pr_err("vhost_scsi_map_to_sgl() pages_nr: %u greater than"
- " preallocated TCM_VHOST_PREALLOC_UPAGES: %u\n",
- pages_nr, TCM_VHOST_PREALLOC_UPAGES);
+ " preallocated VHOST_SCSI_PREALLOC_UPAGES: %u\n",
+ pages_nr, VHOST_SCSI_PREALLOC_UPAGES);
return -ENOBUFS;
}
@@ -829,84 +829,94 @@
}
static int
-vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *cmd,
- struct iovec *iov,
- int niov,
- bool write)
+vhost_scsi_calc_sgls(struct iov_iter *iter, size_t bytes, int max_sgls)
{
- struct scatterlist *sg = cmd->tvc_sgl;
- unsigned int sgl_count = 0;
- int ret, i;
+ int sgl_count = 0;
- for (i = 0; i < niov; i++)
- sgl_count += iov_num_pages(&iov[i]);
-
- if (sgl_count > TCM_VHOST_PREALLOC_SGLS) {
- pr_err("vhost_scsi_map_iov_to_sgl() sgl_count: %u greater than"
- " preallocated TCM_VHOST_PREALLOC_SGLS: %u\n",
- sgl_count, TCM_VHOST_PREALLOC_SGLS);
- return -ENOBUFS;
+ if (!iter || !iter->iov) {
+ pr_err("%s: iter->iov is NULL, but expected bytes: %zu"
+ " present\n", __func__, bytes);
+ return -EINVAL;
}
- pr_debug("%s sg %p sgl_count %u\n", __func__, sg, sgl_count);
- sg_init_table(sg, sgl_count);
- cmd->tvc_sgl_count = sgl_count;
+ sgl_count = iov_iter_npages(iter, 0xffff);
+ if (sgl_count > max_sgls) {
+ pr_err("%s: requested sgl_count: %d exceeds pre-allocated"
+ " max_sgls: %d\n", __func__, sgl_count, max_sgls);
+ return -EINVAL;
+ }
+ return sgl_count;
+}
- pr_debug("Mapping iovec %p for %u pages\n", &iov[0], sgl_count);
+static int
+vhost_scsi_iov_to_sgl(struct vhost_scsi_cmd *cmd, bool write,
+ struct iov_iter *iter,
+ struct scatterlist *sg, int sg_count)
+{
+ size_t off = iter->iov_offset;
+ int i, ret;
- for (i = 0; i < niov; i++) {
- ret = vhost_scsi_map_to_sgl(cmd, sg, sgl_count, &iov[i],
- cmd->tvc_upages, write);
+ for (i = 0; i < iter->nr_segs; i++) {
+ void __user *base = iter->iov[i].iov_base + off;
+ size_t len = iter->iov[i].iov_len - off;
+
+ ret = vhost_scsi_map_to_sgl(cmd, base, len, sg, write);
if (ret < 0) {
- for (i = 0; i < cmd->tvc_sgl_count; i++)
- put_page(sg_page(&cmd->tvc_sgl[i]));
-
- cmd->tvc_sgl_count = 0;
+ for (i = 0; i < sg_count; i++) {
+ struct page *page = sg_page(&sg[i]);
+ if (page)
+ put_page(page);
+ }
return ret;
}
sg += ret;
- sgl_count -= ret;
+ off = 0;
}
return 0;
}
static int
-vhost_scsi_map_iov_to_prot(struct tcm_vhost_cmd *cmd,
- struct iovec *iov,
- int niov,
- bool write)
+vhost_scsi_mapal(struct vhost_scsi_cmd *cmd,
+ size_t prot_bytes, struct iov_iter *prot_iter,
+ size_t data_bytes, struct iov_iter *data_iter)
{
- struct scatterlist *prot_sg = cmd->tvc_prot_sgl;
- unsigned int prot_sgl_count = 0;
- int ret, i;
+ int sgl_count, ret;
+ bool write = (cmd->tvc_data_direction == DMA_FROM_DEVICE);
- for (i = 0; i < niov; i++)
- prot_sgl_count += iov_num_pages(&iov[i]);
+ if (prot_bytes) {
+ sgl_count = vhost_scsi_calc_sgls(prot_iter, prot_bytes,
+ VHOST_SCSI_PREALLOC_PROT_SGLS);
+ if (sgl_count < 0)
+ return sgl_count;
- if (prot_sgl_count > TCM_VHOST_PREALLOC_PROT_SGLS) {
- pr_err("vhost_scsi_map_iov_to_prot() sgl_count: %u greater than"
- " preallocated TCM_VHOST_PREALLOC_PROT_SGLS: %u\n",
- prot_sgl_count, TCM_VHOST_PREALLOC_PROT_SGLS);
- return -ENOBUFS;
- }
+ sg_init_table(cmd->tvc_prot_sgl, sgl_count);
+ cmd->tvc_prot_sgl_count = sgl_count;
+ pr_debug("%s prot_sg %p prot_sgl_count %u\n", __func__,
+ cmd->tvc_prot_sgl, cmd->tvc_prot_sgl_count);
- pr_debug("%s prot_sg %p prot_sgl_count %u\n", __func__,
- prot_sg, prot_sgl_count);
- sg_init_table(prot_sg, prot_sgl_count);
- cmd->tvc_prot_sgl_count = prot_sgl_count;
-
- for (i = 0; i < niov; i++) {
- ret = vhost_scsi_map_to_sgl(cmd, prot_sg, prot_sgl_count, &iov[i],
- cmd->tvc_upages, write);
+ ret = vhost_scsi_iov_to_sgl(cmd, write, prot_iter,
+ cmd->tvc_prot_sgl,
+ cmd->tvc_prot_sgl_count);
if (ret < 0) {
- for (i = 0; i < cmd->tvc_prot_sgl_count; i++)
- put_page(sg_page(&cmd->tvc_prot_sgl[i]));
-
cmd->tvc_prot_sgl_count = 0;
return ret;
}
- prot_sg += ret;
- prot_sgl_count -= ret;
+ }
+ sgl_count = vhost_scsi_calc_sgls(data_iter, data_bytes,
+ VHOST_SCSI_PREALLOC_SGLS);
+ if (sgl_count < 0)
+ return sgl_count;
+
+ sg_init_table(cmd->tvc_sgl, sgl_count);
+ cmd->tvc_sgl_count = sgl_count;
+ pr_debug("%s data_sg %p data_sgl_count %u\n", __func__,
+ cmd->tvc_sgl, cmd->tvc_sgl_count);
+
+ ret = vhost_scsi_iov_to_sgl(cmd, write, data_iter,
+ cmd->tvc_sgl, cmd->tvc_sgl_count);
+ if (ret < 0) {
+ cmd->tvc_sgl_count = 0;
+ return ret;
}
return 0;
}
@@ -928,11 +938,11 @@
return TCM_SIMPLE_TAG;
}
-static void tcm_vhost_submission_work(struct work_struct *work)
+static void vhost_scsi_submission_work(struct work_struct *work)
{
- struct tcm_vhost_cmd *cmd =
- container_of(work, struct tcm_vhost_cmd, work);
- struct tcm_vhost_nexus *tv_nexus;
+ struct vhost_scsi_cmd *cmd =
+ container_of(work, struct vhost_scsi_cmd, work);
+ struct vhost_scsi_nexus *tv_nexus;
struct se_cmd *se_cmd = &cmd->tvc_se_cmd;
struct scatterlist *sg_ptr, *sg_prot_ptr = NULL;
int rc;
@@ -986,19 +996,20 @@
static void
vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
{
- struct tcm_vhost_tpg **vs_tpg;
+ struct vhost_scsi_tpg **vs_tpg, *tpg;
struct virtio_scsi_cmd_req v_req;
struct virtio_scsi_cmd_req_pi v_req_pi;
- struct tcm_vhost_tpg *tpg;
- struct tcm_vhost_cmd *cmd;
+ struct vhost_scsi_cmd *cmd;
+ struct iov_iter out_iter, in_iter, prot_iter, data_iter;
u64 tag;
- u32 exp_data_len, data_first, data_num, data_direction, prot_first;
- unsigned out, in, i;
- int head, ret, data_niov, prot_niov, prot_bytes;
- size_t req_size;
+ u32 exp_data_len, data_direction;
+ unsigned out, in;
+ int head, ret, prot_bytes;
+ size_t req_size, rsp_size = sizeof(struct virtio_scsi_cmd_resp);
+ size_t out_size, in_size;
u16 lun;
u8 *target, *lunp, task_attr;
- bool hdr_pi;
+ bool t10_pi = vhost_has_feature(vq, VIRTIO_SCSI_F_T10_PI);
void *req, *cdb;
mutex_lock(&vq->mutex);
@@ -1014,10 +1025,10 @@
for (;;) {
head = vhost_get_vq_desc(vq, vq->iov,
- ARRAY_SIZE(vq->iov), &out, &in,
- NULL, NULL);
+ ARRAY_SIZE(vq->iov), &out, &in,
+ NULL, NULL);
pr_debug("vhost_get_vq_desc: head: %d, out: %u in: %u\n",
- head, out, in);
+ head, out, in);
/* On error, stop handling until the next kick. */
if (unlikely(head < 0))
break;
@@ -1029,113 +1040,134 @@
}
break;
}
-
- /* FIXME: BIDI operation */
- if (out == 1 && in == 1) {
- data_direction = DMA_NONE;
- data_first = 0;
- data_num = 0;
- } else if (out == 1 && in > 1) {
- data_direction = DMA_FROM_DEVICE;
- data_first = out + 1;
- data_num = in - 1;
- } else if (out > 1 && in == 1) {
- data_direction = DMA_TO_DEVICE;
- data_first = 1;
- data_num = out - 1;
- } else {
- vq_err(vq, "Invalid buffer layout out: %u in: %u\n",
- out, in);
- break;
- }
-
/*
- * Check for a sane resp buffer so we can report errors to
- * the guest.
+ * Check for a sane response buffer so we can report early
+ * errors back to the guest.
*/
- if (unlikely(vq->iov[out].iov_len !=
- sizeof(struct virtio_scsi_cmd_resp))) {
- vq_err(vq, "Expecting virtio_scsi_cmd_resp, got %zu"
- " bytes\n", vq->iov[out].iov_len);
+ if (unlikely(vq->iov[out].iov_len < rsp_size)) {
+ vq_err(vq, "Expecting at least virtio_scsi_cmd_resp"
+ " size, got %zu bytes\n", vq->iov[out].iov_len);
break;
}
-
- if (vhost_has_feature(vq, VIRTIO_SCSI_F_T10_PI)) {
+ /*
+ * Setup pointers and values based upon different virtio-scsi
+ * request header if T10_PI is enabled in KVM guest.
+ */
+ if (t10_pi) {
req = &v_req_pi;
+ req_size = sizeof(v_req_pi);
lunp = &v_req_pi.lun[0];
target = &v_req_pi.lun[1];
- req_size = sizeof(v_req_pi);
- hdr_pi = true;
} else {
req = &v_req;
+ req_size = sizeof(v_req);
lunp = &v_req.lun[0];
target = &v_req.lun[1];
- req_size = sizeof(v_req);
- hdr_pi = false;
}
+ /*
+ * FIXME: Not correct for BIDI operation
+ */
+ out_size = iov_length(vq->iov, out);
+ in_size = iov_length(&vq->iov[out], in);
- if (unlikely(vq->iov[0].iov_len < req_size)) {
- pr_err("Expecting virtio-scsi header: %zu, got %zu\n",
- req_size, vq->iov[0].iov_len);
- break;
- }
- ret = copy_from_user(req, vq->iov[0].iov_base, req_size);
- if (unlikely(ret)) {
- vq_err(vq, "Faulted on virtio_scsi_cmd_req\n");
- break;
- }
+ /*
+ * Copy over the virtio-scsi request header, which for a
+ * ANY_LAYOUT enabled guest may span multiple iovecs, or a
+ * single iovec may contain both the header + outgoing
+ * WRITE payloads.
+ *
+ * copy_from_iter() will advance out_iter, so that it will
+ * point at the start of the outgoing WRITE payload, if
+ * DMA_TO_DEVICE is set.
+ */
+ iov_iter_init(&out_iter, WRITE, vq->iov, out, out_size);
+ ret = copy_from_iter(req, req_size, &out_iter);
+ if (unlikely(ret != req_size)) {
+ vq_err(vq, "Faulted on copy_from_iter\n");
+ vhost_scsi_send_bad_target(vs, vq, head, out);
+ continue;
+ }
/* virtio-scsi spec requires byte 0 of the lun to be 1 */
if (unlikely(*lunp != 1)) {
+ vq_err(vq, "Illegal virtio-scsi lun: %u\n", *lunp);
vhost_scsi_send_bad_target(vs, vq, head, out);
continue;
}
tpg = ACCESS_ONCE(vs_tpg[*target]);
-
- /* Target does not exist, fail the request */
if (unlikely(!tpg)) {
+ /* Target does not exist, fail the request */
vhost_scsi_send_bad_target(vs, vq, head, out);
continue;
}
-
- data_niov = data_num;
- prot_niov = prot_first = prot_bytes = 0;
/*
- * Determine if any protection information iovecs are preceeding
- * the actual data payload, and adjust data_first + data_niov
- * values accordingly for vhost_scsi_map_iov_to_sgl() below.
+ * Determine data_direction by calculating the total outgoing
+ * iovec sizes + incoming iovec sizes vs. virtio-scsi request +
+ * response headers respectively.
*
- * Also extract virtio_scsi header bits for vhost_scsi_get_tag()
+ * For DMA_TO_DEVICE this is out_iter, which is already pointing
+ * to the right place.
+ *
+ * For DMA_FROM_DEVICE, the iovec will be just past the end
+ * of the virtio-scsi response header in either the same
+ * or immediately following iovec.
+ *
+ * Any associated T10_PI bytes for the outgoing / incoming
+ * payloads are included in calculation of exp_data_len here.
*/
- if (hdr_pi) {
+ prot_bytes = 0;
+
+ if (out_size > req_size) {
+ data_direction = DMA_TO_DEVICE;
+ exp_data_len = out_size - req_size;
+ data_iter = out_iter;
+ } else if (in_size > rsp_size) {
+ data_direction = DMA_FROM_DEVICE;
+ exp_data_len = in_size - rsp_size;
+
+ iov_iter_init(&in_iter, READ, &vq->iov[out], in,
+ rsp_size + exp_data_len);
+ iov_iter_advance(&in_iter, rsp_size);
+ data_iter = in_iter;
+ } else {
+ data_direction = DMA_NONE;
+ exp_data_len = 0;
+ }
+ /*
+ * If T10_PI header + payload is present, setup prot_iter values
+ * and recalculate data_iter for vhost_scsi_mapal() mapping to
+ * host scatterlists via get_user_pages_fast().
+ */
+ if (t10_pi) {
if (v_req_pi.pi_bytesout) {
if (data_direction != DMA_TO_DEVICE) {
- vq_err(vq, "Received non zero do_pi_niov"
- ", but wrong data_direction\n");
- goto err_cmd;
+ vq_err(vq, "Received non zero pi_bytesout,"
+ " but wrong data_direction\n");
+ vhost_scsi_send_bad_target(vs, vq, head, out);
+ continue;
}
prot_bytes = vhost32_to_cpu(vq, v_req_pi.pi_bytesout);
} else if (v_req_pi.pi_bytesin) {
if (data_direction != DMA_FROM_DEVICE) {
- vq_err(vq, "Received non zero di_pi_niov"
- ", but wrong data_direction\n");
- goto err_cmd;
+ vq_err(vq, "Received non zero pi_bytesin,"
+ " but wrong data_direction\n");
+ vhost_scsi_send_bad_target(vs, vq, head, out);
+ continue;
}
prot_bytes = vhost32_to_cpu(vq, v_req_pi.pi_bytesin);
}
+ /*
+ * Set prot_iter to data_iter, and advance past any
+ * preceeding prot_bytes that may be present.
+ *
+ * Also fix up the exp_data_len to reflect only the
+ * actual data payload length.
+ */
if (prot_bytes) {
- int tmp = 0;
-
- for (i = 0; i < data_num; i++) {
- tmp += vq->iov[data_first + i].iov_len;
- prot_niov++;
- if (tmp >= prot_bytes)
- break;
- }
- prot_first = data_first;
- data_first += prot_niov;
- data_niov = data_num - prot_niov;
+ exp_data_len -= prot_bytes;
+ prot_iter = data_iter;
+ iov_iter_advance(&data_iter, prot_bytes);
}
tag = vhost64_to_cpu(vq, v_req_pi.tag);
task_attr = v_req_pi.task_attr;
@@ -1147,83 +1179,65 @@
cdb = &v_req.cdb[0];
lun = ((v_req.lun[2] << 8) | v_req.lun[3]) & 0x3FFF;
}
- exp_data_len = 0;
- for (i = 0; i < data_niov; i++)
- exp_data_len += vq->iov[data_first + i].iov_len;
/*
- * Check that the recieved CDB size does not exceeded our
- * hardcoded max for vhost-scsi
+ * Check that the received CDB size does not exceeded our
+ * hardcoded max for vhost-scsi, then get a pre-allocated
+ * cmd descriptor for the new virtio-scsi tag.
*
* TODO what if cdb was too small for varlen cdb header?
*/
- if (unlikely(scsi_command_size(cdb) > TCM_VHOST_MAX_CDB_SIZE)) {
+ if (unlikely(scsi_command_size(cdb) > VHOST_SCSI_MAX_CDB_SIZE)) {
vq_err(vq, "Received SCSI CDB with command_size: %d that"
" exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n",
- scsi_command_size(cdb), TCM_VHOST_MAX_CDB_SIZE);
- goto err_cmd;
+ scsi_command_size(cdb), VHOST_SCSI_MAX_CDB_SIZE);
+ vhost_scsi_send_bad_target(vs, vq, head, out);
+ continue;
}
-
cmd = vhost_scsi_get_tag(vq, tpg, cdb, tag, lun, task_attr,
exp_data_len + prot_bytes,
data_direction);
if (IS_ERR(cmd)) {
vq_err(vq, "vhost_scsi_get_tag failed %ld\n",
- PTR_ERR(cmd));
- goto err_cmd;
+ PTR_ERR(cmd));
+ vhost_scsi_send_bad_target(vs, vq, head, out);
+ continue;
}
-
- pr_debug("Allocated tv_cmd: %p exp_data_len: %d, data_direction"
- ": %d\n", cmd, exp_data_len, data_direction);
-
cmd->tvc_vhost = vs;
cmd->tvc_vq = vq;
- cmd->tvc_resp = vq->iov[out].iov_base;
+ cmd->tvc_resp_iov = &vq->iov[out];
+ cmd->tvc_in_iovs = in;
pr_debug("vhost_scsi got command opcode: %#02x, lun: %d\n",
- cmd->tvc_cdb[0], cmd->tvc_lun);
+ cmd->tvc_cdb[0], cmd->tvc_lun);
+ pr_debug("cmd: %p exp_data_len: %d, prot_bytes: %d data_direction:"
+ " %d\n", cmd, exp_data_len, prot_bytes, data_direction);
- if (prot_niov) {
- ret = vhost_scsi_map_iov_to_prot(cmd,
- &vq->iov[prot_first], prot_niov,
- data_direction == DMA_FROM_DEVICE);
- if (unlikely(ret)) {
- vq_err(vq, "Failed to map iov to"
- " prot_sgl\n");
- goto err_free;
- }
- }
if (data_direction != DMA_NONE) {
- ret = vhost_scsi_map_iov_to_sgl(cmd,
- &vq->iov[data_first], data_niov,
- data_direction == DMA_FROM_DEVICE);
+ ret = vhost_scsi_mapal(cmd,
+ prot_bytes, &prot_iter,
+ exp_data_len, &data_iter);
if (unlikely(ret)) {
vq_err(vq, "Failed to map iov to sgl\n");
- goto err_free;
+ vhost_scsi_release_cmd(&cmd->tvc_se_cmd);
+ vhost_scsi_send_bad_target(vs, vq, head, out);
+ continue;
}
}
/*
* Save the descriptor from vhost_get_vq_desc() to be used to
* complete the virtio-scsi request in TCM callback context via
- * tcm_vhost_queue_data_in() and tcm_vhost_queue_status()
+ * vhost_scsi_queue_data_in() and vhost_scsi_queue_status()
*/
cmd->tvc_vq_desc = head;
/*
- * Dispatch tv_cmd descriptor for cmwq execution in process
- * context provided by tcm_vhost_workqueue. This also ensures
- * tv_cmd is executed on the same kworker CPU as this vhost
- * thread to gain positive L2 cache locality effects..
+ * Dispatch cmd descriptor for cmwq execution in process
+ * context provided by vhost_scsi_workqueue. This also ensures
+ * cmd is executed on the same kworker CPU as this vhost
+ * thread to gain positive L2 cache locality effects.
*/
- INIT_WORK(&cmd->work, tcm_vhost_submission_work);
- queue_work(tcm_vhost_workqueue, &cmd->work);
+ INIT_WORK(&cmd->work, vhost_scsi_submission_work);
+ queue_work(vhost_scsi_workqueue, &cmd->work);
}
-
- mutex_unlock(&vq->mutex);
- return;
-
-err_free:
- vhost_scsi_free_cmd(cmd);
-err_cmd:
- vhost_scsi_send_bad_target(vs, vq, head, out);
out:
mutex_unlock(&vq->mutex);
}
@@ -1234,15 +1248,15 @@
}
static void
-tcm_vhost_send_evt(struct vhost_scsi *vs,
- struct tcm_vhost_tpg *tpg,
+vhost_scsi_send_evt(struct vhost_scsi *vs,
+ struct vhost_scsi_tpg *tpg,
struct se_lun *lun,
u32 event,
u32 reason)
{
- struct tcm_vhost_evt *evt;
+ struct vhost_scsi_evt *evt;
- evt = tcm_vhost_allocate_evt(vs, event, reason);
+ evt = vhost_scsi_allocate_evt(vs, event, reason);
if (!evt)
return;
@@ -1253,7 +1267,7 @@
* lun[4-7] need to be zero according to virtio-scsi spec.
*/
evt->event.lun[0] = 0x01;
- evt->event.lun[1] = tpg->tport_tpgt & 0xFF;
+ evt->event.lun[1] = tpg->tport_tpgt;
if (lun->unpacked_lun >= 256)
evt->event.lun[2] = lun->unpacked_lun >> 8 | 0x40 ;
evt->event.lun[3] = lun->unpacked_lun & 0xFF;
@@ -1274,7 +1288,7 @@
goto out;
if (vs->vs_events_missed)
- tcm_vhost_send_evt(vs, NULL, NULL, VIRTIO_SCSI_T_NO_EVENT, 0);
+ vhost_scsi_send_evt(vs, NULL, NULL, VIRTIO_SCSI_T_NO_EVENT, 0);
out:
mutex_unlock(&vq->mutex);
}
@@ -1300,7 +1314,7 @@
int i;
/* Init new inflight and remember the old inflight */
- tcm_vhost_init_inflight(vs, old_inflight);
+ vhost_scsi_init_inflight(vs, old_inflight);
/*
* The inflight->kref was initialized to 1. We decrement it here to
@@ -1308,7 +1322,7 @@
* when all the reqs are finished.
*/
for (i = 0; i < VHOST_SCSI_MAX_VQ; i++)
- kref_put(&old_inflight[i]->kref, tcm_vhost_done_inflight);
+ kref_put(&old_inflight[i]->kref, vhost_scsi_done_inflight);
/* Flush both the vhost poll and vhost work */
for (i = 0; i < VHOST_SCSI_MAX_VQ; i++)
@@ -1323,24 +1337,24 @@
/*
* Called from vhost_scsi_ioctl() context to walk the list of available
- * tcm_vhost_tpg with an active struct tcm_vhost_nexus
+ * vhost_scsi_tpg with an active struct vhost_scsi_nexus
*
* The lock nesting rule is:
- * tcm_vhost_mutex -> vs->dev.mutex -> tpg->tv_tpg_mutex -> vq->mutex
+ * vhost_scsi_mutex -> vs->dev.mutex -> tpg->tv_tpg_mutex -> vq->mutex
*/
static int
vhost_scsi_set_endpoint(struct vhost_scsi *vs,
struct vhost_scsi_target *t)
{
struct se_portal_group *se_tpg;
- struct tcm_vhost_tport *tv_tport;
- struct tcm_vhost_tpg *tpg;
- struct tcm_vhost_tpg **vs_tpg;
+ struct vhost_scsi_tport *tv_tport;
+ struct vhost_scsi_tpg *tpg;
+ struct vhost_scsi_tpg **vs_tpg;
struct vhost_virtqueue *vq;
int index, ret, i, len;
bool match = false;
- mutex_lock(&tcm_vhost_mutex);
+ mutex_lock(&vhost_scsi_mutex);
mutex_lock(&vs->dev.mutex);
/* Verify that ring has been setup correctly. */
@@ -1361,7 +1375,7 @@
if (vs->vs_tpg)
memcpy(vs_tpg, vs->vs_tpg, len);
- list_for_each_entry(tpg, &tcm_vhost_list, tv_tpg_list) {
+ list_for_each_entry(tpg, &vhost_scsi_list, tv_tpg_list) {
mutex_lock(&tpg->tv_tpg_mutex);
if (!tpg->tpg_nexus) {
mutex_unlock(&tpg->tv_tpg_mutex);
@@ -1429,7 +1443,7 @@
out:
mutex_unlock(&vs->dev.mutex);
- mutex_unlock(&tcm_vhost_mutex);
+ mutex_unlock(&vhost_scsi_mutex);
return ret;
}
@@ -1438,14 +1452,14 @@
struct vhost_scsi_target *t)
{
struct se_portal_group *se_tpg;
- struct tcm_vhost_tport *tv_tport;
- struct tcm_vhost_tpg *tpg;
+ struct vhost_scsi_tport *tv_tport;
+ struct vhost_scsi_tpg *tpg;
struct vhost_virtqueue *vq;
bool match = false;
int index, ret, i;
u8 target;
- mutex_lock(&tcm_vhost_mutex);
+ mutex_lock(&vhost_scsi_mutex);
mutex_lock(&vs->dev.mutex);
/* Verify that ring has been setup correctly. */
for (index = 0; index < vs->dev.nvqs; ++index) {
@@ -1511,14 +1525,14 @@
vs->vs_tpg = NULL;
WARN_ON(vs->vs_events_nr);
mutex_unlock(&vs->dev.mutex);
- mutex_unlock(&tcm_vhost_mutex);
+ mutex_unlock(&vhost_scsi_mutex);
return 0;
err_tpg:
mutex_unlock(&tpg->tv_tpg_mutex);
err_dev:
mutex_unlock(&vs->dev.mutex);
- mutex_unlock(&tcm_vhost_mutex);
+ mutex_unlock(&vhost_scsi_mutex);
return ret;
}
@@ -1565,7 +1579,7 @@
goto err_vqs;
vhost_work_init(&vs->vs_completion_work, vhost_scsi_complete_cmd_work);
- vhost_work_init(&vs->vs_event_work, tcm_vhost_evt_work);
+ vhost_work_init(&vs->vs_event_work, vhost_scsi_evt_work);
vs->vs_events_nr = 0;
vs->vs_events_missed = false;
@@ -1580,7 +1594,7 @@
}
vhost_dev_init(&vs->dev, vqs, VHOST_SCSI_MAX_VQ);
- tcm_vhost_init_inflight(vs, NULL);
+ vhost_scsi_init_inflight(vs, NULL);
f->private_data = vs;
return 0;
@@ -1712,7 +1726,7 @@
return misc_deregister(&vhost_scsi_misc);
}
-static char *tcm_vhost_dump_proto_id(struct tcm_vhost_tport *tport)
+static char *vhost_scsi_dump_proto_id(struct vhost_scsi_tport *tport)
{
switch (tport->tport_proto_id) {
case SCSI_PROTOCOL_SAS:
@@ -1729,7 +1743,7 @@
}
static void
-tcm_vhost_do_plug(struct tcm_vhost_tpg *tpg,
+vhost_scsi_do_plug(struct vhost_scsi_tpg *tpg,
struct se_lun *lun, bool plug)
{
@@ -1750,71 +1764,71 @@
vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
mutex_lock(&vq->mutex);
if (vhost_has_feature(vq, VIRTIO_SCSI_F_HOTPLUG))
- tcm_vhost_send_evt(vs, tpg, lun,
+ vhost_scsi_send_evt(vs, tpg, lun,
VIRTIO_SCSI_T_TRANSPORT_RESET, reason);
mutex_unlock(&vq->mutex);
mutex_unlock(&vs->dev.mutex);
}
-static void tcm_vhost_hotplug(struct tcm_vhost_tpg *tpg, struct se_lun *lun)
+static void vhost_scsi_hotplug(struct vhost_scsi_tpg *tpg, struct se_lun *lun)
{
- tcm_vhost_do_plug(tpg, lun, true);
+ vhost_scsi_do_plug(tpg, lun, true);
}
-static void tcm_vhost_hotunplug(struct tcm_vhost_tpg *tpg, struct se_lun *lun)
+static void vhost_scsi_hotunplug(struct vhost_scsi_tpg *tpg, struct se_lun *lun)
{
- tcm_vhost_do_plug(tpg, lun, false);
+ vhost_scsi_do_plug(tpg, lun, false);
}
-static int tcm_vhost_port_link(struct se_portal_group *se_tpg,
+static int vhost_scsi_port_link(struct se_portal_group *se_tpg,
struct se_lun *lun)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
- mutex_lock(&tcm_vhost_mutex);
+ mutex_lock(&vhost_scsi_mutex);
mutex_lock(&tpg->tv_tpg_mutex);
tpg->tv_tpg_port_count++;
mutex_unlock(&tpg->tv_tpg_mutex);
- tcm_vhost_hotplug(tpg, lun);
+ vhost_scsi_hotplug(tpg, lun);
- mutex_unlock(&tcm_vhost_mutex);
+ mutex_unlock(&vhost_scsi_mutex);
return 0;
}
-static void tcm_vhost_port_unlink(struct se_portal_group *se_tpg,
+static void vhost_scsi_port_unlink(struct se_portal_group *se_tpg,
struct se_lun *lun)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
- mutex_lock(&tcm_vhost_mutex);
+ mutex_lock(&vhost_scsi_mutex);
mutex_lock(&tpg->tv_tpg_mutex);
tpg->tv_tpg_port_count--;
mutex_unlock(&tpg->tv_tpg_mutex);
- tcm_vhost_hotunplug(tpg, lun);
+ vhost_scsi_hotunplug(tpg, lun);
- mutex_unlock(&tcm_vhost_mutex);
+ mutex_unlock(&vhost_scsi_mutex);
}
static struct se_node_acl *
-tcm_vhost_make_nodeacl(struct se_portal_group *se_tpg,
+vhost_scsi_make_nodeacl(struct se_portal_group *se_tpg,
struct config_group *group,
const char *name)
{
struct se_node_acl *se_nacl, *se_nacl_new;
- struct tcm_vhost_nacl *nacl;
+ struct vhost_scsi_nacl *nacl;
u64 wwpn = 0;
u32 nexus_depth;
- /* tcm_vhost_parse_wwn(name, &wwpn, 1) < 0)
+ /* vhost_scsi_parse_wwn(name, &wwpn, 1) < 0)
return ERR_PTR(-EINVAL); */
- se_nacl_new = tcm_vhost_alloc_fabric_acl(se_tpg);
+ se_nacl_new = vhost_scsi_alloc_fabric_acl(se_tpg);
if (!se_nacl_new)
return ERR_PTR(-ENOMEM);
@@ -1826,37 +1840,37 @@
se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,
name, nexus_depth);
if (IS_ERR(se_nacl)) {
- tcm_vhost_release_fabric_acl(se_tpg, se_nacl_new);
+ vhost_scsi_release_fabric_acl(se_tpg, se_nacl_new);
return se_nacl;
}
/*
- * Locate our struct tcm_vhost_nacl and set the FC Nport WWPN
+ * Locate our struct vhost_scsi_nacl and set the FC Nport WWPN
*/
- nacl = container_of(se_nacl, struct tcm_vhost_nacl, se_node_acl);
+ nacl = container_of(se_nacl, struct vhost_scsi_nacl, se_node_acl);
nacl->iport_wwpn = wwpn;
return se_nacl;
}
-static void tcm_vhost_drop_nodeacl(struct se_node_acl *se_acl)
+static void vhost_scsi_drop_nodeacl(struct se_node_acl *se_acl)
{
- struct tcm_vhost_nacl *nacl = container_of(se_acl,
- struct tcm_vhost_nacl, se_node_acl);
+ struct vhost_scsi_nacl *nacl = container_of(se_acl,
+ struct vhost_scsi_nacl, se_node_acl);
core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);
kfree(nacl);
}
-static void tcm_vhost_free_cmd_map_res(struct tcm_vhost_nexus *nexus,
+static void vhost_scsi_free_cmd_map_res(struct vhost_scsi_nexus *nexus,
struct se_session *se_sess)
{
- struct tcm_vhost_cmd *tv_cmd;
+ struct vhost_scsi_cmd *tv_cmd;
unsigned int i;
if (!se_sess->sess_cmd_map)
return;
- for (i = 0; i < TCM_VHOST_DEFAULT_TAGS; i++) {
- tv_cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[i];
+ for (i = 0; i < VHOST_SCSI_DEFAULT_TAGS; i++) {
+ tv_cmd = &((struct vhost_scsi_cmd *)se_sess->sess_cmd_map)[i];
kfree(tv_cmd->tvc_sgl);
kfree(tv_cmd->tvc_prot_sgl);
@@ -1864,13 +1878,13 @@
}
}
-static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg,
+static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg,
const char *name)
{
struct se_portal_group *se_tpg;
struct se_session *se_sess;
- struct tcm_vhost_nexus *tv_nexus;
- struct tcm_vhost_cmd *tv_cmd;
+ struct vhost_scsi_nexus *tv_nexus;
+ struct vhost_scsi_cmd *tv_cmd;
unsigned int i;
mutex_lock(&tpg->tv_tpg_mutex);
@@ -1881,19 +1895,19 @@
}
se_tpg = &tpg->se_tpg;
- tv_nexus = kzalloc(sizeof(struct tcm_vhost_nexus), GFP_KERNEL);
+ tv_nexus = kzalloc(sizeof(struct vhost_scsi_nexus), GFP_KERNEL);
if (!tv_nexus) {
mutex_unlock(&tpg->tv_tpg_mutex);
- pr_err("Unable to allocate struct tcm_vhost_nexus\n");
+ pr_err("Unable to allocate struct vhost_scsi_nexus\n");
return -ENOMEM;
}
/*
* Initialize the struct se_session pointer and setup tagpool
- * for struct tcm_vhost_cmd descriptors
+ * for struct vhost_scsi_cmd descriptors
*/
tv_nexus->tvn_se_sess = transport_init_session_tags(
- TCM_VHOST_DEFAULT_TAGS,
- sizeof(struct tcm_vhost_cmd),
+ VHOST_SCSI_DEFAULT_TAGS,
+ sizeof(struct vhost_scsi_cmd),
TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS);
if (IS_ERR(tv_nexus->tvn_se_sess)) {
mutex_unlock(&tpg->tv_tpg_mutex);
@@ -1901,11 +1915,11 @@
return -ENOMEM;
}
se_sess = tv_nexus->tvn_se_sess;
- for (i = 0; i < TCM_VHOST_DEFAULT_TAGS; i++) {
- tv_cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[i];
+ for (i = 0; i < VHOST_SCSI_DEFAULT_TAGS; i++) {
+ tv_cmd = &((struct vhost_scsi_cmd *)se_sess->sess_cmd_map)[i];
tv_cmd->tvc_sgl = kzalloc(sizeof(struct scatterlist) *
- TCM_VHOST_PREALLOC_SGLS, GFP_KERNEL);
+ VHOST_SCSI_PREALLOC_SGLS, GFP_KERNEL);
if (!tv_cmd->tvc_sgl) {
mutex_unlock(&tpg->tv_tpg_mutex);
pr_err("Unable to allocate tv_cmd->tvc_sgl\n");
@@ -1913,7 +1927,7 @@
}
tv_cmd->tvc_upages = kzalloc(sizeof(struct page *) *
- TCM_VHOST_PREALLOC_UPAGES, GFP_KERNEL);
+ VHOST_SCSI_PREALLOC_UPAGES, GFP_KERNEL);
if (!tv_cmd->tvc_upages) {
mutex_unlock(&tpg->tv_tpg_mutex);
pr_err("Unable to allocate tv_cmd->tvc_upages\n");
@@ -1921,7 +1935,7 @@
}
tv_cmd->tvc_prot_sgl = kzalloc(sizeof(struct scatterlist) *
- TCM_VHOST_PREALLOC_PROT_SGLS, GFP_KERNEL);
+ VHOST_SCSI_PREALLOC_PROT_SGLS, GFP_KERNEL);
if (!tv_cmd->tvc_prot_sgl) {
mutex_unlock(&tpg->tv_tpg_mutex);
pr_err("Unable to allocate tv_cmd->tvc_prot_sgl\n");
@@ -1930,7 +1944,7 @@
}
/*
* Since we are running in 'demo mode' this call with generate a
- * struct se_node_acl for the tcm_vhost struct se_portal_group with
+ * struct se_node_acl for the vhost_scsi struct se_portal_group with
* the SCSI Initiator port name of the passed configfs group 'name'.
*/
tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl(
@@ -1953,16 +1967,16 @@
return 0;
out:
- tcm_vhost_free_cmd_map_res(tv_nexus, se_sess);
+ vhost_scsi_free_cmd_map_res(tv_nexus, se_sess);
transport_free_session(se_sess);
kfree(tv_nexus);
return -ENOMEM;
}
-static int tcm_vhost_drop_nexus(struct tcm_vhost_tpg *tpg)
+static int vhost_scsi_drop_nexus(struct vhost_scsi_tpg *tpg)
{
struct se_session *se_sess;
- struct tcm_vhost_nexus *tv_nexus;
+ struct vhost_scsi_nexus *tv_nexus;
mutex_lock(&tpg->tv_tpg_mutex);
tv_nexus = tpg->tpg_nexus;
@@ -1994,10 +2008,10 @@
}
pr_debug("TCM_vhost_ConfigFS: Removing I_T Nexus to emulated"
- " %s Initiator Port: %s\n", tcm_vhost_dump_proto_id(tpg->tport),
+ " %s Initiator Port: %s\n", vhost_scsi_dump_proto_id(tpg->tport),
tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
- tcm_vhost_free_cmd_map_res(tv_nexus, se_sess);
+ vhost_scsi_free_cmd_map_res(tv_nexus, se_sess);
/*
* Release the SCSI I_T Nexus to the emulated vhost Target Port
*/
@@ -2009,12 +2023,12 @@
return 0;
}
-static ssize_t tcm_vhost_tpg_show_nexus(struct se_portal_group *se_tpg,
+static ssize_t vhost_scsi_tpg_show_nexus(struct se_portal_group *se_tpg,
char *page)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
- struct tcm_vhost_nexus *tv_nexus;
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
+ struct vhost_scsi_nexus *tv_nexus;
ssize_t ret;
mutex_lock(&tpg->tv_tpg_mutex);
@@ -2030,40 +2044,40 @@
return ret;
}
-static ssize_t tcm_vhost_tpg_store_nexus(struct se_portal_group *se_tpg,
+static ssize_t vhost_scsi_tpg_store_nexus(struct se_portal_group *se_tpg,
const char *page,
size_t count)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
- struct tcm_vhost_tport *tport_wwn = tpg->tport;
- unsigned char i_port[TCM_VHOST_NAMELEN], *ptr, *port_ptr;
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
+ struct vhost_scsi_tport *tport_wwn = tpg->tport;
+ unsigned char i_port[VHOST_SCSI_NAMELEN], *ptr, *port_ptr;
int ret;
/*
* Shutdown the active I_T nexus if 'NULL' is passed..
*/
if (!strncmp(page, "NULL", 4)) {
- ret = tcm_vhost_drop_nexus(tpg);
+ ret = vhost_scsi_drop_nexus(tpg);
return (!ret) ? count : ret;
}
/*
* Otherwise make sure the passed virtual Initiator port WWN matches
- * the fabric protocol_id set in tcm_vhost_make_tport(), and call
- * tcm_vhost_make_nexus().
+ * the fabric protocol_id set in vhost_scsi_make_tport(), and call
+ * vhost_scsi_make_nexus().
*/
- if (strlen(page) >= TCM_VHOST_NAMELEN) {
+ if (strlen(page) >= VHOST_SCSI_NAMELEN) {
pr_err("Emulated NAA Sas Address: %s, exceeds"
- " max: %d\n", page, TCM_VHOST_NAMELEN);
+ " max: %d\n", page, VHOST_SCSI_NAMELEN);
return -EINVAL;
}
- snprintf(&i_port[0], TCM_VHOST_NAMELEN, "%s", page);
+ snprintf(&i_port[0], VHOST_SCSI_NAMELEN, "%s", page);
ptr = strstr(i_port, "naa.");
if (ptr) {
if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_SAS) {
pr_err("Passed SAS Initiator Port %s does not"
" match target port protoid: %s\n", i_port,
- tcm_vhost_dump_proto_id(tport_wwn));
+ vhost_scsi_dump_proto_id(tport_wwn));
return -EINVAL;
}
port_ptr = &i_port[0];
@@ -2074,7 +2088,7 @@
if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_FCP) {
pr_err("Passed FCP Initiator Port %s does not"
" match target port protoid: %s\n", i_port,
- tcm_vhost_dump_proto_id(tport_wwn));
+ vhost_scsi_dump_proto_id(tport_wwn));
return -EINVAL;
}
port_ptr = &i_port[3]; /* Skip over "fc." */
@@ -2085,7 +2099,7 @@
if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_ISCSI) {
pr_err("Passed iSCSI Initiator Port %s does not"
" match target port protoid: %s\n", i_port,
- tcm_vhost_dump_proto_id(tport_wwn));
+ vhost_scsi_dump_proto_id(tport_wwn));
return -EINVAL;
}
port_ptr = &i_port[0];
@@ -2101,40 +2115,40 @@
if (i_port[strlen(i_port)-1] == '\n')
i_port[strlen(i_port)-1] = '\0';
- ret = tcm_vhost_make_nexus(tpg, port_ptr);
+ ret = vhost_scsi_make_nexus(tpg, port_ptr);
if (ret < 0)
return ret;
return count;
}
-TF_TPG_BASE_ATTR(tcm_vhost, nexus, S_IRUGO | S_IWUSR);
+TF_TPG_BASE_ATTR(vhost_scsi, nexus, S_IRUGO | S_IWUSR);
-static struct configfs_attribute *tcm_vhost_tpg_attrs[] = {
- &tcm_vhost_tpg_nexus.attr,
+static struct configfs_attribute *vhost_scsi_tpg_attrs[] = {
+ &vhost_scsi_tpg_nexus.attr,
NULL,
};
static struct se_portal_group *
-tcm_vhost_make_tpg(struct se_wwn *wwn,
+vhost_scsi_make_tpg(struct se_wwn *wwn,
struct config_group *group,
const char *name)
{
- struct tcm_vhost_tport *tport = container_of(wwn,
- struct tcm_vhost_tport, tport_wwn);
+ struct vhost_scsi_tport *tport = container_of(wwn,
+ struct vhost_scsi_tport, tport_wwn);
- struct tcm_vhost_tpg *tpg;
- unsigned long tpgt;
+ struct vhost_scsi_tpg *tpg;
+ u16 tpgt;
int ret;
if (strstr(name, "tpgt_") != name)
return ERR_PTR(-EINVAL);
- if (kstrtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX)
+ if (kstrtou16(name + 5, 10, &tpgt) || tpgt >= VHOST_SCSI_MAX_TARGET)
return ERR_PTR(-EINVAL);
- tpg = kzalloc(sizeof(struct tcm_vhost_tpg), GFP_KERNEL);
+ tpg = kzalloc(sizeof(struct vhost_scsi_tpg), GFP_KERNEL);
if (!tpg) {
- pr_err("Unable to allocate struct tcm_vhost_tpg");
+ pr_err("Unable to allocate struct vhost_scsi_tpg");
return ERR_PTR(-ENOMEM);
}
mutex_init(&tpg->tv_tpg_mutex);
@@ -2142,31 +2156,31 @@
tpg->tport = tport;
tpg->tport_tpgt = tpgt;
- ret = core_tpg_register(&tcm_vhost_fabric_configfs->tf_ops, wwn,
+ ret = core_tpg_register(&vhost_scsi_fabric_configfs->tf_ops, wwn,
&tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
if (ret < 0) {
kfree(tpg);
return NULL;
}
- mutex_lock(&tcm_vhost_mutex);
- list_add_tail(&tpg->tv_tpg_list, &tcm_vhost_list);
- mutex_unlock(&tcm_vhost_mutex);
+ mutex_lock(&vhost_scsi_mutex);
+ list_add_tail(&tpg->tv_tpg_list, &vhost_scsi_list);
+ mutex_unlock(&vhost_scsi_mutex);
return &tpg->se_tpg;
}
-static void tcm_vhost_drop_tpg(struct se_portal_group *se_tpg)
+static void vhost_scsi_drop_tpg(struct se_portal_group *se_tpg)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
- mutex_lock(&tcm_vhost_mutex);
+ mutex_lock(&vhost_scsi_mutex);
list_del(&tpg->tv_tpg_list);
- mutex_unlock(&tcm_vhost_mutex);
+ mutex_unlock(&vhost_scsi_mutex);
/*
* Release the virtual I_T Nexus for this vhost TPG
*/
- tcm_vhost_drop_nexus(tpg);
+ vhost_scsi_drop_nexus(tpg);
/*
* Deregister the se_tpg from TCM..
*/
@@ -2175,21 +2189,21 @@
}
static struct se_wwn *
-tcm_vhost_make_tport(struct target_fabric_configfs *tf,
+vhost_scsi_make_tport(struct target_fabric_configfs *tf,
struct config_group *group,
const char *name)
{
- struct tcm_vhost_tport *tport;
+ struct vhost_scsi_tport *tport;
char *ptr;
u64 wwpn = 0;
int off = 0;
- /* if (tcm_vhost_parse_wwn(name, &wwpn, 1) < 0)
+ /* if (vhost_scsi_parse_wwn(name, &wwpn, 1) < 0)
return ERR_PTR(-EINVAL); */
- tport = kzalloc(sizeof(struct tcm_vhost_tport), GFP_KERNEL);
+ tport = kzalloc(sizeof(struct vhost_scsi_tport), GFP_KERNEL);
if (!tport) {
- pr_err("Unable to allocate struct tcm_vhost_tport");
+ pr_err("Unable to allocate struct vhost_scsi_tport");
return ERR_PTR(-ENOMEM);
}
tport->tport_wwpn = wwpn;
@@ -2220,102 +2234,102 @@
return ERR_PTR(-EINVAL);
check_len:
- if (strlen(name) >= TCM_VHOST_NAMELEN) {
+ if (strlen(name) >= VHOST_SCSI_NAMELEN) {
pr_err("Emulated %s Address: %s, exceeds"
- " max: %d\n", name, tcm_vhost_dump_proto_id(tport),
- TCM_VHOST_NAMELEN);
+ " max: %d\n", name, vhost_scsi_dump_proto_id(tport),
+ VHOST_SCSI_NAMELEN);
kfree(tport);
return ERR_PTR(-EINVAL);
}
- snprintf(&tport->tport_name[0], TCM_VHOST_NAMELEN, "%s", &name[off]);
+ snprintf(&tport->tport_name[0], VHOST_SCSI_NAMELEN, "%s", &name[off]);
pr_debug("TCM_VHost_ConfigFS: Allocated emulated Target"
- " %s Address: %s\n", tcm_vhost_dump_proto_id(tport), name);
+ " %s Address: %s\n", vhost_scsi_dump_proto_id(tport), name);
return &tport->tport_wwn;
}
-static void tcm_vhost_drop_tport(struct se_wwn *wwn)
+static void vhost_scsi_drop_tport(struct se_wwn *wwn)
{
- struct tcm_vhost_tport *tport = container_of(wwn,
- struct tcm_vhost_tport, tport_wwn);
+ struct vhost_scsi_tport *tport = container_of(wwn,
+ struct vhost_scsi_tport, tport_wwn);
pr_debug("TCM_VHost_ConfigFS: Deallocating emulated Target"
- " %s Address: %s\n", tcm_vhost_dump_proto_id(tport),
+ " %s Address: %s\n", vhost_scsi_dump_proto_id(tport),
tport->tport_name);
kfree(tport);
}
static ssize_t
-tcm_vhost_wwn_show_attr_version(struct target_fabric_configfs *tf,
+vhost_scsi_wwn_show_attr_version(struct target_fabric_configfs *tf,
char *page)
{
return sprintf(page, "TCM_VHOST fabric module %s on %s/%s"
- "on "UTS_RELEASE"\n", TCM_VHOST_VERSION, utsname()->sysname,
+ "on "UTS_RELEASE"\n", VHOST_SCSI_VERSION, utsname()->sysname,
utsname()->machine);
}
-TF_WWN_ATTR_RO(tcm_vhost, version);
+TF_WWN_ATTR_RO(vhost_scsi, version);
-static struct configfs_attribute *tcm_vhost_wwn_attrs[] = {
- &tcm_vhost_wwn_version.attr,
+static struct configfs_attribute *vhost_scsi_wwn_attrs[] = {
+ &vhost_scsi_wwn_version.attr,
NULL,
};
-static struct target_core_fabric_ops tcm_vhost_ops = {
- .get_fabric_name = tcm_vhost_get_fabric_name,
- .get_fabric_proto_ident = tcm_vhost_get_fabric_proto_ident,
- .tpg_get_wwn = tcm_vhost_get_fabric_wwn,
- .tpg_get_tag = tcm_vhost_get_tag,
- .tpg_get_default_depth = tcm_vhost_get_default_depth,
- .tpg_get_pr_transport_id = tcm_vhost_get_pr_transport_id,
- .tpg_get_pr_transport_id_len = tcm_vhost_get_pr_transport_id_len,
- .tpg_parse_pr_out_transport_id = tcm_vhost_parse_pr_out_transport_id,
- .tpg_check_demo_mode = tcm_vhost_check_true,
- .tpg_check_demo_mode_cache = tcm_vhost_check_true,
- .tpg_check_demo_mode_write_protect = tcm_vhost_check_false,
- .tpg_check_prod_mode_write_protect = tcm_vhost_check_false,
- .tpg_alloc_fabric_acl = tcm_vhost_alloc_fabric_acl,
- .tpg_release_fabric_acl = tcm_vhost_release_fabric_acl,
- .tpg_get_inst_index = tcm_vhost_tpg_get_inst_index,
- .release_cmd = tcm_vhost_release_cmd,
+static struct target_core_fabric_ops vhost_scsi_ops = {
+ .get_fabric_name = vhost_scsi_get_fabric_name,
+ .get_fabric_proto_ident = vhost_scsi_get_fabric_proto_ident,
+ .tpg_get_wwn = vhost_scsi_get_fabric_wwn,
+ .tpg_get_tag = vhost_scsi_get_tpgt,
+ .tpg_get_default_depth = vhost_scsi_get_default_depth,
+ .tpg_get_pr_transport_id = vhost_scsi_get_pr_transport_id,
+ .tpg_get_pr_transport_id_len = vhost_scsi_get_pr_transport_id_len,
+ .tpg_parse_pr_out_transport_id = vhost_scsi_parse_pr_out_transport_id,
+ .tpg_check_demo_mode = vhost_scsi_check_true,
+ .tpg_check_demo_mode_cache = vhost_scsi_check_true,
+ .tpg_check_demo_mode_write_protect = vhost_scsi_check_false,
+ .tpg_check_prod_mode_write_protect = vhost_scsi_check_false,
+ .tpg_alloc_fabric_acl = vhost_scsi_alloc_fabric_acl,
+ .tpg_release_fabric_acl = vhost_scsi_release_fabric_acl,
+ .tpg_get_inst_index = vhost_scsi_tpg_get_inst_index,
+ .release_cmd = vhost_scsi_release_cmd,
.check_stop_free = vhost_scsi_check_stop_free,
- .shutdown_session = tcm_vhost_shutdown_session,
- .close_session = tcm_vhost_close_session,
- .sess_get_index = tcm_vhost_sess_get_index,
+ .shutdown_session = vhost_scsi_shutdown_session,
+ .close_session = vhost_scsi_close_session,
+ .sess_get_index = vhost_scsi_sess_get_index,
.sess_get_initiator_sid = NULL,
- .write_pending = tcm_vhost_write_pending,
- .write_pending_status = tcm_vhost_write_pending_status,
- .set_default_node_attributes = tcm_vhost_set_default_node_attrs,
- .get_task_tag = tcm_vhost_get_task_tag,
- .get_cmd_state = tcm_vhost_get_cmd_state,
- .queue_data_in = tcm_vhost_queue_data_in,
- .queue_status = tcm_vhost_queue_status,
- .queue_tm_rsp = tcm_vhost_queue_tm_rsp,
- .aborted_task = tcm_vhost_aborted_task,
+ .write_pending = vhost_scsi_write_pending,
+ .write_pending_status = vhost_scsi_write_pending_status,
+ .set_default_node_attributes = vhost_scsi_set_default_node_attrs,
+ .get_task_tag = vhost_scsi_get_task_tag,
+ .get_cmd_state = vhost_scsi_get_cmd_state,
+ .queue_data_in = vhost_scsi_queue_data_in,
+ .queue_status = vhost_scsi_queue_status,
+ .queue_tm_rsp = vhost_scsi_queue_tm_rsp,
+ .aborted_task = vhost_scsi_aborted_task,
/*
* Setup callers for generic logic in target_core_fabric_configfs.c
*/
- .fabric_make_wwn = tcm_vhost_make_tport,
- .fabric_drop_wwn = tcm_vhost_drop_tport,
- .fabric_make_tpg = tcm_vhost_make_tpg,
- .fabric_drop_tpg = tcm_vhost_drop_tpg,
- .fabric_post_link = tcm_vhost_port_link,
- .fabric_pre_unlink = tcm_vhost_port_unlink,
+ .fabric_make_wwn = vhost_scsi_make_tport,
+ .fabric_drop_wwn = vhost_scsi_drop_tport,
+ .fabric_make_tpg = vhost_scsi_make_tpg,
+ .fabric_drop_tpg = vhost_scsi_drop_tpg,
+ .fabric_post_link = vhost_scsi_port_link,
+ .fabric_pre_unlink = vhost_scsi_port_unlink,
.fabric_make_np = NULL,
.fabric_drop_np = NULL,
- .fabric_make_nodeacl = tcm_vhost_make_nodeacl,
- .fabric_drop_nodeacl = tcm_vhost_drop_nodeacl,
+ .fabric_make_nodeacl = vhost_scsi_make_nodeacl,
+ .fabric_drop_nodeacl = vhost_scsi_drop_nodeacl,
};
-static int tcm_vhost_register_configfs(void)
+static int vhost_scsi_register_configfs(void)
{
struct target_fabric_configfs *fabric;
int ret;
- pr_debug("TCM_VHOST fabric module %s on %s/%s"
- " on "UTS_RELEASE"\n", TCM_VHOST_VERSION, utsname()->sysname,
+ pr_debug("vhost-scsi fabric module %s on %s/%s"
+ " on "UTS_RELEASE"\n", VHOST_SCSI_VERSION, utsname()->sysname,
utsname()->machine);
/*
* Register the top level struct config_item_type with TCM core
@@ -2326,14 +2340,14 @@
return PTR_ERR(fabric);
}
/*
- * Setup fabric->tf_ops from our local tcm_vhost_ops
+ * Setup fabric->tf_ops from our local vhost_scsi_ops
*/
- fabric->tf_ops = tcm_vhost_ops;
+ fabric->tf_ops = vhost_scsi_ops;
/*
* Setup default attribute lists for various fabric->tf_cit_tmpl
*/
- fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_vhost_wwn_attrs;
- fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = tcm_vhost_tpg_attrs;
+ fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = vhost_scsi_wwn_attrs;
+ fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = vhost_scsi_tpg_attrs;
fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
@@ -2353,37 +2367,37 @@
/*
* Setup our local pointer to *fabric
*/
- tcm_vhost_fabric_configfs = fabric;
- pr_debug("TCM_VHOST[0] - Set fabric -> tcm_vhost_fabric_configfs\n");
+ vhost_scsi_fabric_configfs = fabric;
+ pr_debug("TCM_VHOST[0] - Set fabric -> vhost_scsi_fabric_configfs\n");
return 0;
};
-static void tcm_vhost_deregister_configfs(void)
+static void vhost_scsi_deregister_configfs(void)
{
- if (!tcm_vhost_fabric_configfs)
+ if (!vhost_scsi_fabric_configfs)
return;
- target_fabric_configfs_deregister(tcm_vhost_fabric_configfs);
- tcm_vhost_fabric_configfs = NULL;
- pr_debug("TCM_VHOST[0] - Cleared tcm_vhost_fabric_configfs\n");
+ target_fabric_configfs_deregister(vhost_scsi_fabric_configfs);
+ vhost_scsi_fabric_configfs = NULL;
+ pr_debug("TCM_VHOST[0] - Cleared vhost_scsi_fabric_configfs\n");
};
-static int __init tcm_vhost_init(void)
+static int __init vhost_scsi_init(void)
{
int ret = -ENOMEM;
/*
* Use our own dedicated workqueue for submitting I/O into
* target core to avoid contention within system_wq.
*/
- tcm_vhost_workqueue = alloc_workqueue("tcm_vhost", 0, 0);
- if (!tcm_vhost_workqueue)
+ vhost_scsi_workqueue = alloc_workqueue("vhost_scsi", 0, 0);
+ if (!vhost_scsi_workqueue)
goto out;
ret = vhost_scsi_register();
if (ret < 0)
goto out_destroy_workqueue;
- ret = tcm_vhost_register_configfs();
+ ret = vhost_scsi_register_configfs();
if (ret < 0)
goto out_vhost_scsi_deregister;
@@ -2392,20 +2406,20 @@
out_vhost_scsi_deregister:
vhost_scsi_deregister();
out_destroy_workqueue:
- destroy_workqueue(tcm_vhost_workqueue);
+ destroy_workqueue(vhost_scsi_workqueue);
out:
return ret;
};
-static void tcm_vhost_exit(void)
+static void vhost_scsi_exit(void)
{
- tcm_vhost_deregister_configfs();
+ vhost_scsi_deregister_configfs();
vhost_scsi_deregister();
- destroy_workqueue(tcm_vhost_workqueue);
+ destroy_workqueue(vhost_scsi_workqueue);
};
MODULE_DESCRIPTION("VHOST_SCSI series fabric driver");
MODULE_ALIAS("tcm_vhost");
MODULE_LICENSE("GPL");
-module_init(tcm_vhost_init);
-module_exit(tcm_vhost_exit);
+module_init(vhost_scsi_init);
+module_exit(vhost_scsi_exit);
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 02b1691..995986b 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -645,11 +645,12 @@
static unsigned long randomize_stack_top(unsigned long stack_top)
{
- unsigned int random_variable = 0;
+ unsigned long random_variable = 0;
if ((current->flags & PF_RANDOMIZE) &&
!(current->personality & ADDR_NO_RANDOMIZE)) {
- random_variable = get_random_int() & STACK_RND_MASK;
+ random_variable = (unsigned long) get_random_int();
+ random_variable &= STACK_RND_MASK;
random_variable <<= PAGE_SHIFT;
}
#ifdef CONFIG_STACK_GROWSUP
diff --git a/include/dt-bindings/clock/alphascale,asm9260.h b/include/dt-bindings/clock/alphascale,asm9260.h
new file mode 100644
index 0000000..04e8db2
--- /dev/null
+++ b/include/dt-bindings/clock/alphascale,asm9260.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2014 Oleksij Rempel <linux@rempel-privat.de>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DT_BINDINGS_CLK_ASM9260_H
+#define _DT_BINDINGS_CLK_ASM9260_H
+
+/* ahb gate */
+#define CLKID_AHB_ROM 0
+#define CLKID_AHB_RAM 1
+#define CLKID_AHB_GPIO 2
+#define CLKID_AHB_MAC 3
+#define CLKID_AHB_EMI 4
+#define CLKID_AHB_USB0 5
+#define CLKID_AHB_USB1 6
+#define CLKID_AHB_DMA0 7
+#define CLKID_AHB_DMA1 8
+#define CLKID_AHB_UART0 9
+#define CLKID_AHB_UART1 10
+#define CLKID_AHB_UART2 11
+#define CLKID_AHB_UART3 12
+#define CLKID_AHB_UART4 13
+#define CLKID_AHB_UART5 14
+#define CLKID_AHB_UART6 15
+#define CLKID_AHB_UART7 16
+#define CLKID_AHB_UART8 17
+#define CLKID_AHB_UART9 18
+#define CLKID_AHB_I2S0 19
+#define CLKID_AHB_I2C0 20
+#define CLKID_AHB_I2C1 21
+#define CLKID_AHB_SSP0 22
+#define CLKID_AHB_IOCONFIG 23
+#define CLKID_AHB_WDT 24
+#define CLKID_AHB_CAN0 25
+#define CLKID_AHB_CAN1 26
+#define CLKID_AHB_MPWM 27
+#define CLKID_AHB_SPI0 28
+#define CLKID_AHB_SPI1 29
+#define CLKID_AHB_QEI 30
+#define CLKID_AHB_QUADSPI0 31
+#define CLKID_AHB_CAMIF 32
+#define CLKID_AHB_LCDIF 33
+#define CLKID_AHB_TIMER0 34
+#define CLKID_AHB_TIMER1 35
+#define CLKID_AHB_TIMER2 36
+#define CLKID_AHB_TIMER3 37
+#define CLKID_AHB_IRQ 38
+#define CLKID_AHB_RTC 39
+#define CLKID_AHB_NAND 40
+#define CLKID_AHB_ADC0 41
+#define CLKID_AHB_LED 42
+#define CLKID_AHB_DAC0 43
+#define CLKID_AHB_LCD 44
+#define CLKID_AHB_I2S1 45
+#define CLKID_AHB_MAC1 46
+
+/* devider */
+#define CLKID_SYS_CPU 47
+#define CLKID_SYS_AHB 48
+#define CLKID_SYS_I2S0M 49
+#define CLKID_SYS_I2S0S 50
+#define CLKID_SYS_I2S1M 51
+#define CLKID_SYS_I2S1S 52
+#define CLKID_SYS_UART0 53
+#define CLKID_SYS_UART1 54
+#define CLKID_SYS_UART2 55
+#define CLKID_SYS_UART3 56
+#define CLKID_SYS_UART4 56
+#define CLKID_SYS_UART5 57
+#define CLKID_SYS_UART6 58
+#define CLKID_SYS_UART7 59
+#define CLKID_SYS_UART8 60
+#define CLKID_SYS_UART9 61
+#define CLKID_SYS_SPI0 62
+#define CLKID_SYS_SPI1 63
+#define CLKID_SYS_QUADSPI 64
+#define CLKID_SYS_SSP0 65
+#define CLKID_SYS_NAND 66
+#define CLKID_SYS_TRACE 67
+#define CLKID_SYS_CAMM 68
+#define CLKID_SYS_WDT 69
+#define CLKID_SYS_CLKOUT 70
+#define CLKID_SYS_MAC 71
+#define CLKID_SYS_LCD 72
+#define CLKID_SYS_ADCANA 73
+
+#define MAX_CLKS 74
+#endif
diff --git a/include/dt-bindings/clock/exynos4.h b/include/dt-bindings/clock/exynos4.h
index 34fe28c..c4b1676 100644
--- a/include/dt-bindings/clock/exynos4.h
+++ b/include/dt-bindings/clock/exynos4.h
@@ -262,8 +262,13 @@
#define CLK_DIV_MCUISP1 453 /* Exynos4x12 only */
#define CLK_DIV_ACLK200 454 /* Exynos4x12 only */
#define CLK_DIV_ACLK400_MCUISP 455 /* Exynos4x12 only */
+#define CLK_DIV_ACP 456
+#define CLK_DIV_DMC 457
+#define CLK_DIV_C2C 458 /* Exynos4x12 only */
+#define CLK_DIV_GDL 459
+#define CLK_DIV_GDR 460
/* must be greater than maximal clock id */
-#define CLK_NR_CLKS 456
+#define CLK_NR_CLKS 461
#endif /* _DT_BINDINGS_CLOCK_EXYNOS_4_H */
diff --git a/include/dt-bindings/clock/exynos7-clk.h b/include/dt-bindings/clock/exynos7-clk.h
index 8e4681b..e33c75a 100644
--- a/include/dt-bindings/clock/exynos7-clk.h
+++ b/include/dt-bindings/clock/exynos7-clk.h
@@ -17,7 +17,11 @@
#define DOUT_SCLK_CC_PLL 4
#define DOUT_SCLK_MFC_PLL 5
#define DOUT_ACLK_CCORE_133 6
-#define TOPC_NR_CLK 7
+#define DOUT_ACLK_MSCL_532 7
+#define ACLK_MSCL_532 8
+#define DOUT_SCLK_AUD_PLL 9
+#define FOUT_AUD_PLL 10
+#define TOPC_NR_CLK 11
/* TOP0 */
#define DOUT_ACLK_PERIC1 1
@@ -26,7 +30,15 @@
#define CLK_SCLK_UART1 4
#define CLK_SCLK_UART2 5
#define CLK_SCLK_UART3 6
-#define TOP0_NR_CLK 7
+#define CLK_SCLK_SPI0 7
+#define CLK_SCLK_SPI1 8
+#define CLK_SCLK_SPI2 9
+#define CLK_SCLK_SPI3 10
+#define CLK_SCLK_SPI4 11
+#define CLK_SCLK_SPDIF 12
+#define CLK_SCLK_PCM1 13
+#define CLK_SCLK_I2S1 14
+#define TOP0_NR_CLK 15
/* TOP1 */
#define DOUT_ACLK_FSYS1_200 1
@@ -70,7 +82,23 @@
#define PCLK_HSI2C6 9
#define PCLK_HSI2C7 10
#define PCLK_HSI2C8 11
-#define PERIC1_NR_CLK 12
+#define PCLK_SPI0 12
+#define PCLK_SPI1 13
+#define PCLK_SPI2 14
+#define PCLK_SPI3 15
+#define PCLK_SPI4 16
+#define SCLK_SPI0 17
+#define SCLK_SPI1 18
+#define SCLK_SPI2 19
+#define SCLK_SPI3 20
+#define SCLK_SPI4 21
+#define PCLK_I2S1 22
+#define PCLK_PCM1 23
+#define PCLK_SPDIF 24
+#define SCLK_I2S1 25
+#define SCLK_PCM1 26
+#define SCLK_SPDIF 27
+#define PERIC1_NR_CLK 28
/* PERIS */
#define PCLK_CHIPID 1
@@ -82,11 +110,63 @@
/* FSYS0 */
#define ACLK_MMC2 1
-#define FSYS0_NR_CLK 2
+#define ACLK_AXIUS_USBDRD30X_FSYS0X 2
+#define ACLK_USBDRD300 3
+#define SCLK_USBDRD300_SUSPENDCLK 4
+#define SCLK_USBDRD300_REFCLK 5
+#define PHYCLK_USBDRD300_UDRD30_PIPE_PCLK_USER 6
+#define PHYCLK_USBDRD300_UDRD30_PHYCLK_USER 7
+#define OSCCLK_PHY_CLKOUT_USB30_PHY 8
+#define ACLK_PDMA0 9
+#define ACLK_PDMA1 10
+#define FSYS0_NR_CLK 11
/* FSYS1 */
#define ACLK_MMC1 1
#define ACLK_MMC0 2
#define FSYS1_NR_CLK 3
+/* MSCL */
+#define USERMUX_ACLK_MSCL_532 1
+#define DOUT_PCLK_MSCL 2
+#define ACLK_MSCL_0 3
+#define ACLK_MSCL_1 4
+#define ACLK_JPEG 5
+#define ACLK_G2D 6
+#define ACLK_LH_ASYNC_SI_MSCL_0 7
+#define ACLK_LH_ASYNC_SI_MSCL_1 8
+#define ACLK_AXI2ACEL_BRIDGE 9
+#define ACLK_XIU_MSCLX_0 10
+#define ACLK_XIU_MSCLX_1 11
+#define ACLK_QE_MSCL_0 12
+#define ACLK_QE_MSCL_1 13
+#define ACLK_QE_JPEG 14
+#define ACLK_QE_G2D 15
+#define ACLK_PPMU_MSCL_0 16
+#define ACLK_PPMU_MSCL_1 17
+#define ACLK_MSCLNP_133 18
+#define ACLK_AHB2APB_MSCL0P 19
+#define ACLK_AHB2APB_MSCL1P 20
+
+#define PCLK_MSCL_0 21
+#define PCLK_MSCL_1 22
+#define PCLK_JPEG 23
+#define PCLK_G2D 24
+#define PCLK_QE_MSCL_0 25
+#define PCLK_QE_MSCL_1 26
+#define PCLK_QE_JPEG 27
+#define PCLK_QE_G2D 28
+#define PCLK_PPMU_MSCL_0 29
+#define PCLK_PPMU_MSCL_1 30
+#define PCLK_AXI2ACEL_BRIDGE 31
+#define PCLK_PMU_MSCL 32
+#define MSCL_NR_CLK 33
+
+/* AUD */
+#define SCLK_I2S 1
+#define SCLK_PCM 2
+#define PCLK_I2S 3
+#define PCLK_PCM 4
+#define ACLK_ADMA 5
+#define AUD_NR_CLK 6
#endif /* _DT_BINDINGS_CLOCK_EXYNOS7_H */
diff --git a/include/dt-bindings/clock/qcom,gcc-ipq806x.h b/include/dt-bindings/clock/qcom,gcc-ipq806x.h
index b857cad..04fb29a 100644
--- a/include/dt-bindings/clock/qcom,gcc-ipq806x.h
+++ b/include/dt-bindings/clock/qcom,gcc-ipq806x.h
@@ -238,7 +238,6 @@
#define PLL0_VOTE 221
#define PLL3 222
#define PLL3_VOTE 223
-#define PLL4 224
#define PLL4_VOTE 225
#define PLL8 226
#define PLL8_VOTE 227
diff --git a/include/dt-bindings/clock/qcom,lcc-ipq806x.h b/include/dt-bindings/clock/qcom,lcc-ipq806x.h
new file mode 100644
index 0000000..4e944b8
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,lcc-ipq806x.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DT_BINDINGS_CLK_LCC_IPQ806X_H
+#define _DT_BINDINGS_CLK_LCC_IPQ806X_H
+
+#define PLL4 0
+#define MI2S_OSR_SRC 1
+#define MI2S_OSR_CLK 2
+#define MI2S_DIV_CLK 3
+#define MI2S_BIT_DIV_CLK 4
+#define MI2S_BIT_CLK 5
+#define PCM_SRC 6
+#define PCM_CLK_OUT 7
+#define PCM_CLK 8
+#define SPDIF_SRC 9
+#define SPDIF_CLK 10
+#define AHBIX_CLK 11
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,lcc-msm8960.h b/include/dt-bindings/clock/qcom,lcc-msm8960.h
new file mode 100644
index 0000000..4fb2aa6
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,lcc-msm8960.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DT_BINDINGS_CLK_LCC_MSM8960_H
+#define _DT_BINDINGS_CLK_LCC_MSM8960_H
+
+#define PLL4 0
+#define MI2S_OSR_SRC 1
+#define MI2S_OSR_CLK 2
+#define MI2S_DIV_CLK 3
+#define MI2S_BIT_DIV_CLK 4
+#define MI2S_BIT_CLK 5
+#define PCM_SRC 6
+#define PCM_CLK_OUT 7
+#define PCM_CLK 8
+#define SLIMBUS_SRC 9
+#define AUDIO_SLIMBUS_CLK 10
+#define SPS_SLIMBUS_CLK 11
+#define CODEC_I2S_MIC_OSR_SRC 12
+#define CODEC_I2S_MIC_OSR_CLK 13
+#define CODEC_I2S_MIC_DIV_CLK 14
+#define CODEC_I2S_MIC_BIT_DIV_CLK 15
+#define CODEC_I2S_MIC_BIT_CLK 16
+#define SPARE_I2S_MIC_OSR_SRC 17
+#define SPARE_I2S_MIC_OSR_CLK 18
+#define SPARE_I2S_MIC_DIV_CLK 19
+#define SPARE_I2S_MIC_BIT_DIV_CLK 20
+#define SPARE_I2S_MIC_BIT_CLK 21
+#define CODEC_I2S_SPKR_OSR_SRC 22
+#define CODEC_I2S_SPKR_OSR_CLK 23
+#define CODEC_I2S_SPKR_DIV_CLK 24
+#define CODEC_I2S_SPKR_BIT_DIV_CLK 25
+#define CODEC_I2S_SPKR_BIT_CLK 26
+#define SPARE_I2S_SPKR_OSR_SRC 27
+#define SPARE_I2S_SPKR_OSR_CLK 28
+#define SPARE_I2S_SPKR_DIV_CLK 29
+#define SPARE_I2S_SPKR_BIT_DIV_CLK 30
+#define SPARE_I2S_SPKR_BIT_CLK 31
+
+#endif
diff --git a/include/dt-bindings/clock/tegra124-car-common.h b/include/dt-bindings/clock/tegra124-car-common.h
new file mode 100644
index 0000000..ae2eb17
--- /dev/null
+++ b/include/dt-bindings/clock/tegra124-car-common.h
@@ -0,0 +1,345 @@
+/*
+ * This header provides constants for binding nvidia,tegra124-car or
+ * nvidia,tegra132-car.
+ *
+ * The first 192 clocks are numbered to match the bits in the CAR's CLK_OUT_ENB
+ * registers. These IDs often match those in the CAR's RST_DEVICES registers,
+ * but not in all cases. Some bits in CLK_OUT_ENB affect multiple clocks. In
+ * this case, those clocks are assigned IDs above 185 in order to highlight
+ * this issue. Implementations that interpret these clock IDs as bit values
+ * within the CLK_OUT_ENB or RST_DEVICES registers should be careful to
+ * explicitly handle these special cases.
+ *
+ * The balance of the clocks controlled by the CAR are assigned IDs of 185 and
+ * above.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_TEGRA124_CAR_COMMON_H
+#define _DT_BINDINGS_CLOCK_TEGRA124_CAR_COMMON_H
+
+/* 0 */
+/* 1 */
+/* 2 */
+#define TEGRA124_CLK_ISPB 3
+#define TEGRA124_CLK_RTC 4
+#define TEGRA124_CLK_TIMER 5
+#define TEGRA124_CLK_UARTA 6
+/* 7 (register bit affects uartb and vfir) */
+/* 8 */
+#define TEGRA124_CLK_SDMMC2 9
+/* 10 (register bit affects spdif_in and spdif_out) */
+#define TEGRA124_CLK_I2S1 11
+#define TEGRA124_CLK_I2C1 12
+/* 13 */
+#define TEGRA124_CLK_SDMMC1 14
+#define TEGRA124_CLK_SDMMC4 15
+/* 16 */
+#define TEGRA124_CLK_PWM 17
+#define TEGRA124_CLK_I2S2 18
+/* 20 (register bit affects vi and vi_sensor) */
+/* 21 */
+#define TEGRA124_CLK_USBD 22
+#define TEGRA124_CLK_ISP 23
+/* 26 */
+/* 25 */
+#define TEGRA124_CLK_DISP2 26
+#define TEGRA124_CLK_DISP1 27
+#define TEGRA124_CLK_HOST1X 28
+#define TEGRA124_CLK_VCP 29
+#define TEGRA124_CLK_I2S0 30
+/* 31 */
+
+#define TEGRA124_CLK_MC 32
+/* 33 */
+#define TEGRA124_CLK_APBDMA 34
+/* 35 */
+#define TEGRA124_CLK_KBC 36
+/* 37 */
+/* 38 */
+/* 39 (register bit affects fuse and fuse_burn) */
+#define TEGRA124_CLK_KFUSE 40
+#define TEGRA124_CLK_SBC1 41
+#define TEGRA124_CLK_NOR 42
+/* 43 */
+#define TEGRA124_CLK_SBC2 44
+/* 45 */
+#define TEGRA124_CLK_SBC3 46
+#define TEGRA124_CLK_I2C5 47
+#define TEGRA124_CLK_DSIA 48
+/* 49 */
+#define TEGRA124_CLK_MIPI 50
+#define TEGRA124_CLK_HDMI 51
+#define TEGRA124_CLK_CSI 52
+/* 53 */
+#define TEGRA124_CLK_I2C2 54
+#define TEGRA124_CLK_UARTC 55
+#define TEGRA124_CLK_MIPI_CAL 56
+#define TEGRA124_CLK_EMC 57
+#define TEGRA124_CLK_USB2 58
+#define TEGRA124_CLK_USB3 59
+/* 60 */
+#define TEGRA124_CLK_VDE 61
+#define TEGRA124_CLK_BSEA 62
+#define TEGRA124_CLK_BSEV 63
+
+/* 64 */
+#define TEGRA124_CLK_UARTD 65
+/* 66 */
+#define TEGRA124_CLK_I2C3 67
+#define TEGRA124_CLK_SBC4 68
+#define TEGRA124_CLK_SDMMC3 69
+#define TEGRA124_CLK_PCIE 70
+#define TEGRA124_CLK_OWR 71
+#define TEGRA124_CLK_AFI 72
+#define TEGRA124_CLK_CSITE 73
+/* 74 */
+/* 75 */
+#define TEGRA124_CLK_LA 76
+#define TEGRA124_CLK_TRACE 77
+#define TEGRA124_CLK_SOC_THERM 78
+#define TEGRA124_CLK_DTV 79
+/* 80 */
+#define TEGRA124_CLK_I2CSLOW 81
+#define TEGRA124_CLK_DSIB 82
+#define TEGRA124_CLK_TSEC 83
+/* 84 */
+/* 85 */
+/* 86 */
+/* 87 */
+/* 88 */
+#define TEGRA124_CLK_XUSB_HOST 89
+/* 90 */
+#define TEGRA124_CLK_MSENC 91
+#define TEGRA124_CLK_CSUS 92
+/* 93 */
+/* 94 */
+/* 95 (bit affects xusb_dev and xusb_dev_src) */
+
+/* 96 */
+/* 97 */
+/* 98 */
+#define TEGRA124_CLK_MSELECT 99
+#define TEGRA124_CLK_TSENSOR 100
+#define TEGRA124_CLK_I2S3 101
+#define TEGRA124_CLK_I2S4 102
+#define TEGRA124_CLK_I2C4 103
+#define TEGRA124_CLK_SBC5 104
+#define TEGRA124_CLK_SBC6 105
+#define TEGRA124_CLK_D_AUDIO 106
+#define TEGRA124_CLK_APBIF 107
+#define TEGRA124_CLK_DAM0 108
+#define TEGRA124_CLK_DAM1 109
+#define TEGRA124_CLK_DAM2 110
+#define TEGRA124_CLK_HDA2CODEC_2X 111
+/* 112 */
+#define TEGRA124_CLK_AUDIO0_2X 113
+#define TEGRA124_CLK_AUDIO1_2X 114
+#define TEGRA124_CLK_AUDIO2_2X 115
+#define TEGRA124_CLK_AUDIO3_2X 116
+#define TEGRA124_CLK_AUDIO4_2X 117
+#define TEGRA124_CLK_SPDIF_2X 118
+#define TEGRA124_CLK_ACTMON 119
+#define TEGRA124_CLK_EXTERN1 120
+#define TEGRA124_CLK_EXTERN2 121
+#define TEGRA124_CLK_EXTERN3 122
+#define TEGRA124_CLK_SATA_OOB 123
+#define TEGRA124_CLK_SATA 124
+#define TEGRA124_CLK_HDA 125
+/* 126 */
+#define TEGRA124_CLK_SE 127
+
+#define TEGRA124_CLK_HDA2HDMI 128
+#define TEGRA124_CLK_SATA_COLD 129
+/* 130 */
+/* 131 */
+/* 132 */
+/* 133 */
+/* 134 */
+/* 135 */
+/* 136 */
+/* 137 */
+/* 138 */
+/* 139 */
+/* 140 */
+/* 141 */
+/* 142 */
+/* 143 (bit affects xusb_falcon_src, xusb_fs_src, */
+/* xusb_host_src and xusb_ss_src) */
+#define TEGRA124_CLK_CILAB 144
+#define TEGRA124_CLK_CILCD 145
+#define TEGRA124_CLK_CILE 146
+#define TEGRA124_CLK_DSIALP 147
+#define TEGRA124_CLK_DSIBLP 148
+#define TEGRA124_CLK_ENTROPY 149
+#define TEGRA124_CLK_DDS 150
+/* 151 */
+#define TEGRA124_CLK_DP2 152
+#define TEGRA124_CLK_AMX 153
+#define TEGRA124_CLK_ADX 154
+/* 155 (bit affects dfll_ref and dfll_soc) */
+#define TEGRA124_CLK_XUSB_SS 156
+/* 157 */
+/* 158 */
+/* 159 */
+
+/* 160 */
+/* 161 */
+/* 162 */
+/* 163 */
+/* 164 */
+/* 165 */
+#define TEGRA124_CLK_I2C6 166
+/* 167 */
+/* 168 */
+/* 169 */
+/* 170 */
+#define TEGRA124_CLK_VIM2_CLK 171
+/* 172 */
+/* 173 */
+/* 174 */
+/* 175 */
+#define TEGRA124_CLK_HDMI_AUDIO 176
+#define TEGRA124_CLK_CLK72MHZ 177
+#define TEGRA124_CLK_VIC03 178
+/* 179 */
+#define TEGRA124_CLK_ADX1 180
+#define TEGRA124_CLK_DPAUX 181
+#define TEGRA124_CLK_SOR0 182
+/* 183 */
+#define TEGRA124_CLK_GPU 184
+#define TEGRA124_CLK_AMX1 185
+/* 186 */
+/* 187 */
+/* 188 */
+/* 189 */
+/* 190 */
+/* 191 */
+#define TEGRA124_CLK_UARTB 192
+#define TEGRA124_CLK_VFIR 193
+#define TEGRA124_CLK_SPDIF_IN 194
+#define TEGRA124_CLK_SPDIF_OUT 195
+#define TEGRA124_CLK_VI 196
+#define TEGRA124_CLK_VI_SENSOR 197
+#define TEGRA124_CLK_FUSE 198
+#define TEGRA124_CLK_FUSE_BURN 199
+#define TEGRA124_CLK_CLK_32K 200
+#define TEGRA124_CLK_CLK_M 201
+#define TEGRA124_CLK_CLK_M_DIV2 202
+#define TEGRA124_CLK_CLK_M_DIV4 203
+#define TEGRA124_CLK_PLL_REF 204
+#define TEGRA124_CLK_PLL_C 205
+#define TEGRA124_CLK_PLL_C_OUT1 206
+#define TEGRA124_CLK_PLL_C2 207
+#define TEGRA124_CLK_PLL_C3 208
+#define TEGRA124_CLK_PLL_M 209
+#define TEGRA124_CLK_PLL_M_OUT1 210
+#define TEGRA124_CLK_PLL_P 211
+#define TEGRA124_CLK_PLL_P_OUT1 212
+#define TEGRA124_CLK_PLL_P_OUT2 213
+#define TEGRA124_CLK_PLL_P_OUT3 214
+#define TEGRA124_CLK_PLL_P_OUT4 215
+#define TEGRA124_CLK_PLL_A 216
+#define TEGRA124_CLK_PLL_A_OUT0 217
+#define TEGRA124_CLK_PLL_D 218
+#define TEGRA124_CLK_PLL_D_OUT0 219
+#define TEGRA124_CLK_PLL_D2 220
+#define TEGRA124_CLK_PLL_D2_OUT0 221
+#define TEGRA124_CLK_PLL_U 222
+#define TEGRA124_CLK_PLL_U_480M 223
+
+#define TEGRA124_CLK_PLL_U_60M 224
+#define TEGRA124_CLK_PLL_U_48M 225
+#define TEGRA124_CLK_PLL_U_12M 226
+/* 227 */
+/* 228 */
+#define TEGRA124_CLK_PLL_RE_VCO 229
+#define TEGRA124_CLK_PLL_RE_OUT 230
+#define TEGRA124_CLK_PLL_E 231
+#define TEGRA124_CLK_SPDIF_IN_SYNC 232
+#define TEGRA124_CLK_I2S0_SYNC 233
+#define TEGRA124_CLK_I2S1_SYNC 234
+#define TEGRA124_CLK_I2S2_SYNC 235
+#define TEGRA124_CLK_I2S3_SYNC 236
+#define TEGRA124_CLK_I2S4_SYNC 237
+#define TEGRA124_CLK_VIMCLK_SYNC 238
+#define TEGRA124_CLK_AUDIO0 239
+#define TEGRA124_CLK_AUDIO1 240
+#define TEGRA124_CLK_AUDIO2 241
+#define TEGRA124_CLK_AUDIO3 242
+#define TEGRA124_CLK_AUDIO4 243
+#define TEGRA124_CLK_SPDIF 244
+#define TEGRA124_CLK_CLK_OUT_1 245
+#define TEGRA124_CLK_CLK_OUT_2 246
+#define TEGRA124_CLK_CLK_OUT_3 247
+#define TEGRA124_CLK_BLINK 248
+/* 249 */
+/* 250 */
+/* 251 */
+#define TEGRA124_CLK_XUSB_HOST_SRC 252
+#define TEGRA124_CLK_XUSB_FALCON_SRC 253
+#define TEGRA124_CLK_XUSB_FS_SRC 254
+#define TEGRA124_CLK_XUSB_SS_SRC 255
+
+#define TEGRA124_CLK_XUSB_DEV_SRC 256
+#define TEGRA124_CLK_XUSB_DEV 257
+#define TEGRA124_CLK_XUSB_HS_SRC 258
+#define TEGRA124_CLK_SCLK 259
+#define TEGRA124_CLK_HCLK 260
+#define TEGRA124_CLK_PCLK 261
+/* 262 */
+/* 263 */
+#define TEGRA124_CLK_DFLL_REF 264
+#define TEGRA124_CLK_DFLL_SOC 265
+#define TEGRA124_CLK_VI_SENSOR2 266
+#define TEGRA124_CLK_PLL_P_OUT5 267
+#define TEGRA124_CLK_CML0 268
+#define TEGRA124_CLK_CML1 269
+#define TEGRA124_CLK_PLL_C4 270
+#define TEGRA124_CLK_PLL_DP 271
+#define TEGRA124_CLK_PLL_E_MUX 272
+#define TEGRA124_CLK_PLLD_DSI 273
+/* 274 */
+/* 275 */
+/* 276 */
+/* 277 */
+/* 278 */
+/* 279 */
+/* 280 */
+/* 281 */
+/* 282 */
+/* 283 */
+/* 284 */
+/* 285 */
+/* 286 */
+/* 287 */
+
+/* 288 */
+/* 289 */
+/* 290 */
+/* 291 */
+/* 292 */
+/* 293 */
+/* 294 */
+/* 295 */
+/* 296 */
+/* 297 */
+/* 298 */
+/* 299 */
+#define TEGRA124_CLK_AUDIO0_MUX 300
+#define TEGRA124_CLK_AUDIO1_MUX 301
+#define TEGRA124_CLK_AUDIO2_MUX 302
+#define TEGRA124_CLK_AUDIO3_MUX 303
+#define TEGRA124_CLK_AUDIO4_MUX 304
+#define TEGRA124_CLK_SPDIF_MUX 305
+#define TEGRA124_CLK_CLK_OUT_1_MUX 306
+#define TEGRA124_CLK_CLK_OUT_2_MUX 307
+#define TEGRA124_CLK_CLK_OUT_3_MUX 308
+/* 309 */
+/* 310 */
+#define TEGRA124_CLK_SOR0_LVDS 311
+#define TEGRA124_CLK_XUSB_SS_DIV2 312
+
+#define TEGRA124_CLK_PLL_M_UD 313
+#define TEGRA124_CLK_PLL_C_UD 314
+
+#endif /* _DT_BINDINGS_CLOCK_TEGRA124_CAR_COMMON_H */
diff --git a/include/dt-bindings/clock/tegra124-car.h b/include/dt-bindings/clock/tegra124-car.h
index af9bc9a..2860737 100644
--- a/include/dt-bindings/clock/tegra124-car.h
+++ b/include/dt-bindings/clock/tegra124-car.h
@@ -1,346 +1,19 @@
/*
- * This header provides constants for binding nvidia,tegra124-car.
- *
- * The first 192 clocks are numbered to match the bits in the CAR's CLK_OUT_ENB
- * registers. These IDs often match those in the CAR's RST_DEVICES registers,
- * but not in all cases. Some bits in CLK_OUT_ENB affect multiple clocks. In
- * this case, those clocks are assigned IDs above 185 in order to highlight
- * this issue. Implementations that interpret these clock IDs as bit values
- * within the CLK_OUT_ENB or RST_DEVICES registers should be careful to
- * explicitly handle these special cases.
- *
- * The balance of the clocks controlled by the CAR are assigned IDs of 185 and
- * above.
+ * This header provides Tegra124-specific constants for binding
+ * nvidia,tegra124-car.
*/
+#include <dt-bindings/clock/tegra124-car-common.h>
+
#ifndef _DT_BINDINGS_CLOCK_TEGRA124_CAR_H
#define _DT_BINDINGS_CLOCK_TEGRA124_CAR_H
-/* 0 */
-/* 1 */
-/* 2 */
-#define TEGRA124_CLK_ISPB 3
-#define TEGRA124_CLK_RTC 4
-#define TEGRA124_CLK_TIMER 5
-#define TEGRA124_CLK_UARTA 6
-/* 7 (register bit affects uartb and vfir) */
-/* 8 */
-#define TEGRA124_CLK_SDMMC2 9
-/* 10 (register bit affects spdif_in and spdif_out) */
-#define TEGRA124_CLK_I2S1 11
-#define TEGRA124_CLK_I2C1 12
-/* 13 */
-#define TEGRA124_CLK_SDMMC1 14
-#define TEGRA124_CLK_SDMMC4 15
-/* 16 */
-#define TEGRA124_CLK_PWM 17
-#define TEGRA124_CLK_I2S2 18
-/* 20 (register bit affects vi and vi_sensor) */
-/* 21 */
-#define TEGRA124_CLK_USBD 22
-#define TEGRA124_CLK_ISP 23
-/* 26 */
-/* 25 */
-#define TEGRA124_CLK_DISP2 26
-#define TEGRA124_CLK_DISP1 27
-#define TEGRA124_CLK_HOST1X 28
-#define TEGRA124_CLK_VCP 29
-#define TEGRA124_CLK_I2S0 30
-/* 31 */
+#define TEGRA124_CLK_PLL_X 227
+#define TEGRA124_CLK_PLL_X_OUT0 228
-#define TEGRA124_CLK_MC 32
-/* 33 */
-#define TEGRA124_CLK_APBDMA 34
-/* 35 */
-#define TEGRA124_CLK_KBC 36
-/* 37 */
-/* 38 */
-/* 39 (register bit affects fuse and fuse_burn) */
-#define TEGRA124_CLK_KFUSE 40
-#define TEGRA124_CLK_SBC1 41
-#define TEGRA124_CLK_NOR 42
-/* 43 */
-#define TEGRA124_CLK_SBC2 44
-/* 45 */
-#define TEGRA124_CLK_SBC3 46
-#define TEGRA124_CLK_I2C5 47
-#define TEGRA124_CLK_DSIA 48
-/* 49 */
-#define TEGRA124_CLK_MIPI 50
-#define TEGRA124_CLK_HDMI 51
-#define TEGRA124_CLK_CSI 52
-/* 53 */
-#define TEGRA124_CLK_I2C2 54
-#define TEGRA124_CLK_UARTC 55
-#define TEGRA124_CLK_MIPI_CAL 56
-#define TEGRA124_CLK_EMC 57
-#define TEGRA124_CLK_USB2 58
-#define TEGRA124_CLK_USB3 59
-/* 60 */
-#define TEGRA124_CLK_VDE 61
-#define TEGRA124_CLK_BSEA 62
-#define TEGRA124_CLK_BSEV 63
+#define TEGRA124_CLK_CCLK_G 262
+#define TEGRA124_CLK_CCLK_LP 263
-/* 64 */
-#define TEGRA124_CLK_UARTD 65
-/* 66 */
-#define TEGRA124_CLK_I2C3 67
-#define TEGRA124_CLK_SBC4 68
-#define TEGRA124_CLK_SDMMC3 69
-#define TEGRA124_CLK_PCIE 70
-#define TEGRA124_CLK_OWR 71
-#define TEGRA124_CLK_AFI 72
-#define TEGRA124_CLK_CSITE 73
-/* 74 */
-/* 75 */
-#define TEGRA124_CLK_LA 76
-#define TEGRA124_CLK_TRACE 77
-#define TEGRA124_CLK_SOC_THERM 78
-#define TEGRA124_CLK_DTV 79
-/* 80 */
-#define TEGRA124_CLK_I2CSLOW 81
-#define TEGRA124_CLK_DSIB 82
-#define TEGRA124_CLK_TSEC 83
-/* 84 */
-/* 85 */
-/* 86 */
-/* 87 */
-/* 88 */
-#define TEGRA124_CLK_XUSB_HOST 89
-/* 90 */
-#define TEGRA124_CLK_MSENC 91
-#define TEGRA124_CLK_CSUS 92
-/* 93 */
-/* 94 */
-/* 95 (bit affects xusb_dev and xusb_dev_src) */
-
-/* 96 */
-/* 97 */
-/* 98 */
-#define TEGRA124_CLK_MSELECT 99
-#define TEGRA124_CLK_TSENSOR 100
-#define TEGRA124_CLK_I2S3 101
-#define TEGRA124_CLK_I2S4 102
-#define TEGRA124_CLK_I2C4 103
-#define TEGRA124_CLK_SBC5 104
-#define TEGRA124_CLK_SBC6 105
-#define TEGRA124_CLK_D_AUDIO 106
-#define TEGRA124_CLK_APBIF 107
-#define TEGRA124_CLK_DAM0 108
-#define TEGRA124_CLK_DAM1 109
-#define TEGRA124_CLK_DAM2 110
-#define TEGRA124_CLK_HDA2CODEC_2X 111
-/* 112 */
-#define TEGRA124_CLK_AUDIO0_2X 113
-#define TEGRA124_CLK_AUDIO1_2X 114
-#define TEGRA124_CLK_AUDIO2_2X 115
-#define TEGRA124_CLK_AUDIO3_2X 116
-#define TEGRA124_CLK_AUDIO4_2X 117
-#define TEGRA124_CLK_SPDIF_2X 118
-#define TEGRA124_CLK_ACTMON 119
-#define TEGRA124_CLK_EXTERN1 120
-#define TEGRA124_CLK_EXTERN2 121
-#define TEGRA124_CLK_EXTERN3 122
-#define TEGRA124_CLK_SATA_OOB 123
-#define TEGRA124_CLK_SATA 124
-#define TEGRA124_CLK_HDA 125
-/* 126 */
-#define TEGRA124_CLK_SE 127
-
-#define TEGRA124_CLK_HDA2HDMI 128
-#define TEGRA124_CLK_SATA_COLD 129
-/* 130 */
-/* 131 */
-/* 132 */
-/* 133 */
-/* 134 */
-/* 135 */
-/* 136 */
-/* 137 */
-/* 138 */
-/* 139 */
-/* 140 */
-/* 141 */
-/* 142 */
-/* 143 (bit affects xusb_falcon_src, xusb_fs_src, */
-/* xusb_host_src and xusb_ss_src) */
-#define TEGRA124_CLK_CILAB 144
-#define TEGRA124_CLK_CILCD 145
-#define TEGRA124_CLK_CILE 146
-#define TEGRA124_CLK_DSIALP 147
-#define TEGRA124_CLK_DSIBLP 148
-#define TEGRA124_CLK_ENTROPY 149
-#define TEGRA124_CLK_DDS 150
-/* 151 */
-#define TEGRA124_CLK_DP2 152
-#define TEGRA124_CLK_AMX 153
-#define TEGRA124_CLK_ADX 154
-/* 155 (bit affects dfll_ref and dfll_soc) */
-#define TEGRA124_CLK_XUSB_SS 156
-/* 157 */
-/* 158 */
-/* 159 */
-
-/* 160 */
-/* 161 */
-/* 162 */
-/* 163 */
-/* 164 */
-/* 165 */
-#define TEGRA124_CLK_I2C6 166
-/* 167 */
-/* 168 */
-/* 169 */
-/* 170 */
-#define TEGRA124_CLK_VIM2_CLK 171
-/* 172 */
-/* 173 */
-/* 174 */
-/* 175 */
-#define TEGRA124_CLK_HDMI_AUDIO 176
-#define TEGRA124_CLK_CLK72MHZ 177
-#define TEGRA124_CLK_VIC03 178
-/* 179 */
-#define TEGRA124_CLK_ADX1 180
-#define TEGRA124_CLK_DPAUX 181
-#define TEGRA124_CLK_SOR0 182
-/* 183 */
-#define TEGRA124_CLK_GPU 184
-#define TEGRA124_CLK_AMX1 185
-/* 186 */
-/* 187 */
-/* 188 */
-/* 189 */
-/* 190 */
-/* 191 */
-#define TEGRA124_CLK_UARTB 192
-#define TEGRA124_CLK_VFIR 193
-#define TEGRA124_CLK_SPDIF_IN 194
-#define TEGRA124_CLK_SPDIF_OUT 195
-#define TEGRA124_CLK_VI 196
-#define TEGRA124_CLK_VI_SENSOR 197
-#define TEGRA124_CLK_FUSE 198
-#define TEGRA124_CLK_FUSE_BURN 199
-#define TEGRA124_CLK_CLK_32K 200
-#define TEGRA124_CLK_CLK_M 201
-#define TEGRA124_CLK_CLK_M_DIV2 202
-#define TEGRA124_CLK_CLK_M_DIV4 203
-#define TEGRA124_CLK_PLL_REF 204
-#define TEGRA124_CLK_PLL_C 205
-#define TEGRA124_CLK_PLL_C_OUT1 206
-#define TEGRA124_CLK_PLL_C2 207
-#define TEGRA124_CLK_PLL_C3 208
-#define TEGRA124_CLK_PLL_M 209
-#define TEGRA124_CLK_PLL_M_OUT1 210
-#define TEGRA124_CLK_PLL_P 211
-#define TEGRA124_CLK_PLL_P_OUT1 212
-#define TEGRA124_CLK_PLL_P_OUT2 213
-#define TEGRA124_CLK_PLL_P_OUT3 214
-#define TEGRA124_CLK_PLL_P_OUT4 215
-#define TEGRA124_CLK_PLL_A 216
-#define TEGRA124_CLK_PLL_A_OUT0 217
-#define TEGRA124_CLK_PLL_D 218
-#define TEGRA124_CLK_PLL_D_OUT0 219
-#define TEGRA124_CLK_PLL_D2 220
-#define TEGRA124_CLK_PLL_D2_OUT0 221
-#define TEGRA124_CLK_PLL_U 222
-#define TEGRA124_CLK_PLL_U_480M 223
-
-#define TEGRA124_CLK_PLL_U_60M 224
-#define TEGRA124_CLK_PLL_U_48M 225
-#define TEGRA124_CLK_PLL_U_12M 226
-#define TEGRA124_CLK_PLL_X 227
-#define TEGRA124_CLK_PLL_X_OUT0 228
-#define TEGRA124_CLK_PLL_RE_VCO 229
-#define TEGRA124_CLK_PLL_RE_OUT 230
-#define TEGRA124_CLK_PLL_E 231
-#define TEGRA124_CLK_SPDIF_IN_SYNC 232
-#define TEGRA124_CLK_I2S0_SYNC 233
-#define TEGRA124_CLK_I2S1_SYNC 234
-#define TEGRA124_CLK_I2S2_SYNC 235
-#define TEGRA124_CLK_I2S3_SYNC 236
-#define TEGRA124_CLK_I2S4_SYNC 237
-#define TEGRA124_CLK_VIMCLK_SYNC 238
-#define TEGRA124_CLK_AUDIO0 239
-#define TEGRA124_CLK_AUDIO1 240
-#define TEGRA124_CLK_AUDIO2 241
-#define TEGRA124_CLK_AUDIO3 242
-#define TEGRA124_CLK_AUDIO4 243
-#define TEGRA124_CLK_SPDIF 244
-#define TEGRA124_CLK_CLK_OUT_1 245
-#define TEGRA124_CLK_CLK_OUT_2 246
-#define TEGRA124_CLK_CLK_OUT_3 247
-#define TEGRA124_CLK_BLINK 248
-/* 249 */
-/* 250 */
-/* 251 */
-#define TEGRA124_CLK_XUSB_HOST_SRC 252
-#define TEGRA124_CLK_XUSB_FALCON_SRC 253
-#define TEGRA124_CLK_XUSB_FS_SRC 254
-#define TEGRA124_CLK_XUSB_SS_SRC 255
-
-#define TEGRA124_CLK_XUSB_DEV_SRC 256
-#define TEGRA124_CLK_XUSB_DEV 257
-#define TEGRA124_CLK_XUSB_HS_SRC 258
-#define TEGRA124_CLK_SCLK 259
-#define TEGRA124_CLK_HCLK 260
-#define TEGRA124_CLK_PCLK 261
-#define TEGRA124_CLK_CCLK_G 262
-#define TEGRA124_CLK_CCLK_LP 263
-#define TEGRA124_CLK_DFLL_REF 264
-#define TEGRA124_CLK_DFLL_SOC 265
-#define TEGRA124_CLK_VI_SENSOR2 266
-#define TEGRA124_CLK_PLL_P_OUT5 267
-#define TEGRA124_CLK_CML0 268
-#define TEGRA124_CLK_CML1 269
-#define TEGRA124_CLK_PLL_C4 270
-#define TEGRA124_CLK_PLL_DP 271
-#define TEGRA124_CLK_PLL_E_MUX 272
-/* 273 */
-/* 274 */
-/* 275 */
-/* 276 */
-/* 277 */
-/* 278 */
-/* 279 */
-/* 280 */
-/* 281 */
-/* 282 */
-/* 283 */
-/* 284 */
-/* 285 */
-/* 286 */
-/* 287 */
-
-/* 288 */
-/* 289 */
-/* 290 */
-/* 291 */
-/* 292 */
-/* 293 */
-/* 294 */
-/* 295 */
-/* 296 */
-/* 297 */
-/* 298 */
-/* 299 */
-#define TEGRA124_CLK_AUDIO0_MUX 300
-#define TEGRA124_CLK_AUDIO1_MUX 301
-#define TEGRA124_CLK_AUDIO2_MUX 302
-#define TEGRA124_CLK_AUDIO3_MUX 303
-#define TEGRA124_CLK_AUDIO4_MUX 304
-#define TEGRA124_CLK_SPDIF_MUX 305
-#define TEGRA124_CLK_CLK_OUT_1_MUX 306
-#define TEGRA124_CLK_CLK_OUT_2_MUX 307
-#define TEGRA124_CLK_CLK_OUT_3_MUX 308
-#define TEGRA124_CLK_DSIA_MUX 309
-#define TEGRA124_CLK_DSIB_MUX 310
-#define TEGRA124_CLK_SOR0_LVDS 311
-#define TEGRA124_CLK_XUSB_SS_DIV2 312
-
-#define TEGRA124_CLK_PLL_M_UD 313
-#define TEGRA124_CLK_PLL_C_UD 314
-
-#define TEGRA124_CLK_CLK_MAX 315
+#define TEGRA124_CLK_CLK_MAX 315
#endif /* _DT_BINDINGS_CLOCK_TEGRA124_CAR_H */
diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h
deleted file mode 100644
index 0ca5f604..0000000
--- a/include/linux/clk-private.h
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * linux/include/linux/clk-private.h
- *
- * Copyright (c) 2010-2011 Jeremy Kerr <jeremy.kerr@canonical.com>
- * Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#ifndef __LINUX_CLK_PRIVATE_H
-#define __LINUX_CLK_PRIVATE_H
-
-#include <linux/clk-provider.h>
-#include <linux/kref.h>
-#include <linux/list.h>
-
-/*
- * WARNING: Do not include clk-private.h from any file that implements struct
- * clk_ops. Doing so is a layering violation!
- *
- * This header exists only to allow for statically initialized clock data. Any
- * static clock data must be defined in a separate file from the logic that
- * implements the clock operations for that same data.
- */
-
-#ifdef CONFIG_COMMON_CLK
-
-struct module;
-
-struct clk {
- const char *name;
- const struct clk_ops *ops;
- struct clk_hw *hw;
- struct module *owner;
- struct clk *parent;
- const char **parent_names;
- struct clk **parents;
- u8 num_parents;
- u8 new_parent_index;
- unsigned long rate;
- unsigned long new_rate;
- struct clk *new_parent;
- struct clk *new_child;
- unsigned long flags;
- unsigned int enable_count;
- unsigned int prepare_count;
- unsigned long accuracy;
- int phase;
- struct hlist_head children;
- struct hlist_node child_node;
- struct hlist_node debug_node;
- unsigned int notifier_count;
-#ifdef CONFIG_DEBUG_FS
- struct dentry *dentry;
-#endif
- struct kref ref;
-};
-
-/*
- * DOC: Basic clock implementations common to many platforms
- *
- * Each basic clock hardware type is comprised of a structure describing the
- * clock hardware, implementations of the relevant callbacks in struct clk_ops,
- * unique flags for that hardware type, a registration function and an
- * alternative macro for static initialization
- */
-
-#define DEFINE_CLK(_name, _ops, _flags, _parent_names, \
- _parents) \
- static struct clk _name = { \
- .name = #_name, \
- .ops = &_ops, \
- .hw = &_name##_hw.hw, \
- .parent_names = _parent_names, \
- .num_parents = ARRAY_SIZE(_parent_names), \
- .parents = _parents, \
- .flags = _flags | CLK_IS_BASIC, \
- }
-
-#define DEFINE_CLK_FIXED_RATE(_name, _flags, _rate, \
- _fixed_rate_flags) \
- static struct clk _name; \
- static const char *_name##_parent_names[] = {}; \
- static struct clk_fixed_rate _name##_hw = { \
- .hw = { \
- .clk = &_name, \
- }, \
- .fixed_rate = _rate, \
- .flags = _fixed_rate_flags, \
- }; \
- DEFINE_CLK(_name, clk_fixed_rate_ops, _flags, \
- _name##_parent_names, NULL);
-
-#define DEFINE_CLK_GATE(_name, _parent_name, _parent_ptr, \
- _flags, _reg, _bit_idx, \
- _gate_flags, _lock) \
- static struct clk _name; \
- static const char *_name##_parent_names[] = { \
- _parent_name, \
- }; \
- static struct clk *_name##_parents[] = { \
- _parent_ptr, \
- }; \
- static struct clk_gate _name##_hw = { \
- .hw = { \
- .clk = &_name, \
- }, \
- .reg = _reg, \
- .bit_idx = _bit_idx, \
- .flags = _gate_flags, \
- .lock = _lock, \
- }; \
- DEFINE_CLK(_name, clk_gate_ops, _flags, \
- _name##_parent_names, _name##_parents);
-
-#define _DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \
- _flags, _reg, _shift, _width, \
- _divider_flags, _table, _lock) \
- static struct clk _name; \
- static const char *_name##_parent_names[] = { \
- _parent_name, \
- }; \
- static struct clk *_name##_parents[] = { \
- _parent_ptr, \
- }; \
- static struct clk_divider _name##_hw = { \
- .hw = { \
- .clk = &_name, \
- }, \
- .reg = _reg, \
- .shift = _shift, \
- .width = _width, \
- .flags = _divider_flags, \
- .table = _table, \
- .lock = _lock, \
- }; \
- DEFINE_CLK(_name, clk_divider_ops, _flags, \
- _name##_parent_names, _name##_parents);
-
-#define DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \
- _flags, _reg, _shift, _width, \
- _divider_flags, _lock) \
- _DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \
- _flags, _reg, _shift, _width, \
- _divider_flags, NULL, _lock)
-
-#define DEFINE_CLK_DIVIDER_TABLE(_name, _parent_name, \
- _parent_ptr, _flags, _reg, \
- _shift, _width, _divider_flags, \
- _table, _lock) \
- _DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \
- _flags, _reg, _shift, _width, \
- _divider_flags, _table, _lock) \
-
-#define DEFINE_CLK_MUX(_name, _parent_names, _parents, _flags, \
- _reg, _shift, _width, \
- _mux_flags, _lock) \
- static struct clk _name; \
- static struct clk_mux _name##_hw = { \
- .hw = { \
- .clk = &_name, \
- }, \
- .reg = _reg, \
- .shift = _shift, \
- .mask = BIT(_width) - 1, \
- .flags = _mux_flags, \
- .lock = _lock, \
- }; \
- DEFINE_CLK(_name, clk_mux_ops, _flags, _parent_names, \
- _parents);
-
-#define DEFINE_CLK_FIXED_FACTOR(_name, _parent_name, \
- _parent_ptr, _flags, \
- _mult, _div) \
- static struct clk _name; \
- static const char *_name##_parent_names[] = { \
- _parent_name, \
- }; \
- static struct clk *_name##_parents[] = { \
- _parent_ptr, \
- }; \
- static struct clk_fixed_factor _name##_hw = { \
- .hw = { \
- .clk = &_name, \
- }, \
- .mult = _mult, \
- .div = _div, \
- }; \
- DEFINE_CLK(_name, clk_fixed_factor_ops, _flags, \
- _name##_parent_names, _name##_parents);
-
-/**
- * __clk_init - initialize the data structures in a struct clk
- * @dev: device initializing this clk, placeholder for now
- * @clk: clk being initialized
- *
- * Initializes the lists in struct clk, queries the hardware for the
- * parent and rate and sets them both.
- *
- * Any struct clk passed into __clk_init must have the following members
- * populated:
- * .name
- * .ops
- * .hw
- * .parent_names
- * .num_parents
- * .flags
- *
- * It is not necessary to call clk_register if __clk_init is used directly with
- * statically initialized clock data.
- *
- * Returns 0 on success, otherwise an error code.
- */
-int __clk_init(struct device *dev, struct clk *clk);
-
-struct clk *__clk_register(struct device *dev, struct clk_hw *hw);
-
-#endif /* CONFIG_COMMON_CLK */
-#endif /* CLK_PRIVATE_H */
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index d936409..5591ea7 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -33,6 +33,7 @@
#define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */
struct clk_hw;
+struct clk_core;
struct dentry;
/**
@@ -174,9 +175,12 @@
unsigned long parent_rate);
long (*round_rate)(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate);
- long (*determine_rate)(struct clk_hw *hw, unsigned long rate,
- unsigned long *best_parent_rate,
- struct clk_hw **best_parent_hw);
+ long (*determine_rate)(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
+ unsigned long *best_parent_rate,
+ struct clk_hw **best_parent_hw);
int (*set_parent)(struct clk_hw *hw, u8 index);
u8 (*get_parent)(struct clk_hw *hw);
int (*set_rate)(struct clk_hw *hw, unsigned long rate,
@@ -216,13 +220,17 @@
* clk_foo and then referenced by the struct clk instance that uses struct
* clk_foo's clk_ops
*
- * @clk: pointer to the struct clk instance that points back to this struct
- * clk_hw instance
+ * @core: pointer to the struct clk_core instance that points back to this
+ * struct clk_hw instance
+ *
+ * @clk: pointer to the per-user struct clk instance that can be used to call
+ * into the clk API
*
* @init: pointer to struct clk_init_data that contains the init data shared
* with the common clock framework.
*/
struct clk_hw {
+ struct clk_core *core;
struct clk *clk;
const struct clk_init_data *init;
};
@@ -294,6 +302,7 @@
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 bit_idx,
u8 clk_gate_flags, spinlock_t *lock);
+void clk_unregister_gate(struct clk *clk);
struct clk_div_table {
unsigned int val;
@@ -352,6 +361,17 @@
#define CLK_DIVIDER_READ_ONLY BIT(5)
extern const struct clk_ops clk_divider_ops;
+
+unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate,
+ unsigned int val, const struct clk_div_table *table,
+ unsigned long flags);
+long divider_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate, const struct clk_div_table *table,
+ u8 width, unsigned long flags);
+int divider_get_val(unsigned long rate, unsigned long parent_rate,
+ const struct clk_div_table *table, u8 width,
+ unsigned long flags);
+
struct clk *clk_register_divider(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
@@ -361,6 +381,7 @@
void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, const struct clk_div_table *table,
spinlock_t *lock);
+void clk_unregister_divider(struct clk *clk);
/**
* struct clk_mux - multiplexer clock
@@ -382,6 +403,8 @@
* register, and mask of mux bits are in higher 16-bit of this register.
* While setting the mux bits, higher 16-bit should also be updated to
* indicate changing mux bits.
+ * CLK_MUX_ROUND_CLOSEST - Use the parent rate that is closest to the desired
+ * frequency.
*/
struct clk_mux {
struct clk_hw hw;
@@ -396,7 +419,8 @@
#define CLK_MUX_INDEX_ONE BIT(0)
#define CLK_MUX_INDEX_BIT BIT(1)
#define CLK_MUX_HIWORD_MASK BIT(2)
-#define CLK_MUX_READ_ONLY BIT(3) /* mux setting cannot be changed */
+#define CLK_MUX_READ_ONLY BIT(3) /* mux can't be changed */
+#define CLK_MUX_ROUND_CLOSEST BIT(4)
extern const struct clk_ops clk_mux_ops;
extern const struct clk_ops clk_mux_ro_ops;
@@ -411,6 +435,8 @@
void __iomem *reg, u8 shift, u32 mask,
u8 clk_mux_flags, u32 *table, spinlock_t *lock);
+void clk_unregister_mux(struct clk *clk);
+
void of_fixed_factor_clk_setup(struct device_node *node);
/**
@@ -550,15 +576,29 @@
bool __clk_is_enabled(struct clk *clk);
struct clk *__clk_lookup(const char *name);
long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_p);
+unsigned long __clk_determine_rate(struct clk_hw *core,
+ unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate);
+long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
+ unsigned long *best_parent_rate,
+ struct clk_hw **best_parent_p);
+
+static inline void __clk_hw_set_clk(struct clk_hw *dst, struct clk_hw *src)
+{
+ dst->clk = src->clk;
+ dst->core = src->core;
+}
/*
* FIXME clock api without lock protection
*/
-int __clk_prepare(struct clk *clk);
-void __clk_unprepare(struct clk *clk);
-void __clk_reparent(struct clk *clk, struct clk *new_parent);
unsigned long __clk_round_rate(struct clk *clk, unsigned long rate);
struct of_device_id;
diff --git a/include/linux/clk.h b/include/linux/clk.h
index c7f258a..8381bbf 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -302,6 +302,46 @@
int clk_set_rate(struct clk *clk, unsigned long rate);
/**
+ * clk_has_parent - check if a clock is a possible parent for another
+ * @clk: clock source
+ * @parent: parent clock source
+ *
+ * This function can be used in drivers that need to check that a clock can be
+ * the parent of another without actually changing the parent.
+ *
+ * Returns true if @parent is a possible parent for @clk, false otherwise.
+ */
+bool clk_has_parent(struct clk *clk, struct clk *parent);
+
+/**
+ * clk_set_rate_range - set a rate range for a clock source
+ * @clk: clock source
+ * @min: desired minimum clock rate in Hz, inclusive
+ * @max: desired maximum clock rate in Hz, inclusive
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max);
+
+/**
+ * clk_set_min_rate - set a minimum clock rate for a clock source
+ * @clk: clock source
+ * @rate: desired minimum clock rate in Hz, inclusive
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_set_min_rate(struct clk *clk, unsigned long rate);
+
+/**
+ * clk_set_max_rate - set a maximum clock rate for a clock source
+ * @clk: clock source
+ * @rate: desired maximum clock rate in Hz, inclusive
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_set_max_rate(struct clk *clk, unsigned long rate);
+
+/**
* clk_set_parent - set the parent clock source for this clock
* @clk: clock source
* @parent: parent clock source
@@ -374,6 +414,11 @@
return 0;
}
+static inline bool clk_has_parent(struct clk *clk, struct clk *parent)
+{
+ return true;
+}
+
static inline int clk_set_parent(struct clk *clk, struct clk *parent)
{
return 0;
diff --git a/include/linux/clk/sunxi.h b/include/linux/clk/sunxi.h
deleted file mode 100644
index aed28c4..0000000
--- a/include/linux/clk/sunxi.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 2013 - Hans de Goede <hdegoede@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef __LINUX_CLK_SUNXI_H_
-#define __LINUX_CLK_SUNXI_H_
-
-#include <linux/clk.h>
-
-void clk_sunxi_mmc_phase_control(struct clk *clk, u8 sample, u8 output);
-
-#endif
diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h
index 3ca9fca..19c4208 100644
--- a/include/linux/clk/tegra.h
+++ b/include/linux/clk/tegra.h
@@ -120,6 +120,4 @@
}
#endif
-void tegra_clocks_apply_init_table(void);
-
#endif /* __LINUX_CLK_TEGRA_H_ */
diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h
index 55ef529..6784400 100644
--- a/include/linux/clk/ti.h
+++ b/include/linux/clk/ti.h
@@ -15,6 +15,7 @@
#ifndef __LINUX_CLK_TI_H__
#define __LINUX_CLK_TI_H__
+#include <linux/clk-provider.h>
#include <linux/clkdev.h>
/**
@@ -217,6 +218,13 @@
/* Maximum number of clock memmaps */
#define CLK_MAX_MEMMAPS 4
+/* Static memmap indices */
+enum {
+ TI_CLKM_CM = 0,
+ TI_CLKM_PRM,
+ TI_CLKM_SCRM,
+};
+
typedef void (*ti_of_clk_init_cb_t)(struct clk_hw *, struct device_node *);
/**
@@ -263,6 +271,8 @@
u8 index);
long omap3_noncore_dpll_determine_rate(struct clk_hw *hw,
unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk);
unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw,
@@ -272,6 +282,8 @@
unsigned long *parent_rate);
long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw,
unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk);
u8 omap2_init_dpll_parent(struct clk_hw *hw);
@@ -348,4 +360,17 @@
extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait;
extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait;
+#ifdef CONFIG_ATAGS
+int omap3430_clk_legacy_init(void);
+int omap3430es1_clk_legacy_init(void);
+int omap36xx_clk_legacy_init(void);
+int am35xx_clk_legacy_init(void);
+#else
+static inline int omap3430_clk_legacy_init(void) { return -ENXIO; }
+static inline int omap3430es1_clk_legacy_init(void) { return -ENXIO; }
+static inline int omap36xx_clk_legacy_init(void) { return -ENXIO; }
+static inline int am35xx_clk_legacy_init(void) { return -ENXIO; }
+#endif
+
+
#endif
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index d1ec10a..1b45e4a 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -202,7 +202,7 @@
{
}
-static __always_inline void __read_once_size(volatile void *p, void *res, int size)
+static __always_inline void __read_once_size(const volatile void *p, void *res, int size)
{
switch (size) {
case 1: *(__u8 *)res = *(volatile __u8 *)p; break;
@@ -259,10 +259,10 @@
*/
#define READ_ONCE(x) \
- ({ typeof(x) __val; __read_once_size(&x, &__val, sizeof(__val)); __val; })
+ ({ union { typeof(x) __val; char __c[1]; } __u; __read_once_size(&(x), __u.__c, sizeof(x)); __u.__val; })
#define WRITE_ONCE(x, val) \
- ({ typeof(x) __val; __val = val; __write_once_size(&x, &__val, sizeof(__val)); __val; })
+ ({ typeof(x) __val = (val); __write_once_size(&(x), &__val, sizeof(__val)); __val; })
#endif /* __KERNEL__ */
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 7c76959..f17da50 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -130,8 +130,6 @@
* @probe: Callback for device binding
* @remove: Callback for device unbinding
* @shutdown: Callback for device shutdown
- * @suspend: Callback for device suspend
- * @resume: Callback for device resume
* @alert: Alert callback, for example for the SMBus alert protocol
* @command: Callback for bus-wide signaling (optional)
* @driver: Device driver model driver
@@ -174,8 +172,6 @@
/* driver model interfaces that don't relate to enumeration */
void (*shutdown)(struct i2c_client *);
- int (*suspend)(struct i2c_client *, pm_message_t mesg);
- int (*resume)(struct i2c_client *);
/* Alert callback, for example for the SMBus alert protocol.
* The format and meaning of the data value depends on the protocol.
diff --git a/include/linux/kdb.h b/include/linux/kdb.h
index 75ae2e2..a19bcf9 100644
--- a/include/linux/kdb.h
+++ b/include/linux/kdb.h
@@ -156,8 +156,14 @@
KDB_REASON_SYSTEM_NMI, /* In NMI due to SYSTEM cmd; regs valid */
} kdb_reason_t;
+enum kdb_msgsrc {
+ KDB_MSGSRC_INTERNAL, /* direct call to kdb_printf() */
+ KDB_MSGSRC_PRINTK, /* trapped from printk() */
+};
+
extern int kdb_trap_printk;
-extern __printf(1, 0) int vkdb_printf(const char *fmt, va_list args);
+extern __printf(2, 0) int vkdb_printf(enum kdb_msgsrc src, const char *fmt,
+ va_list args);
extern __printf(1, 2) int kdb_printf(const char *, ...);
typedef __printf(1, 2) int (*kdb_printf_t)(const char *, ...);
diff --git a/arch/blackfin/include/asm/bfin_rotary.h b/include/linux/platform_data/bfin_rotary.h
similarity index 98%
rename from arch/blackfin/include/asm/bfin_rotary.h
rename to include/linux/platform_data/bfin_rotary.h
index 8895a75..9882937 100644
--- a/arch/blackfin/include/asm/bfin_rotary.h
+++ b/include/linux/platform_data/bfin_rotary.h
@@ -40,6 +40,7 @@
unsigned short debounce; /* 0..17 */
unsigned short mode;
unsigned short pm_wakeup;
+ unsigned short *pin_list;
};
/* CNT_CONFIG bitmasks */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 41c60e5..6d77432 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -363,9 +363,6 @@
*/
extern void show_stack(struct task_struct *task, unsigned long *sp);
-void io_schedule(void);
-long io_schedule_timeout(long timeout);
-
extern void cpu_init (void);
extern void trap_init(void);
extern void update_process_times(int user);
@@ -422,6 +419,13 @@
asmlinkage void schedule(void);
extern void schedule_preempt_disabled(void);
+extern long io_schedule_timeout(long timeout);
+
+static inline void io_schedule(void)
+{
+ io_schedule_timeout(MAX_SCHEDULE_TIMEOUT);
+}
+
struct nsproxy;
struct user_namespace;
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index d320411..2d67b89 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -26,6 +26,7 @@
* @ioctl: Perform ioctl(2) on device file descriptor, supporting VFIO_DEVICE_*
* operations documented below
* @mmap: Perform mmap(2) on a region of the device file descriptor
+ * @request: Request for the bus driver to release the device
*/
struct vfio_device_ops {
char *name;
@@ -38,6 +39,7 @@
long (*ioctl)(void *device_data, unsigned int cmd,
unsigned long arg);
int (*mmap)(void *device_data, struct vm_area_struct *vma);
+ void (*request)(void *device_data, unsigned int count);
};
extern int vfio_add_group_dev(struct device *dev,
diff --git a/drivers/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h
similarity index 98%
rename from drivers/target/iscsi/iscsi_target_core.h
rename to include/target/iscsi/iscsi_target_core.h
index cbcff38..d3583d3 100644
--- a/drivers/target/iscsi/iscsi_target_core.h
+++ b/include/target/iscsi/iscsi_target_core.h
@@ -880,4 +880,18 @@
struct iscsi_portal_group *discovery_tpg;
};
+static inline u32 session_get_next_ttt(struct iscsi_session *session)
+{
+ u32 ttt;
+
+ spin_lock_bh(&session->ttt_lock);
+ ttt = session->targ_xfer_tag++;
+ if (ttt == 0xFFFFFFFF)
+ ttt = session->targ_xfer_tag++;
+ spin_unlock_bh(&session->ttt_lock);
+
+ return ttt;
+}
+
+extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, itt_t);
#endif /* ISCSI_TARGET_CORE_H */
diff --git a/drivers/target/iscsi/iscsi_target_stat.h b/include/target/iscsi/iscsi_target_stat.h
similarity index 100%
rename from drivers/target/iscsi/iscsi_target_stat.h
rename to include/target/iscsi/iscsi_target_stat.h
diff --git a/include/target/iscsi/iscsi_transport.h b/include/target/iscsi/iscsi_transport.h
index daef9da..e6bb166 100644
--- a/include/target/iscsi/iscsi_transport.h
+++ b/include/target/iscsi/iscsi_transport.h
@@ -1,6 +1,6 @@
#include <linux/module.h>
#include <linux/list.h>
-#include "../../../drivers/target/iscsi/iscsi_target_core.h"
+#include "iscsi_target_core.h"
struct iscsit_transport {
#define ISCSIT_TRANSPORT_NAME 16
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index 4a8795a..672150b6 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -407,7 +407,7 @@
/* Activate Persistence across Target Power Loss enabled
* for SCSI device */
int pr_aptpl_active;
-#define PR_APTPL_BUF_LEN 8192
+#define PR_APTPL_BUF_LEN 262144
u32 pr_generation;
spinlock_t registration_lock;
spinlock_t aptpl_reg_lock;
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index 29715d2..82889c30 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -333,6 +333,7 @@
VFIO_PCI_MSI_IRQ_INDEX,
VFIO_PCI_MSIX_IRQ_INDEX,
VFIO_PCI_ERR_IRQ_INDEX,
+ VFIO_PCI_REQ_IRQ_INDEX,
VFIO_PCI_NUM_IRQS
};
diff --git a/include/uapi/rdma/ib_user_verbs.h b/include/uapi/rdma/ib_user_verbs.h
index 867cc50..b513e66 100644
--- a/include/uapi/rdma/ib_user_verbs.h
+++ b/include/uapi/rdma/ib_user_verbs.h
@@ -90,6 +90,7 @@
};
enum {
+ IB_USER_VERBS_EX_CMD_QUERY_DEVICE = IB_USER_VERBS_CMD_QUERY_DEVICE,
IB_USER_VERBS_EX_CMD_CREATE_FLOW = IB_USER_VERBS_CMD_THRESHOLD,
IB_USER_VERBS_EX_CMD_DESTROY_FLOW,
};
@@ -201,6 +202,28 @@
__u8 reserved[4];
};
+struct ib_uverbs_ex_query_device {
+ __u32 comp_mask;
+ __u32 reserved;
+};
+
+struct ib_uverbs_odp_caps {
+ __u64 general_caps;
+ struct {
+ __u32 rc_odp_caps;
+ __u32 uc_odp_caps;
+ __u32 ud_odp_caps;
+ } per_transport_caps;
+ __u32 reserved;
+};
+
+struct ib_uverbs_ex_query_device_resp {
+ struct ib_uverbs_query_device_resp base;
+ __u32 comp_mask;
+ __u32 response_length;
+ struct ib_uverbs_odp_caps odp_caps;
+};
+
struct ib_uverbs_query_port {
__u64 response;
__u8 port_num;
diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c
index 07ce18c..0874e2e 100644
--- a/kernel/debug/debug_core.c
+++ b/kernel/debug/debug_core.c
@@ -604,7 +604,7 @@
online_cpus)
cpu_relax();
if (!time_left)
- pr_crit("KGDB: Timed out waiting for secondary CPUs.\n");
+ pr_crit("Timed out waiting for secondary CPUs.\n");
/*
* At this point the primary processor is completely
@@ -696,6 +696,14 @@
if (arch_kgdb_ops.enable_nmi)
arch_kgdb_ops.enable_nmi(0);
+ /*
+ * Avoid entering the debugger if we were triggered due to an oops
+ * but panic_timeout indicates the system should automatically
+ * reboot on panic. We don't want to get stuck waiting for input
+ * on such systems, especially if its "just" an oops.
+ */
+ if (signo != SIGTRAP && panic_timeout)
+ return 1;
memset(ks, 0, sizeof(struct kgdb_state));
ks->cpu = raw_smp_processor_id();
@@ -828,6 +836,15 @@
unsigned long val,
void *data)
{
+ /*
+ * Avoid entering the debugger if we were triggered due to a panic
+ * We don't want to get stuck waiting for input from user in such case.
+ * panic_timeout indicates the system should automatically
+ * reboot on panic.
+ */
+ if (panic_timeout)
+ return NOTIFY_DONE;
+
if (dbg_kdb_mode)
kdb_printf("PANIC: %s\n", (char *)data);
kgdb_breakpoint();
diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c
index 7c70812..fc1ef73 100644
--- a/kernel/debug/kdb/kdb_io.c
+++ b/kernel/debug/kdb/kdb_io.c
@@ -439,7 +439,7 @@
* substituted for %d, %x or %o in the prompt.
*/
-char *kdb_getstr(char *buffer, size_t bufsize, char *prompt)
+char *kdb_getstr(char *buffer, size_t bufsize, const char *prompt)
{
if (prompt && kdb_prompt_str != prompt)
strncpy(kdb_prompt_str, prompt, CMD_BUFLEN);
@@ -548,7 +548,7 @@
return 0;
}
-int vkdb_printf(const char *fmt, va_list ap)
+int vkdb_printf(enum kdb_msgsrc src, const char *fmt, va_list ap)
{
int diag;
int linecount;
@@ -680,6 +680,12 @@
size_avail = sizeof(kdb_buffer) - len;
goto kdb_print_out;
}
+ if (kdb_grepping_flag >= KDB_GREPPING_FLAG_SEARCH)
+ /*
+ * This was a interactive search (using '/' at more
+ * prompt) and it has completed. Clear the flag.
+ */
+ kdb_grepping_flag = 0;
/*
* at this point the string is a full line and
* should be printed, up to the null.
@@ -691,19 +697,20 @@
* Write to all consoles.
*/
retlen = strlen(kdb_buffer);
+ cp = (char *) printk_skip_level(kdb_buffer);
if (!dbg_kdb_mode && kgdb_connected) {
- gdbstub_msg_write(kdb_buffer, retlen);
+ gdbstub_msg_write(cp, retlen - (cp - kdb_buffer));
} else {
if (dbg_io_ops && !dbg_io_ops->is_console) {
- len = retlen;
- cp = kdb_buffer;
+ len = retlen - (cp - kdb_buffer);
+ cp2 = cp;
while (len--) {
- dbg_io_ops->write_char(*cp);
- cp++;
+ dbg_io_ops->write_char(*cp2);
+ cp2++;
}
}
while (c) {
- c->write(c, kdb_buffer, retlen);
+ c->write(c, cp, retlen - (cp - kdb_buffer));
touch_nmi_watchdog();
c = c->next;
}
@@ -711,7 +718,10 @@
if (logging) {
saved_loglevel = console_loglevel;
console_loglevel = CONSOLE_LOGLEVEL_SILENT;
- printk(KERN_INFO "%s", kdb_buffer);
+ if (printk_get_level(kdb_buffer) || src == KDB_MSGSRC_PRINTK)
+ printk("%s", kdb_buffer);
+ else
+ pr_info("%s", kdb_buffer);
}
if (KDB_STATE(PAGER)) {
@@ -794,11 +804,23 @@
kdb_nextline = linecount - 1;
kdb_printf("\r");
suspend_grep = 1; /* for this recursion */
+ } else if (buf1[0] == '/' && !kdb_grepping_flag) {
+ kdb_printf("\r");
+ kdb_getstr(kdb_grep_string, KDB_GREP_STRLEN,
+ kdbgetenv("SEARCHPROMPT") ?: "search> ");
+ *strchrnul(kdb_grep_string, '\n') = '\0';
+ kdb_grepping_flag += KDB_GREPPING_FLAG_SEARCH;
+ suspend_grep = 1; /* for this recursion */
} else if (buf1[0] && buf1[0] != '\n') {
/* user hit something other than enter */
suspend_grep = 1; /* for this recursion */
- kdb_printf("\nOnly 'q' or 'Q' are processed at more "
- "prompt, input ignored\n");
+ if (buf1[0] != '/')
+ kdb_printf(
+ "\nOnly 'q', 'Q' or '/' are processed at "
+ "more prompt, input ignored\n");
+ else
+ kdb_printf("\n'/' cannot be used during | "
+ "grep filtering, input ignored\n");
} else if (kdb_grepping_flag) {
/* user hit enter */
suspend_grep = 1; /* for this recursion */
@@ -844,7 +866,7 @@
int r;
va_start(ap, fmt);
- r = vkdb_printf(fmt, ap);
+ r = vkdb_printf(KDB_MSGSRC_INTERNAL, fmt, ap);
va_end(ap);
return r;
diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c
index 7b40c5f..4121345 100644
--- a/kernel/debug/kdb/kdb_main.c
+++ b/kernel/debug/kdb/kdb_main.c
@@ -50,8 +50,7 @@
static int kdb_cmd_enabled = CONFIG_KDB_DEFAULT_ENABLE;
module_param_named(cmd_enable, kdb_cmd_enabled, int, 0600);
-#define GREP_LEN 256
-char kdb_grep_string[GREP_LEN];
+char kdb_grep_string[KDB_GREP_STRLEN];
int kdb_grepping_flag;
EXPORT_SYMBOL(kdb_grepping_flag);
int kdb_grep_leading;
@@ -870,7 +869,7 @@
len = strlen(cp);
if (!len)
return;
- if (len >= GREP_LEN) {
+ if (len >= KDB_GREP_STRLEN) {
kdb_printf("search string too long\n");
return;
}
@@ -915,13 +914,12 @@
char *cp;
char *cpp, quoted;
kdbtab_t *tp;
- int i, escaped, ignore_errors = 0, check_grep;
+ int i, escaped, ignore_errors = 0, check_grep = 0;
/*
* First tokenize the command string.
*/
cp = (char *)cmdstr;
- kdb_grepping_flag = check_grep = 0;
if (KDB_FLAG(CMD_INTERRUPT)) {
/* Previous command was interrupted, newline must not
@@ -1247,7 +1245,6 @@
kdb_printf("due to NonMaskable Interrupt @ "
kdb_machreg_fmt "\n",
instruction_pointer(regs));
- kdb_dumpregs(regs);
break;
case KDB_REASON_SSTEP:
case KDB_REASON_BREAK:
@@ -1281,6 +1278,9 @@
*/
kdb_nextline = 1;
KDB_STATE_CLEAR(SUPPRESS);
+ kdb_grepping_flag = 0;
+ /* ensure the old search does not leak into '/' commands */
+ kdb_grep_string[0] = '\0';
cmdbuf = cmd_cur;
*cmdbuf = '\0';
@@ -2256,7 +2256,7 @@
/*
* Validate cpunum
*/
- if ((cpunum > NR_CPUS) || !kgdb_info[cpunum].enter_kgdb)
+ if ((cpunum >= CONFIG_NR_CPUS) || !kgdb_info[cpunum].enter_kgdb)
return KDB_BADCPUNUM;
dbg_switch_cpu = cpunum;
@@ -2583,7 +2583,7 @@
#define K(x) ((x) << (PAGE_SHIFT - 10))
kdb_printf("\nMemTotal: %8lu kB\nMemFree: %8lu kB\n"
"Buffers: %8lu kB\n",
- val.totalram, val.freeram, val.bufferram);
+ K(val.totalram), K(val.freeram), K(val.bufferram));
return 0;
}
diff --git a/kernel/debug/kdb/kdb_private.h b/kernel/debug/kdb/kdb_private.h
index eaacd16..75014d7 100644
--- a/kernel/debug/kdb/kdb_private.h
+++ b/kernel/debug/kdb/kdb_private.h
@@ -196,7 +196,9 @@
/* Miscellaneous functions and data areas */
extern int kdb_grepping_flag;
+#define KDB_GREPPING_FLAG_SEARCH 0x8000
extern char kdb_grep_string[];
+#define KDB_GREP_STRLEN 256
extern int kdb_grep_leading;
extern int kdb_grep_trailing;
extern char *kdb_cmds[];
@@ -209,7 +211,7 @@
extern void kdb_print_nameval(const char *name, unsigned long val);
extern void kdb_send_sig_info(struct task_struct *p, struct siginfo *info);
extern void kdb_meminfo_proc_show(void);
-extern char *kdb_getstr(char *, size_t, char *);
+extern char *kdb_getstr(char *, size_t, const char *);
extern void kdb_gdb_state_pass(char *buf);
/* Defines for kdb_symbol_print */
diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c
index 3059bc2f..e16e554 100644
--- a/kernel/locking/rtmutex.c
+++ b/kernel/locking/rtmutex.c
@@ -1193,7 +1193,8 @@
ret = __rt_mutex_slowlock(lock, state, timeout, &waiter);
if (unlikely(ret)) {
- remove_waiter(lock, &waiter);
+ if (rt_mutex_has_waiters(lock))
+ remove_waiter(lock, &waiter);
rt_mutex_handle_deadlock(ret, chwalk, &waiter);
}
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index c06df7d..01cfd69 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1811,7 +1811,7 @@
#ifdef CONFIG_KGDB_KDB
if (unlikely(kdb_trap_printk)) {
- r = vkdb_printf(fmt, args);
+ r = vkdb_printf(KDB_MSGSRC_PRINTK, fmt, args);
return r;
}
#endif
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index 0d7bbe3..0a571e9 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -326,6 +326,7 @@
special = t->rcu_read_unlock_special;
if (special.b.need_qs) {
rcu_preempt_qs();
+ t->rcu_read_unlock_special.b.need_qs = false;
if (!t->rcu_read_unlock_special.s) {
local_irq_restore(flags);
return;
diff --git a/kernel/sched/auto_group.c b/kernel/sched/auto_group.c
index 8a2e230..eae160d 100644
--- a/kernel/sched/auto_group.c
+++ b/kernel/sched/auto_group.c
@@ -87,8 +87,7 @@
* so we don't have to move tasks around upon policy change,
* or flail around trying to allocate bandwidth on the fly.
* A bandwidth exception in __sched_setscheduler() allows
- * the policy change to proceed. Thereafter, task_group()
- * returns &root_task_group, so zero bandwidth is required.
+ * the policy change to proceed.
*/
free_rt_sched_group(tg);
tg->rt_se = root_task_group.rt_se;
@@ -115,9 +114,6 @@
if (tg != &root_task_group)
return false;
- if (p->sched_class != &fair_sched_class)
- return false;
-
/*
* We can only assume the task group can't go away on us if
* autogroup_move_group() can see us on ->thread_group list.
diff --git a/kernel/sched/completion.c b/kernel/sched/completion.c
index 7052d3f..8d0f35d 100644
--- a/kernel/sched/completion.c
+++ b/kernel/sched/completion.c
@@ -274,7 +274,7 @@
* first without taking the lock so we can
* return early in the blocking case.
*/
- if (!ACCESS_ONCE(x->done))
+ if (!READ_ONCE(x->done))
return 0;
spin_lock_irqsave(&x->wait.lock, flags);
@@ -297,6 +297,21 @@
*/
bool completion_done(struct completion *x)
{
- return !!ACCESS_ONCE(x->done);
+ if (!READ_ONCE(x->done))
+ return false;
+
+ /*
+ * If ->done, we need to wait for complete() to release ->wait.lock
+ * otherwise we can end up freeing the completion before complete()
+ * is done referencing it.
+ *
+ * The RMB pairs with complete()'s RELEASE of ->wait.lock and orders
+ * the loads of ->done and ->wait.lock such that we cannot observe
+ * the lock before complete() acquires it while observing the ->done
+ * after it's acquired the lock.
+ */
+ smp_rmb();
+ spin_unlock_wait(&x->wait.lock);
+ return true;
}
EXPORT_SYMBOL(completion_done);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 13049aa..f0f831e 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -307,66 +307,6 @@
int sysctl_sched_rt_runtime = 950000;
/*
- * __task_rq_lock - lock the rq @p resides on.
- */
-static inline struct rq *__task_rq_lock(struct task_struct *p)
- __acquires(rq->lock)
-{
- struct rq *rq;
-
- lockdep_assert_held(&p->pi_lock);
-
- for (;;) {
- rq = task_rq(p);
- raw_spin_lock(&rq->lock);
- if (likely(rq == task_rq(p) && !task_on_rq_migrating(p)))
- return rq;
- raw_spin_unlock(&rq->lock);
-
- while (unlikely(task_on_rq_migrating(p)))
- cpu_relax();
- }
-}
-
-/*
- * task_rq_lock - lock p->pi_lock and lock the rq @p resides on.
- */
-static struct rq *task_rq_lock(struct task_struct *p, unsigned long *flags)
- __acquires(p->pi_lock)
- __acquires(rq->lock)
-{
- struct rq *rq;
-
- for (;;) {
- raw_spin_lock_irqsave(&p->pi_lock, *flags);
- rq = task_rq(p);
- raw_spin_lock(&rq->lock);
- if (likely(rq == task_rq(p) && !task_on_rq_migrating(p)))
- return rq;
- raw_spin_unlock(&rq->lock);
- raw_spin_unlock_irqrestore(&p->pi_lock, *flags);
-
- while (unlikely(task_on_rq_migrating(p)))
- cpu_relax();
- }
-}
-
-static void __task_rq_unlock(struct rq *rq)
- __releases(rq->lock)
-{
- raw_spin_unlock(&rq->lock);
-}
-
-static inline void
-task_rq_unlock(struct rq *rq, struct task_struct *p, unsigned long *flags)
- __releases(rq->lock)
- __releases(p->pi_lock)
-{
- raw_spin_unlock(&rq->lock);
- raw_spin_unlock_irqrestore(&p->pi_lock, *flags);
-}
-
-/*
* this_rq_lock - lock this runqueue and disable interrupts.
*/
static struct rq *this_rq_lock(void)
@@ -2899,7 +2839,7 @@
preempt_disable();
}
-static void preempt_schedule_common(void)
+static void __sched notrace preempt_schedule_common(void)
{
do {
__preempt_count_add(PREEMPT_ACTIVE);
@@ -4418,36 +4358,29 @@
* This task is about to go to sleep on IO. Increment rq->nr_iowait so
* that process accounting knows that this is a task in IO wait state.
*/
-void __sched io_schedule(void)
-{
- struct rq *rq = raw_rq();
-
- delayacct_blkio_start();
- atomic_inc(&rq->nr_iowait);
- blk_flush_plug(current);
- current->in_iowait = 1;
- schedule();
- current->in_iowait = 0;
- atomic_dec(&rq->nr_iowait);
- delayacct_blkio_end();
-}
-EXPORT_SYMBOL(io_schedule);
-
long __sched io_schedule_timeout(long timeout)
{
- struct rq *rq = raw_rq();
+ int old_iowait = current->in_iowait;
+ struct rq *rq;
long ret;
- delayacct_blkio_start();
- atomic_inc(&rq->nr_iowait);
- blk_flush_plug(current);
current->in_iowait = 1;
+ if (old_iowait)
+ blk_schedule_flush_plug(current);
+ else
+ blk_flush_plug(current);
+
+ delayacct_blkio_start();
+ rq = raw_rq();
+ atomic_inc(&rq->nr_iowait);
ret = schedule_timeout(timeout);
- current->in_iowait = 0;
+ current->in_iowait = old_iowait;
atomic_dec(&rq->nr_iowait);
delayacct_blkio_end();
+
return ret;
}
+EXPORT_SYMBOL(io_schedule_timeout);
/**
* sys_sched_get_priority_max - return maximum RT priority.
@@ -7642,6 +7575,12 @@
{
struct task_struct *g, *p;
+ /*
+ * Autogroups do not have RT tasks; see autogroup_create().
+ */
+ if (task_group_is_autogroup(tg))
+ return 0;
+
for_each_process_thread(g, p) {
if (rt_task(p) && task_group(p) == tg)
return 1;
@@ -7734,6 +7673,17 @@
{
int i, err = 0;
+ /*
+ * Disallowing the root group RT runtime is BAD, it would disallow the
+ * kernel creating (and or operating) RT threads.
+ */
+ if (tg == &root_task_group && rt_runtime == 0)
+ return -EINVAL;
+
+ /* No period doesn't make any sense. */
+ if (rt_period == 0)
+ return -EINVAL;
+
mutex_lock(&rt_constraints_mutex);
read_lock(&tasklist_lock);
err = __rt_schedulable(tg, rt_period, rt_runtime);
@@ -7790,9 +7740,6 @@
rt_period = (u64)rt_period_us * NSEC_PER_USEC;
rt_runtime = tg->rt_bandwidth.rt_runtime;
- if (rt_period == 0)
- return -EINVAL;
-
return tg_set_rt_bandwidth(tg, rt_period, rt_runtime);
}
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index a027799..3fa8fa6 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -511,16 +511,10 @@
struct sched_dl_entity,
dl_timer);
struct task_struct *p = dl_task_of(dl_se);
+ unsigned long flags;
struct rq *rq;
-again:
- rq = task_rq(p);
- raw_spin_lock(&rq->lock);
- if (rq != task_rq(p)) {
- /* Task was moved, retrying. */
- raw_spin_unlock(&rq->lock);
- goto again;
- }
+ rq = task_rq_lock(current, &flags);
/*
* We need to take care of several possible races here:
@@ -541,6 +535,26 @@
sched_clock_tick();
update_rq_clock(rq);
+
+ /*
+ * If the throttle happened during sched-out; like:
+ *
+ * schedule()
+ * deactivate_task()
+ * dequeue_task_dl()
+ * update_curr_dl()
+ * start_dl_timer()
+ * __dequeue_task_dl()
+ * prev->on_rq = 0;
+ *
+ * We can be both throttled and !queued. Replenish the counter
+ * but do not enqueue -- wait for our wakeup to do that.
+ */
+ if (!task_on_rq_queued(p)) {
+ replenish_dl_entity(dl_se, dl_se);
+ goto unlock;
+ }
+
enqueue_task_dl(rq, p, ENQUEUE_REPLENISH);
if (dl_task(rq->curr))
check_preempt_curr_dl(rq, p, 0);
@@ -555,7 +569,7 @@
push_dl_task(rq);
#endif
unlock:
- raw_spin_unlock(&rq->lock);
+ task_rq_unlock(rq, current, &flags);
return HRTIMER_NORESTART;
}
@@ -898,6 +912,7 @@
rq->curr->dl.dl_yielded = 1;
p->dl.runtime = 0;
}
+ update_rq_clock(rq);
update_curr_dl(rq);
}
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 0870db2..dc0f435 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1380,6 +1380,82 @@
extern void start_bandwidth_timer(struct hrtimer *period_timer, ktime_t period);
+/*
+ * __task_rq_lock - lock the rq @p resides on.
+ */
+static inline struct rq *__task_rq_lock(struct task_struct *p)
+ __acquires(rq->lock)
+{
+ struct rq *rq;
+
+ lockdep_assert_held(&p->pi_lock);
+
+ for (;;) {
+ rq = task_rq(p);
+ raw_spin_lock(&rq->lock);
+ if (likely(rq == task_rq(p) && !task_on_rq_migrating(p)))
+ return rq;
+ raw_spin_unlock(&rq->lock);
+
+ while (unlikely(task_on_rq_migrating(p)))
+ cpu_relax();
+ }
+}
+
+/*
+ * task_rq_lock - lock p->pi_lock and lock the rq @p resides on.
+ */
+static inline struct rq *task_rq_lock(struct task_struct *p, unsigned long *flags)
+ __acquires(p->pi_lock)
+ __acquires(rq->lock)
+{
+ struct rq *rq;
+
+ for (;;) {
+ raw_spin_lock_irqsave(&p->pi_lock, *flags);
+ rq = task_rq(p);
+ raw_spin_lock(&rq->lock);
+ /*
+ * move_queued_task() task_rq_lock()
+ *
+ * ACQUIRE (rq->lock)
+ * [S] ->on_rq = MIGRATING [L] rq = task_rq()
+ * WMB (__set_task_cpu()) ACQUIRE (rq->lock);
+ * [S] ->cpu = new_cpu [L] task_rq()
+ * [L] ->on_rq
+ * RELEASE (rq->lock)
+ *
+ * If we observe the old cpu in task_rq_lock, the acquire of
+ * the old rq->lock will fully serialize against the stores.
+ *
+ * If we observe the new cpu in task_rq_lock, the acquire will
+ * pair with the WMB to ensure we must then also see migrating.
+ */
+ if (likely(rq == task_rq(p) && !task_on_rq_migrating(p)))
+ return rq;
+ raw_spin_unlock(&rq->lock);
+ raw_spin_unlock_irqrestore(&p->pi_lock, *flags);
+
+ while (unlikely(task_on_rq_migrating(p)))
+ cpu_relax();
+ }
+}
+
+static inline void __task_rq_unlock(struct rq *rq)
+ __releases(rq->lock)
+{
+ raw_spin_unlock(&rq->lock);
+}
+
+static inline void
+task_rq_unlock(struct rq *rq, struct task_struct *p, unsigned long *flags)
+ __releases(rq->lock)
+ __releases(p->pi_lock)
+{
+ raw_spin_unlock(&rq->lock);
+ raw_spin_unlock_irqrestore(&p->pi_lock, *flags);
+}
+
#ifdef CONFIG_SMP
#ifdef CONFIG_PREEMPT
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index 4b585e0..0f60b08 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -633,10 +633,14 @@
if ((txc->modes & ADJ_SETOFFSET) && (!capable(CAP_SYS_TIME)))
return -EPERM;
- if (txc->modes & ADJ_FREQUENCY) {
- if (LONG_MIN / PPM_SCALE > txc->freq)
+ /*
+ * Check for potential multiplication overflows that can
+ * only happen on 64-bit systems:
+ */
+ if ((txc->modes & ADJ_FREQUENCY) && (BITS_PER_LONG == 64)) {
+ if (LLONG_MIN / PPM_SCALE > txc->freq)
return -EINVAL;
- if (LONG_MAX / PPM_SCALE < txc->freq)
+ if (LLONG_MAX / PPM_SCALE < txc->freq)
return -EINVAL;
}
diff --git a/sound/core/seq/seq_midi_emul.c b/sound/core/seq/seq_midi_emul.c
index 9b6470c..7ba9373 100644
--- a/sound/core/seq/seq_midi_emul.c
+++ b/sound/core/seq/seq_midi_emul.c
@@ -269,6 +269,9 @@
{
int i;
+ if (control >= ARRAY_SIZE(chan->control))
+ return;
+
/* Switches */
if ((control >=64 && control <=69) || (control >= 80 && control <= 83)) {
/* These are all switches; either off or on so set to 0 or 127 */
diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c
index 227990b..375e94f 100644
--- a/sound/pci/hda/hda_tegra.c
+++ b/sound/pci/hda/hda_tegra.c
@@ -329,8 +329,8 @@
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hda->regs = devm_ioremap_resource(dev, res);
- if (IS_ERR(chip->remap_addr))
- return PTR_ERR(chip->remap_addr);
+ if (IS_ERR(hda->regs))
+ return PTR_ERR(hda->regs);
chip->remap_addr = hda->regs + HDA_BAR0;
chip->addr = res->start + HDA_BAR0;
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index ddb9308..b2b24a8 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -4937,6 +4937,7 @@
SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x225f, "HP", ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY),
/* ALC282 */
+ SND_PCI_QUIRK(0x103c, 0x21f9, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x2210, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x2236, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 2c363fd..ca67f89 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -6082,6 +6082,9 @@
snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
64, 8192);
+ snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS,
+ 2, 2);
break;
}
@@ -6156,6 +6159,9 @@
snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
64, 8192);
+ snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS,
+ 2, 2);
break;
}
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c
index d6fa9d5..7e21e8f 100644
--- a/sound/soc/intel/sst-haswell-pcm.c
+++ b/sound/soc/intel/sst-haswell-pcm.c
@@ -91,7 +91,8 @@
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME |
- SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
+ SNDRV_PCM_INFO_DRAIN_TRIGGER,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.period_bytes_min = PAGE_SIZE,
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index 03fed66..2ed260b 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -303,6 +303,11 @@
return err;
}
+ /* Don't check the sample rate for devices which we know don't
+ * support reading */
+ if (snd_usb_get_sample_rate_quirk(chip))
+ return 0;
+
if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c
index 99b63a7..81b7da8 100644
--- a/sound/usb/line6/driver.c
+++ b/sound/usb/line6/driver.c
@@ -302,14 +302,17 @@
/*
Read data from device.
*/
-int line6_read_data(struct usb_line6 *line6, int address, void *data,
- size_t datalen)
+int line6_read_data(struct usb_line6 *line6, unsigned address, void *data,
+ unsigned datalen)
{
struct usb_device *usbdev = line6->usbdev;
int ret;
unsigned char len;
unsigned count;
+ if (address > 0xffff || datalen > 0xff)
+ return -EINVAL;
+
/* query the serial number: */
ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
@@ -370,14 +373,17 @@
/*
Write data to device.
*/
-int line6_write_data(struct usb_line6 *line6, int address, void *data,
- size_t datalen)
+int line6_write_data(struct usb_line6 *line6, unsigned address, void *data,
+ unsigned datalen)
{
struct usb_device *usbdev = line6->usbdev;
int ret;
unsigned char status;
int count;
+ if (address > 0xffff || datalen > 0xffff)
+ return -EINVAL;
+
ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
0x0022, address, data, datalen,
diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h
index 5d20294..7da643e 100644
--- a/sound/usb/line6/driver.h
+++ b/sound/usb/line6/driver.h
@@ -147,8 +147,8 @@
extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1,
int code2, int size);
-extern int line6_read_data(struct usb_line6 *line6, int address, void *data,
- size_t datalen);
+extern int line6_read_data(struct usb_line6 *line6, unsigned address,
+ void *data, unsigned datalen);
extern int line6_read_serial_number(struct usb_line6 *line6,
u32 *serial_number);
extern int line6_send_raw_message_async(struct usb_line6 *line6,
@@ -161,8 +161,8 @@
void (*function)(unsigned long),
unsigned long data);
extern int line6_version_request_async(struct usb_line6 *line6);
-extern int line6_write_data(struct usb_line6 *line6, int address, void *data,
- size_t datalen);
+extern int line6_write_data(struct usb_line6 *line6, unsigned address,
+ void *data, unsigned datalen);
int line6_probe(struct usb_interface *interface,
const struct usb_device_id *id,
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index a739841..753a47d 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1111,6 +1111,11 @@
}
}
+bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
+{
+ /* MS Lifecam HD-5000 doesn't support reading the sample rate. */
+ return chip->usb_id == USB_ID(0x045E, 0x076D);
+}
/* Marantz/Denon USB DACs need a vendor cmd to switch
* between PCM and native DSD mode
@@ -1122,6 +1127,7 @@
int err;
switch (subs->stream->chip->usb_id) {
+ case USB_ID(0x154e, 0x1003): /* Denon DA-300USB */
case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */
case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */
@@ -1201,6 +1207,7 @@
(requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) {
switch (le16_to_cpu(dev->descriptor.idProduct)) {
+ case 0x1003: /* Denon DA300-USB */
case 0x3005: /* Marantz HD-DAC1 */
case 0x3006: /* Marantz SA-14S1 */
mdelay(20);
@@ -1262,6 +1269,7 @@
/* Denon/Marantz devices with USB DAC functionality */
switch (chip->usb_id) {
+ case USB_ID(0x154e, 0x1003): /* Denon DA300-USB */
case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */
case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */
if (fp->altsetting == 2)
diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h
index 1b86238..2cd71ed 100644
--- a/sound/usb/quirks.h
+++ b/sound/usb/quirks.h
@@ -21,6 +21,8 @@
void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
struct audioformat *fmt);
+bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip);
+
int snd_usb_is_big_endian_format(struct snd_usb_audio *chip,
struct audioformat *fp);