提交 d71fc239 编写于 作者: L Linus Torvalds

Merge tag 'armsoc-late' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc

Pull late ARM SoC updates from Kevin Hilman:
 "This is a collection of a few late fixes and other misc stuff that had
  dependencies on things being merged from other trees.

  The bulk of the changes are for samsung/exynos SoCs for some changes
  that needed a few minor reworks so ended up a bit late.  The others
  are mainly for qcom SoCs: a couple fixes and some DTS updates"

* tag 'armsoc-late' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (37 commits)
  ARM: multi_v7_defconfig: Enable PBIAS regulator
  soc: qcom: smd: Correct fBLOCKREADINTR handling
  soc: qcom: smd: Use correct remote processor ID
  soc: qcom: smem: Fix errant private access
  ARM: dts: qcom: msm8974-sony-xperia-honami: Use stdout-path
  ARM: dts: qcom: msm8960-cdp: Use stdout-path
  ARM: dts: qcom: msm8660-surf: Use stdout-path
  ARM: dts: qcom: ipq8064-ap148: Use stdout-path
  ARM: dts: qcom: apq8084-mtp: Use stdout-path
  ARM: dts: qcom: apq8084-ifc6540: Use stdout-path
  ARM: dts: qcom: apq8074-dragonboard: Use stdout-path
  ARM: dts: qcom: apq8064-ifc6410: Use stdout-path
  ARM: dts: qcom: apq8064-cm-qs600: Use stdout-path
  ARM: dts: qcom: Label serial nodes for aliasing and stdout-path
  reset: ath79: Fix missing spin_lock_init
  reset: Add (devm_)reset_control_get stub functions
  ARM: EXYNOS: switch to using generic cpufreq driver for exynos4x12
  cpufreq: exynos: Remove unselectable rule for arm-exynos-cpufreq.o
  ARM: dts: add iommu property to JPEG device for exynos4
  ARM: dts: enable SPI1 for exynos4412-odroidu3
  ...
......@@ -37,6 +37,12 @@ The edge is described by the following properties:
Definition: the identifier of the remote processor in the smd channel
allocation table
- qcom,remote-pid:
Usage: optional
Value type: <u32>
Definition: the identifier for the remote processor as known by the rest
of the system.
= SMD DEVICES
In turn, subnodes of the "edges" represent devices tied to SMD channels on that
......
......@@ -116,6 +116,21 @@
min-microvolt = <1100000>;
max-microvolt = <2700000>;
};
thermal-zones {
cpu_thermal: cpu-thermal {
cooling-maps {
map0 {
/* Correspond to 500MHz at freq_table */
cooling-device = <&cpu0 5 5>;
};
map1 {
/* Correspond to 200MHz at freq_table */
cooling-device = <&cpu0 8 8>;
};
};
};
};
};
&adc {
......@@ -141,6 +156,10 @@
};
};
&cpu0 {
cpu0-supply = <&buck2_reg>;
};
&exynos_usbphy {
status = "okay";
};
......
......@@ -107,6 +107,21 @@
min-microvolt = <1100000>;
max-microvolt = <2700000>;
};
thermal-zones {
cpu_thermal: cpu-thermal {
cooling-maps {
map0 {
/* Corresponds to 500MHz */
cooling-device = <&cpu0 5 5>;
};
map1 {
/* Corresponds to 200MHz */
cooling-device = <&cpu0 8 8>;
};
};
};
};
};
&adc {
......@@ -132,6 +147,10 @@
};
};
&cpu0 {
cpu0-supply = <&buck2_reg>;
};
&exynos_usbphy {
status = "okay";
};
......
......@@ -53,6 +53,22 @@
compatible = "arm,cortex-a7";
reg = <0>;
clock-frequency = <1000000000>;
clocks = <&cmu CLK_ARM_CLK>;
clock-names = "cpu";
#cooling-cells = <2>;
operating-points = <
1000000 1150000
900000 1112500
800000 1075000
700000 1037500
600000 1000000
500000 962500
400000 925000
300000 887500
200000 850000
100000 850000
>;
};
cpu1: cpu@1 {
......
......@@ -702,6 +702,7 @@
clocks = <&clock CLK_JPEG>;
clock-names = "jpeg";
power-domains = <&pd_cam>;
iommus = <&sysmmu_jpeg>;
};
hdmi: hdmi@12D00000 {
......
......@@ -30,6 +30,9 @@
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0xA00>;
clocks = <&clock CLK_ARM_CLK>;
clock-names = "cpu";
operating-points-v2 = <&cpu0_opp_table>;
cooling-min-level = <13>;
cooling-max-level = <7>;
#cooling-cells = <2>; /* min followed by max */
......@@ -39,6 +42,84 @@
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0xA01>;
operating-points-v2 = <&cpu0_opp_table>;
};
};
cpu0_opp_table: opp_table0 {
compatible = "operating-points-v2";
opp-shared;
opp00 {
opp-hz = /bits/ 64 <200000000>;
opp-microvolt = <900000>;
clock-latency-ns = <200000>;
};
opp01 {
opp-hz = /bits/ 64 <300000000>;
opp-microvolt = <900000>;
clock-latency-ns = <200000>;
};
opp02 {
opp-hz = /bits/ 64 <400000000>;
opp-microvolt = <925000>;
clock-latency-ns = <200000>;
};
opp03 {
opp-hz = /bits/ 64 <500000000>;
opp-microvolt = <950000>;
clock-latency-ns = <200000>;
};
opp04 {
opp-hz = /bits/ 64 <600000000>;
opp-microvolt = <975000>;
clock-latency-ns = <200000>;
};
opp05 {
opp-hz = /bits/ 64 <700000000>;
opp-microvolt = <987500>;
clock-latency-ns = <200000>;
};
opp06 {
opp-hz = /bits/ 64 <800000000>;
opp-microvolt = <1000000>;
clock-latency-ns = <200000>;
};
opp07 {
opp-hz = /bits/ 64 <900000000>;
opp-microvolt = <1037500>;
clock-latency-ns = <200000>;
};
opp08 {
opp-hz = /bits/ 64 <1000000000>;
opp-microvolt = <1087500>;
clock-latency-ns = <200000>;
};
opp09 {
opp-hz = /bits/ 64 <1100000000>;
opp-microvolt = <1137500>;
clock-latency-ns = <200000>;
};
opp10 {
opp-hz = /bits/ 64 <1200000000>;
opp-microvolt = <1187500>;
clock-latency-ns = <200000>;
};
opp11 {
opp-hz = /bits/ 64 <1300000000>;
opp-microvolt = <1250000>;
clock-latency-ns = <200000>;
};
opp12 {
opp-hz = /bits/ 64 <1400000000>;
opp-microvolt = <1287500>;
clock-latency-ns = <200000>;
};
opp13 {
opp-hz = /bits/ 64 <1500000000>;
opp-microvolt = <1350000>;
clock-latency-ns = <200000>;
turbo-mode;
};
};
};
......
......@@ -107,6 +107,10 @@
};
};
&cpu0 {
cpu0-supply = <&buck2_reg>;
};
/* RSTN signal for eMMC */
&sd1_cd {
samsung,pin-pud = <0>;
......
......@@ -13,6 +13,7 @@
/dts-v1/;
#include "exynos4412-odroid-common.dtsi"
#include <dt-bindings/gpio/gpio.h>
/ {
model = "Hardkernel ODROID-U3 board based on Exynos4412";
......@@ -61,3 +62,10 @@
"Speakers", "SPKL",
"Speakers", "SPKR";
};
&spi_1 {
pinctrl-names = "default";
pinctrl-0 = <&spi1_bus>;
cs-gpios = <&gpb 5 GPIO_ACTIVE_HIGH>;
status = "okay";
};
......@@ -78,6 +78,10 @@
};
};
&cpu0 {
cpu0-supply = <&buck2_reg>;
};
&fimd {
pinctrl-0 = <&lcd_clk &lcd_data24 &pwm1_out>;
pinctrl-names = "default";
......
......@@ -288,6 +288,10 @@
status = "okay";
};
&cpu0 {
cpu0-supply = <&buck2_reg>;
};
&csis_0 {
status = "okay";
vddcore-supply = <&ldo8_reg>;
......
......@@ -30,6 +30,9 @@
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0xA00>;
clocks = <&clock CLK_ARM_CLK>;
clock-names = "cpu";
operating-points-v2 = <&cpu0_opp_table>;
cooling-min-level = <13>;
cooling-max-level = <7>;
#cooling-cells = <2>; /* min followed by max */
......@@ -39,18 +42,98 @@
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0xA01>;
operating-points-v2 = <&cpu0_opp_table>;
};
cpu@A02 {
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0xA02>;
operating-points-v2 = <&cpu0_opp_table>;
};
cpu@A03 {
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0xA03>;
operating-points-v2 = <&cpu0_opp_table>;
};
};
cpu0_opp_table: opp_table0 {
compatible = "operating-points-v2";
opp-shared;
opp00 {
opp-hz = /bits/ 64 <200000000>;
opp-microvolt = <900000>;
clock-latency-ns = <200000>;
};
opp01 {
opp-hz = /bits/ 64 <300000000>;
opp-microvolt = <900000>;
clock-latency-ns = <200000>;
};
opp02 {
opp-hz = /bits/ 64 <400000000>;
opp-microvolt = <925000>;
clock-latency-ns = <200000>;
};
opp03 {
opp-hz = /bits/ 64 <500000000>;
opp-microvolt = <950000>;
clock-latency-ns = <200000>;
};
opp04 {
opp-hz = /bits/ 64 <600000000>;
opp-microvolt = <975000>;
clock-latency-ns = <200000>;
};
opp05 {
opp-hz = /bits/ 64 <700000000>;
opp-microvolt = <987500>;
clock-latency-ns = <200000>;
};
opp06 {
opp-hz = /bits/ 64 <800000000>;
opp-microvolt = <1000000>;
clock-latency-ns = <200000>;
};
opp07 {
opp-hz = /bits/ 64 <900000000>;
opp-microvolt = <1037500>;
clock-latency-ns = <200000>;
};
opp08 {
opp-hz = /bits/ 64 <1000000000>;
opp-microvolt = <1087500>;
clock-latency-ns = <200000>;
};
opp09 {
opp-hz = /bits/ 64 <1100000000>;
opp-microvolt = <1137500>;
clock-latency-ns = <200000>;
};
opp10 {
opp-hz = /bits/ 64 <1200000000>;
opp-microvolt = <1187500>;
clock-latency-ns = <200000>;
};
opp11 {
opp-hz = /bits/ 64 <1300000000>;
opp-microvolt = <1250000>;
clock-latency-ns = <200000>;
};
opp12 {
opp-hz = /bits/ 64 <1400000000>;
opp-microvolt = <1287500>;
clock-latency-ns = <200000>;
};
opp13 {
opp-hz = /bits/ 64 <1500000000>;
opp-microvolt = <1350000>;
clock-latency-ns = <200000>;
turbo-mode;
};
};
......
......@@ -117,6 +117,10 @@
};
};
&cpu0 {
cpu0-supply = <&buck2_reg>;
};
&dp {
status = "okay";
samsung,color-space = <0>;
......
......@@ -74,6 +74,10 @@
};
};
&cpu0 {
cpu0-supply = <&buck2_reg>;
};
&dp {
samsung,color-space = <0>;
samsung,dynamic-range = <0>;
......
......@@ -235,6 +235,10 @@
};
};
&cpu0 {
cpu0-supply = <&buck2_reg>;
};
&dp {
status = "okay";
pinctrl-names = "default";
......@@ -688,6 +692,7 @@
status = "okay";
samsung,spi-src-clk = <0>;
num-cs = <1>;
cs-gpios = <&gpa2 5 GPIO_ACTIVE_HIGH>;
};
&usbdrd_dwc3 {
......
......@@ -65,6 +65,10 @@
};
};
&cpu0 {
cpu0-supply = <&buck2_reg>;
};
&dp {
status = "okay";
pinctrl-names = "default";
......
......@@ -62,6 +62,28 @@
compatible = "arm,cortex-a15";
reg = <0>;
clock-frequency = <1700000000>;
clocks = <&clock CLK_ARM_CLK>;
clock-names = "cpu";
clock-latency = <140000>;
operating-points = <
1700000 1300000
1600000 1250000
1500000 1225000
1400000 1200000
1300000 1150000
1200000 1125000
1100000 1100000
1000000 1075000
900000 1050000
800000 1025000
700000 1012500
600000 1000000
500000 975000
400000 950000
300000 937500
200000 925000
>;
cooling-min-level = <15>;
cooling-max-level = <9>;
#cooling-cells = <2>; /* min followed by max */
......
/*
* SAMSUNG EXYNOS5422 SoC cpu device tree source
*
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* The only difference between EXYNOS5422 and EXYNOS5800 is cpu ordering. The
* EXYNOS5422 is booting from Cortex-A7 core while the EXYNOS5800 is booting
* from Cortex-A15 core.
*
* EXYNOS5422 based board files can include this file to provide cpu ordering
* which could boot a cortex-a7 from cpu0.
*
* 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.
*/
&cpu0 {
device_type = "cpu";
compatible = "arm,cortex-a7";
reg = <0x100>;
clock-frequency = <1000000000>;
cci-control-port = <&cci_control0>;
};
&cpu1 {
device_type = "cpu";
compatible = "arm,cortex-a7";
reg = <0x101>;
clock-frequency = <1000000000>;
cci-control-port = <&cci_control0>;
};
&cpu2 {
device_type = "cpu";
compatible = "arm,cortex-a7";
reg = <0x102>;
clock-frequency = <1000000000>;
cci-control-port = <&cci_control0>;
};
&cpu3 {
device_type = "cpu";
compatible = "arm,cortex-a7";
reg = <0x103>;
clock-frequency = <1000000000>;
cci-control-port = <&cci_control0>;
};
&cpu4 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <0x0>;
clock-frequency = <1800000000>;
cci-control-port = <&cci_control1>;
};
&cpu5 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <0x1>;
clock-frequency = <1800000000>;
cci-control-port = <&cci_control1>;
};
&cpu6 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <0x2>;
clock-frequency = <1800000000>;
cci-control-port = <&cci_control1>;
};
&cpu7 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <0x3>;
clock-frequency = <1800000000>;
cci-control-port = <&cci_control1>;
};
......@@ -15,6 +15,7 @@
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/sound/samsung-i2s.h>
#include "exynos5800.dtsi"
#include "exynos5422-cpus.dtsi"
#include "exynos5422-cpu-thermal.dtsi"
/ {
......
......@@ -4,6 +4,14 @@
model = "CompuLab CM-QS600";
compatible = "qcom,apq8064-cm-qs600", "qcom,apq8064";
aliases {
serial0 = &gsbi7_serial;
};
chosen {
stdout-path = "serial0:115200n8";
};
soc {
pinctrl@800000 {
i2c1_pins: i2c1 {
......
......@@ -10,6 +10,10 @@
serial1 = &gsbi6_serial;
};
chosen {
stdout-path = "serial0:115200n8";
};
soc {
pinctrl@800000 {
card_detect: card_detect {
......
......@@ -6,6 +6,14 @@
model = "Qualcomm APQ8074 Dragonboard";
compatible = "qcom,apq8074-dragonboard", "qcom,apq8074";
aliases {
serial0 = &blsp1_uart2;
};
chosen {
stdout-path = "serial0:115200n8";
};
soc {
serial@f991e000 {
status = "ok";
......
......@@ -5,6 +5,14 @@
model = "Qualcomm APQ8084/IFC6540";
compatible = "qcom,apq8084-ifc6540", "qcom,apq8084";
aliases {
serial0 = &blsp2_uart2;
};
chosen {
stdout-path = "serial0:115200n8";
};
soc {
serial@f995e000 {
status = "okay";
......
......@@ -5,6 +5,14 @@
model = "Qualcomm APQ 8084-MTP";
compatible = "qcom,apq8084-mtp", "qcom,apq8084";
aliases {
serial0 = &blsp2_uart2;
};
chosen {
stdout-path = "serial0:115200n8";
};
soc {
serial@f995e000 {
status = "okay";
......
......@@ -234,7 +234,7 @@
interrupts = <0 208 0>;
};
serial@f995e000 {
blsp2_uart2: serial@f995e000 {
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
reg = <0xf995e000 0x1000>;
interrupts = <0 114 0x0>;
......
......@@ -4,6 +4,14 @@
model = "Qualcomm IPQ8064/AP148";
compatible = "qcom,ipq8064-ap148", "qcom,ipq8064";
aliases {
serial0 = &gsbi4_serial;
};
chosen {
stdout-path = "serial0:115200n8";
};
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
......
......@@ -197,7 +197,7 @@
syscon-tcsr = <&tcsr>;
serial@16340000 {
gsbi4_serial: serial@16340000 {
compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
reg = <0x16340000 0x1000>,
<0x16300000 0x1000>;
......
......@@ -6,6 +6,14 @@
model = "Qualcomm MSM8660 SURF";
compatible = "qcom,msm8660-surf", "qcom,msm8660";
aliases {
serial0 = &gsbi12_serial;
};
chosen {
stdout-path = "serial0:115200n8";
};
soc {
gsbi@19c00000 {
status = "ok";
......
......@@ -98,7 +98,7 @@
syscon-tcsr = <&tcsr>;
serial@19c40000 {
gsbi12_serial: serial@19c40000 {
compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
reg = <0x19c40000 0x1000>,
<0x19c00000 0x1000>;
......
......@@ -6,6 +6,14 @@
model = "Qualcomm MSM8960 CDP";
compatible = "qcom,msm8960-cdp", "qcom,msm8960";
aliases {
serial0 = &gsbi5_serial;
};
chosen {
stdout-path = "serial0:115200n8";
};
soc {
gsbi@16400000 {
status = "ok";
......
......@@ -157,7 +157,7 @@
syscon-tcsr = <&tcsr>;
serial@16440000 {
gsbi5_serial: serial@16440000 {
compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
reg = <0x16440000 0x1000>,
<0x16400000 0x1000>;
......
......@@ -6,6 +6,14 @@
model = "Sony Xperia Z1";
compatible = "sony,xperia-honami", "qcom,msm8974";
aliases {
serial0 = &blsp1_uart2;
};
chosen {
stdout-path = "serial0:115200n8";
};
memory@0 {
reg = <0 0x40000000>, <0x40000000 0x40000000>;
device_type = "memory";
......
......@@ -259,7 +259,7 @@
hwlocks = <&tcsr_mutex 3>;
};
serial@f991e000 {
blsp1_uart2: serial@f991e000 {
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
reg = <0xf991e000 0x1000>;
interrupts = <0 108 0x0>;
......
......@@ -27,6 +27,8 @@ CONFIG_ARM_APPENDED_DTB=y
CONFIG_ARM_ATAG_DTB_COMPAT=y
CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC1,115200 init=/linuxrc mem=256M"
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPUFREQ_DT=y
CONFIG_CPU_IDLE=y
CONFIG_ARM_EXYNOS_CPUIDLE=y
CONFIG_VFP=y
......@@ -94,6 +96,7 @@ CONFIG_CHARGER_MAX14577=y
CONFIG_CHARGER_MAX77693=y
CONFIG_CHARGER_TPS65090=y
CONFIG_SENSORS_LM90=y
CONFIG_SENSORS_NTC_THERMISTOR=y
CONFIG_SENSORS_PWM_FAN=y
CONFIG_SENSORS_INA2XX=y
CONFIG_THERMAL=y
......@@ -144,6 +147,8 @@ CONFIG_SND=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_SAMSUNG=y
CONFIG_SND_SOC_SNOW=y
CONFIG_SND_SOC_ODROIDX2=y
CONFIG_SND_SIMPLE_CARD=y
CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_XHCI_HCD=y
......
......@@ -362,6 +362,7 @@ CONFIG_POWER_RESET_KEYSTONE=y
CONFIG_POWER_RESET_RMOBILE=y
CONFIG_SENSORS_LM90=y
CONFIG_SENSORS_LM95245=y
CONFIG_SENSORS_NTC_THERMISTOR=m
CONFIG_THERMAL=y
CONFIG_CPU_THERMAL=y
CONFIG_RCAR_THERMAL=y
......@@ -410,7 +411,9 @@ CONFIG_REGULATOR_MAX8907=y
CONFIG_REGULATOR_MAX8973=y
CONFIG_REGULATOR_MAX77686=y
CONFIG_REGULATOR_MAX77693=m
CONFIG_REGULATOR_MAX77802=m
CONFIG_REGULATOR_PALMAS=y
CONFIG_REGULATOR_PBIAS=y
CONFIG_REGULATOR_PWM=m
CONFIG_REGULATOR_S2MPS11=y
CONFIG_REGULATOR_S5M8767=y
......@@ -509,8 +512,6 @@ CONFIG_USB_CHIPIDEA_HOST=y
CONFIG_AB8500_USB=y
CONFIG_KEYSTONE_USB_PHY=y
CONFIG_OMAP_USB3=y
CONFIG_SAMSUNG_USB2PHY=y
CONFIG_SAMSUNG_USB3PHY=y
CONFIG_USB_GPIO_VBUS=y
CONFIG_USB_ISP1301=y
CONFIG_USB_MXS_PHY=y
......@@ -635,6 +636,7 @@ CONFIG_EXTCON=y
CONFIG_TI_AEMIF=y
CONFIG_IIO=y
CONFIG_AT91_ADC=m
CONFIG_EXYNOS_ADC=m
CONFIG_XILINX_XADC=y
CONFIG_AK8975=y
CONFIG_PWM=y
......
......@@ -15,6 +15,7 @@ menuconfig ARCH_EXYNOS
select ARM_AMBA
select ARM_GIC
select COMMON_CLK_SAMSUNG
select EXYNOS_THERMAL
select HAVE_ARM_SCU if SMP
select HAVE_S3C2410_I2C if I2C
select HAVE_S3C2410_WATCHDOG if WATCHDOG
......@@ -24,6 +25,7 @@ menuconfig ARCH_EXYNOS
select PM_GENERIC_DOMAINS if PM
select S5P_DEV_MFC
select SRAM
select THERMAL
select MFD_SYSCON
help
Support for SAMSUNG EXYNOS SoCs (EXYNOS4/5)
......
......@@ -225,7 +225,11 @@ static void __init exynos_init_irq(void)
}
static const struct of_device_id exynos_cpufreq_matches[] = {
{ .compatible = "samsung,exynos3250", .data = "cpufreq-dt" },
{ .compatible = "samsung,exynos4210", .data = "cpufreq-dt" },
{ .compatible = "samsung,exynos4212", .data = "cpufreq-dt" },
{ .compatible = "samsung,exynos4412", .data = "cpufreq-dt" },
{ .compatible = "samsung,exynos5250", .data = "cpufreq-dt" },
{ /* sentinel */ }
};
......
......@@ -1398,6 +1398,45 @@ static const struct exynos_cpuclk_cfg_data e4210_armclk_d[] __initconst = {
{ 0 },
};
static const struct exynos_cpuclk_cfg_data e4212_armclk_d[] __initconst = {
{ 1500000, E4210_CPU_DIV0(2, 1, 6, 0, 7, 3), E4210_CPU_DIV1(2, 6), },
{ 1400000, E4210_CPU_DIV0(2, 1, 6, 0, 7, 3), E4210_CPU_DIV1(2, 6), },
{ 1300000, E4210_CPU_DIV0(2, 1, 5, 0, 7, 3), E4210_CPU_DIV1(2, 5), },
{ 1200000, E4210_CPU_DIV0(2, 1, 5, 0, 7, 3), E4210_CPU_DIV1(2, 5), },
{ 1100000, E4210_CPU_DIV0(2, 1, 4, 0, 6, 3), E4210_CPU_DIV1(2, 4), },
{ 1000000, E4210_CPU_DIV0(1, 1, 4, 0, 5, 2), E4210_CPU_DIV1(2, 4), },
{ 900000, E4210_CPU_DIV0(1, 1, 3, 0, 5, 2), E4210_CPU_DIV1(2, 3), },
{ 800000, E4210_CPU_DIV0(1, 1, 3, 0, 5, 2), E4210_CPU_DIV1(2, 3), },
{ 700000, E4210_CPU_DIV0(1, 1, 3, 0, 4, 2), E4210_CPU_DIV1(2, 3), },
{ 600000, E4210_CPU_DIV0(1, 1, 3, 0, 4, 2), E4210_CPU_DIV1(2, 3), },
{ 500000, E4210_CPU_DIV0(1, 1, 3, 0, 4, 2), E4210_CPU_DIV1(2, 3), },
{ 400000, E4210_CPU_DIV0(1, 1, 3, 0, 4, 2), E4210_CPU_DIV1(2, 3), },
{ 300000, E4210_CPU_DIV0(1, 1, 2, 0, 4, 2), E4210_CPU_DIV1(2, 3), },
{ 200000, E4210_CPU_DIV0(1, 1, 1, 0, 3, 1), E4210_CPU_DIV1(2, 3), },
{ 0 },
};
#define E4412_CPU_DIV1(cores, hpm, copy) \
(((cores) << 8) | ((hpm) << 4) | ((copy) << 0))
static const struct exynos_cpuclk_cfg_data e4412_armclk_d[] __initconst = {
{ 1500000, E4210_CPU_DIV0(2, 1, 6, 0, 7, 3), E4412_CPU_DIV1(7, 0, 6), },
{ 1400000, E4210_CPU_DIV0(2, 1, 6, 0, 7, 3), E4412_CPU_DIV1(6, 0, 6), },
{ 1300000, E4210_CPU_DIV0(2, 1, 5, 0, 7, 3), E4412_CPU_DIV1(6, 0, 5), },
{ 1200000, E4210_CPU_DIV0(2, 1, 5, 0, 7, 3), E4412_CPU_DIV1(5, 0, 5), },
{ 1100000, E4210_CPU_DIV0(2, 1, 4, 0, 6, 3), E4412_CPU_DIV1(5, 0, 4), },
{ 1000000, E4210_CPU_DIV0(1, 1, 4, 0, 5, 2), E4412_CPU_DIV1(4, 0, 4), },
{ 900000, E4210_CPU_DIV0(1, 1, 3, 0, 5, 2), E4412_CPU_DIV1(4, 0, 3), },
{ 800000, E4210_CPU_DIV0(1, 1, 3, 0, 5, 2), E4412_CPU_DIV1(3, 0, 3), },
{ 700000, E4210_CPU_DIV0(1, 1, 3, 0, 4, 2), E4412_CPU_DIV1(3, 0, 3), },
{ 600000, E4210_CPU_DIV0(1, 1, 3, 0, 4, 2), E4412_CPU_DIV1(2, 0, 3), },
{ 500000, E4210_CPU_DIV0(1, 1, 3, 0, 4, 2), E4412_CPU_DIV1(2, 0, 3), },
{ 400000, E4210_CPU_DIV0(1, 1, 3, 0, 4, 2), E4412_CPU_DIV1(1, 0, 3), },
{ 300000, E4210_CPU_DIV0(1, 1, 2, 0, 4, 2), E4412_CPU_DIV1(1, 0, 3), },
{ 200000, E4210_CPU_DIV0(1, 1, 1, 0, 3, 1), E4412_CPU_DIV1(0, 0, 3), },
{ 0 },
};
/* register exynos4 clocks */
static void __init exynos4_clk_init(struct device_node *np,
enum exynos4_soc soc)
......@@ -1491,6 +1530,17 @@ static void __init exynos4_clk_init(struct device_node *np,
samsung_clk_register_fixed_factor(ctx,
exynos4x12_fixed_factor_clks,
ARRAY_SIZE(exynos4x12_fixed_factor_clks));
if (of_machine_is_compatible("samsung,exynos4412")) {
exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk",
mout_core_p4x12[0], mout_core_p4x12[1], 0x14200,
e4412_armclk_d, ARRAY_SIZE(e4412_armclk_d),
CLK_CPU_NEEDS_DEBUG_ALT_DIV | CLK_CPU_HAS_DIV1);
} else {
exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk",
mout_core_p4x12[0], mout_core_p4x12[1], 0x14200,
e4212_armclk_d, ARRAY_SIZE(e4212_armclk_d),
CLK_CPU_NEEDS_DEBUG_ALT_DIV | CLK_CPU_HAS_DIV1);
}
}
samsung_clk_register_alias(ctx, exynos4_aliases,
......
......@@ -24,55 +24,6 @@ config ARM_VEXPRESS_SPC_CPUFREQ
This add the CPUfreq driver support for Versatile Express
big.LITTLE platforms using SPC for power management.
config ARM_EXYNOS_CPUFREQ
tristate "SAMSUNG EXYNOS CPUfreq Driver"
depends on CPU_EXYNOS4210 || SOC_EXYNOS4212 || SOC_EXYNOS4412 || SOC_EXYNOS5250
depends on THERMAL
help
This adds the CPUFreq driver for Samsung EXYNOS platforms.
Supported SoC versions are:
Exynos4210, Exynos4212, Exynos4412, and Exynos5250.
If in doubt, say N.
config ARM_EXYNOS4X12_CPUFREQ
bool "SAMSUNG EXYNOS4x12"
depends on SOC_EXYNOS4212 || SOC_EXYNOS4412
depends on ARM_EXYNOS_CPUFREQ
default y
help
This adds the CPUFreq driver for Samsung EXYNOS4X12
SoC (EXYNOS4212 or EXYNOS4412).
If in doubt, say N.
config ARM_EXYNOS5250_CPUFREQ
bool "SAMSUNG EXYNOS5250"
depends on SOC_EXYNOS5250
depends on ARM_EXYNOS_CPUFREQ
default y
help
This adds the CPUFreq driver for Samsung EXYNOS5250
SoC.
If in doubt, say N.
config ARM_EXYNOS_CPU_FREQ_BOOST_SW
bool "EXYNOS Frequency Overclocking - Software"
depends on ARM_EXYNOS_CPUFREQ && THERMAL
select CPU_FREQ_BOOST_SW
select EXYNOS_THERMAL
help
This driver supports software managed overclocking (BOOST).
It allows usage of special frequencies for Samsung Exynos
processors if thermal conditions are appropriate.
It requires, for safe operation, thermal framework with properly
defined trip points.
If in doubt, say N.
config ARM_EXYNOS5440_CPUFREQ
tristate "SAMSUNG EXYNOS5440"
depends on SOC_EXYNOS5440
......
......@@ -52,10 +52,6 @@ obj-$(CONFIG_ARM_DT_BL_CPUFREQ) += arm_big_little_dt.o
obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o
obj-$(CONFIG_UX500_SOC_DB8500) += dbx500-cpufreq.o
obj-$(CONFIG_ARM_EXYNOS_CPUFREQ) += arm-exynos-cpufreq.o
arm-exynos-cpufreq-y := exynos-cpufreq.o
arm-exynos-cpufreq-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ) += exynos4x12-cpufreq.o
arm-exynos-cpufreq-$(CONFIG_ARM_EXYNOS5250_CPUFREQ) += exynos5250-cpufreq.o
obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o
obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o
obj-$(CONFIG_ARM_HISI_ACPU_CPUFREQ) += hisi-acpu-cpufreq.o
......
/*
* Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* EXYNOS - CPU frequency scaling support for EXYNOS series
*
* 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/module.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <linux/cpufreq.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/cpu_cooling.h>
#include <linux/cpu.h>
#include "exynos-cpufreq.h"
static struct exynos_dvfs_info *exynos_info;
static struct thermal_cooling_device *cdev;
static struct regulator *arm_regulator;
static unsigned int locking_frequency;
static int exynos_cpufreq_get_index(unsigned int freq)
{
struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
struct cpufreq_frequency_table *pos;
cpufreq_for_each_entry(pos, freq_table)
if (pos->frequency == freq)
break;
if (pos->frequency == CPUFREQ_TABLE_END)
return -EINVAL;
return pos - freq_table;
}
static int exynos_cpufreq_scale(unsigned int target_freq)
{
struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
unsigned int *volt_table = exynos_info->volt_table;
struct cpufreq_policy *policy = cpufreq_cpu_get(0);
unsigned int arm_volt, safe_arm_volt = 0;
unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz;
struct device *dev = exynos_info->dev;
unsigned int old_freq;
int index, old_index;
int ret = 0;
old_freq = policy->cur;
/*
* The policy max have been changed so that we cannot get proper
* old_index with cpufreq_frequency_table_target(). Thus, ignore
* policy and get the index from the raw frequency table.
*/
old_index = exynos_cpufreq_get_index(old_freq);
if (old_index < 0) {
ret = old_index;
goto out;
}
index = exynos_cpufreq_get_index(target_freq);
if (index < 0) {
ret = index;
goto out;
}
/*
* ARM clock source will be changed APLL to MPLL temporary
* To support this level, need to control regulator for
* required voltage level
*/
if (exynos_info->need_apll_change != NULL) {
if (exynos_info->need_apll_change(old_index, index) &&
(freq_table[index].frequency < mpll_freq_khz) &&
(freq_table[old_index].frequency < mpll_freq_khz))
safe_arm_volt = volt_table[exynos_info->pll_safe_idx];
}
arm_volt = volt_table[index];
/* When the new frequency is higher than current frequency */
if ((target_freq > old_freq) && !safe_arm_volt) {
/* Firstly, voltage up to increase frequency */
ret = regulator_set_voltage(arm_regulator, arm_volt, arm_volt);
if (ret) {
dev_err(dev, "failed to set cpu voltage to %d\n",
arm_volt);
return ret;
}
}
if (safe_arm_volt) {
ret = regulator_set_voltage(arm_regulator, safe_arm_volt,
safe_arm_volt);
if (ret) {
dev_err(dev, "failed to set cpu voltage to %d\n",
safe_arm_volt);
return ret;
}
}
exynos_info->set_freq(old_index, index);
/* When the new frequency is lower than current frequency */
if ((target_freq < old_freq) ||
((target_freq > old_freq) && safe_arm_volt)) {
/* down the voltage after frequency change */
ret = regulator_set_voltage(arm_regulator, arm_volt,
arm_volt);
if (ret) {
dev_err(dev, "failed to set cpu voltage to %d\n",
arm_volt);
goto out;
}
}
out:
cpufreq_cpu_put(policy);
return ret;
}
static int exynos_target(struct cpufreq_policy *policy, unsigned int index)
{
return exynos_cpufreq_scale(exynos_info->freq_table[index].frequency);
}
static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
policy->clk = exynos_info->cpu_clk;
policy->suspend_freq = locking_frequency;
return cpufreq_generic_init(policy, exynos_info->freq_table, 100000);
}
static struct cpufreq_driver exynos_driver = {
.flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
.verify = cpufreq_generic_frequency_table_verify,
.target_index = exynos_target,
.get = cpufreq_generic_get,
.init = exynos_cpufreq_cpu_init,
.name = "exynos_cpufreq",
.attr = cpufreq_generic_attr,
#ifdef CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
.boost_supported = true,
#endif
#ifdef CONFIG_PM
.suspend = cpufreq_generic_suspend,
#endif
};
static int exynos_cpufreq_probe(struct platform_device *pdev)
{
struct device_node *cpu0;
int ret = -EINVAL;
exynos_info = kzalloc(sizeof(*exynos_info), GFP_KERNEL);
if (!exynos_info)
return -ENOMEM;
exynos_info->dev = &pdev->dev;
if (of_machine_is_compatible("samsung,exynos4212")) {
exynos_info->type = EXYNOS_SOC_4212;
ret = exynos4x12_cpufreq_init(exynos_info);
} else if (of_machine_is_compatible("samsung,exynos4412")) {
exynos_info->type = EXYNOS_SOC_4412;
ret = exynos4x12_cpufreq_init(exynos_info);
} else if (of_machine_is_compatible("samsung,exynos5250")) {
exynos_info->type = EXYNOS_SOC_5250;
ret = exynos5250_cpufreq_init(exynos_info);
} else {
pr_err("%s: Unknown SoC type\n", __func__);
ret = -ENODEV;
}
if (ret)
goto err_vdd_arm;
if (exynos_info->set_freq == NULL) {
dev_err(&pdev->dev, "No set_freq function (ERR)\n");
ret = -EINVAL;
goto err_vdd_arm;
}
arm_regulator = regulator_get(NULL, "vdd_arm");
if (IS_ERR(arm_regulator)) {
dev_err(&pdev->dev, "failed to get resource vdd_arm\n");
ret = -EINVAL;
goto err_vdd_arm;
}
/* Done here as we want to capture boot frequency */
locking_frequency = clk_get_rate(exynos_info->cpu_clk) / 1000;
ret = cpufreq_register_driver(&exynos_driver);
if (ret)
goto err_cpufreq_reg;
cpu0 = of_get_cpu_node(0, NULL);
if (!cpu0) {
pr_err("failed to find cpu0 node\n");
return 0;
}
if (of_find_property(cpu0, "#cooling-cells", NULL)) {
cdev = of_cpufreq_cooling_register(cpu0,
cpu_present_mask);
if (IS_ERR(cdev))
pr_err("running cpufreq without cooling device: %ld\n",
PTR_ERR(cdev));
}
return 0;
err_cpufreq_reg:
dev_err(&pdev->dev, "failed to register cpufreq driver\n");
regulator_put(arm_regulator);
err_vdd_arm:
kfree(exynos_info);
return ret;
}
static struct platform_driver exynos_cpufreq_platdrv = {
.driver = {
.name = "exynos-cpufreq",
},
.probe = exynos_cpufreq_probe,
};
module_platform_driver(exynos_cpufreq_platdrv);
/*
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* EXYNOS - CPUFreq support
*
* 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.
*/
enum cpufreq_level_index {
L0, L1, L2, L3, L4,
L5, L6, L7, L8, L9,
L10, L11, L12, L13, L14,
L15, L16, L17, L18, L19,
L20,
};
enum exynos_soc_type {
EXYNOS_SOC_4212,
EXYNOS_SOC_4412,
EXYNOS_SOC_5250,
};
#define APLL_FREQ(f, a0, a1, a2, a3, a4, a5, a6, a7, b0, b1, b2, m, p, s) \
{ \
.freq = (f) * 1000, \
.clk_div_cpu0 = ((a0) | (a1) << 4 | (a2) << 8 | (a3) << 12 | \
(a4) << 16 | (a5) << 20 | (a6) << 24 | (a7) << 28), \
.clk_div_cpu1 = (b0 << 0 | b1 << 4 | b2 << 8), \
.mps = ((m) << 16 | (p) << 8 | (s)), \
}
struct apll_freq {
unsigned int freq;
u32 clk_div_cpu0;
u32 clk_div_cpu1;
u32 mps;
};
struct exynos_dvfs_info {
enum exynos_soc_type type;
struct device *dev;
unsigned long mpll_freq_khz;
unsigned int pll_safe_idx;
struct clk *cpu_clk;
unsigned int *volt_table;
struct cpufreq_frequency_table *freq_table;
void (*set_freq)(unsigned int, unsigned int);
bool (*need_apll_change)(unsigned int, unsigned int);
void __iomem *cmu_regs;
};
#ifdef CONFIG_ARM_EXYNOS4X12_CPUFREQ
extern int exynos4x12_cpufreq_init(struct exynos_dvfs_info *);
#else
static inline int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info)
{
return -EOPNOTSUPP;
}
#endif
#ifdef CONFIG_ARM_EXYNOS5250_CPUFREQ
extern int exynos5250_cpufreq_init(struct exynos_dvfs_info *);
#else
static inline int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
{
return -EOPNOTSUPP;
}
#endif
#define EXYNOS4_CLKSRC_CPU 0x14200
#define EXYNOS4_CLKMUX_STATCPU 0x14400
#define EXYNOS4_CLKDIV_CPU 0x14500
#define EXYNOS4_CLKDIV_CPU1 0x14504
#define EXYNOS4_CLKDIV_STATCPU 0x14600
#define EXYNOS4_CLKDIV_STATCPU1 0x14604
#define EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT (16)
#define EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK (0x7 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT)
#define EXYNOS5_APLL_LOCK 0x00000
#define EXYNOS5_APLL_CON0 0x00100
#define EXYNOS5_CLKMUX_STATCPU 0x00400
#define EXYNOS5_CLKDIV_CPU0 0x00500
#define EXYNOS5_CLKDIV_CPU1 0x00504
#define EXYNOS5_CLKDIV_STATCPU0 0x00600
#define EXYNOS5_CLKDIV_STATCPU1 0x00604
/*
* Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* EXYNOS4X12 - CPU frequency scaling support
*
* 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/module.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/cpufreq.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include "exynos-cpufreq.h"
static struct clk *cpu_clk;
static struct clk *moutcore;
static struct clk *mout_mpll;
static struct clk *mout_apll;
static struct exynos_dvfs_info *cpufreq;
static unsigned int exynos4x12_volt_table[] = {
1350000, 1287500, 1250000, 1187500, 1137500, 1087500, 1037500,
1000000, 987500, 975000, 950000, 925000, 900000, 900000
};
static struct cpufreq_frequency_table exynos4x12_freq_table[] = {
{CPUFREQ_BOOST_FREQ, L0, 1500 * 1000},
{0, L1, 1400 * 1000},
{0, L2, 1300 * 1000},
{0, L3, 1200 * 1000},
{0, L4, 1100 * 1000},
{0, L5, 1000 * 1000},
{0, L6, 900 * 1000},
{0, L7, 800 * 1000},
{0, L8, 700 * 1000},
{0, L9, 600 * 1000},
{0, L10, 500 * 1000},
{0, L11, 400 * 1000},
{0, L12, 300 * 1000},
{0, L13, 200 * 1000},
{0, 0, CPUFREQ_TABLE_END},
};
static struct apll_freq *apll_freq_4x12;
static struct apll_freq apll_freq_4212[] = {
/*
* values:
* freq
* clock divider for CORE, COREM0, COREM1, PERIPH, ATB, PCLK_DBG, APLL, CORE2
* clock divider for COPY, HPM, RESERVED
* PLL M, P, S
*/
APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 250, 4, 0),
APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 175, 3, 0),
APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 325, 6, 0),
APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 200, 4, 0),
APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 2, 0, 275, 6, 0),
APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 2, 0, 125, 3, 0),
APLL_FREQ(900, 0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 150, 4, 0),
APLL_FREQ(800, 0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3, 0),
APLL_FREQ(700, 0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 175, 3, 1),
APLL_FREQ(600, 0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 200, 4, 1),
APLL_FREQ(500, 0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 125, 3, 1),
APLL_FREQ(400, 0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3, 1),
APLL_FREQ(300, 0, 2, 4, 0, 2, 1, 1, 0, 3, 2, 0, 200, 4, 2),
APLL_FREQ(200, 0, 1, 3, 0, 1, 1, 1, 0, 3, 2, 0, 100, 3, 2),
};
static struct apll_freq apll_freq_4412[] = {
/*
* values:
* freq
* clock divider for CORE, COREM0, COREM1, PERIPH, ATB, PCLK_DBG, APLL, CORE2
* clock divider for COPY, HPM, CORES
* PLL M, P, S
*/
APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 7, 250, 4, 0),
APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 6, 175, 3, 0),
APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 6, 325, 6, 0),
APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 5, 200, 4, 0),
APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 0, 5, 275, 6, 0),
APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 0, 4, 125, 3, 0),
APLL_FREQ(900, 0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 4, 150, 4, 0),
APLL_FREQ(800, 0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 3, 100, 3, 0),
APLL_FREQ(700, 0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 3, 175, 3, 1),
APLL_FREQ(600, 0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 200, 4, 1),
APLL_FREQ(500, 0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 125, 3, 1),
APLL_FREQ(400, 0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 1, 100, 3, 1),
APLL_FREQ(300, 0, 2, 4, 0, 2, 1, 1, 0, 3, 0, 1, 200, 4, 2),
APLL_FREQ(200, 0, 1, 3, 0, 1, 1, 1, 0, 3, 0, 0, 100, 3, 2),
};
static void exynos4x12_set_clkdiv(unsigned int div_index)
{
unsigned int tmp;
/* Change Divider - CPU0 */
tmp = apll_freq_4x12[div_index].clk_div_cpu0;
__raw_writel(tmp, cpufreq->cmu_regs + EXYNOS4_CLKDIV_CPU);
while (__raw_readl(cpufreq->cmu_regs + EXYNOS4_CLKDIV_STATCPU)
& 0x11111111)
cpu_relax();
/* Change Divider - CPU1 */
tmp = apll_freq_4x12[div_index].clk_div_cpu1;
__raw_writel(tmp, cpufreq->cmu_regs + EXYNOS4_CLKDIV_CPU1);
do {
cpu_relax();
tmp = __raw_readl(cpufreq->cmu_regs + EXYNOS4_CLKDIV_STATCPU1);
} while (tmp != 0x0);
}
static void exynos4x12_set_apll(unsigned int index)
{
unsigned int tmp, freq = apll_freq_4x12[index].freq;
/* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
clk_set_parent(moutcore, mout_mpll);
do {
cpu_relax();
tmp = (__raw_readl(cpufreq->cmu_regs + EXYNOS4_CLKMUX_STATCPU)
>> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT);
tmp &= 0x7;
} while (tmp != 0x2);
clk_set_rate(mout_apll, freq * 1000);
/* MUX_CORE_SEL = APLL */
clk_set_parent(moutcore, mout_apll);
do {
cpu_relax();
tmp = __raw_readl(cpufreq->cmu_regs + EXYNOS4_CLKMUX_STATCPU);
tmp &= EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK;
} while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
}
static void exynos4x12_set_frequency(unsigned int old_index,
unsigned int new_index)
{
if (old_index > new_index) {
exynos4x12_set_clkdiv(new_index);
exynos4x12_set_apll(new_index);
} else if (old_index < new_index) {
exynos4x12_set_apll(new_index);
exynos4x12_set_clkdiv(new_index);
}
}
int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info)
{
struct device_node *np;
unsigned long rate;
/*
* HACK: This is a temporary workaround to get access to clock
* controller registers directly and remove static mappings and
* dependencies on platform headers. It is necessary to enable
* Exynos multi-platform support and will be removed together with
* this whole driver as soon as Exynos gets migrated to use
* cpufreq-dt driver.
*/
np = of_find_compatible_node(NULL, NULL, "samsung,exynos4412-clock");
if (!np) {
pr_err("%s: failed to find clock controller DT node\n",
__func__);
return -ENODEV;
}
info->cmu_regs = of_iomap(np, 0);
if (!info->cmu_regs) {
pr_err("%s: failed to map CMU registers\n", __func__);
return -EFAULT;
}
cpu_clk = clk_get(NULL, "armclk");
if (IS_ERR(cpu_clk))
return PTR_ERR(cpu_clk);
moutcore = clk_get(NULL, "moutcore");
if (IS_ERR(moutcore))
goto err_moutcore;
mout_mpll = clk_get(NULL, "mout_mpll");
if (IS_ERR(mout_mpll))
goto err_mout_mpll;
rate = clk_get_rate(mout_mpll) / 1000;
mout_apll = clk_get(NULL, "mout_apll");
if (IS_ERR(mout_apll))
goto err_mout_apll;
if (info->type == EXYNOS_SOC_4212)
apll_freq_4x12 = apll_freq_4212;
else
apll_freq_4x12 = apll_freq_4412;
info->mpll_freq_khz = rate;
/* 800Mhz */
info->pll_safe_idx = L7;
info->cpu_clk = cpu_clk;
info->volt_table = exynos4x12_volt_table;
info->freq_table = exynos4x12_freq_table;
info->set_freq = exynos4x12_set_frequency;
cpufreq = info;
return 0;
err_mout_apll:
clk_put(mout_mpll);
err_mout_mpll:
clk_put(moutcore);
err_moutcore:
clk_put(cpu_clk);
pr_debug("%s: failed initialization\n", __func__);
return -EINVAL;
}
/*
* Copyright (c) 2010-20122Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* EXYNOS5250 - CPU frequency scaling support
*
* 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/module.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/cpufreq.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include "exynos-cpufreq.h"
static struct clk *cpu_clk;
static struct clk *moutcore;
static struct clk *mout_mpll;
static struct clk *mout_apll;
static struct exynos_dvfs_info *cpufreq;
static unsigned int exynos5250_volt_table[] = {
1300000, 1250000, 1225000, 1200000, 1150000,
1125000, 1100000, 1075000, 1050000, 1025000,
1012500, 1000000, 975000, 950000, 937500,
925000
};
static struct cpufreq_frequency_table exynos5250_freq_table[] = {
{0, L0, 1700 * 1000},
{0, L1, 1600 * 1000},
{0, L2, 1500 * 1000},
{0, L3, 1400 * 1000},
{0, L4, 1300 * 1000},
{0, L5, 1200 * 1000},
{0, L6, 1100 * 1000},
{0, L7, 1000 * 1000},
{0, L8, 900 * 1000},
{0, L9, 800 * 1000},
{0, L10, 700 * 1000},
{0, L11, 600 * 1000},
{0, L12, 500 * 1000},
{0, L13, 400 * 1000},
{0, L14, 300 * 1000},
{0, L15, 200 * 1000},
{0, 0, CPUFREQ_TABLE_END},
};
static struct apll_freq apll_freq_5250[] = {
/*
* values:
* freq
* clock divider for ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG, APLL, ARM2
* clock divider for COPY, HPM, RESERVED
* PLL M, P, S
*/
APLL_FREQ(1700, 0, 3, 7, 7, 7, 3, 5, 0, 0, 2, 0, 425, 6, 0),
APLL_FREQ(1600, 0, 3, 7, 7, 7, 1, 4, 0, 0, 2, 0, 200, 3, 0),
APLL_FREQ(1500, 0, 2, 7, 7, 7, 1, 4, 0, 0, 2, 0, 250, 4, 0),
APLL_FREQ(1400, 0, 2, 7, 7, 6, 1, 4, 0, 0, 2, 0, 175, 3, 0),
APLL_FREQ(1300, 0, 2, 7, 7, 6, 1, 3, 0, 0, 2, 0, 325, 6, 0),
APLL_FREQ(1200, 0, 2, 7, 7, 5, 1, 3, 0, 0, 2, 0, 200, 4, 0),
APLL_FREQ(1100, 0, 3, 7, 7, 5, 1, 3, 0, 0, 2, 0, 275, 6, 0),
APLL_FREQ(1000, 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 125, 3, 0),
APLL_FREQ(900, 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 150, 4, 0),
APLL_FREQ(800, 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 100, 3, 0),
APLL_FREQ(700, 0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 175, 3, 1),
APLL_FREQ(600, 0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 200, 4, 1),
APLL_FREQ(500, 0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 125, 3, 1),
APLL_FREQ(400, 0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 100, 3, 1),
APLL_FREQ(300, 0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 200, 4, 2),
APLL_FREQ(200, 0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 100, 3, 2),
};
static void set_clkdiv(unsigned int div_index)
{
unsigned int tmp;
/* Change Divider - CPU0 */
tmp = apll_freq_5250[div_index].clk_div_cpu0;
__raw_writel(tmp, cpufreq->cmu_regs + EXYNOS5_CLKDIV_CPU0);
while (__raw_readl(cpufreq->cmu_regs + EXYNOS5_CLKDIV_STATCPU0)
& 0x11111111)
cpu_relax();
/* Change Divider - CPU1 */
tmp = apll_freq_5250[div_index].clk_div_cpu1;
__raw_writel(tmp, cpufreq->cmu_regs + EXYNOS5_CLKDIV_CPU1);
while (__raw_readl(cpufreq->cmu_regs + EXYNOS5_CLKDIV_STATCPU1) & 0x11)
cpu_relax();
}
static void set_apll(unsigned int index)
{
unsigned int tmp;
unsigned int freq = apll_freq_5250[index].freq;
/* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
clk_set_parent(moutcore, mout_mpll);
do {
cpu_relax();
tmp = (__raw_readl(cpufreq->cmu_regs + EXYNOS5_CLKMUX_STATCPU)
>> 16);
tmp &= 0x7;
} while (tmp != 0x2);
clk_set_rate(mout_apll, freq * 1000);
/* MUX_CORE_SEL = APLL */
clk_set_parent(moutcore, mout_apll);
do {
cpu_relax();
tmp = __raw_readl(cpufreq->cmu_regs + EXYNOS5_CLKMUX_STATCPU);
tmp &= (0x7 << 16);
} while (tmp != (0x1 << 16));
}
static void exynos5250_set_frequency(unsigned int old_index,
unsigned int new_index)
{
if (old_index > new_index) {
set_clkdiv(new_index);
set_apll(new_index);
} else if (old_index < new_index) {
set_apll(new_index);
set_clkdiv(new_index);
}
}
int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
{
struct device_node *np;
unsigned long rate;
/*
* HACK: This is a temporary workaround to get access to clock
* controller registers directly and remove static mappings and
* dependencies on platform headers. It is necessary to enable
* Exynos multi-platform support and will be removed together with
* this whole driver as soon as Exynos gets migrated to use
* cpufreq-dt driver.
*/
np = of_find_compatible_node(NULL, NULL, "samsung,exynos5250-clock");
if (!np) {
pr_err("%s: failed to find clock controller DT node\n",
__func__);
return -ENODEV;
}
info->cmu_regs = of_iomap(np, 0);
if (!info->cmu_regs) {
pr_err("%s: failed to map CMU registers\n", __func__);
return -EFAULT;
}
cpu_clk = clk_get(NULL, "armclk");
if (IS_ERR(cpu_clk))
return PTR_ERR(cpu_clk);
moutcore = clk_get(NULL, "mout_cpu");
if (IS_ERR(moutcore))
goto err_moutcore;
mout_mpll = clk_get(NULL, "mout_mpll");
if (IS_ERR(mout_mpll))
goto err_mout_mpll;
rate = clk_get_rate(mout_mpll) / 1000;
mout_apll = clk_get(NULL, "mout_apll");
if (IS_ERR(mout_apll))
goto err_mout_apll;
info->mpll_freq_khz = rate;
/* 800Mhz */
info->pll_safe_idx = L9;
info->cpu_clk = cpu_clk;
info->volt_table = exynos5250_volt_table;
info->freq_table = exynos5250_freq_table;
info->set_freq = exynos5250_set_frequency;
cpufreq = info;
return 0;
err_mout_apll:
clk_put(mout_mpll);
err_mout_mpll:
clk_put(moutcore);
err_moutcore:
clk_put(cpu_clk);
pr_err("%s: failed initialization\n", __func__);
return -EINVAL;
}
......@@ -89,6 +89,7 @@ static int ath79_reset_probe(struct platform_device *pdev)
if (IS_ERR(ath79_reset->base))
return PTR_ERR(ath79_reset->base);
spin_lock_init(&ath79_reset->lock);
ath79_reset->rcdev.ops = &ath79_reset_ops;
ath79_reset->rcdev.owner = THIS_MODULE;
ath79_reset->rcdev.of_node = pdev->dev.of_node;
......
......@@ -96,6 +96,7 @@ static const struct {
* @smd: handle to qcom_smd
* @of_node: of_node handle for information related to this edge
* @edge_id: identifier of this edge
* @remote_pid: identifier of remote processor
* @irq: interrupt for signals on this edge
* @ipc_regmap: regmap handle holding the outgoing ipc register
* @ipc_offset: offset within @ipc_regmap of the register for ipc
......@@ -111,6 +112,7 @@ struct qcom_smd_edge {
struct qcom_smd *smd;
struct device_node *of_node;
unsigned edge_id;
unsigned remote_pid;
int irq;
......@@ -310,7 +312,7 @@ static void qcom_smd_channel_reset(struct qcom_smd_channel *channel)
SET_TX_CHANNEL_INFO(channel, fHEAD, 0);
SET_TX_CHANNEL_INFO(channel, fTAIL, 0);
SET_TX_CHANNEL_INFO(channel, fSTATE, 1);
SET_TX_CHANNEL_INFO(channel, fBLOCKREADINTR, 0);
SET_TX_CHANNEL_INFO(channel, fBLOCKREADINTR, 1);
SET_TX_CHANNEL_INFO(channel, head, 0);
SET_TX_CHANNEL_INFO(channel, tail, 0);
......@@ -572,7 +574,7 @@ static irqreturn_t qcom_smd_edge_intr(int irq, void *data)
* have to scan if the amount of available space in smem have changed
* since last scan.
*/
available = qcom_smem_get_free_space(edge->edge_id);
available = qcom_smem_get_free_space(edge->remote_pid);
if (available != edge->smem_available) {
edge->smem_available = available;
edge->need_rescan = true;
......@@ -681,7 +683,7 @@ int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len)
goto out;
}
SET_TX_CHANNEL_INFO(channel, fBLOCKREADINTR, 1);
SET_TX_CHANNEL_INFO(channel, fBLOCKREADINTR, 0);
ret = wait_event_interruptible(channel->fblockread_event,
qcom_smd_get_tx_avail(channel) >= tlen ||
......@@ -689,7 +691,7 @@ int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len)
if (ret)
goto out;
SET_TX_CHANNEL_INFO(channel, fBLOCKREADINTR, 0);
SET_TX_CHANNEL_INFO(channel, fBLOCKREADINTR, 1);
}
SET_TX_CHANNEL_INFO(channel, fTAIL, 0);
......@@ -976,7 +978,8 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed
spin_lock_init(&channel->recv_lock);
init_waitqueue_head(&channel->fblockread_event);
ret = qcom_smem_get(edge->edge_id, smem_info_item, (void **)&info, &info_size);
ret = qcom_smem_get(edge->remote_pid, smem_info_item, (void **)&info,
&info_size);
if (ret)
goto free_name_and_channel;
......@@ -997,7 +1000,8 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed
goto free_name_and_channel;
}
ret = qcom_smem_get(edge->edge_id, smem_fifo_item, &fifo_base, &fifo_size);
ret = qcom_smem_get(edge->remote_pid, smem_fifo_item, &fifo_base,
&fifo_size);
if (ret)
goto free_name_and_channel;
......@@ -1041,7 +1045,7 @@ static void qcom_discover_channels(struct qcom_smd_edge *edge)
int i;
for (tbl = 0; tbl < SMD_ALLOC_TBL_COUNT; tbl++) {
ret = qcom_smem_get(edge->edge_id,
ret = qcom_smem_get(edge->remote_pid,
smem_items[tbl].alloc_tbl_id,
(void **)&alloc_tbl,
NULL);
......@@ -1184,6 +1188,10 @@ static int qcom_smd_parse_edge(struct device *dev,
return -EINVAL;
}
edge->remote_pid = QCOM_SMEM_HOST_ANY;
key = "qcom,remote-pid";
of_property_read_u32(node, key, &edge->remote_pid);
syscon_np = of_parse_phandle(node, "qcom,ipc", 0);
if (!syscon_np) {
dev_err(dev, "no qcom,ipc node\n");
......
......@@ -258,10 +258,6 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
size_t alloc_size;
void *p;
/* We're not going to find it if there's no matching partition */
if (host >= SMEM_HOST_COUNT || !smem->partitions[host])
return -ENOENT;
phdr = smem->partitions[host];
p = (void *)phdr + sizeof(*phdr);
......@@ -371,8 +367,9 @@ int qcom_smem_alloc(unsigned host, unsigned item, size_t size)
if (ret)
return ret;
ret = qcom_smem_alloc_private(__smem, host, item, size);
if (ret == -ENOENT)
if (host < SMEM_HOST_COUNT && __smem->partitions[host])
ret = qcom_smem_alloc_private(__smem, host, item, size);
else
ret = qcom_smem_alloc_global(__smem, item, size);
hwspin_unlock_irqrestore(__smem->hwlock, &flags);
......@@ -428,10 +425,6 @@ static int qcom_smem_get_private(struct qcom_smem *smem,
struct smem_private_entry *hdr;
void *p;
/* We're not going to find it if there's no matching partition */
if (host >= SMEM_HOST_COUNT || !smem->partitions[host])
return -ENOENT;
phdr = smem->partitions[host];
p = (void *)phdr + sizeof(*phdr);
......@@ -484,8 +477,9 @@ int qcom_smem_get(unsigned host, unsigned item, void **ptr, size_t *size)
if (ret)
return ret;
ret = qcom_smem_get_private(__smem, host, item, ptr, size);
if (ret == -ENOENT)
if (host < SMEM_HOST_COUNT && __smem->partitions[host])
ret = qcom_smem_get_private(__smem, host, item, ptr, size);
else
ret = qcom_smem_get_global(__smem, item, ptr, size);
hwspin_unlock_irqrestore(__smem->hwlock, &flags);
......
......@@ -74,6 +74,20 @@ static inline int device_reset_optional(struct device *dev)
return -ENOSYS;
}
static inline struct reset_control *__must_check reset_control_get(
struct device *dev, const char *id)
{
WARN_ON(1);
return ERR_PTR(-EINVAL);
}
static inline struct reset_control *__must_check devm_reset_control_get(
struct device *dev, const char *id)
{
WARN_ON(1);
return ERR_PTR(-EINVAL);
}
static inline struct reset_control *reset_control_get_optional(
struct device *dev, const char *id)
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册