Commit 4bcec913 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc

Pull more powerpc bits from Ben Herrenschmidt:
 "Here are a few more powerpc bits for this merge window.  The bulk is
  made of two pull requests from Scott and Anatolij that I had missed
  previously (they arrived while I was away).  Since both their branches
  are in -next independently, and the content has been around for a
  little while, they can still go in.

  The rest is mostly bug and regression fixes, a small series of
  cleanups to our pseries cpuidle code (including moving it to the right
  place), and one new cpuidle bakend for the powernv platform.  I also
  wired up the new sched_attr syscalls"

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (37 commits)
  powerpc: Wire up sched_setattr and sched_getattr syscalls
  powerpc/hugetlb: Replace __get_cpu_var with get_cpu_var
  powerpc: Make sure "cache" directory is removed when offlining cpu
  powerpc/mm: Fix mmap errno when MAP_FIXED is set and mapping exceeds the allowed address space
  powerpc/powernv/cpuidle: Back-end cpuidle driver for powernv platform.
  powerpc/pseries/cpuidle: smt-snooze-delay cleanup.
  powerpc/pseries/cpuidle: Remove MAX_IDLE_STATE macro.
  powerpc/pseries/cpuidle: Make cpuidle-pseries backend driver a non-module.
  powerpc/pseries/cpuidle: Use cpuidle_register() for initialisation.
  powerpc/pseries/cpuidle: Move processor_idle.c to drivers/cpuidle.
  powerpc: Fix 32-bit frames for signals delivered when transactional
  powerpc/iommu: Fix initialisation of DART iommu table
  powerpc/numa: Fix decimal permissions
  powerpc/mm: Fix compile error of pgtable-ppc64.h
  powerpc: Fix hw breakpoints on !HAVE_HW_BREAKPOINT configurations
  clk: corenet: Adds the clock binding
  powerpc/booke64: Guard e6500 tlb handler with CONFIG_PPC_FSL_BOOK3E
  powerpc/512x: dts: add MPC5125 clock specs
  powerpc/512x: clk: support MPC5121/5123/5125 SoC variants
  powerpc/512x: clk: enforce even SDHC divider values
  ...
parents 03c7287d f878f843
* Clock Block on Freescale CoreNet Platforms
Freescale CoreNet 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
cores and peripheral IP blocks.
Please refer to the Reference Manual for details.
1. Clock Block Binding
Required properties:
- compatible: Should contain a specific clock block compatible string
and a single chassis clock compatible string.
Clock block strings include, but not limited to, one of the:
* "fsl,p2041-clockgen"
* "fsl,p3041-clockgen"
* "fsl,p4080-clockgen"
* "fsl,p5020-clockgen"
* "fsl,p5040-clockgen"
* "fsl,t4240-clockgen"
* "fsl,b4420-clockgen"
* "fsl,b4860-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
- reg: Describes the address of the device's resources within the
address space defined by its parent bus, and resource zero
represents the clock register set
- clock-frequency: Input system clock frequency
Recommended properties:
- ranges: Allows valid translation between child's address space and
parent's. Must be present if the device has sub-nodes.
- #address-cells: Specifies the number of cells used to represent
physical base addresses. Must be present if the device has
sub-nodes and set to 1 if present
- #size-cells: Specifies the number of cells used to represent
the size of an address. Must be present if the device has
sub-nodes and set to 1 if present
2. Clock Provider/Consumer Binding
Most of the bindings are from the common clock binding[1].
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
Required properties:
- compatible : Should include one of the following:
* "fsl,qoriq-core-pll-1.0" for core PLL clocks (v1.0)
* "fsl,qoriq-core-pll-2.0" for core PLL clocks (v2.0)
* "fsl,qoriq-core-mux-1.0" for core mux clocks (v1.0)
* "fsl,qoriq-core-mux-2.0" for core mux clocks (v2.0)
* "fsl,qoriq-sysclk-1.0": for input system clock (v1.0).
It takes parent's clock-frequency as its clock.
* "fsl,qoriq-sysclk-2.0": for input system clock (v2.0).
It takes parent's clock-frequency as its clock.
- #clock-cells: From common clock binding. The number of cells in a
clock-specifier. Should be <0> for "fsl,qoriq-sysclk-[1,2].0"
clocks, or <1> for "fsl,qoriq-core-pll-[1,2].0" clocks.
For "fsl,qoriq-core-pll-[1,2].0" clocks, the single
clock-specifier cell may take the following values:
* 0 - equal to the PLL frequency
* 1 - equal to the PLL frequency divided by 2
* 2 - equal to the PLL frequency divided by 4
Recommended properties:
- clocks: Should be the phandle of input parent clock
- clock-names: From common clock binding, indicates the clock name
- clock-output-names: From common clock binding, indicates the names of
output clocks
- reg: Should be the offset and length of clock block base address.
The length should be 4.
Example for clock block and clock provider:
/ {
clockgen: global-utilities@e1000 {
compatible = "fsl,p5020-clockgen", "fsl,qoriq-clockgen-1.0";
ranges = <0x0 0xe1000 0x1000>;
clock-frequency = <133333333>;
reg = <0xe1000 0x1000>;
#address-cells = <1>;
#size-cells = <1>;
sysclk: sysclk {
#clock-cells = <0>;
compatible = "fsl,qoriq-sysclk-1.0";
clock-output-names = "sysclk";
}
pll0: pll0@800 {
#clock-cells = <1>;
reg = <0x800 0x4>;
compatible = "fsl,qoriq-core-pll-1.0";
clocks = <&sysclk>;
clock-output-names = "pll0", "pll0-div2";
};
pll1: pll1@820 {
#clock-cells = <1>;
reg = <0x820 0x4>;
compatible = "fsl,qoriq-core-pll-1.0";
clocks = <&sysclk>;
clock-output-names = "pll1", "pll1-div2";
};
mux0: mux0@0 {
#clock-cells = <0>;
reg = <0x0 0x4>;
compatible = "fsl,qoriq-core-mux-1.0";
clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
clock-output-names = "cmux0";
};
mux1: mux1@20 {
#clock-cells = <0>;
reg = <0x20 0x4>;
compatible = "fsl,qoriq-core-mux-1.0";
clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
clock-output-names = "cmux1";
};
};
}
Example for clock consumer:
/ {
cpu0: PowerPC,e5500@0 {
...
clocks = <&mux0>;
...
};
}
......@@ -532,6 +532,7 @@ config PPC_16K_PAGES
config PPC_64K_PAGES
bool "64k page size" if 44x || PPC_STD_MMU_64 || PPC_BOOK3E_64
depends on !PPC_FSL_BOOK3E
select PPC_HAS_HASH_64K if PPC_STD_MMU_64
config PPC_256K_PAGES
......@@ -1045,11 +1046,6 @@ config KEYS_COMPAT
source "crypto/Kconfig"
config PPC_CLOCK
bool
default n
select HAVE_CLK
config PPC_LIB_RHEAP
bool
......
......@@ -139,7 +139,14 @@ &gpio_pic 11 0 /* done */
};
};
clocks {
osc {
clock-frequency = <25000000>;
};
};
soc@80000000 {
bus-frequency = <80000000>; /* 80 MHz ips bus */
clock@f00 {
compatible = "fsl,mpc5121rev2-clock", "fsl,mpc5121-clock";
......
......@@ -9,6 +9,8 @@
* option) any later version.
*/
#include <dt-bindings/clock/mpc512x-clock.h>
/dts-v1/;
/ {
......@@ -49,6 +51,10 @@ mbx@20000000 {
compatible = "fsl,mpc5121-mbx";
reg = <0x20000000 0x4000>;
interrupts = <66 0x8>;
clocks = <&clks MPC512x_CLK_MBX_BUS>,
<&clks MPC512x_CLK_MBX_3D>,
<&clks MPC512x_CLK_MBX>;
clock-names = "mbx-bus", "mbx-3d", "mbx";
};
sram@30000000 {
......@@ -62,6 +68,8 @@ nfc@40000000 {
interrupts = <6 8>;
#address-cells = <1>;
#size-cells = <1>;
clocks = <&clks MPC512x_CLK_NFC>;
clock-names = "ipg";
};
localbus@80000020 {
......@@ -73,6 +81,17 @@ localbus@80000020 {
ranges = <0x0 0x0 0xfc000000 0x04000000>;
};
clocks {
#address-cells = <1>;
#size-cells = <0>;
osc: osc {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <33000000>;
};
};
soc@80000000 {
compatible = "fsl,mpc5121-immr";
#address-cells = <1>;
......@@ -117,9 +136,12 @@ reset@e00 {
};
/* Clock control */
clock@f00 {
clks: clock@f00 {
compatible = "fsl,mpc5121-clock";
reg = <0xf00 0x100>;
#clock-cells = <1>;
clocks = <&osc>;
clock-names = "osc";
};
/* Power Management Controller */
......@@ -139,12 +161,24 @@ can@1300 {
compatible = "fsl,mpc5121-mscan";
reg = <0x1300 0x80>;
interrupts = <12 0x8>;
clocks = <&clks MPC512x_CLK_BDLC>,
<&clks MPC512x_CLK_IPS>,
<&clks MPC512x_CLK_SYS>,
<&clks MPC512x_CLK_REF>,
<&clks MPC512x_CLK_MSCAN0_MCLK>;
clock-names = "ipg", "ips", "sys", "ref", "mclk";
};
can@1380 {
compatible = "fsl,mpc5121-mscan";
reg = <0x1380 0x80>;
interrupts = <13 0x8>;
clocks = <&clks MPC512x_CLK_BDLC>,
<&clks MPC512x_CLK_IPS>,
<&clks MPC512x_CLK_SYS>,
<&clks MPC512x_CLK_REF>,
<&clks MPC512x_CLK_MSCAN1_MCLK>;
clock-names = "ipg", "ips", "sys", "ref", "mclk";
};
sdhc@1500 {
......@@ -153,6 +187,9 @@ sdhc@1500 {
interrupts = <8 0x8>;
dmas = <&dma0 30>;
dma-names = "rx-tx";
clocks = <&clks MPC512x_CLK_IPS>,
<&clks MPC512x_CLK_SDHC>;
clock-names = "ipg", "per";
};
i2c@1700 {
......@@ -161,6 +198,8 @@ i2c@1700 {
compatible = "fsl,mpc5121-i2c", "fsl-i2c";
reg = <0x1700 0x20>;
interrupts = <9 0x8>;
clocks = <&clks MPC512x_CLK_I2C>;
clock-names = "ipg";
};
i2c@1720 {
......@@ -169,6 +208,8 @@ i2c@1720 {
compatible = "fsl,mpc5121-i2c", "fsl-i2c";
reg = <0x1720 0x20>;
interrupts = <10 0x8>;
clocks = <&clks MPC512x_CLK_I2C>;
clock-names = "ipg";
};
i2c@1740 {
......@@ -177,6 +218,8 @@ i2c@1740 {
compatible = "fsl,mpc5121-i2c", "fsl-i2c";
reg = <0x1740 0x20>;
interrupts = <11 0x8>;
clocks = <&clks MPC512x_CLK_I2C>;
clock-names = "ipg";
};
i2ccontrol@1760 {
......@@ -188,30 +231,48 @@ axe@2000 {
compatible = "fsl,mpc5121-axe";
reg = <0x2000 0x100>;
interrupts = <42 0x8>;
clocks = <&clks MPC512x_CLK_AXE>;
clock-names = "ipg";
};
display@2100 {
compatible = "fsl,mpc5121-diu";
reg = <0x2100 0x100>;
interrupts = <64 0x8>;
clocks = <&clks MPC512x_CLK_DIU>;
clock-names = "ipg";
};
can@2300 {
compatible = "fsl,mpc5121-mscan";
reg = <0x2300 0x80>;
interrupts = <90 0x8>;
clocks = <&clks MPC512x_CLK_BDLC>,
<&clks MPC512x_CLK_IPS>,
<&clks MPC512x_CLK_SYS>,
<&clks MPC512x_CLK_REF>,
<&clks MPC512x_CLK_MSCAN2_MCLK>;
clock-names = "ipg", "ips", "sys", "ref", "mclk";
};
can@2380 {
compatible = "fsl,mpc5121-mscan";
reg = <0x2380 0x80>;
interrupts = <91 0x8>;
clocks = <&clks MPC512x_CLK_BDLC>,
<&clks MPC512x_CLK_IPS>,
<&clks MPC512x_CLK_SYS>,
<&clks MPC512x_CLK_REF>,
<&clks MPC512x_CLK_MSCAN3_MCLK>;
clock-names = "ipg", "ips", "sys", "ref", "mclk";
};
viu@2400 {
compatible = "fsl,mpc5121-viu";
reg = <0x2400 0x400>;
interrupts = <67 0x8>;
clocks = <&clks MPC512x_CLK_VIU>;
clock-names = "ipg";
};
mdio@2800 {
......@@ -219,6 +280,8 @@ mdio@2800 {
reg = <0x2800 0x800>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&clks MPC512x_CLK_FEC>;
clock-names = "per";
};
eth0: ethernet@2800 {
......@@ -227,6 +290,8 @@ eth0: ethernet@2800 {
reg = <0x2800 0x800>;
local-mac-address = [ 00 00 00 00 00 00 ];
interrupts = <4 0x8>;
clocks = <&clks MPC512x_CLK_FEC>;
clock-names = "per";
};
/* USB1 using external ULPI PHY */
......@@ -238,6 +303,8 @@ usb@3000 {
interrupts = <43 0x8>;
dr_mode = "otg";
phy_type = "ulpi";
clocks = <&clks MPC512x_CLK_USB1>;
clock-names = "ipg";
};
/* USB0 using internal UTMI PHY */
......@@ -249,6 +316,8 @@ usb@4000 {
interrupts = <44 0x8>;
dr_mode = "otg";
phy_type = "utmi_wide";
clocks = <&clks MPC512x_CLK_USB2>;
clock-names = "ipg";
};
/* IO control */
......@@ -267,6 +336,8 @@ pata@10200 {
compatible = "fsl,mpc5121-pata";
reg = <0x10200 0x100>;
interrupts = <5 0x8>;
clocks = <&clks MPC512x_CLK_PATA>;
clock-names = "ipg";
};
/* 512x PSCs are not 52xx PSC compatible */
......@@ -278,6 +349,9 @@ psc@11000 {
interrupts = <40 0x8>;
fsl,rx-fifo-size = <16>;
fsl,tx-fifo-size = <16>;
clocks = <&clks MPC512x_CLK_PSC0>,
<&clks MPC512x_CLK_PSC0_MCLK>;
clock-names = "ipg", "mclk";
};
/* PSC1 */
......@@ -287,6 +361,9 @@ psc@11100 {
interrupts = <40 0x8>;
fsl,rx-fifo-size = <16>;
fsl,tx-fifo-size = <16>;
clocks = <&clks MPC512x_CLK_PSC1>,
<&clks MPC512x_CLK_PSC1_MCLK>;
clock-names = "ipg", "mclk";
};
/* PSC2 */
......@@ -296,6 +373,9 @@ psc@11200 {
interrupts = <40 0x8>;
fsl,rx-fifo-size = <16>;
fsl,tx-fifo-size = <16>;
clocks = <&clks MPC512x_CLK_PSC2>,
<&clks MPC512x_CLK_PSC2_MCLK>;
clock-names = "ipg", "mclk";
};
/* PSC3 */
......@@ -305,6 +385,9 @@ psc@11300 {
interrupts = <40 0x8>;
fsl,rx-fifo-size = <16>;
fsl,tx-fifo-size = <16>;
clocks = <&clks MPC512x_CLK_PSC3>,
<&clks MPC512x_CLK_PSC3_MCLK>;
clock-names = "ipg", "mclk";
};
/* PSC4 */
......@@ -314,6 +397,9 @@ psc@11400 {
interrupts = <40 0x8>;
fsl,rx-fifo-size = <16>;
fsl,tx-fifo-size = <16>;
clocks = <&clks MPC512x_CLK_PSC4>,
<&clks MPC512x_CLK_PSC4_MCLK>;
clock-names = "ipg", "mclk";
};
/* PSC5 */
......@@ -323,6 +409,9 @@ psc@11500 {
interrupts = <40 0x8>;
fsl,rx-fifo-size = <16>;
fsl,tx-fifo-size = <16>;
clocks = <&clks MPC512x_CLK_PSC5>,
<&clks MPC512x_CLK_PSC5_MCLK>;
clock-names = "ipg", "mclk";
};
/* PSC6 */
......@@ -332,6 +421,9 @@ psc@11600 {
interrupts = <40 0x8>;
fsl,rx-fifo-size = <16>;
fsl,tx-fifo-size = <16>;
clocks = <&clks MPC512x_CLK_PSC6>,
<&clks MPC512x_CLK_PSC6_MCLK>;
clock-names = "ipg", "mclk";
};
/* PSC7 */
......@@ -341,6 +433,9 @@ psc@11700 {
interrupts = <40 0x8>;
fsl,rx-fifo-size = <16>;
fsl,tx-fifo-size = <16>;
clocks = <&clks MPC512x_CLK_PSC7>,
<&clks MPC512x_CLK_PSC7_MCLK>;
clock-names = "ipg", "mclk";
};
/* PSC8 */
......@@ -350,6 +445,9 @@ psc@11800 {
interrupts = <40 0x8>;
fsl,rx-fifo-size = <16>;
fsl,tx-fifo-size = <16>;
clocks = <&clks MPC512x_CLK_PSC8>,
<&clks MPC512x_CLK_PSC8_MCLK>;
clock-names = "ipg", "mclk";
};
/* PSC9 */
......@@ -359,6 +457,9 @@ psc@11900 {
interrupts = <40 0x8>;
fsl,rx-fifo-size = <16>;
fsl,tx-fifo-size = <16>;
clocks = <&clks MPC512x_CLK_PSC9>,
<&clks MPC512x_CLK_PSC9_MCLK>;
clock-names = "ipg", "mclk";
};
/* PSC10 */
......@@ -368,6 +469,9 @@ psc@11a00 {
interrupts = <40 0x8>;
fsl,rx-fifo-size = <16>;
fsl,tx-fifo-size = <16>;
clocks = <&clks MPC512x_CLK_PSC10>,
<&clks MPC512x_CLK_PSC10_MCLK>;
clock-names = "ipg", "mclk";
};
/* PSC11 */
......@@ -377,12 +481,17 @@ psc@11b00 {
interrupts = <40 0x8>;
fsl,rx-fifo-size = <16>;
fsl,tx-fifo-size = <16>;
clocks = <&clks MPC512x_CLK_PSC11>,
<&clks MPC512x_CLK_PSC11_MCLK>;
clock-names = "ipg", "mclk";
};
pscfifo@11f00 {
compatible = "fsl,mpc5121-psc-fifo";
reg = <0x11f00 0x100>;
interrupts = <40 0x8>;
clocks = <&clks MPC512x_CLK_PSC_FIFO>;
clock-names = "ipg";
};
dma0: dma@14000 {
......@@ -400,6 +509,8 @@ pci: pci@80008500 {
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
clocks = <&clks MPC512x_CLK_PCI>;
clock-names = "ipg";
reg = <0x80008500 0x100 /* internal registers */
0x80008300 0x8>; /* config space access registers */
......
......@@ -12,6 +12,8 @@
* option) any later version.
*/
#include <dt-bindings/clock/mpc512x-clock.h>
/dts-v1/;
/ {
......@@ -54,6 +56,17 @@ sram@30000000 {
reg = <0x30000000 0x08000>; // 32K at 0x30000000
};
clocks {
#address-cells = <1>;
#size-cells = <0>;
osc: osc {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <33000000>;
};
};
soc@80000000 {
compatible = "fsl,mpc5121-immr";
#address-cells = <1>;
......@@ -87,9 +100,12 @@ reset@e00 { // Reset module
reg = <0xe00 0x100>;
};
clock@f00 { // Clock control
clks: clock@f00 { // Clock control
compatible = "fsl,mpc5121-clock";
reg = <0xf00 0x100>;
#clock-cells = <1>;
clocks = <&osc>;
clock-names = "osc";
};
pmc@1000{ // Power Management Controller
......@@ -114,18 +130,33 @@ can@1300 { // CAN rev.2
compatible = "fsl,mpc5121-mscan";
interrupts = <12 0x8>;
reg = <0x1300 0x80>;
clocks = <&clks MPC512x_CLK_BDLC>,
<&clks MPC512x_CLK_IPS>,
<&clks MPC512x_CLK_SYS>,
<&clks MPC512x_CLK_REF>,
<&clks MPC512x_CLK_MSCAN0_MCLK>;
clock-names = "ipg", "ips", "sys", "ref", "mclk";
};
can@1380 {
compatible = "fsl,mpc5121-mscan";
interrupts = <13 0x8>;
reg = <0x1380 0x80>;
clocks = <&clks MPC512x_CLK_BDLC>,
<&clks MPC512x_CLK_IPS>,
<&clks MPC512x_CLK_SYS>,
<&clks MPC512x_CLK_REF>,
<&clks MPC512x_CLK_MSCAN1_MCLK>;
clock-names = "ipg", "ips", "sys", "ref", "mclk";
};
sdhc@1500 {
compatible = "fsl,mpc5121-sdhc";
interrupts = <8 0x8>;
reg = <0x1500 0x100>;
clocks = <&clks MPC512x_CLK_IPS>,
<&clks MPC512x_CLK_SDHC>;
clock-names = "ipg", "per";
};
i2c@1700 {
......@@ -134,6 +165,8 @@ i2c@1700 {
compatible = "fsl,mpc5121-i2c", "fsl-i2c";
reg = <0x1700 0x20>;
interrupts = <0x9 0x8>;
clocks = <&clks MPC512x_CLK_I2C>;
clock-names = "ipg";
};
i2c@1720 {
......@@ -142,6 +175,8 @@ i2c@1720 {
compatible = "fsl,mpc5121-i2c", "fsl-i2c";
reg = <0x1720 0x20>;
interrupts = <0xa 0x8>;
clocks = <&clks MPC512x_CLK_I2C>;
clock-names = "ipg";
};
i2c@1740 {
......@@ -150,6 +185,8 @@ i2c@1740 {
compatible = "fsl,mpc5121-i2c", "fsl-i2c";
reg = <0x1740 0x20>;
interrupts = <0xb 0x8>;
clocks = <&clks MPC512x_CLK_I2C>;
clock-names = "ipg";
};
i2ccontrol@1760 {
......@@ -161,6 +198,8 @@ diu@2100 {
compatible = "fsl,mpc5121-diu";
reg = <0x2100 0x100>;
interrupts = <64 0x8>;
clocks = <&clks MPC512x_CLK_DIU>;
clock-names = "ipg";
};
mdio@2800 {
......@@ -180,6 +219,8 @@ eth0: ethernet@2800 {
interrupts = <4 0x8>;
phy-handle = < &phy0 >;
phy-connection-type = "rmii";
clocks = <&clks MPC512x_CLK_FEC>;
clock-names = "per";
};
// IO control
......@@ -200,6 +241,8 @@ usb@3000 {
interrupts = <43 0x8>;
dr_mode = "host";
phy_type = "ulpi";
clocks = <&clks MPC512x_CLK_USB1>;
clock-names = "ipg";
status = "disabled";
};
......@@ -211,6 +254,9 @@ serial@11100 {
interrupts = <40 0x8>;
fsl,rx-fifo-size = <16>;
fsl,tx-fifo-size = <16>;
clocks = <&clks MPC512x_CLK_PSC1>,
<&clks MPC512x_CLK_PSC1_MCLK>;
clock-names = "ipg", "mclk";
};
// PSC9 uart1 aka ttyPSC1
......@@ -220,12 +266,17 @@ serial@11900 {
interrupts = <40 0x8>;
fsl,rx-fifo-size = <16>;
fsl,tx-fifo-size = <16>;
clocks = <&clks MPC512x_CLK_PSC9>,
<&clks MPC512x_CLK_PSC9_MCLK>;
clock-names = "ipg", "mclk";
};
pscfifo@11f00 {
compatible = "fsl,mpc5121-psc-fifo";
reg = <0x11f00 0x100>;
interrupts = <40 0x8>;
clocks = <&clks MPC512x_CLK_PSC_FIFO>;
clock-names = "ipg";
};
dma@14000 {
......
#ifndef __ASM_POWERPC_CLK_INTERFACE_H
#define __ASM_POWERPC_CLK_INTERFACE_H
#include <linux/clk.h>
struct clk_interface {
struct clk* (*clk_get) (struct device *dev, const char *id);
int (*clk_enable) (struct clk *clk);
void (*clk_disable) (struct clk *clk);
unsigned long (*clk_get_rate) (struct clk *clk);
void (*clk_put) (struct clk *clk);
long (*clk_round_rate) (struct clk *clk, unsigned long rate);
int (*clk_set_rate) (struct clk *clk, unsigned long rate);
int (*clk_set_parent) (struct clk *clk, struct clk *parent);
struct clk* (*clk_get_parent) (struct clk *clk);
};
extern struct clk_interface clk_functions;
#endif /* __ASM_POWERPC_CLK_INTERFACE_H */
......@@ -37,7 +37,12 @@ struct mpc512x_ccm {
u32 cccr; /* CFM Clock Control Register */
u32 dccr; /* DIU Clock Control Register */
u32 mscan_ccr[4]; /* MSCAN Clock Control Registers */
u8 res[0x98]; /* Reserved */
u32 out_ccr[4]; /* OUT CLK Configure Registers */
u32 rsv0[2]; /* Reserved */
u32 scfr3; /* System Clock Frequency Register 3 */
u32 rsv1[3]; /* Reserved */
u32 spll_lock_cnt; /* System PLL Lock Counter */
u8 res[0x6c]; /* Reserved */
};
/*
......
......@@ -560,9 +560,9 @@ extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
pmd_t *pmdp);
#define pmd_move_must_withdraw pmd_move_must_withdraw
typedef struct spinlock spinlock_t;
static inline int pmd_move_must_withdraw(spinlock_t *new_pmd_ptl,
spinlock_t *old_pmd_ptl)
struct spinlock;
static inline int pmd_move_must_withdraw(struct spinlock *new_pmd_ptl,
struct spinlock *old_pmd_ptl)
{
/*
* Archs like ppc64 use pgtable to store per pmd
......
......@@ -450,13 +450,6 @@ enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_POWERSAVE_OFF};
extern int powersave_nap; /* set if nap mode can be used in idle loop */
extern void power7_nap(void);
#ifdef CONFIG_PSERIES_IDLE
extern void update_smt_snooze_delay(int cpu, int residency);
#else
static inline void update_smt_snooze_delay(int cpu, int residency) {}
#endif
extern void flush_instruction_cache(void);
extern void hard_reset_now(void);
extern void poweroff_now(void);
......
......@@ -359,3 +359,5 @@ COMPAT_SYS(process_vm_readv)
COMPAT_SYS(process_vm_writev)
SYSCALL(finit_module)
SYSCALL(ni_syscall) /* sys_kcmp */
SYSCALL_SPU(sched_setattr)
SYSCALL_SPU(sched_getattr)
......@@ -12,7 +12,7 @@
#include <uapi/asm/unistd.h>
#define __NR_syscalls 355
#define __NR_syscalls 357
#define __NR__exit __NR_exit
#define NR_syscalls __NR_syscalls
......
......@@ -377,6 +377,7 @@
#define __NR_process_vm_writev 352
#define __NR_finit_module 353
#define __NR_kcmp 354
#define __NR_sched_setattr 355
#define __NR_sched_getattr 356
#endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */
......@@ -48,7 +48,6 @@ obj-$(CONFIG_ALTIVEC) += vecemu.o
obj-$(CONFIG_PPC_970_NAP) += idle_power4.o
obj-$(CONFIG_PPC_P7_NAP) += idle_power7.o
obj-$(CONFIG_PPC_OF) += of_platform.o prom_parse.o
obj-$(CONFIG_PPC_CLOCK) += clock.o
procfs-y := proc_powerpc.o
obj-$(CONFIG_PROC_FS) += $(procfs-y)
rtaspci-$(CONFIG_PPC64)-$(CONFIG_PCI) := rtas_pci.o
......
......@@ -793,6 +793,9 @@ static void remove_cache_dir(struct cache_dir *cache_dir)
{
remove_index_dirs(cache_dir);
/* Remove cache dir from sysfs */
kobject_del(cache_dir->kobj);
kobject_put(cache_dir->kobj);
kfree(cache_dir);
......
/*
* Dummy clk implementations for powerpc.
* These need to be overridden in platform code.
*/
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/export.h>
#include <asm/clk_interface.h>
struct clk_interface clk_functions;
struct clk *clk_get(struct device *dev, const char *id)
{
if (clk_functions.clk_get)
return clk_functions.clk_get(dev, id);
return ERR_PTR(-ENOSYS);
}
EXPORT_SYMBOL(clk_get);
void clk_put(struct clk *clk)
{
if (clk_functions.clk_put)
clk_functions.clk_put(clk);
}
EXPORT_SYMBOL(clk_put);
int clk_enable(struct clk *clk)
{
if (clk_functions.clk_enable)
return clk_functions.clk_enable(clk);
return -ENOSYS;
}
EXPORT_SYMBOL(clk_enable);
void clk_disable(struct clk *clk)
{
if (clk_functions.clk_disable)
clk_functions.clk_disable(clk);
}
EXPORT_SYMBOL(clk_disable);
unsigned long clk_get_rate(struct clk *clk)
{
if (clk_functions.clk_get_rate)
return clk_functions.clk_get_rate(clk);
return 0;
}
EXPORT_SYMBOL(clk_get_rate);
long clk_round_rate(struct clk *clk, unsigned long rate)
{
if (clk_functions.clk_round_rate)
return clk_functions.clk_round_rate(clk, rate);
return -ENOSYS;
}
EXPORT_SYMBOL(clk_round_rate);
int clk_set_rate(struct clk *clk, unsigned long rate)
{
if (clk_functions.clk_set_rate)
return clk_functions.clk_set_rate(clk, rate);
return -ENOSYS;
}
EXPORT_SYMBOL(clk_set_rate);
struct clk *clk_get_parent(struct clk *clk)
{
if (clk_functions.clk_get_parent)
return clk_functions.clk_get_parent(clk);
return ERR_PTR(-ENOSYS);
}
EXPORT_SYMBOL(clk_get_parent);
int clk_set_parent(struct clk *clk, struct clk *parent)
{
if (clk_functions.clk_set_parent)
return clk_functions.clk_set_parent(clk, parent);
return -ENOSYS;
}
EXPORT_SYMBOL(clk_set_parent);
......@@ -811,7 +811,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
* schedule DABR
*/
#ifndef CONFIG_HAVE_HW_BREAKPOINT
if (unlikely(hw_brk_match(&__get_cpu_var(current_brk), &new->thread.hw_brk)))
if (unlikely(!hw_brk_match(&__get_cpu_var(current_brk), &new->thread.hw_brk)))
set_breakpoint(&new->thread.hw_brk);
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
#endif
......
......@@ -1022,29 +1022,24 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
tm_frame = &rt_sf->uc_transact.uc_mcontext;
if (MSR_TM_ACTIVE(regs->msr)) {
if (__put_user((unsigned long)&rt_sf->uc_transact,
&rt_sf->uc.uc_link) ||
__put_user((unsigned long)tm_frame,
&rt_sf->uc_transact.uc_regs))
goto badframe;
if (save_tm_user_regs(regs, frame, tm_frame, sigret))
goto badframe;
}
else
#endif
{
if (__put_user(0, &rt_sf->uc.uc_link))
goto badframe;
if (save_user_regs(regs, frame, tm_frame, sigret, 1))
goto badframe;
}
regs->link = tramp;
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
if (MSR_TM_ACTIVE(regs->msr)) {
if (__put_user((unsigned long)&rt_sf->uc_transact,
&rt_sf->uc.uc_link)
|| __put_user((unsigned long)tm_frame, &rt_sf->uc_transact.uc_regs))
goto badframe;
}
else
#endif
if (__put_user(0, &rt_sf->uc.uc_link))
goto badframe;
current->thread.fp_state.fpscr = 0; /* turn off all fp exceptions */
/* create a stack frame for the caller of the handler */
......
......@@ -51,8 +51,6 @@ static ssize_t store_smt_snooze_delay(struct device *dev,
return -EINVAL;
per_cpu(smt_snooze_delay, cpu->dev.id) = snooze;
update_smt_snooze_delay(cpu->dev.id, snooze);
return count;
}
......
......@@ -472,12 +472,13 @@ static void hugepd_free(struct mmu_gather *tlb, void *hugepte)
{
struct hugepd_freelist **batchp;
batchp = &__get_cpu_var(hugepd_freelist_cur);
batchp = &get_cpu_var(hugepd_freelist_cur);
if (atomic_read(&tlb->mm->mm_users) < 2 ||
cpumask_equal(mm_cpumask(tlb->mm),
cpumask_of(smp_processor_id()))) {
kmem_cache_free(hugepte_cache, hugepte);
put_cpu_var(hugepd_freelist_cur);
return;
}
......@@ -491,6 +492,7 @@ static void hugepd_free(struct mmu_gather *tlb, void *hugepte)
call_rcu_sched(&(*batchp)->rcu, hugepd_free_rcu_callback);
*batchp = NULL;
}
put_cpu_var(hugepd_freelist_cur);
}
#endif
......
......@@ -1785,7 +1785,7 @@ static const struct file_operations topology_ops = {
static int topology_update_init(void)
{
start_topology_update();
proc_create("powerpc/topology_updates", 644, NULL, &topology_ops);
proc_create("powerpc/topology_updates", 0644, NULL, &topology_ops);
return 0;
}
......
......@@ -408,7 +408,7 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len,
if (fixed && (addr & ((1ul << pshift) - 1)))
return -EINVAL;
if (fixed && addr > (mm->task_size - len))
return -EINVAL;
return -ENOMEM;
/* If hint, make sure it matches our alignment restrictions */
if (!fixed && addr) {
......
......@@ -240,6 +240,7 @@ itlb_miss_fault_bolted:
beq tlb_miss_common_bolted
b itlb_miss_kernel_bolted
#ifdef CONFIG_PPC_FSL_BOOK3E
/*
* TLB miss handling for e6500 and derivatives, using hardware tablewalk.
*
......@@ -409,7 +410,7 @@ itlb_miss_fault_e6500:
TLB_MISS_STATS_I(MMSTAT_TLB_MISS_NORM_FAULT)
tlb_epilog_bolted
b exc_instruction_storage_book3e
#endif /* CONFIG_PPC_FSL_BOOK3E */
/**********************************************************************
* *
......
......@@ -557,10 +557,12 @@ static void setup_mmu_htw(void)
patch_exception(0x1c0, exc_data_tlb_miss_htw_book3e);
patch_exception(0x1e0, exc_instruction_tlb_miss_htw_book3e);
break;
#ifdef CONFIG_PPC_FSL_BOOK3E
case PPC_HTW_E6500:
patch_exception(0x1c0, exc_data_tlb_miss_e6500_book3e);
patch_exception(0x1e0, exc_instruction_tlb_miss_e6500_book3e);
break;
#endif
}
pr_info("MMU: Book3E HW tablewalk %s\n",
book3e_htw_mode != PPC_HTW_NONE ? "enabled" : "not supported");
......
config PPC_MPC512x
bool "512x-based boards"
depends on 6xx
select COMMON_CLK
select FSL_SOC
select IPIC
select PPC_CLOCK
select PPC_PCI_CHOICE
select FSL_PCI if PCI
select ARCH_WANT_OPTIONAL_GPIOLIB
......
#
# Makefile for the Freescale PowerPC 512x linux kernel.
#
obj-y += clock.o mpc512x_shared.o
obj-$(CONFIG_COMMON_CLK) += clock-commonclk.o
obj-y += mpc512x_shared.o
obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o mpc5121_ads_cpld.o
obj-$(CONFIG_MPC512x_GENERIC) += mpc512x_generic.o
obj-$(CONFIG_PDM360NG) += pdm360ng.o
/*
* Copyright (C) 2013 DENX Software Engineering
*
* Gerhard Sittig, <gsi@denx.de>
*
* common clock driver support for the MPC512x platform
*
* This 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.
*/
#include <linux/bitops.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <asm/mpc5121.h>
#include <dt-bindings/clock/mpc512x-clock.h>
#include "mpc512x.h" /* our public mpc5121_clk_init() API */
/* helpers to keep the MCLK intermediates "somewhere" in our table */
enum {
MCLK_IDX_MUX0,
MCLK_IDX_EN0,
MCLK_IDX_DIV0,
MCLK_MAX_IDX,
};
#define NR_PSCS 12
#define NR_MSCANS 4
#define NR_SPDIFS 1
#define NR_OUTCLK 4
#define NR_MCLKS (NR_PSCS + NR_MSCANS + NR_SPDIFS + NR_OUTCLK)
/* extend the public set of clocks by adding internal slots for management */
enum {
/* arrange for adjacent numbers after the public set */
MPC512x_CLK_START_PRIVATE = MPC512x_CLK_LAST_PUBLIC,
/* clocks which aren't announced to the public */
MPC512x_CLK_DDR,
MPC512x_CLK_MEM,
MPC512x_CLK_IIM,
/* intermediates in div+gate combos or fractional dividers */
MPC512x_CLK_DDR_UG,
MPC512x_CLK_SDHC_x4,
MPC512x_CLK_SDHC_UG,
MPC512x_CLK_SDHC2_UG,
MPC512x_CLK_DIU_x4,
MPC512x_CLK_DIU_UG,
MPC512x_CLK_MBX_BUS_UG,
MPC512x_CLK_MBX_UG,
MPC512x_CLK_MBX_3D_UG,
MPC512x_CLK_PCI_UG,
MPC512x_CLK_NFC_UG,
MPC512x_CLK_LPC_UG,
MPC512x_CLK_SPDIF_TX_IN,
/* intermediates for the mux+gate+div+mux MCLK generation */
MPC512x_CLK_MCLKS_FIRST,
MPC512x_CLK_MCLKS_LAST = MPC512x_CLK_MCLKS_FIRST
+ NR_MCLKS * MCLK_MAX_IDX,
/* internal, symbolic spec for the number of slots */
MPC512x_CLK_LAST_PRIVATE,
};
/* data required for the OF clock provider registration */
static struct clk *clks[MPC512x_CLK_LAST_PRIVATE];
static struct clk_onecell_data clk_data;
/* CCM register access */
static struct mpc512x_ccm __iomem *clkregs;
static DEFINE_SPINLOCK(clklock);
/* SoC variants {{{ */
/*
* tell SoC variants apart as they are rather similar yet not identical,
* cache the result in an enum to not repeatedly run the expensive OF test
*
* MPC5123 is an MPC5121 without the MBX graphics accelerator
*
* MPC5125 has many more differences: no MBX, no AXE, no VIU, no SPDIF,
* no PATA, no SATA, no PCI, two FECs (of different compatibility name),
* only 10 PSCs (of different compatibility name), two SDHCs, different
* NFC IP block, output clocks, system PLL status query, different CPMF
* interpretation, no CFM, different fourth PSC/CAN mux0 input -- yet
* those differences can get folded into this clock provider support
* code and don't warrant a separate highly redundant implementation
*/
static enum soc_type {
MPC512x_SOC_MPC5121,
MPC512x_SOC_MPC5123,
MPC512x_SOC_MPC5125,
} soc;
static void mpc512x_clk_determine_soc(void)
{
if (of_machine_is_compatible("fsl,mpc5121")) {
soc = MPC512x_SOC_MPC5121;
return;
}
if (of_machine_is_compatible("fsl,mpc5123")) {
soc = MPC512x_SOC_MPC5123;
return;
}
if (of_machine_is_compatible("fsl,mpc5125")) {
soc = MPC512x_SOC_MPC5125;
return;
}
}
static bool soc_has_mbx(void)
{
if (soc == MPC512x_SOC_MPC5121)
return true;
return false;
}
static bool soc_has_axe(void)
{
if (soc == MPC512x_SOC_MPC5125)
return false;
return true;
}
static bool soc_has_viu(void)
{
if (soc == MPC512x_SOC_MPC5125)
return false;
return true;
}
static bool soc_has_spdif(void)
{
if (soc == MPC512x_SOC_MPC5125)
return false;
return true;
}
static bool soc_has_pata(void)
{
if (soc == MPC512x_SOC_MPC5125)
return false;
return true;
}
static bool soc_has_sata(void)
{
if (soc == MPC512x_SOC_MPC5125)
return false;
return true;
}
static bool soc_has_pci(void)
{
if (soc == MPC512x_SOC_MPC5125)
return false;
return true;
}
static bool soc_has_fec2(void)
{
if (soc == MPC512x_SOC_MPC5125)
return true;
return false;
}
static int soc_max_pscnum(void)
{
if (soc == MPC512x_SOC_MPC5125)
return 10;
return 12;
}
static bool soc_has_sdhc2(void)
{
if (soc == MPC512x_SOC_MPC5125)
return true;
return false;
}
static bool soc_has_nfc_5125(void)
{
if (soc == MPC512x_SOC_MPC5125)
return true;
return false;
}
static bool soc_has_outclk(void)
{
if (soc == MPC512x_SOC_MPC5125)
return true;
return false;
}
static bool soc_has_cpmf_0_bypass(void)
{
if (soc == MPC512x_SOC_MPC5125)
return true;
return false;
}
static bool soc_has_mclk_mux0_canin(void)
{
if (soc == MPC512x_SOC_MPC5125)
return true;
return false;
}
/* }}} SoC variants */
/* common clk API wrappers {{{ */
/* convenience wrappers around the common clk API */
static inline struct clk *mpc512x_clk_fixed(const char *name, int rate)
{
return clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate);
}
static inline struct clk *mpc512x_clk_factor(
const char *name, const char *parent_name,
int mul, int div)
{
int clkflags;
clkflags = CLK_SET_RATE_PARENT;
return clk_register_fixed_factor(NULL, name, parent_name, clkflags,
mul, div);
}
static inline struct clk *mpc512x_clk_divider(
const char *name, const char *parent_name, u8 clkflags,
u32 __iomem *reg, u8 pos, u8 len, int divflags)
{
return clk_register_divider(NULL, name, parent_name, clkflags,
reg, pos, len, divflags, &clklock);
}
static inline struct clk *mpc512x_clk_divtable(
const char *name, const char *parent_name,
u32 __iomem *reg, u8 pos, u8 len,
const struct clk_div_table *divtab)
{
u8 divflags;
divflags = 0;
return clk_register_divider_table(NULL, name, parent_name, 0,
reg, pos, len, divflags,
divtab, &clklock);
}
static inline struct clk *mpc512x_clk_gated(
const char *name, const char *parent_name,
u32 __iomem *reg, u8 pos)
{
int clkflags;
clkflags = CLK_SET_RATE_PARENT;
return clk_register_gate(NULL, name, parent_name, clkflags,
reg, pos, 0, &clklock);
}
static inline struct clk *mpc512x_clk_muxed(const char *name,
const char **parent_names, int parent_count,
u32 __iomem *reg, u8 pos, u8 len)
{
int clkflags;
u8 muxflags;
clkflags = CLK_SET_RATE_PARENT;
muxflags = 0;
return clk_register_mux(NULL, name,
parent_names, parent_count, clkflags,
reg, pos, len, muxflags, &clklock);
}
/* }}} common clk API wrappers */
/* helper to isolate a bit field from a register */
static inline int get_bit_field(uint32_t __iomem *reg, uint8_t pos, uint8_t len)
{
uint32_t val;
val = in_be32(reg);
val >>= pos;
val &= (1 << len) - 1;
return val;
}
/* get the SPMF and translate it into the "sys pll" multiplier */
static int get_spmf_mult(void)
{
static int spmf_to_mult[] = {
68, 1, 12, 16, 20, 24, 28, 32,
36, 40, 44, 48, 52, 56, 60, 64,
};
int spmf;
spmf = get_bit_field(&clkregs->spmr, 24, 4);
return spmf_to_mult[spmf];
}
/*
* get the SYS_DIV value and translate it into a divide factor
*
* values returned from here are a multiple of the real factor since the
* divide ratio is fractional
*/
static int get_sys_div_x2(void)
{
static int sysdiv_code_to_x2[] = {
4, 5, 6, 7, 8, 9, 10, 14,
12, 16, 18, 22, 20, 24, 26, 30,
28, 32, 34, 38, 36, 40, 42, 46,
44, 48, 50, 54, 52, 56, 58, 62,
60, 64, 66,
};
int divcode;
divcode = get_bit_field(&clkregs->scfr2, 26, 6);
return sysdiv_code_to_x2[divcode];
}
/*
* get the CPMF value and translate it into a multiplier factor
*
* values returned from here are a multiple of the real factor since the
* multiplier ratio is fractional
*/
static int get_cpmf_mult_x2(void)
{
static int cpmf_to_mult_x36[] = {
/* 0b000 is "times 36" */
72, 2, 2, 3, 4, 5, 6, 7,
};
static int cpmf_to_mult_0by[] = {
/* 0b000 is "bypass" */
2, 2, 2, 3, 4, 5, 6, 7,
};
int *cpmf_to_mult;
int cpmf;
cpmf = get_bit_field(&clkregs->spmr, 16, 4);
if (soc_has_cpmf_0_bypass())
cpmf_to_mult = cpmf_to_mult_0by;
else
cpmf_to_mult = cpmf_to_mult_x36;
return cpmf_to_mult[cpmf];
}
/*
* some of the clock dividers do scale in a linear way, yet not all of
* their bit combinations are legal; use a divider table to get a
* resulting set of applicable divider values
*/
/* applies to the IPS_DIV, and PCI_DIV values */
static struct clk_div_table divtab_2346[] = {
{ .val = 2, .div = 2, },
{ .val = 3, .div = 3, },
{ .val = 4, .div = 4, },
{ .val = 6, .div = 6, },
{ .div = 0, },
};
/* applies to the MBX_DIV, LPC_DIV, and NFC_DIV values */
static struct clk_div_table divtab_1234[] = {
{ .val = 1, .div = 1, },
{ .val = 2, .div = 2, },
{ .val = 3, .div = 3, },
{ .val = 4, .div = 4, },
{ .div = 0, },
};
static int get_freq_from_dt(char *propname)
{
struct device_node *np;
const unsigned int *prop;
int val;
val = 0;
np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr");
if (np) {
prop = of_get_property(np, propname, NULL);
if (prop)
val = *prop;
of_node_put(np);
}
return val;
}
static void mpc512x_clk_preset_data(void)
{
size_t i;
for (i = 0; i < ARRAY_SIZE(clks); i++)
clks[i] = ERR_PTR(-ENODEV);
}
/*
* - receives the "bus frequency" from the caller (that's the IPS clock
* rate, the historical source of clock information)
* - fetches the system PLL multiplier and divider values as well as the
* IPS divider value from hardware
* - determines the REF clock rate either from the XTAL/OSC spec (if
* there is a device tree node describing the oscillator) or from the
* IPS bus clock (supported for backwards compatibility, such that
* setups without XTAL/OSC specs keep working)
* - creates the "ref" clock item in the clock tree, such that
* subsequent code can create the remainder of the hierarchy (REF ->
* SYS -> CSB -> IPS) from the REF clock rate and the returned mul/div
* values
*/
static void mpc512x_clk_setup_ref_clock(struct device_node *np, int bus_freq,
int *sys_mul, int *sys_div,
int *ips_div)
{
struct clk *osc_clk;
int calc_freq;
/* fetch mul/div factors from the hardware */
*sys_mul = get_spmf_mult();
*sys_mul *= 2; /* compensate for the fractional divider */
*sys_div = get_sys_div_x2();
*ips_div = get_bit_field(&clkregs->scfr1, 23, 3);
/* lookup the oscillator clock for its rate */
osc_clk = of_clk_get_by_name(np, "osc");
/*
* either descend from OSC to REF (and in bypassing verify the
* IPS rate), or backtrack from IPS and multiplier values that
* were fetched from hardware to REF and thus to the OSC value
*
* in either case the REF clock gets created here and the
* remainder of the clock tree can get spanned from there
*/
if (!IS_ERR(osc_clk)) {
clks[MPC512x_CLK_REF] = mpc512x_clk_factor("ref", "osc", 1, 1);
calc_freq = clk_get_rate(clks[MPC512x_CLK_REF]);
calc_freq *= *sys_mul;
calc_freq /= *sys_div;
calc_freq /= 2;
calc_freq /= *ips_div;
if (bus_freq && calc_freq != bus_freq)
pr_warn("calc rate %d != OF spec %d\n",
calc_freq, bus_freq);
} else {
calc_freq = bus_freq; /* start with IPS */
calc_freq *= *ips_div; /* IPS -> CSB */
calc_freq *= 2; /* CSB -> SYS */
calc_freq *= *sys_div; /* SYS -> PLL out */
calc_freq /= *sys_mul; /* PLL out -> REF == OSC */
clks[MPC512x_CLK_REF] = mpc512x_clk_fixed("ref", calc_freq);
}
}
/* MCLK helpers {{{ */
/*
* helper code for the MCLK subtree setup
*
* the overview in section 5.2.4 of the MPC5121e Reference Manual rev4
* suggests that all instances of the "PSC clock generation" are equal,
* and that one might re-use the PSC setup for MSCAN clock generation
* (section 5.2.5) as well, at least the logic if not the data for
* description
*
* the details (starting at page 5-20) show differences in the specific
* inputs of the first mux stage ("can clk in", "spdif tx"), and the
* factual non-availability of the second mux stage (it's present yet
* only one input is valid)
*
* the MSCAN clock related registers (starting at page 5-35) all
* reference "spdif clk" at the first mux stage and don't mention any
* "can clk" at all, which somehow is unexpected
*
* TODO re-check the document, and clarify whether the RM is correct in
* the overview or in the details, and whether the difference is a
* clipboard induced error or results from chip revisions
*
* it turns out that the RM rev4 as of 2012-06 talks about "can" for the
* PSCs while RM rev3 as of 2008-10 talks about "spdif", so I guess that
* first a doc update is required which better reflects reality in the
* SoC before the implementation should follow while no questions remain
*/
/*
* note that this declaration raises a checkpatch warning, but
* it's the very data type dictated by <linux/clk-provider.h>,
* "fixing" this warning will break compilation
*/
static const char *parent_names_mux0_spdif[] = {
"sys", "ref", "psc-mclk-in", "spdif-tx",
};
static const char *parent_names_mux0_canin[] = {
"sys", "ref", "psc-mclk-in", "can-clk-in",
};
enum mclk_type {
MCLK_TYPE_PSC,
MCLK_TYPE_MSCAN,
MCLK_TYPE_SPDIF,
MCLK_TYPE_OUTCLK,
};
struct mclk_setup_data {
enum mclk_type type;
bool has_mclk1;
const char *name_mux0;
const char *name_en0;
const char *name_div0;
const char *parent_names_mux1[2];
const char *name_mclk;
};
#define MCLK_SETUP_DATA_PSC(id) { \
MCLK_TYPE_PSC, 0, \
"psc" #id "-mux0", \
"psc" #id "-en0", \
"psc" #id "_mclk_div", \
{ "psc" #id "_mclk_div", "dummy", }, \
"psc" #id "_mclk", \
}
#define MCLK_SETUP_DATA_MSCAN(id) { \
MCLK_TYPE_MSCAN, 0, \
"mscan" #id "-mux0", \
"mscan" #id "-en0", \
"mscan" #id "_mclk_div", \
{ "mscan" #id "_mclk_div", "dummy", }, \
"mscan" #id "_mclk", \
}
#define MCLK_SETUP_DATA_SPDIF { \
MCLK_TYPE_SPDIF, 1, \
"spdif-mux0", \
"spdif-en0", \
"spdif_mclk_div", \
{ "spdif_mclk_div", "spdif-rx", }, \
"spdif_mclk", \
}
#define MCLK_SETUP_DATA_OUTCLK(id) { \
MCLK_TYPE_OUTCLK, 0, \
"out" #id "-mux0", \
"out" #id "-en0", \
"out" #id "_mclk_div", \
{ "out" #id "_mclk_div", "dummy", }, \
"out" #id "_clk", \
}
static struct mclk_setup_data mclk_psc_data[] = {
MCLK_SETUP_DATA_PSC(0),
MCLK_SETUP_DATA_PSC(1),
MCLK_SETUP_DATA_PSC(2),
MCLK_SETUP_DATA_PSC(3),
MCLK_SETUP_DATA_PSC(4),
MCLK_SETUP_DATA_PSC(5),
MCLK_SETUP_DATA_PSC(6),
MCLK_SETUP_DATA_PSC(7),
MCLK_SETUP_DATA_PSC(8),
MCLK_SETUP_DATA_PSC(9),
MCLK_SETUP_DATA_PSC(10),
MCLK_SETUP_DATA_PSC(11),
};
static struct mclk_setup_data mclk_mscan_data[] = {
MCLK_SETUP_DATA_MSCAN(0),
MCLK_SETUP_DATA_MSCAN(1),
MCLK_SETUP_DATA_MSCAN(2),
MCLK_SETUP_DATA_MSCAN(3),
};
static struct mclk_setup_data mclk_spdif_data[] = {
MCLK_SETUP_DATA_SPDIF,
};
static struct mclk_setup_data mclk_outclk_data[] = {
MCLK_SETUP_DATA_OUTCLK(0),
MCLK_SETUP_DATA_OUTCLK(1),
MCLK_SETUP_DATA_OUTCLK(2),
MCLK_SETUP_DATA_OUTCLK(3),
};
/* setup the MCLK clock subtree of an individual PSC/MSCAN/SPDIF */
static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry, size_t idx)
{
size_t clks_idx_pub, clks_idx_int;
u32 __iomem *mccr_reg; /* MCLK control register (mux, en, div) */
int div;
/* derive a few parameters from the component type and index */
switch (entry->type) {
case MCLK_TYPE_PSC:
clks_idx_pub = MPC512x_CLK_PSC0_MCLK + idx;
clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+ (idx) * MCLK_MAX_IDX;
mccr_reg = &clkregs->psc_ccr[idx];
break;
case MCLK_TYPE_MSCAN:
clks_idx_pub = MPC512x_CLK_MSCAN0_MCLK + idx;
clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+ (NR_PSCS + idx) * MCLK_MAX_IDX;
mccr_reg = &clkregs->mscan_ccr[idx];
break;
case MCLK_TYPE_SPDIF:
clks_idx_pub = MPC512x_CLK_SPDIF_MCLK;
clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+ (NR_PSCS + NR_MSCANS) * MCLK_MAX_IDX;
mccr_reg = &clkregs->spccr;
break;
case MCLK_TYPE_OUTCLK:
clks_idx_pub = MPC512x_CLK_OUT0_CLK + idx;
clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+ (NR_PSCS + NR_MSCANS + NR_SPDIFS + idx)
* MCLK_MAX_IDX;
mccr_reg = &clkregs->out_ccr[idx];
break;
default:
return;
}
/*
* this was grabbed from the PPC_CLOCK implementation, which
* enforced a specific MCLK divider while the clock was gated
* during setup (that's a documented hardware requirement)
*
* the PPC_CLOCK implementation might even have violated the
* "MCLK <= IPS" constraint, the fixed divider value of 1
* results in a divider of 2 and thus MCLK = SYS/2 which equals
* CSB which is greater than IPS; the serial port setup may have
* adjusted the divider which the clock setup might have left in
* an undesirable state
*
* initial setup is:
* - MCLK 0 from SYS
* - MCLK DIV such to not exceed the IPS clock
* - MCLK 0 enabled
* - MCLK 1 from MCLK DIV
*/
div = clk_get_rate(clks[MPC512x_CLK_SYS]);
div /= clk_get_rate(clks[MPC512x_CLK_IPS]);
out_be32(mccr_reg, (0 << 16));
out_be32(mccr_reg, (0 << 16) | ((div - 1) << 17));
out_be32(mccr_reg, (1 << 16) | ((div - 1) << 17));
/*
* create the 'struct clk' items of the MCLK's clock subtree
*
* note that by design we always create all nodes and won't take
* shortcuts here, because
* - the "internal" MCLK_DIV and MCLK_OUT signal in turn are
* selectable inputs to the CFM while those who "actually use"
* the PSC/MSCAN/SPDIF (serial drivers et al) need the MCLK
* for their bitrate
* - in the absence of "aliases" for clocks we need to create
* individial 'struct clk' items for whatever might get
* referenced or looked up, even if several of those items are
* identical from the logical POV (their rate value)
* - for easier future maintenance and for better reflection of
* the SoC's documentation, it appears appropriate to generate
* clock items even for those muxers which actually are NOPs
* (those with two inputs of which one is reserved)
*/
clks[clks_idx_int + MCLK_IDX_MUX0] = mpc512x_clk_muxed(
entry->name_mux0,
soc_has_mclk_mux0_canin()
? &parent_names_mux0_canin[0]
: &parent_names_mux0_spdif[0],
ARRAY_SIZE(parent_names_mux0_spdif),
mccr_reg, 14, 2);
clks[clks_idx_int + MCLK_IDX_EN0] = mpc512x_clk_gated(
entry->name_en0, entry->name_mux0,
mccr_reg, 16);
clks[clks_idx_int + MCLK_IDX_DIV0] = mpc512x_clk_divider(
entry->name_div0,
entry->name_en0, CLK_SET_RATE_GATE,
mccr_reg, 17, 15, 0);
if (entry->has_mclk1) {
clks[clks_idx_pub] = mpc512x_clk_muxed(
entry->name_mclk,
&entry->parent_names_mux1[0],
ARRAY_SIZE(entry->parent_names_mux1),
mccr_reg, 7, 1);
} else {
clks[clks_idx_pub] = mpc512x_clk_factor(
entry->name_mclk,
entry->parent_names_mux1[0],
1, 1);
}
}
/* }}} MCLK helpers */
static void mpc512x_clk_setup_clock_tree(struct device_node *np, int busfreq)
{
int sys_mul, sys_div, ips_div;
int mul, div;
size_t mclk_idx;
int freq;
/*
* developer's notes:
* - consider whether to handle clocks which have both gates and
* dividers via intermediates or by means of composites
* - fractional dividers appear to not map well to composites
* since they can be seen as a fixed multiplier and an
* adjustable divider, while composites can only combine at
* most one of a mux, div, and gate each into one 'struct clk'
* item
* - PSC/MSCAN/SPDIF clock generation OTOH already is very
* specific and cannot get mapped to componsites (at least not
* a single one, maybe two of them, but then some of these
* intermediate clock signals get referenced elsewhere (e.g.
* in the clock frequency measurement, CFM) and thus need
* publicly available names
* - the current source layout appropriately reflects the
* hardware setup, and it works, so it's questionable whether
* further changes will result in big enough a benefit
*/
/* regardless of whether XTAL/OSC exists, have REF created */
mpc512x_clk_setup_ref_clock(np, busfreq, &sys_mul, &sys_div, &ips_div);
/* now setup the REF -> SYS -> CSB -> IPS hierarchy */
clks[MPC512x_CLK_SYS] = mpc512x_clk_factor("sys", "ref",
sys_mul, sys_div);
clks[MPC512x_CLK_CSB] = mpc512x_clk_factor("csb", "sys", 1, 2);
clks[MPC512x_CLK_IPS] = mpc512x_clk_divtable("ips", "csb",
&clkregs->scfr1, 23, 3,
divtab_2346);
/* now setup anything below SYS and CSB and IPS */
clks[MPC512x_CLK_DDR_UG] = mpc512x_clk_factor("ddr-ug", "sys", 1, 2);
/*
* the Reference Manual discusses that for SDHC only even divide
* ratios are supported because clock domain synchronization
* between 'per' and 'ipg' is broken;
* keep the divider's bit 0 cleared (per reset value), and only
* allow to setup the divider's bits 7:1, which results in that
* only even divide ratios can get configured upon rate changes;
* keep the "x4" name because this bit shift hack is an internal
* implementation detail, the "fractional divider with quarters"
* semantics remains
*/
clks[MPC512x_CLK_SDHC_x4] = mpc512x_clk_factor("sdhc-x4", "csb", 2, 1);
clks[MPC512x_CLK_SDHC_UG] = mpc512x_clk_divider("sdhc-ug", "sdhc-x4", 0,
&clkregs->scfr2, 1, 7,
CLK_DIVIDER_ONE_BASED);
if (soc_has_sdhc2()) {
clks[MPC512x_CLK_SDHC2_UG] = mpc512x_clk_divider(
"sdhc2-ug", "sdhc-x4", 0, &clkregs->scfr2,
9, 7, CLK_DIVIDER_ONE_BASED);
}
clks[MPC512x_CLK_DIU_x4] = mpc512x_clk_factor("diu-x4", "csb", 4, 1);
clks[MPC512x_CLK_DIU_UG] = mpc512x_clk_divider("diu-ug", "diu-x4", 0,
&clkregs->scfr1, 0, 8,
CLK_DIVIDER_ONE_BASED);
/*
* the "power architecture PLL" was setup from data which was
* sampled from the reset config word, at this point in time the
* configuration can be considered fixed and read only (i.e. no
* longer adjustable, or no longer in need of adjustment), which
* is why we don't register a PLL here but assume fixed factors
*/
mul = get_cpmf_mult_x2();
div = 2; /* compensate for the fractional factor */
clks[MPC512x_CLK_E300] = mpc512x_clk_factor("e300", "csb", mul, div);
if (soc_has_mbx()) {
clks[MPC512x_CLK_MBX_BUS_UG] = mpc512x_clk_factor(
"mbx-bus-ug", "csb", 1, 2);
clks[MPC512x_CLK_MBX_UG] = mpc512x_clk_divtable(
"mbx-ug", "mbx-bus-ug", &clkregs->scfr1,
14, 3, divtab_1234);
clks[MPC512x_CLK_MBX_3D_UG] = mpc512x_clk_factor(
"mbx-3d-ug", "mbx-ug", 1, 1);
}
if (soc_has_pci()) {
clks[MPC512x_CLK_PCI_UG] = mpc512x_clk_divtable(
"pci-ug", "csb", &clkregs->scfr1,
20, 3, divtab_2346);
}
if (soc_has_nfc_5125()) {
/*
* XXX TODO implement 5125 NFC clock setup logic,
* with high/low period counters in clkregs->scfr3,
* currently there are no users so it's ENOIMPL
*/
clks[MPC512x_CLK_NFC_UG] = ERR_PTR(-ENOTSUPP);
} else {
clks[MPC512x_CLK_NFC_UG] = mpc512x_clk_divtable(
"nfc-ug", "ips", &clkregs->scfr1,
8, 3, divtab_1234);
}
clks[MPC512x_CLK_LPC_UG] = mpc512x_clk_divtable("lpc-ug", "ips",
&clkregs->scfr1, 11, 3,
divtab_1234);
clks[MPC512x_CLK_LPC] = mpc512x_clk_gated("lpc", "lpc-ug",
&clkregs->sccr1, 30);
clks[MPC512x_CLK_NFC] = mpc512x_clk_gated("nfc", "nfc-ug",
&clkregs->sccr1, 29);
if (soc_has_pata()) {
clks[MPC512x_CLK_PATA] = mpc512x_clk_gated(
"pata", "ips", &clkregs->sccr1, 28);
}
/* for PSCs there is a "registers" gate and a bitrate MCLK subtree */
for (mclk_idx = 0; mclk_idx < soc_max_pscnum(); mclk_idx++) {
char name[12];
snprintf(name, sizeof(name), "psc%d", mclk_idx);
clks[MPC512x_CLK_PSC0 + mclk_idx] = mpc512x_clk_gated(
name, "ips", &clkregs->sccr1, 27 - mclk_idx);
mpc512x_clk_setup_mclk(&mclk_psc_data[mclk_idx], mclk_idx);
}
clks[MPC512x_CLK_PSC_FIFO] = mpc512x_clk_gated("psc-fifo", "ips",
&clkregs->sccr1, 15);
if (soc_has_sata()) {
clks[MPC512x_CLK_SATA] = mpc512x_clk_gated(
"sata", "ips", &clkregs->sccr1, 14);
}
clks[MPC512x_CLK_FEC] = mpc512x_clk_gated("fec", "ips",
&clkregs->sccr1, 13);
if (soc_has_pci()) {
clks[MPC512x_CLK_PCI] = mpc512x_clk_gated(
"pci", "pci-ug", &clkregs->sccr1, 11);
}
clks[MPC512x_CLK_DDR] = mpc512x_clk_gated("ddr", "ddr-ug",
&clkregs->sccr1, 10);
if (soc_has_fec2()) {
clks[MPC512x_CLK_FEC2] = mpc512x_clk_gated(
"fec2", "ips", &clkregs->sccr1, 9);
}
clks[MPC512x_CLK_DIU] = mpc512x_clk_gated("diu", "diu-ug",
&clkregs->sccr2, 31);
if (soc_has_axe()) {
clks[MPC512x_CLK_AXE] = mpc512x_clk_gated(
"axe", "csb", &clkregs->sccr2, 30);
}
clks[MPC512x_CLK_MEM] = mpc512x_clk_gated("mem", "ips",
&clkregs->sccr2, 29);
clks[MPC512x_CLK_USB1] = mpc512x_clk_gated("usb1", "csb",
&clkregs->sccr2, 28);
clks[MPC512x_CLK_USB2] = mpc512x_clk_gated("usb2", "csb",
&clkregs->sccr2, 27);
clks[MPC512x_CLK_I2C] = mpc512x_clk_gated("i2c", "ips",
&clkregs->sccr2, 26);
/* MSCAN differs from PSC with just one gate for multiple components */
clks[MPC512x_CLK_BDLC] = mpc512x_clk_gated("bdlc", "ips",
&clkregs->sccr2, 25);
for (mclk_idx = 0; mclk_idx < ARRAY_SIZE(mclk_mscan_data); mclk_idx++)
mpc512x_clk_setup_mclk(&mclk_mscan_data[mclk_idx], mclk_idx);
clks[MPC512x_CLK_SDHC] = mpc512x_clk_gated("sdhc", "sdhc-ug",
&clkregs->sccr2, 24);
/* there is only one SPDIF component, which shares MCLK support code */
if (soc_has_spdif()) {
clks[MPC512x_CLK_SPDIF] = mpc512x_clk_gated(
"spdif", "ips", &clkregs->sccr2, 23);
mpc512x_clk_setup_mclk(&mclk_spdif_data[0], 0);
}
if (soc_has_mbx()) {
clks[MPC512x_CLK_MBX_BUS] = mpc512x_clk_gated(
"mbx-bus", "mbx-bus-ug", &clkregs->sccr2, 22);
clks[MPC512x_CLK_MBX] = mpc512x_clk_gated(
"mbx", "mbx-ug", &clkregs->sccr2, 21);
clks[MPC512x_CLK_MBX_3D] = mpc512x_clk_gated(
"mbx-3d", "mbx-3d-ug", &clkregs->sccr2, 20);
}
clks[MPC512x_CLK_IIM] = mpc512x_clk_gated("iim", "csb",
&clkregs->sccr2, 19);
if (soc_has_viu()) {
clks[MPC512x_CLK_VIU] = mpc512x_clk_gated(
"viu", "csb", &clkregs->sccr2, 18);
}
if (soc_has_sdhc2()) {
clks[MPC512x_CLK_SDHC2] = mpc512x_clk_gated(
"sdhc-2", "sdhc2-ug", &clkregs->sccr2, 17);
}
if (soc_has_outclk()) {
size_t idx; /* used as mclk_idx, just to trim line length */
for (idx = 0; idx < ARRAY_SIZE(mclk_outclk_data); idx++)
mpc512x_clk_setup_mclk(&mclk_outclk_data[idx], idx);
}
/*
* externally provided clocks (when implemented in hardware,
* device tree may specify values which otherwise were unknown)
*/
freq = get_freq_from_dt("psc_mclk_in");
if (!freq)
freq = 25000000;
clks[MPC512x_CLK_PSC_MCLK_IN] = mpc512x_clk_fixed("psc_mclk_in", freq);
if (soc_has_mclk_mux0_canin()) {
freq = get_freq_from_dt("can_clk_in");
clks[MPC512x_CLK_CAN_CLK_IN] = mpc512x_clk_fixed(
"can_clk_in", freq);
} else {
freq = get_freq_from_dt("spdif_tx_in");
clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed(
"spdif_tx_in", freq);
freq = get_freq_from_dt("spdif_rx_in");
clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed(
"spdif_rx_in", freq);
}
/* fixed frequency for AC97, always 24.567MHz */
clks[MPC512x_CLK_AC97] = mpc512x_clk_fixed("ac97", 24567000);
/*
* pre-enable those "internal" clock items which never get
* claimed by any peripheral driver, to not have the clock
* subsystem disable them late at startup
*/
clk_prepare_enable(clks[MPC512x_CLK_DUMMY]);
clk_prepare_enable(clks[MPC512x_CLK_E300]); /* PowerPC CPU */
clk_prepare_enable(clks[MPC512x_CLK_DDR]); /* DRAM */
clk_prepare_enable(clks[MPC512x_CLK_MEM]); /* SRAM */
clk_prepare_enable(clks[MPC512x_CLK_IPS]); /* SoC periph */
clk_prepare_enable(clks[MPC512x_CLK_LPC]); /* boot media */
}
/*
* registers the set of public clocks (those listed in the dt-bindings/
* header file) for OF lookups, keeps the intermediates private to us
*/
static void mpc5121_clk_register_of_provider(struct device_node *np)
{
clk_data.clks = clks;
clk_data.clk_num = MPC512x_CLK_LAST_PUBLIC + 1; /* _not_ ARRAY_SIZE() */
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
}
/*
* temporary support for the period of time between introduction of CCF
* support and the adjustment of peripheral drivers to OF based lookups
*/
static void mpc5121_clk_provide_migration_support(void)
{
/*
* pre-enable those clock items which are not yet appropriately
* acquired by their peripheral driver
*
* the PCI clock cannot get acquired by its peripheral driver,
* because for this platform the driver won't probe(), instead
* initialization is done from within the .setup_arch() routine
* at a point in time where the clock provider has not been
* setup yet and thus isn't available yet
*
* so we "pre-enable" the clock here, to not have the clock
* subsystem automatically disable this item in a late init call
*
* this PCI clock pre-enable workaround only applies when there
* are device tree nodes for PCI and thus the peripheral driver
* has attached to bridges, otherwise the PCI clock remains
* unused and so it gets disabled
*/
clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
if (of_find_compatible_node(NULL, "pci", "fsl,mpc5121-pci"))
clk_prepare_enable(clks[MPC512x_CLK_PCI]);
}
/*
* those macros are not exactly pretty, but they encapsulate a lot
* of copy'n'paste heavy code which is even more ugly, and reduce
* the potential for inconsistencies in those many code copies
*/
#define FOR_NODES(compatname) \
for_each_compatible_node(np, NULL, compatname)
#define NODE_PREP do { \
of_address_to_resource(np, 0, &res); \
snprintf(devname, sizeof(devname), "%08x.%s", res.start, np->name); \
} while (0)
#define NODE_CHK(clkname, clkitem, regnode, regflag) do { \
struct clk *clk; \
clk = of_clk_get_by_name(np, clkname); \
if (IS_ERR(clk)) { \
clk = clkitem; \
clk_register_clkdev(clk, clkname, devname); \
if (regnode) \
clk_register_clkdev(clk, clkname, np->name); \
did_register |= DID_REG_ ## regflag; \
pr_debug("clock alias name '%s' for dev '%s' pointer %p\n", \
clkname, devname, clk); \
} else { \
clk_put(clk); \
} \
} while (0)
/*
* register source code provided fallback results for clock lookups,
* these get consulted when OF based clock lookup fails (that is in the
* case of not yet adjusted device tree data, where clock related specs
* are missing)
*/
static void mpc5121_clk_provide_backwards_compat(void)
{
enum did_reg_flags {
DID_REG_PSC = BIT(0),
DID_REG_PSCFIFO = BIT(1),
DID_REG_NFC = BIT(2),
DID_REG_CAN = BIT(3),
DID_REG_I2C = BIT(4),
DID_REG_DIU = BIT(5),
DID_REG_VIU = BIT(6),
DID_REG_FEC = BIT(7),
DID_REG_USB = BIT(8),
DID_REG_PATA = BIT(9),
};
int did_register;
struct device_node *np;
struct resource res;
int idx;
char devname[32];
did_register = 0;
FOR_NODES(mpc512x_select_psc_compat()) {
NODE_PREP;
idx = (res.start >> 8) & 0xf;
NODE_CHK("ipg", clks[MPC512x_CLK_PSC0 + idx], 0, PSC);
NODE_CHK("mclk", clks[MPC512x_CLK_PSC0_MCLK + idx], 0, PSC);
}
FOR_NODES("fsl,mpc5121-psc-fifo") {
NODE_PREP;
NODE_CHK("ipg", clks[MPC512x_CLK_PSC_FIFO], 1, PSCFIFO);
}
FOR_NODES("fsl,mpc5121-nfc") {
NODE_PREP;
NODE_CHK("ipg", clks[MPC512x_CLK_NFC], 0, NFC);
}
FOR_NODES("fsl,mpc5121-mscan") {
NODE_PREP;
idx = 0;
idx += (res.start & 0x2000) ? 2 : 0;
idx += (res.start & 0x0080) ? 1 : 0;
NODE_CHK("ipg", clks[MPC512x_CLK_BDLC], 0, CAN);
NODE_CHK("mclk", clks[MPC512x_CLK_MSCAN0_MCLK + idx], 0, CAN);
}
/*
* do register the 'ips', 'sys', and 'ref' names globally
* instead of inside each individual CAN node, as there is no
* potential for a name conflict (in contrast to 'ipg' and 'mclk')
*/
if (did_register & DID_REG_CAN) {
clk_register_clkdev(clks[MPC512x_CLK_IPS], "ips", NULL);
clk_register_clkdev(clks[MPC512x_CLK_SYS], "sys", NULL);
clk_register_clkdev(clks[MPC512x_CLK_REF], "ref", NULL);
}
FOR_NODES("fsl,mpc5121-i2c") {
NODE_PREP;
NODE_CHK("ipg", clks[MPC512x_CLK_I2C], 0, I2C);
}
/*
* workaround for the fact that the I2C driver does an "anonymous"
* lookup (NULL name spec, which yields the first clock spec) for
* which we cannot register an alias -- a _global_ 'ipg' alias that
* is not bound to any device name and returns the I2C clock item
* is not a good idea
*
* so we have the lookup in the peripheral driver fail, which is
* silent and non-fatal, and pre-enable the clock item here such
* that register access is possible
*
* see commit b3bfce2b "i2c: mpc: cleanup clock API use" for
* details, adjusting s/NULL/"ipg"/ in i2c-mpc.c would make this
* workaround obsolete
*/
if (did_register & DID_REG_I2C)
clk_prepare_enable(clks[MPC512x_CLK_I2C]);
FOR_NODES("fsl,mpc5121-diu") {
NODE_PREP;
NODE_CHK("ipg", clks[MPC512x_CLK_DIU], 1, DIU);
}
FOR_NODES("fsl,mpc5121-viu") {
NODE_PREP;
NODE_CHK("ipg", clks[MPC512x_CLK_VIU], 0, VIU);
}
/*
* note that 2771399a "fs_enet: cleanup clock API use" did use the
* "per" string for the clock lookup in contrast to the "ipg" name
* which most other nodes are using -- this is not a fatal thing
* but just something to keep in mind when doing compatibility
* registration, it's a non-issue with up-to-date device tree data
*/
FOR_NODES("fsl,mpc5121-fec") {
NODE_PREP;
NODE_CHK("per", clks[MPC512x_CLK_FEC], 0, FEC);
}
FOR_NODES("fsl,mpc5121-fec-mdio") {
NODE_PREP;
NODE_CHK("per", clks[MPC512x_CLK_FEC], 0, FEC);
}
/*
* MPC5125 has two FECs: FEC1 at 0x2800, FEC2 at 0x4800;
* the clock items don't "form an array" since FEC2 was
* added only later and was not allowed to shift all other
* clock item indices, so the numbers aren't adjacent
*/
FOR_NODES("fsl,mpc5125-fec") {
NODE_PREP;
if (res.start & 0x4000)
idx = MPC512x_CLK_FEC2;
else
idx = MPC512x_CLK_FEC;
NODE_CHK("per", clks[idx], 0, FEC);
}
FOR_NODES("fsl,mpc5121-usb2-dr") {
NODE_PREP;
idx = (res.start & 0x4000) ? 1 : 0;
NODE_CHK("ipg", clks[MPC512x_CLK_USB1 + idx], 0, USB);
}
FOR_NODES("fsl,mpc5121-pata") {
NODE_PREP;
NODE_CHK("ipg", clks[MPC512x_CLK_PATA], 0, PATA);
}
/*
* try to collapse diagnostics into a single line of output yet
* provide a full list of what is missing, to avoid noise in the
* absence of up-to-date device tree data -- backwards
* compatibility to old DTBs is a requirement, updates may be
* desirable or preferrable but are not at all mandatory
*/
if (did_register) {
pr_notice("device tree lacks clock specs, adding fallbacks (0x%x,%s%s%s%s%s%s%s%s%s%s)\n",
did_register,
(did_register & DID_REG_PSC) ? " PSC" : "",
(did_register & DID_REG_PSCFIFO) ? " PSCFIFO" : "",
(did_register & DID_REG_NFC) ? " NFC" : "",
(did_register & DID_REG_CAN) ? " CAN" : "",
(did_register & DID_REG_I2C) ? " I2C" : "",
(did_register & DID_REG_DIU) ? " DIU" : "",
(did_register & DID_REG_VIU) ? " VIU" : "",
(did_register & DID_REG_FEC) ? " FEC" : "",
(did_register & DID_REG_USB) ? " USB" : "",
(did_register & DID_REG_PATA) ? " PATA" : "");
} else {
pr_debug("device tree has clock specs, no fallbacks added\n");
}
}
int __init mpc5121_clk_init(void)
{
struct device_node *clk_np;
int busfreq;
/* map the clock control registers */
clk_np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
if (!clk_np)
return -ENODEV;
clkregs = of_iomap(clk_np, 0);
WARN_ON(!clkregs);
/* determine the SoC variant we run on */
mpc512x_clk_determine_soc();
/* invalidate all not yet registered clock slots */
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
*/
clks[MPC512x_CLK_DUMMY] = mpc512x_clk_fixed("dummy", 0);
/*
* have all the real nodes in the clock tree populated from REF
* down to all leaves, either starting from the OSC node or from
* a REF root that was created from the IPS bus clock input
*/
busfreq = get_freq_from_dt("bus-frequency");
mpc512x_clk_setup_clock_tree(clk_np, busfreq);
/* register as an OF clock provider */
mpc5121_clk_register_of_provider(clk_np);
/*
* unbreak not yet adjusted peripheral drivers during migration
* towards fully operational common clock support, and allow
* operation in the absence of clock related device tree specs
*/
mpc5121_clk_provide_migration_support();
mpc5121_clk_provide_backwards_compat();
return 0;
}
/*
* Copyright (C) 2007,2008 Freescale Semiconductor, Inc. All rights reserved.
*
* Author: John Rigby <jrigby@freescale.com>
*
* Implements the clk api defined in include/linux/clk.h
*
* Original based on linux/arch/arm/mach-integrator/clock.c
*
* Copyright (C) 2004 ARM Limited.
* Written by Deep Blue Solutions Limited.
*
* 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/kernel.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <asm/mpc5xxx.h>
#include <asm/mpc5121.h>
#include <asm/clk_interface.h>
#include "mpc512x.h"
#undef CLK_DEBUG
static int clocks_initialized;
#define CLK_HAS_RATE 0x1 /* has rate in MHz */
#define CLK_HAS_CTRL 0x2 /* has control reg and bit */
struct clk {
struct list_head node;
char name[32];
int flags;
struct device *dev;
unsigned long rate;
struct module *owner;
void (*calc) (struct clk *);
struct clk *parent;
int reg, bit; /* CLK_HAS_CTRL */
int div_shift; /* only used by generic_div_clk_calc */
};
static LIST_HEAD(clocks);
static DEFINE_MUTEX(clocks_mutex);
static struct clk *mpc5121_clk_get(struct device *dev, const char *id)
{
struct clk *p, *clk = ERR_PTR(-ENOENT);
int dev_match;
int id_match;
if (dev == NULL || id == NULL)
return clk;
mutex_lock(&clocks_mutex);
list_for_each_entry(p, &clocks, node) {
dev_match = id_match = 0;
if (dev == p->dev)
dev_match++;
if (strcmp(id, p->name) == 0)
id_match++;
if ((dev_match || id_match) && try_module_get(p->owner)) {
clk = p;
break;
}
}
mutex_unlock(&clocks_mutex);
return clk;
}
#ifdef CLK_DEBUG
static void dump_clocks(void)
{
struct clk *p;
mutex_lock(&clocks_mutex);
printk(KERN_INFO "CLOCKS:\n");
list_for_each_entry(p, &clocks, node) {
pr_info(" %s=%ld", p->name, p->rate);
if (p->parent)
pr_cont(" %s=%ld", p->parent->name,
p->parent->rate);
if (p->flags & CLK_HAS_CTRL)
pr_cont(" reg/bit=%d/%d", p->reg, p->bit);
pr_cont("\n");
}
mutex_unlock(&clocks_mutex);
}
#define DEBUG_CLK_DUMP() dump_clocks()
#else
#define DEBUG_CLK_DUMP()
#endif
static void mpc5121_clk_put(struct clk *clk)
{
module_put(clk->owner);
}
#define NRPSC 12
struct mpc512x_clockctl {
u32 spmr; /* System PLL Mode Reg */
u32 sccr[2]; /* System Clk Ctrl Reg 1 & 2 */
u32 scfr1; /* System Clk Freq Reg 1 */
u32 scfr2; /* System Clk Freq Reg 2 */
u32 reserved;
u32 bcr; /* Bread Crumb Reg */
u32 pccr[NRPSC]; /* PSC Clk Ctrl Reg 0-11 */
u32 spccr; /* SPDIF Clk Ctrl Reg */
u32 cccr; /* CFM Clk Ctrl Reg */
u32 dccr; /* DIU Clk Cnfg Reg */
};
static struct mpc512x_clockctl __iomem *clockctl;
static int mpc5121_clk_enable(struct clk *clk)
{
unsigned int mask;
if (clk->flags & CLK_HAS_CTRL) {
mask = in_be32(&clockctl->sccr[clk->reg]);
mask |= 1 << clk->bit;
out_be32(&clockctl->sccr[clk->reg], mask);
}
return 0;
}
static void mpc5121_clk_disable(struct clk *clk)
{
unsigned int mask;
if (clk->flags & CLK_HAS_CTRL) {
mask = in_be32(&clockctl->sccr[clk->reg]);
mask &= ~(1 << clk->bit);
out_be32(&clockctl->sccr[clk->reg], mask);
}
}
static unsigned long mpc5121_clk_get_rate(struct clk *clk)
{
if (clk->flags & CLK_HAS_RATE)
return clk->rate;
else
return 0;
}
static long mpc5121_clk_round_rate(struct clk *clk, unsigned long rate)
{
return rate;
}
static int mpc5121_clk_set_rate(struct clk *clk, unsigned long rate)
{
return 0;
}
static int clk_register(struct clk *clk)
{
mutex_lock(&clocks_mutex);
list_add(&clk->node, &clocks);
mutex_unlock(&clocks_mutex);
return 0;
}
static unsigned long spmf_mult(void)
{
/*
* Convert spmf to multiplier
*/
static int spmf_to_mult[] = {
68, 1, 12, 16,
20, 24, 28, 32,
36, 40, 44, 48,
52, 56, 60, 64
};
int spmf = (in_be32(&clockctl->spmr) >> 24) & 0xf;
return spmf_to_mult[spmf];
}
static unsigned long sysdiv_div_x_2(void)
{
/*
* Convert sysdiv to divisor x 2
* Some divisors have fractional parts so
* multiply by 2 then divide by this value
*/
static int sysdiv_to_div_x_2[] = {
4, 5, 6, 7,
8, 9, 10, 14,
12, 16, 18, 22,
20, 24, 26, 30,
28, 32, 34, 38,
36, 40, 42, 46,
44, 48, 50, 54,
52, 56, 58, 62,
60, 64, 66,
};
int sysdiv = (in_be32(&clockctl->scfr2) >> 26) & 0x3f;
return sysdiv_to_div_x_2[sysdiv];
}
static unsigned long ref_to_sys(unsigned long rate)
{
rate *= spmf_mult();
rate *= 2;
rate /= sysdiv_div_x_2();
return rate;
}
static unsigned long sys_to_ref(unsigned long rate)
{
rate *= sysdiv_div_x_2();
rate /= 2;
rate /= spmf_mult();
return rate;
}
static long ips_to_ref(unsigned long rate)
{
int ips_div = (in_be32(&clockctl->scfr1) >> 23) & 0x7;
rate *= ips_div; /* csb_clk = ips_clk * ips_div */
rate *= 2; /* sys_clk = csb_clk * 2 */
return sys_to_ref(rate);
}
static unsigned long devtree_getfreq(char *clockname)
{
struct device_node *np;
const unsigned int *prop;
unsigned int val = 0;
np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr");
if (np) {
prop = of_get_property(np, clockname, NULL);
if (prop)
val = *prop;
of_node_put(np);
}
return val;
}
static void ref_clk_calc(struct clk *clk)
{
unsigned long rate;
rate = devtree_getfreq("bus-frequency");
if (rate == 0) {
printk(KERN_ERR "No bus-frequency in dev tree\n");
clk->rate = 0;
return;
}
clk->rate = ips_to_ref(rate);
}
static struct clk ref_clk = {
.name = "ref_clk",
.calc = ref_clk_calc,
};
static void sys_clk_calc(struct clk *clk)
{
clk->rate = ref_to_sys(ref_clk.rate);
}
static struct clk sys_clk = {
.name = "sys_clk",
.calc = sys_clk_calc,
};
static void diu_clk_calc(struct clk *clk)
{
int diudiv_x_2 = in_be32(&clockctl->scfr1) & 0xff;
unsigned long rate;
rate = sys_clk.rate;
rate *= 2;
rate /= diudiv_x_2;
clk->rate = rate;
}
static void viu_clk_calc(struct clk *clk)
{
unsigned long rate;
rate = sys_clk.rate;
rate /= 2;
clk->rate = rate;
}
static void half_clk_calc(struct clk *clk)
{
clk->rate = clk->parent->rate / 2;
}
static void generic_div_clk_calc(struct clk *clk)
{
int div = (in_be32(&clockctl->scfr1) >> clk->div_shift) & 0x7;
clk->rate = clk->parent->rate / div;
}
static void unity_clk_calc(struct clk *clk)
{
clk->rate = clk->parent->rate;
}
static struct clk csb_clk = {
.name = "csb_clk",
.calc = half_clk_calc,
.parent = &sys_clk,
};
static void e300_clk_calc(struct clk *clk)
{
int spmf = (in_be32(&clockctl->spmr) >> 16) & 0xf;
int ratex2 = clk->parent->rate * spmf;
clk->rate = ratex2 / 2;
}
static struct clk e300_clk = {
.name = "e300_clk",
.calc = e300_clk_calc,
.parent = &csb_clk,
};
static struct clk ips_clk = {
.name = "ips_clk",
.calc = generic_div_clk_calc,
.parent = &csb_clk,
.div_shift = 23,
};
/*
* Clocks controlled by SCCR1 (.reg = 0)
*/
static struct clk lpc_clk = {
.name = "lpc_clk",
.flags = CLK_HAS_CTRL,
.reg = 0,
.bit = 30,
.calc = generic_div_clk_calc,
.parent = &ips_clk,
.div_shift = 11,
};
static struct clk nfc_clk = {
.name = "nfc_clk",
.flags = CLK_HAS_CTRL,
.reg = 0,
.bit = 29,
.calc = generic_div_clk_calc,
.parent = &ips_clk,
.div_shift = 8,
};
static struct clk pata_clk = {
.name = "pata_clk",
.flags = CLK_HAS_CTRL,
.reg = 0,
.bit = 28,
.calc = unity_clk_calc,
.parent = &ips_clk,
};
/*
* PSC clocks (bits 27 - 16)
* are setup elsewhere
*/
static struct clk sata_clk = {
.name = "sata_clk",
.flags = CLK_HAS_CTRL,
.reg = 0,
.bit = 14,
.calc = unity_clk_calc,
.parent = &ips_clk,
};
static struct clk fec_clk = {
.name = "fec_clk",
.flags = CLK_HAS_CTRL,
.reg = 0,
.bit = 13,
.calc = unity_clk_calc,
.parent = &ips_clk,
};
static struct clk pci_clk = {
.name = "pci_clk",
.flags = CLK_HAS_CTRL,
.reg = 0,
.bit = 11,
.calc = generic_div_clk_calc,
.parent = &csb_clk,
.div_shift = 20,
};
/*
* Clocks controlled by SCCR2 (.reg = 1)
*/
static struct clk diu_clk = {
.name = "diu_clk",
.flags = CLK_HAS_CTRL,
.reg = 1,
.bit = 31,
.calc = diu_clk_calc,
};
static struct clk viu_clk = {
.name = "viu_clk",
.flags = CLK_HAS_CTRL,
.reg = 1,
.bit = 18,
.calc = viu_clk_calc,
};
static struct clk axe_clk = {
.name = "axe_clk",
.flags = CLK_HAS_CTRL,
.reg = 1,
.bit = 30,
.calc = unity_clk_calc,
.parent = &csb_clk,
};
static struct clk usb1_clk = {
.name = "usb1_clk",
.flags = CLK_HAS_CTRL,
.reg = 1,
.bit = 28,
.calc = unity_clk_calc,
.parent = &csb_clk,
};
static struct clk usb2_clk = {
.name = "usb2_clk",
.flags = CLK_HAS_CTRL,
.reg = 1,
.bit = 27,
.calc = unity_clk_calc,
.parent = &csb_clk,
};
static struct clk i2c_clk = {
.name = "i2c_clk",
.flags = CLK_HAS_CTRL,
.reg = 1,
.bit = 26,
.calc = unity_clk_calc,
.parent = &ips_clk,
};
static struct clk mscan_clk = {
.name = "mscan_clk",
.flags = CLK_HAS_CTRL,
.reg = 1,
.bit = 25,
.calc = unity_clk_calc,
.parent = &ips_clk,
};
static struct clk sdhc_clk = {
.name = "sdhc_clk",
.flags = CLK_HAS_CTRL,
.reg = 1,
.bit = 24,
.calc = unity_clk_calc,
.parent = &ips_clk,
};
static struct clk mbx_bus_clk = {
.name = "mbx_bus_clk",
.flags = CLK_HAS_CTRL,
.reg = 1,
.bit = 22,
.calc = half_clk_calc,
.parent = &csb_clk,
};
static struct clk mbx_clk = {
.name = "mbx_clk",
.flags = CLK_HAS_CTRL,
.reg = 1,
.bit = 21,
.calc = unity_clk_calc,
.parent = &csb_clk,
};
static struct clk mbx_3d_clk = {
.name = "mbx_3d_clk",
.flags = CLK_HAS_CTRL,
.reg = 1,
.bit = 20,
.calc = generic_div_clk_calc,
.parent = &mbx_bus_clk,
.div_shift = 14,
};
static void psc_mclk_in_calc(struct clk *clk)
{
clk->rate = devtree_getfreq("psc_mclk_in");
if (!clk->rate)
clk->rate = 25000000;
}
static struct clk psc_mclk_in = {
.name = "psc_mclk_in",
.calc = psc_mclk_in_calc,
};
static struct clk spdif_txclk = {
.name = "spdif_txclk",
.flags = CLK_HAS_CTRL,
.reg = 1,
.bit = 23,
};
static struct clk spdif_rxclk = {
.name = "spdif_rxclk",
.flags = CLK_HAS_CTRL,
.reg = 1,
.bit = 23,
};
static void ac97_clk_calc(struct clk *clk)
{
/* ac97 bit clock is always 24.567 MHz */
clk->rate = 24567000;
}
static struct clk ac97_clk = {
.name = "ac97_clk_in",
.calc = ac97_clk_calc,
};
static struct clk *rate_clks[] = {
&ref_clk,
&sys_clk,
&diu_clk,
&viu_clk,
&csb_clk,
&e300_clk,
&ips_clk,
&fec_clk,
&sata_clk,
&pata_clk,
&nfc_clk,
&lpc_clk,
&mbx_bus_clk,
&mbx_clk,
&mbx_3d_clk,
&axe_clk,
&usb1_clk,
&usb2_clk,
&i2c_clk,
&mscan_clk,
&sdhc_clk,
&pci_clk,
&psc_mclk_in,
&spdif_txclk,
&spdif_rxclk,
&ac97_clk,
NULL
};
static void rate_clk_init(struct clk *clk)
{
if (clk->calc) {
clk->calc(clk);
clk->flags |= CLK_HAS_RATE;
clk_register(clk);
} else {
printk(KERN_WARNING
"Could not initialize clk %s without a calc routine\n",
clk->name);
}
}
static void rate_clks_init(void)
{
struct clk **cpp, *clk;
cpp = rate_clks;
while ((clk = *cpp++))
rate_clk_init(clk);
}
/*
* There are two clk enable registers with 32 enable bits each
* psc clocks and device clocks are all stored in dev_clks
*/
static struct clk dev_clks[2][32];
/*
* Given a psc number return the dev_clk
* associated with it
*/
static struct clk *psc_dev_clk(int pscnum)
{
int reg, bit;
struct clk *clk;
reg = 0;
bit = 27 - pscnum;
clk = &dev_clks[reg][bit];
clk->reg = 0;
clk->bit = bit;
return clk;
}
/*
* PSC clock rate calculation
*/
static void psc_calc_rate(struct clk *clk, int pscnum, struct device_node *np)
{
unsigned long mclk_src = sys_clk.rate;
unsigned long mclk_div;
/*
* Can only change value of mclk divider
* when the divider is disabled.
*
* Zero is not a valid divider so minimum
* divider is 1
*
* disable/set divider/enable
*/
out_be32(&clockctl->pccr[pscnum], 0);
out_be32(&clockctl->pccr[pscnum], 0x00020000);
out_be32(&clockctl->pccr[pscnum], 0x00030000);
if (in_be32(&clockctl->pccr[pscnum]) & 0x80) {
clk->rate = spdif_rxclk.rate;
return;
}
switch ((in_be32(&clockctl->pccr[pscnum]) >> 14) & 0x3) {
case 0:
mclk_src = sys_clk.rate;
break;
case 1:
mclk_src = ref_clk.rate;
break;
case 2:
mclk_src = psc_mclk_in.rate;
break;
case 3:
mclk_src = spdif_txclk.rate;
break;
}
mclk_div = ((in_be32(&clockctl->pccr[pscnum]) >> 17) & 0x7fff) + 1;
clk->rate = mclk_src / mclk_div;
}
/*
* Find all psc nodes in device tree and assign a clock
* with name "psc%d_mclk" and dev pointing at the device
* returned from of_find_device_by_node
*/
static void psc_clks_init(void)
{
struct device_node *np;
struct platform_device *ofdev;
u32 reg;
const char *psc_compat;
psc_compat = mpc512x_select_psc_compat();
if (!psc_compat)
return;
for_each_compatible_node(np, NULL, psc_compat) {
if (!of_property_read_u32(np, "reg", &reg)) {
int pscnum = (reg & 0xf00) >> 8;
struct clk *clk = psc_dev_clk(pscnum);
clk->flags = CLK_HAS_RATE | CLK_HAS_CTRL;
ofdev = of_find_device_by_node(np);
clk->dev = &ofdev->dev;
/*
* AC97 is special rate clock does
* not go through normal path
*/
if (of_device_is_compatible(np, "fsl,mpc5121-psc-ac97"))
clk->rate = ac97_clk.rate;
else
psc_calc_rate(clk, pscnum, np);
sprintf(clk->name, "psc%d_mclk", pscnum);
clk_register(clk);
clk_enable(clk);
}
}
}
static struct clk_interface mpc5121_clk_functions = {
.clk_get = mpc5121_clk_get,
.clk_enable = mpc5121_clk_enable,
.clk_disable = mpc5121_clk_disable,
.clk_get_rate = mpc5121_clk_get_rate,
.clk_put = mpc5121_clk_put,
.clk_round_rate = mpc5121_clk_round_rate,
.clk_set_rate = mpc5121_clk_set_rate,
.clk_set_parent = NULL,
.clk_get_parent = NULL,
};
int __init mpc5121_clk_init(void)
{
struct device_node *np;
np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
if (np) {
clockctl = of_iomap(np, 0);
of_node_put(np);
}
if (!clockctl) {
printk(KERN_ERR "Could not map clock control registers\n");
return 0;
}
rate_clks_init();
psc_clks_init();
/* leave clockctl mapped forever */
/*iounmap(clockctl); */
DEBUG_CLK_DUMP();
clocks_initialized++;
clk_functions = mpc5121_clk_functions;
return 0;
}
......@@ -12,6 +12,7 @@
* (at your option) any later version.
*/
#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/irq.h>
......@@ -68,98 +69,112 @@ struct fsl_diu_shared_fb {
bool in_use;
};
#define DIU_DIV_MASK 0x000000ff
/* receives a pixel clock spec in pico seconds, adjusts the DIU clock rate */
static void mpc512x_set_pixel_clock(unsigned int pixclock)
{
unsigned long bestval, bestfreq, speed, busfreq;
unsigned long minpixclock, maxpixclock, pixval;
struct mpc512x_ccm __iomem *ccm;
struct device_node *np;
u32 temp;
long err;
int i;
struct clk *clk_diu;
unsigned long epsilon, minpixclock, maxpixclock;
unsigned long offset, want, got, delta;
np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
/* lookup and enable the DIU clock */
np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-diu");
if (!np) {
pr_err("Can't find clock control module.\n");
pr_err("Could not find DIU device tree node.\n");
return;
}
ccm = of_iomap(np, 0);
clk_diu = of_clk_get(np, 0);
if (IS_ERR(clk_diu)) {
/* backwards compat with device trees that lack clock specs */
clk_diu = clk_get_sys(np->name, "ipg");
}
of_node_put(np);
if (!ccm) {
pr_err("Can't map clock control module reg.\n");
if (IS_ERR(clk_diu)) {
pr_err("Could not lookup DIU clock.\n");
return;
}
np = of_find_node_by_type(NULL, "cpu");
if (np) {
const unsigned int *prop =
of_get_property(np, "bus-frequency", NULL);
of_node_put(np);
if (prop) {
busfreq = *prop;
} else {
pr_err("Can't get bus-frequency property\n");
return;
}
} else {
pr_err("Can't find 'cpu' node.\n");
if (clk_prepare_enable(clk_diu)) {
pr_err("Could not enable DIU clock.\n");
return;
}
/* Pixel Clock configuration */
pr_debug("DIU: Bus Frequency = %lu\n", busfreq);
speed = busfreq * 4; /* DIU_DIV ratio is 4 * CSB_CLK / DIU_CLK */
/* Calculate the pixel clock with the smallest error */
/* calculate the following in steps to avoid overflow */
pr_debug("DIU pixclock in ps - %d\n", pixclock);
temp = (1000000000 / pixclock) * 1000;
pixclock = temp;
pr_debug("DIU pixclock freq - %u\n", pixclock);
temp = temp / 20; /* pixclock * 0.05 */
pr_debug("deviation = %d\n", temp);
minpixclock = pixclock - temp;
maxpixclock = pixclock + temp;
pr_debug("DIU minpixclock - %lu\n", minpixclock);
pr_debug("DIU maxpixclock - %lu\n", maxpixclock);
pixval = speed/pixclock;
pr_debug("DIU pixval = %lu\n", pixval);
err = LONG_MAX;
bestval = pixval;
pr_debug("DIU bestval = %lu\n", bestval);
bestfreq = 0;
for (i = -1; i <= 1; i++) {
temp = speed / (pixval+i);
pr_debug("DIU test pixval i=%d, pixval=%lu, temp freq. = %u\n",
i, pixval, temp);
if ((temp < minpixclock) || (temp > maxpixclock))
pr_debug("DIU exceeds monitor range (%lu to %lu)\n",
minpixclock, maxpixclock);
else if (abs(temp - pixclock) < err) {
pr_debug("Entered the else if block %d\n", i);
err = abs(temp - pixclock);
bestval = pixval + i;
bestfreq = temp;
}
/*
* convert the picoseconds spec into the desired clock rate,
* determine the acceptable clock range for the monitor (+/- 5%),
* do the calculation in steps to avoid integer overflow
*/
pr_debug("DIU pixclock in ps - %u\n", pixclock);
pixclock = (1000000000 / pixclock) * 1000;
pr_debug("DIU pixclock freq - %u\n", pixclock);
epsilon = pixclock / 20; /* pixclock * 0.05 */
pr_debug("DIU deviation - %lu\n", epsilon);
minpixclock = pixclock - epsilon;
maxpixclock = pixclock + epsilon;
pr_debug("DIU minpixclock - %lu\n", minpixclock);
pr_debug("DIU maxpixclock - %lu\n", maxpixclock);
/*
* check whether the DIU supports the desired pixel clock
*
* - simply request the desired clock and see what the
* platform's clock driver will make of it, assuming that it
* will setup the best approximation of the requested value
* - try other candidate frequencies in the order of decreasing
* preference (i.e. with increasing distance from the desired
* pixel clock, and checking the lower frequency before the
* higher frequency to not overload the hardware) until the
* first match is found -- any potential subsequent match
* would only be as good as the former match or typically
* would be less preferrable
*
* the offset increment of pixelclock divided by 64 is an
* arbitrary choice -- it's simple to calculate, in the typical
* case we expect the first check to succeed already, in the
* worst case seven frequencies get tested (the exact center and
* three more values each to the left and to the right) before
* the 5% tolerance window is exceeded, resulting in fast enough
* execution yet high enough probability of finding a suitable
* value, while the error rate will be in the order of single
* percents
*/
for (offset = 0; offset <= epsilon; offset += pixclock / 64) {
want = pixclock - offset;
pr_debug("DIU checking clock - %lu\n", want);
clk_set_rate(clk_diu, want);
got = clk_get_rate(clk_diu);
delta = abs(pixclock - got);
if (delta < epsilon)
break;
if (!offset)
continue;
want = pixclock + offset;
pr_debug("DIU checking clock - %lu\n", want);
clk_set_rate(clk_diu, want);
got = clk_get_rate(clk_diu);
delta = abs(pixclock - got);
if (delta < epsilon)
break;
}
if (offset <= epsilon) {
pr_debug("DIU clock accepted - %lu\n", want);
pr_debug("DIU pixclock want %u, got %lu, delta %lu, eps %lu\n",
pixclock, got, delta, epsilon);
return;
}
pr_warn("DIU pixclock auto search unsuccessful\n");
pr_debug("DIU chose = %lx\n", bestval);
pr_debug("DIU error = %ld\n NomPixClk ", err);
pr_debug("DIU: Best Freq = %lx\n", bestfreq);
/* Modify DIU_DIV in CCM SCFR1 */
temp = in_be32(&ccm->scfr1);
pr_debug("DIU: Current value of SCFR1: 0x%08x\n", temp);
temp &= ~DIU_DIV_MASK;
temp |= (bestval & DIU_DIV_MASK);
out_be32(&ccm->scfr1, temp);
pr_debug("DIU: Modified value of SCFR1: 0x%08x\n", temp);
iounmap(ccm);
/*
* what is the most appropriate action to take when the search
* for an available pixel clock which is acceptable to the
* monitor has failed? disable the DIU (clock) or just provide
* a "best effort"? we go with the latter
*/
pr_warn("DIU pixclock best effort fallback (backend's choice)\n");
clk_set_rate(clk_diu, pixclock);
got = clk_get_rate(clk_diu);
delta = abs(pixclock - got);
pr_debug("DIU pixclock want %u, got %lu, delta %lu, eps %lu\n",
pixclock, got, delta, epsilon);
}
static enum fsl_diu_monitor_port
......
config PPC_MPC52xx
bool "52xx-based boards"
depends on 6xx
select PPC_CLOCK
select COMMON_CLK
select PPC_PCI_CHOICE
config PPC_MPC5200_SIMPLE
......
......@@ -26,6 +26,7 @@
#include <linux/of_fdt.h>
#include <linux/interrupt.h>
#include <linux/bug.h>
#include <linux/cpuidle.h>
#include <asm/machdep.h>
#include <asm/firmware.h>
......@@ -216,6 +217,16 @@ static int __init pnv_probe(void)
return 1;
}
void powernv_idle(void)
{
/* Hook to cpuidle framework if available, else
* call on default platform idle code
*/
if (cpuidle_idle_call()) {
power7_idle();
}
}
define_machine(powernv) {
.name = "PowerNV",
.probe = pnv_probe,
......@@ -225,7 +236,7 @@ define_machine(powernv) {
.show_cpuinfo = pnv_show_cpuinfo,
.progress = pnv_progress,
.machine_shutdown = pnv_shutdown,
.power_save = power7_idle,
.power_save = powernv_idle,
.calibrate_decr = generic_calibrate_decr,
#ifdef CONFIG_KEXEC
.kexec_cpu_down = pnv_kexec_cpu_down,
......
......@@ -119,12 +119,3 @@ config DTL
which are accessible through a debugfs file.
Say N if you are unsure.
config PSERIES_IDLE
bool "Cpuidle driver for pSeries platforms"
depends on CPU_IDLE
depends on PPC_PSERIES
default y
help
Select this option to enable processor idle state management
through cpuidle subsystem.
......@@ -21,7 +21,6 @@ obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o
obj-$(CONFIG_CMM) += cmm.o
obj-$(CONFIG_DTL) += dtl.o
obj-$(CONFIG_IO_EVENT_IRQ) += io_event_irq.o
obj-$(CONFIG_PSERIES_IDLE) += processor_idle.o
obj-$(CONFIG_LPARCFG) += lparcfg.o
ifeq ($(CONFIG_PPC_PSERIES),y)
......
......@@ -292,6 +292,7 @@ static void iommu_table_dart_setup(void)
iommu_table_dart.it_offset = 0;
/* it_size is in number of entries */
iommu_table_dart.it_size = dart_tablesize / sizeof(u32);
iommu_table_dart.it_page_shift = IOMMU_PAGE_SHIFT_4K;
/* Initialize the common IOMMU code */
iommu_table_dart.it_base = (unsigned long)dart_vbase;
......
......@@ -35,6 +35,11 @@ depends on ARM
source "drivers/cpuidle/Kconfig.arm"
endmenu
menu "POWERPC CPU Idle Drivers"
depends on PPC
source "drivers/cpuidle/Kconfig.powerpc"
endmenu
endif
config ARCH_NEEDS_CPU_IDLE_COUPLED
......
#
# POWERPC CPU Idle Drivers
#
config PSERIES_CPUIDLE
bool "Cpuidle driver for pSeries platforms"
depends on CPU_IDLE
depends on PPC_PSERIES
default y
help
Select this option to enable processor idle state management
through cpuidle subsystem.
config POWERNV_CPUIDLE
bool "Cpuidle driver for powernv platforms"
depends on CPU_IDLE
depends on PPC_POWERNV
default y
help
Select this option to enable processor idle state management
through cpuidle subsystem.
......@@ -13,3 +13,8 @@ obj-$(CONFIG_ARM_KIRKWOOD_CPUIDLE) += cpuidle-kirkwood.o
obj-$(CONFIG_ARM_ZYNQ_CPUIDLE) += cpuidle-zynq.o
obj-$(CONFIG_ARM_U8500_CPUIDLE) += cpuidle-ux500.o
obj-$(CONFIG_ARM_AT91_CPUIDLE) += cpuidle-at91.o
###############################################################################
# POWERPC drivers
obj-$(CONFIG_PSERIES_CPUIDLE) += cpuidle-pseries.o
obj-$(CONFIG_POWERNV_CPUIDLE) += cpuidle-powernv.o
/*
* cpuidle-powernv - idle state cpuidle driver.
* Adapted from drivers/cpuidle/cpuidle-pseries
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/cpuidle.h>
#include <linux/cpu.h>
#include <linux/notifier.h>
#include <asm/machdep.h>
#include <asm/firmware.h>
struct cpuidle_driver powernv_idle_driver = {
.name = "powernv_idle",
.owner = THIS_MODULE,
};
static int max_idle_state;
static struct cpuidle_state *cpuidle_state_table;
static int snooze_loop(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
local_irq_enable();
set_thread_flag(TIF_POLLING_NRFLAG);
while (!need_resched()) {
HMT_low();
HMT_very_low();
}
HMT_medium();
clear_thread_flag(TIF_POLLING_NRFLAG);
smp_mb();
return index;
}
static int nap_loop(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
power7_idle();
return index;
}
/*
* States for dedicated partition case.
*/
static struct cpuidle_state powernv_states[] = {
{ /* Snooze */
.name = "snooze",
.desc = "snooze",
.flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 0,
.target_residency = 0,
.enter = &snooze_loop },
{ /* NAP */
.name = "NAP",
.desc = "NAP",
.flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 10,
.target_residency = 100,
.enter = &nap_loop },
};
static int powernv_cpuidle_add_cpu_notifier(struct notifier_block *n,
unsigned long action, void *hcpu)
{
int hotcpu = (unsigned long)hcpu;
struct cpuidle_device *dev =
per_cpu(cpuidle_devices, hotcpu);
if (dev && cpuidle_get_driver()) {
switch (action) {
case CPU_ONLINE:
case CPU_ONLINE_FROZEN:
cpuidle_pause_and_lock();
cpuidle_enable_device(dev);
cpuidle_resume_and_unlock();
break;
case CPU_DEAD:
case CPU_DEAD_FROZEN:
cpuidle_pause_and_lock();
cpuidle_disable_device(dev);
cpuidle_resume_and_unlock();
break;
default:
return NOTIFY_DONE;
}
}
return NOTIFY_OK;
}
static struct notifier_block setup_hotplug_notifier = {
.notifier_call = powernv_cpuidle_add_cpu_notifier,
};
/*
* powernv_cpuidle_driver_init()
*/
static int powernv_cpuidle_driver_init(void)
{
int idle_state;
struct cpuidle_driver *drv = &powernv_idle_driver;
drv->state_count = 0;
for (idle_state = 0; idle_state < max_idle_state; ++idle_state) {
/* Is the state not enabled? */
if (cpuidle_state_table[idle_state].enter == NULL)
continue;
drv->states[drv->state_count] = /* structure copy */
cpuidle_state_table[idle_state];
drv->state_count += 1;
}
return 0;
}
/*
* powernv_idle_probe()
* Choose state table for shared versus dedicated partition
*/
static int powernv_idle_probe(void)
{
if (cpuidle_disable != IDLE_NO_OVERRIDE)
return -ENODEV;
if (firmware_has_feature(FW_FEATURE_OPALv3)) {
cpuidle_state_table = powernv_states;
max_idle_state = ARRAY_SIZE(powernv_states);
} else
return -ENODEV;
return 0;
}
static int __init powernv_processor_idle_init(void)
{
int retval;
retval = powernv_idle_probe();
if (retval)
return retval;
powernv_cpuidle_driver_init();
retval = cpuidle_register(&powernv_idle_driver, NULL);
if (retval) {
printk(KERN_DEBUG "Registration of powernv driver failed.\n");
return retval;
}
register_cpu_notifier(&setup_hotplug_notifier);
printk(KERN_DEBUG "powernv_idle_driver registered\n");
return 0;
}
device_initcall(powernv_processor_idle_init);
/*
* processor_idle - idle state cpuidle driver.
* cpuidle-pseries - idle state cpuidle driver.
* Adapted from drivers/idle/intel_idle.c and
* drivers/acpi/processor_idle.c
*
......@@ -24,9 +24,7 @@ struct cpuidle_driver pseries_idle_driver = {
.owner = THIS_MODULE,
};
#define MAX_IDLE_STATE_COUNT 2
static int max_idle_state = MAX_IDLE_STATE_COUNT - 1;
static int max_idle_state;
static struct cpuidle_state *cpuidle_state_table;
static inline void idle_loop_prolog(unsigned long *in_purr)
......@@ -54,13 +52,12 @@ static int snooze_loop(struct cpuidle_device *dev,
int index)
{
unsigned long in_purr;
int cpu = dev->cpu;
idle_loop_prolog(&in_purr);
local_irq_enable();
set_thread_flag(TIF_POLLING_NRFLAG);
while ((!need_resched()) && cpu_online(cpu)) {
while (!need_resched()) {
HMT_low();
HMT_very_low();
}
......@@ -135,7 +132,7 @@ static int shared_cede_loop(struct cpuidle_device *dev,
/*
* States for dedicated partition case.
*/
static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = {
static struct cpuidle_state dedicated_states[] = {
{ /* Snooze */
.name = "snooze",
.desc = "snooze",
......@@ -155,7 +152,7 @@ static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = {
/*
* States for shared partition case.
*/
static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = {
static struct cpuidle_state shared_states[] = {
{ /* Shared Cede */
.name = "Shared Cede",
.desc = "Shared Cede",
......@@ -165,29 +162,12 @@ static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = {
.enter = &shared_cede_loop },
};
void update_smt_snooze_delay(int cpu, int residency)
{
struct cpuidle_driver *drv = cpuidle_get_driver();
struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu);
if (cpuidle_state_table != dedicated_states)
return;
if (residency < 0) {
/* Disable the Nap state on that cpu */
if (dev)
dev->states_usage[1].disable = 1;
} else
if (drv)
drv->states[1].target_residency = residency;
}
static int pseries_cpuidle_add_cpu_notifier(struct notifier_block *n,
unsigned long action, void *hcpu)
{
int hotcpu = (unsigned long)hcpu;
struct cpuidle_device *dev =
per_cpu_ptr(cpuidle_devices, hotcpu);
per_cpu(cpuidle_devices, hotcpu);
if (dev && cpuidle_get_driver()) {
switch (action) {
......@@ -226,12 +206,8 @@ static int pseries_cpuidle_driver_init(void)
drv->state_count = 0;
for (idle_state = 0; idle_state < MAX_IDLE_STATE_COUNT; ++idle_state) {
if (idle_state > max_idle_state)
break;
/* is the state not enabled? */
for (idle_state = 0; idle_state < max_idle_state; ++idle_state) {
/* Is the state not enabled? */
if (cpuidle_state_table[idle_state].enter == NULL)
continue;
......@@ -251,21 +227,19 @@ static int pseries_cpuidle_driver_init(void)
static int pseries_idle_probe(void)
{
if (!firmware_has_feature(FW_FEATURE_SPLPAR))
return -ENODEV;
if (cpuidle_disable != IDLE_NO_OVERRIDE)
return -ENODEV;
if (max_idle_state == 0) {
printk(KERN_DEBUG "pseries processor idle disabled.\n");
return -EPERM;
}
if (lppaca_shared_proc(get_lppaca()))
cpuidle_state_table = shared_states;
else
cpuidle_state_table = dedicated_states;
if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
if (lppaca_shared_proc(get_lppaca())) {
cpuidle_state_table = shared_states;
max_idle_state = ARRAY_SIZE(shared_states);
} else {
cpuidle_state_table = dedicated_states;
max_idle_state = ARRAY_SIZE(dedicated_states);
}
} else
return -ENODEV;
return 0;
}
......@@ -287,22 +261,7 @@ static int __init pseries_processor_idle_init(void)
register_cpu_notifier(&setup_hotplug_notifier);
printk(KERN_DEBUG "pseries_idle_driver registered\n");
return 0;
}
static void __exit pseries_processor_idle_exit(void)
{
unregister_cpu_notifier(&setup_hotplug_notifier);
cpuidle_unregister(&pseries_idle_driver);
return;
}
module_init(pseries_processor_idle_init);
module_exit(pseries_processor_idle_exit);
MODULE_AUTHOR("Deepthi Dharwar <deepthi@linux.vnet.ibm.com>");
MODULE_DESCRIPTION("Cpuidle driver for POWER");
MODULE_LICENSE("GPL");
device_initcall(pseries_processor_idle_init);
......@@ -1580,7 +1580,7 @@ static int viu_of_probe(struct platform_device *op)
}
/* enable VIU clock */
clk = devm_clk_get(&op->dev, "viu_clk");
clk = devm_clk_get(&op->dev, "ipg");
if (IS_ERR(clk)) {
dev_err(&op->dev, "failed to lookup the clock!\n");
ret = PTR_ERR(clk);
......
......@@ -729,7 +729,7 @@ static int mpc5121_nfc_probe(struct platform_device *op)
of_node_put(rootnode);
/* Enable NFC clock */
clk = devm_clk_get(dev, "nfc_clk");
clk = devm_clk_get(dev, "ipg");
if (IS_ERR(clk)) {
dev_err(dev, "Unable to acquire NFC clock!\n");
retval = PTR_ERR(clk);
......
......@@ -108,135 +108,170 @@ static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,
#endif /* CONFIG_PPC_MPC52xx */
#ifdef CONFIG_PPC_MPC512x
struct mpc512x_clockctl {
u32 spmr; /* System PLL Mode Reg */
u32 sccr[2]; /* System Clk Ctrl Reg 1 & 2 */
u32 scfr1; /* System Clk Freq Reg 1 */
u32 scfr2; /* System Clk Freq Reg 2 */
u32 reserved;
u32 bcr; /* Bread Crumb Reg */
u32 pccr[12]; /* PSC Clk Ctrl Reg 0-11 */
u32 spccr; /* SPDIF Clk Ctrl Reg */
u32 cccr; /* CFM Clk Ctrl Reg */
u32 dccr; /* DIU Clk Cnfg Reg */
u32 mccr[4]; /* MSCAN Clk Ctrl Reg 1-3 */
};
static struct of_device_id mpc512x_clock_ids[] = {
{ .compatible = "fsl,mpc5121-clock", },
{}
};
static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
const char *clock_name, int *mscan_clksrc)
const char *clock_source, int *mscan_clksrc)
{
struct mpc512x_clockctl __iomem *clockctl;
struct device_node *np_clock;
struct clk *sys_clk, *ref_clk;
int plen, clockidx, clocksrc = -1;
u32 sys_freq, val, clockdiv = 1, freq = 0;
const u32 *pval;
np_clock = of_find_matching_node(NULL, mpc512x_clock_ids);
if (!np_clock) {
dev_err(&ofdev->dev, "couldn't find clock node\n");
return 0;
}
clockctl = of_iomap(np_clock, 0);
if (!clockctl) {
dev_err(&ofdev->dev, "couldn't map clock registers\n");
goto exit_put;
}
struct device_node *np;
u32 clockdiv;
enum {
CLK_FROM_AUTO,
CLK_FROM_IPS,
CLK_FROM_SYS,
CLK_FROM_REF,
} clk_from;
struct clk *clk_in, *clk_can;
unsigned long freq_calc;
struct mscan_priv *priv;
struct clk *clk_ipg;
/* Determine the MSCAN device index from the peripheral's
* physical address. Register address offsets against the
* IMMR base are: 0x1300, 0x1380, 0x2300, 0x2380
/* the caller passed in the clock source spec that was read from
* the device tree, get the optional clock divider as well
*/
pval = of_get_property(ofdev->dev.of_node, "reg", &plen);
BUG_ON(!pval || plen < sizeof(*pval));
clockidx = (*pval & 0x80) ? 1 : 0;
if (*pval & 0x2000)
clockidx += 2;
np = ofdev->dev.of_node;
clockdiv = 1;
of_property_read_u32(np, "fsl,mscan-clock-divider", &clockdiv);
dev_dbg(&ofdev->dev, "device tree specs: clk src[%s] div[%d]\n",
clock_source ? clock_source : "<NULL>", clockdiv);
/* when clock-source is 'ip', the CANCTL1[CLKSRC] bit needs to
* get set, and the 'ips' clock is the input to the MSCAN
* component
*
* for clock-source values of 'ref' or 'sys' the CANCTL1[CLKSRC]
* bit needs to get cleared, an optional clock-divider may have
* been specified (the default value is 1), the appropriate
* MSCAN related MCLK is the input to the MSCAN component
*
* in the absence of a clock-source spec, first an optimal clock
* gets determined based on the 'sys' clock, if that fails the
* 'ref' clock is used
*/
clk_from = CLK_FROM_AUTO;
if (clock_source) {
/* interpret the device tree's spec for the clock source */
if (!strcmp(clock_source, "ip"))
clk_from = CLK_FROM_IPS;
else if (!strcmp(clock_source, "sys"))
clk_from = CLK_FROM_SYS;
else if (!strcmp(clock_source, "ref"))
clk_from = CLK_FROM_REF;
else
goto err_invalid;
dev_dbg(&ofdev->dev, "got a clk source spec[%d]\n", clk_from);
}
if (clk_from == CLK_FROM_AUTO) {
/* no spec so far, try the 'sys' clock; round to the
* next MHz and see if we can get a multiple of 16MHz
*/
dev_dbg(&ofdev->dev, "no clk source spec, trying SYS\n");
clk_in = devm_clk_get(&ofdev->dev, "sys");
if (IS_ERR(clk_in))
goto err_notavail;
freq_calc = clk_get_rate(clk_in);
freq_calc += 499999;
freq_calc /= 1000000;
freq_calc *= 1000000;
if ((freq_calc % 16000000) == 0) {
clk_from = CLK_FROM_SYS;
clockdiv = freq_calc / 16000000;
dev_dbg(&ofdev->dev,
"clk fit, sys[%lu] div[%d] freq[%lu]\n",
freq_calc, clockdiv, freq_calc / clockdiv);
}
}
if (clk_from == CLK_FROM_AUTO) {
/* no spec so far, use the 'ref' clock */
dev_dbg(&ofdev->dev, "no clk source spec, trying REF\n");
clk_in = devm_clk_get(&ofdev->dev, "ref");
if (IS_ERR(clk_in))
goto err_notavail;
clk_from = CLK_FROM_REF;
freq_calc = clk_get_rate(clk_in);
dev_dbg(&ofdev->dev,
"clk fit, ref[%lu] (no div) freq[%lu]\n",
freq_calc, freq_calc);
}
/*
* Clock source and divider selection: 3 different clock sources
* can be selected: "ip", "ref" or "sys". For the latter two, a
* clock divider can be defined as well. If the clock source is
* not specified by the device tree, we first try to find an
* optimal CAN source clock based on the system clock. If that
* is not posslible, the reference clock will be used.
/* select IPS or MCLK as the MSCAN input (returned to the caller),
* setup the MCLK mux source and rate if applicable, apply the
* optionally specified or derived above divider, and determine
* the actual resulting clock rate to return to the caller
*/
if (clock_name && !strcmp(clock_name, "ip")) {
switch (clk_from) {
case CLK_FROM_IPS:
clk_can = devm_clk_get(&ofdev->dev, "ips");
if (IS_ERR(clk_can))
goto err_notavail;
priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
priv->clk_can = clk_can;
freq_calc = clk_get_rate(clk_can);
*mscan_clksrc = MSCAN_CLKSRC_IPS;
freq = mpc5xxx_get_bus_frequency(ofdev->dev.of_node);
} else {
dev_dbg(&ofdev->dev, "clk from IPS, clksrc[%d] freq[%lu]\n",
*mscan_clksrc, freq_calc);
break;
case CLK_FROM_SYS:
case CLK_FROM_REF:
clk_can = devm_clk_get(&ofdev->dev, "mclk");
if (IS_ERR(clk_can))
goto err_notavail;
priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
priv->clk_can = clk_can;
if (clk_from == CLK_FROM_SYS)
clk_in = devm_clk_get(&ofdev->dev, "sys");
if (clk_from == CLK_FROM_REF)
clk_in = devm_clk_get(&ofdev->dev, "ref");
if (IS_ERR(clk_in))
goto err_notavail;
clk_set_parent(clk_can, clk_in);
freq_calc = clk_get_rate(clk_in);
freq_calc /= clockdiv;
clk_set_rate(clk_can, freq_calc);
freq_calc = clk_get_rate(clk_can);
*mscan_clksrc = MSCAN_CLKSRC_BUS;
pval = of_get_property(ofdev->dev.of_node,
"fsl,mscan-clock-divider", &plen);
if (pval && plen == sizeof(*pval))
clockdiv = *pval;
if (!clockdiv)
clockdiv = 1;
if (!clock_name || !strcmp(clock_name, "sys")) {
sys_clk = devm_clk_get(&ofdev->dev, "sys_clk");
if (IS_ERR(sys_clk)) {
dev_err(&ofdev->dev, "couldn't get sys_clk\n");
goto exit_unmap;
}
/* Get and round up/down sys clock rate */
sys_freq = 1000000 *
((clk_get_rate(sys_clk) + 499999) / 1000000);
if (!clock_name) {
/* A multiple of 16 MHz would be optimal */
if ((sys_freq % 16000000) == 0) {
clocksrc = 0;
clockdiv = sys_freq / 16000000;
freq = sys_freq / clockdiv;
}
} else {
clocksrc = 0;
freq = sys_freq / clockdiv;
}
}
if (clocksrc < 0) {
ref_clk = devm_clk_get(&ofdev->dev, "ref_clk");
if (IS_ERR(ref_clk)) {
dev_err(&ofdev->dev, "couldn't get ref_clk\n");
goto exit_unmap;
}
clocksrc = 1;
freq = clk_get_rate(ref_clk) / clockdiv;
}
dev_dbg(&ofdev->dev, "clk from MCLK, clksrc[%d] freq[%lu]\n",
*mscan_clksrc, freq_calc);
break;
default:
goto err_invalid;
}
/* Disable clock */
out_be32(&clockctl->mccr[clockidx], 0x0);
if (clocksrc >= 0) {
/* Set source and divider */
val = (clocksrc << 14) | ((clockdiv - 1) << 17);
out_be32(&clockctl->mccr[clockidx], val);
/* Enable clock */
out_be32(&clockctl->mccr[clockidx], val | 0x10000);
}
/* the above clk_can item is used for the bitrate, access to
* the peripheral's register set needs the clk_ipg item
*/
clk_ipg = devm_clk_get(&ofdev->dev, "ipg");
if (IS_ERR(clk_ipg))
goto err_notavail_ipg;
if (clk_prepare_enable(clk_ipg))
goto err_notavail_ipg;
priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
priv->clk_ipg = clk_ipg;
/* return the determined clock source rate */
return freq_calc;
err_invalid:
dev_err(&ofdev->dev, "invalid clock source specification\n");
/* clock source rate could not get determined */
return 0;
/* Enable MSCAN clock domain */
val = in_be32(&clockctl->sccr[1]);
if (!(val & (1 << 25)))
out_be32(&clockctl->sccr[1], val | (1 << 25));
err_notavail:
dev_err(&ofdev->dev, "cannot acquire or setup bitrate clock source\n");
/* clock source rate could not get determined */
return 0;
dev_dbg(&ofdev->dev, "using '%s' with frequency divider %d\n",
*mscan_clksrc == MSCAN_CLKSRC_IPS ? "ips_clk" :
clocksrc == 1 ? "ref_clk" : "sys_clk", clockdiv);
err_notavail_ipg:
dev_err(&ofdev->dev, "cannot acquire or setup register clock\n");
/* clock source rate could not get determined */
return 0;
}
exit_unmap:
iounmap(clockctl);
exit_put:
of_node_put(np_clock);
return freq;
static void mpc512x_can_put_clock(struct platform_device *ofdev)
{
struct mscan_priv *priv;
priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
if (priv->clk_ipg)
clk_disable_unprepare(priv->clk_ipg);
}
#else /* !CONFIG_PPC_MPC512x */
static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
......@@ -244,6 +279,7 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
{
return 0;
}
#define mpc512x_can_put_clock NULL
#endif /* CONFIG_PPC_MPC512x */
static const struct of_device_id mpc5xxx_can_table[];
......@@ -385,11 +421,13 @@ static int mpc5xxx_can_resume(struct platform_device *ofdev)
static const struct mpc5xxx_can_data mpc5200_can_data = {
.type = MSCAN_TYPE_MPC5200,
.get_clock = mpc52xx_can_get_clock,
/* .put_clock not applicable */
};
static const struct mpc5xxx_can_data mpc5121_can_data = {
.type = MSCAN_TYPE_MPC5121,
.get_clock = mpc512x_can_get_clock,
.put_clock = mpc512x_can_put_clock,
};
static const struct of_device_id mpc5xxx_can_table[] = {
......
......@@ -40,6 +40,7 @@ struct mpc512x_psc_spi {
unsigned int irq;
u8 bits_per_word;
struct clk *clk_mclk;
struct clk *clk_ipg;
u32 mclk_rate;
struct completion txisrdone;
......@@ -475,8 +476,6 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
struct spi_master *master;
int ret;
void *tempp;
int psc_num;
char clk_name[16];
struct clk *clk;
master = spi_alloc_master(dev, sizeof *mps);
......@@ -519,9 +518,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
goto free_master;
init_completion(&mps->txisrdone);
psc_num = master->bus_num;
snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
clk = devm_clk_get(dev, clk_name);
clk = devm_clk_get(dev, "mclk");
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
goto free_master;
......@@ -532,17 +529,29 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
mps->clk_mclk = clk;
mps->mclk_rate = clk_get_rate(clk);
clk = devm_clk_get(dev, "ipg");
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
goto free_mclk_clock;
}
ret = clk_prepare_enable(clk);
if (ret)
goto free_mclk_clock;
mps->clk_ipg = clk;
ret = mpc512x_psc_spi_port_config(master, mps);
if (ret < 0)
goto free_clock;
goto free_ipg_clock;
ret = devm_spi_register_master(dev, master);
if (ret < 0)
goto free_clock;
goto free_ipg_clock;
return ret;
free_clock:
free_ipg_clock:
clk_disable_unprepare(mps->clk_ipg);
free_mclk_clock:
clk_disable_unprepare(mps->clk_mclk);
free_master:
spi_master_put(master);
......@@ -556,6 +565,7 @@ static int mpc512x_psc_spi_do_remove(struct device *dev)
struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
clk_disable_unprepare(mps->clk_mclk);
clk_disable_unprepare(mps->clk_ipg);
return 0;
}
......
......@@ -421,6 +421,7 @@ struct psc_fifoc {
static struct psc_fifoc __iomem *psc_fifoc;
static unsigned int psc_fifoc_irq;
static struct clk *psc_fifoc_clk;
static void mpc512x_psc_fifo_init(struct uart_port *port)
{
......@@ -568,36 +569,73 @@ static unsigned int mpc512x_psc_set_baudrate(struct uart_port *port,
/* Init PSC FIFO Controller */
static int __init mpc512x_psc_fifoc_init(void)
{
int err;
struct device_node *np;
struct clk *clk;
/* default error code, potentially overwritten by clock calls */
err = -ENODEV;
np = of_find_compatible_node(NULL, NULL,
"fsl,mpc5121-psc-fifo");
if (!np) {
pr_err("%s: Can't find FIFOC node\n", __func__);
return -ENODEV;
goto out_err;
}
clk = of_clk_get(np, 0);
if (IS_ERR(clk)) {
/* backwards compat with device trees that lack clock specs */
clk = clk_get_sys(np->name, "ipg");
}
if (IS_ERR(clk)) {
pr_err("%s: Can't lookup FIFO clock\n", __func__);
err = PTR_ERR(clk);
goto out_ofnode_put;
}
if (clk_prepare_enable(clk)) {
pr_err("%s: Can't enable FIFO clock\n", __func__);
clk_put(clk);
goto out_ofnode_put;
}
psc_fifoc_clk = clk;
psc_fifoc = of_iomap(np, 0);
if (!psc_fifoc) {
pr_err("%s: Can't map FIFOC\n", __func__);
of_node_put(np);
return -ENODEV;
goto out_clk_disable;
}
psc_fifoc_irq = irq_of_parse_and_map(np, 0);
of_node_put(np);
if (psc_fifoc_irq == 0) {
pr_err("%s: Can't get FIFOC irq\n", __func__);
iounmap(psc_fifoc);
return -ENODEV;
goto out_unmap;
}
of_node_put(np);
return 0;
out_unmap:
iounmap(psc_fifoc);
out_clk_disable:
clk_disable_unprepare(psc_fifoc_clk);
clk_put(psc_fifoc_clk);
out_ofnode_put:
of_node_put(np);
out_err:
return err;
}
static void __exit mpc512x_psc_fifoc_uninit(void)
{
iounmap(psc_fifoc);
/* disable the clock, errors are not fatal */
if (psc_fifoc_clk) {
clk_disable_unprepare(psc_fifoc_clk);
clk_put(psc_fifoc_clk);
psc_fifoc_clk = NULL;
}
}
/* 512x specific interrupt handler. The caller holds the port lock */
......@@ -619,29 +657,55 @@ static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port)
}
static struct clk *psc_mclk_clk[MPC52xx_PSC_MAXNUM];
static struct clk *psc_ipg_clk[MPC52xx_PSC_MAXNUM];
/* called from within the .request_port() callback (allocation) */
static int mpc512x_psc_alloc_clock(struct uart_port *port)
{
int psc_num;
char clk_name[16];
struct clk *clk;
int err;
psc_num = (port->mapbase & 0xf00) >> 8;
snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
clk = devm_clk_get(port->dev, clk_name);
clk = devm_clk_get(port->dev, "mclk");
if (IS_ERR(clk)) {
dev_err(port->dev, "Failed to get MCLK!\n");
return PTR_ERR(clk);
err = PTR_ERR(clk);
goto out_err;
}
err = clk_prepare_enable(clk);
if (err) {
dev_err(port->dev, "Failed to enable MCLK!\n");
return err;
goto out_err;
}
psc_mclk_clk[psc_num] = clk;
clk = devm_clk_get(port->dev, "ipg");
if (IS_ERR(clk)) {
dev_err(port->dev, "Failed to get IPG clock!\n");
err = PTR_ERR(clk);
goto out_err;
}
err = clk_prepare_enable(clk);
if (err) {
dev_err(port->dev, "Failed to enable IPG clock!\n");
goto out_err;
}
psc_ipg_clk[psc_num] = clk;
return 0;
out_err:
if (psc_mclk_clk[psc_num]) {
clk_disable_unprepare(psc_mclk_clk[psc_num]);
psc_mclk_clk[psc_num] = NULL;
}
if (psc_ipg_clk[psc_num]) {
clk_disable_unprepare(psc_ipg_clk[psc_num]);
psc_ipg_clk[psc_num] = NULL;
}
return err;
}
/* called from within the .release_port() callback (release) */
......@@ -656,6 +720,10 @@ static void mpc512x_psc_relse_clock(struct uart_port *port)
clk_disable_unprepare(clk);
psc_mclk_clk[psc_num] = NULL;
}
if (psc_ipg_clk[psc_num]) {
clk_disable_unprepare(psc_ipg_clk[psc_num]);
psc_ipg_clk[psc_num] = NULL;
}
}
/* implementation of the .clock() callback (enable/disable) */
......
......@@ -261,19 +261,8 @@ int fsl_usb2_mpc5121_init(struct platform_device *pdev)
struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct clk *clk;
int err;
char clk_name[10];
int base, clk_num;
base = pdev->resource->start & 0xf000;
if (base == 0x3000)
clk_num = 1;
else if (base == 0x4000)
clk_num = 2;
else
return -ENODEV;
snprintf(clk_name, sizeof(clk_name), "usb%d_clk", clk_num);
clk = devm_clk_get(pdev->dev.parent, clk_name);
clk = devm_clk_get(pdev->dev.parent, "ipg");
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "failed to get clk\n");
return PTR_ERR(clk);
......
/*
* This header provides constants for MPC512x clock specs in DT bindings.
*/
#ifndef _DT_BINDINGS_CLOCK_MPC512x_CLOCK_H
#define _DT_BINDINGS_CLOCK_MPC512x_CLOCK_H
#define MPC512x_CLK_DUMMY 0
#define MPC512x_CLK_REF 1
#define MPC512x_CLK_SYS 2
#define MPC512x_CLK_DIU 3
#define MPC512x_CLK_VIU 4
#define MPC512x_CLK_CSB 5
#define MPC512x_CLK_E300 6
#define MPC512x_CLK_IPS 7
#define MPC512x_CLK_FEC 8
#define MPC512x_CLK_SATA 9
#define MPC512x_CLK_PATA 10
#define MPC512x_CLK_NFC 11
#define MPC512x_CLK_LPC 12
#define MPC512x_CLK_MBX_BUS 13
#define MPC512x_CLK_MBX 14
#define MPC512x_CLK_MBX_3D 15
#define MPC512x_CLK_AXE 16
#define MPC512x_CLK_USB1 17
#define MPC512x_CLK_USB2 18
#define MPC512x_CLK_I2C 19
#define MPC512x_CLK_MSCAN0_MCLK 20
#define MPC512x_CLK_MSCAN1_MCLK 21
#define MPC512x_CLK_MSCAN2_MCLK 22
#define MPC512x_CLK_MSCAN3_MCLK 23
#define MPC512x_CLK_BDLC 24
#define MPC512x_CLK_SDHC 25
#define MPC512x_CLK_PCI 26
#define MPC512x_CLK_PSC_MCLK_IN 27
#define MPC512x_CLK_SPDIF_TX 28
#define MPC512x_CLK_SPDIF_RX 29
#define MPC512x_CLK_SPDIF_MCLK 30
#define MPC512x_CLK_SPDIF 31
#define MPC512x_CLK_AC97 32
#define MPC512x_CLK_PSC0_MCLK 33
#define MPC512x_CLK_PSC1_MCLK 34
#define MPC512x_CLK_PSC2_MCLK 35
#define MPC512x_CLK_PSC3_MCLK 36
#define MPC512x_CLK_PSC4_MCLK 37
#define MPC512x_CLK_PSC5_MCLK 38
#define MPC512x_CLK_PSC6_MCLK 39
#define MPC512x_CLK_PSC7_MCLK 40
#define MPC512x_CLK_PSC8_MCLK 41
#define MPC512x_CLK_PSC9_MCLK 42
#define MPC512x_CLK_PSC10_MCLK 43
#define MPC512x_CLK_PSC11_MCLK 44
#define MPC512x_CLK_PSC_FIFO 45
#define MPC512x_CLK_PSC0 46
#define MPC512x_CLK_PSC1 47
#define MPC512x_CLK_PSC2 48
#define MPC512x_CLK_PSC3 49
#define MPC512x_CLK_PSC4 50
#define MPC512x_CLK_PSC5 51
#define MPC512x_CLK_PSC6 52
#define MPC512x_CLK_PSC7 53
#define MPC512x_CLK_PSC8 54
#define MPC512x_CLK_PSC9 55
#define MPC512x_CLK_PSC10 56
#define MPC512x_CLK_PSC11 57
#define MPC512x_CLK_SDHC2 58
#define MPC512x_CLK_FEC2 59
#define MPC512x_CLK_OUT0_CLK 60
#define MPC512x_CLK_OUT1_CLK 61
#define MPC512x_CLK_OUT2_CLK 62
#define MPC512x_CLK_OUT3_CLK 63
#define MPC512x_CLK_CAN_CLK_IN 64
#define MPC512x_CLK_LAST_PUBLIC 64
#endif
......@@ -544,6 +544,20 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
* for improved portability across platforms
*/
#if IS_ENABLED(CONFIG_PPC)
static inline u32 clk_readl(u32 __iomem *reg)
{
return ioread32be(reg);
}
static inline void clk_writel(u32 val, u32 __iomem *reg)
{
iowrite32be(val, reg);
}
#else /* platform dependent I/O accessors */
static inline u32 clk_readl(u32 __iomem *reg)
{
return readl(reg);
......@@ -554,5 +568,7 @@ static inline void clk_writel(u32 val, u32 __iomem *reg)
writel(val, reg);
}
#endif /* platform dependent I/O accessors */
#endif /* CONFIG_COMMON_CLK */
#endif /* CLK_PROVIDER_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment