1041 lines
26 KiB
Diff
1041 lines
26 KiB
Diff
From e7c97c57e2d5040e90662459239bc28c8ea89be5 Mon Sep 17 00:00:00 2001
|
|
From: Paolo Sabatino <paolo.sabatino@gmail.com>
|
|
Date: Wed, 7 Jul 2021 19:27:03 +0000
|
|
Subject: [PATCH] rk3228/rk3328: add dmc driver
|
|
|
|
---
|
|
arch/arm/boot/dts/rk322x.dtsi | 69 +-
|
|
drivers/devfreq/Kconfig | 24 +
|
|
drivers/devfreq/Makefile | 2 +
|
|
drivers/devfreq/rk3228_dmc.c | 623 ++++++++++++++
|
|
include/dt-bindings/clock/rockchip-ddr.h | 63 ++
|
|
include/dt-bindings/memory/rockchip,rk322x.h | 90 ++
|
|
7 files changed, 1714 insertions(+), 3 deletions(-)
|
|
create mode 100644 drivers/devfreq/rk3228_dmc.c
|
|
create mode 100644 drivers/devfreq/rk3328_dmc.c
|
|
create mode 100644 include/dt-bindings/clock/rockchip-ddr.h
|
|
create mode 100644 include/dt-bindings/memory/rockchip,rk322x.h
|
|
|
|
diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi
|
|
index 88e33eb11..22da2e3cd 100644
|
|
--- a/arch/arm/boot/dts/rk322x.dtsi
|
|
+++ b/arch/arm/boot/dts/rk322x.dtsi
|
|
@@ -7,6 +7,8 @@
|
|
#include <dt-bindings/clock/rk3228-cru.h>
|
|
#include <dt-bindings/thermal/thermal.h>
|
|
#include <dt-bindings/power/rk3228-power.h>
|
|
+#include <dt-bindings/clock/rockchip-ddr.h>
|
|
+#include <dt-bindings/memory/rockchip,rk322x.h>
|
|
|
|
/ {
|
|
#address-cells = <1>;
|
|
@@ -106,6 +106,68 @@ dfi: dfi@11210000 {
|
|
status = "okay";
|
|
};
|
|
|
|
+ dmc: dmc@11200000 {
|
|
+ compatible = "rockchip,rk3228-dmc", "rockchip,rk322x-dram";
|
|
+ reg = <0x11200000 0x400>;
|
|
+ clocks = <&cru SCLK_DDRCLK>;
|
|
+ clock-names = "ddr_sclk";
|
|
+ operating-points-v2 = <&dmc_opp_table>;
|
|
+ rockchip,dram_timing = <&dram_timing>;
|
|
+ rockchip,grf = <&grf>;
|
|
+ devfreq-events = <&dfi>;
|
|
+ upthreshold = <15>;
|
|
+ downdifferential = <10>;
|
|
+ #cooling-cells = <2>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ dmc_opp_table: dmc-opp-table {
|
|
+ compatible = "operating-points-v2";
|
|
+
|
|
+ opp-330000000 {
|
|
+ opp-hz = /bits/ 64 <330000000>;
|
|
+ opp-microvolt = <1050000 1000000 1200000>;
|
|
+ };
|
|
+ opp-534000000 {
|
|
+ opp-hz = /bits/ 64 <534000000>;
|
|
+ opp-microvolt = <1050000 1000000 1200000>;
|
|
+ };
|
|
+ opp-660000000 {
|
|
+ opp-hz = /bits/ 64 <660000000>;
|
|
+ opp-microvolt = <1100000 1000000 1200000>;
|
|
+ };
|
|
+ opp-786000000 {
|
|
+ opp-hz = /bits/ 64 <786000000>;
|
|
+ opp-microvolt = <1150000 1000000 1200000>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+ };
|
|
+
|
|
+ dram_timing: dram-timing {
|
|
+ compatible = "rockchip,dram-timing";
|
|
+ dram_spd_bin = <DDR3_DEFAULT>;
|
|
+ sr_idle = <0x18>;
|
|
+ pd_idle = <0x20>;
|
|
+ dram_dll_disb_freq = <300>;
|
|
+ phy_dll_disb_freq = <400>;
|
|
+ dram_odt_disb_freq = <333>;
|
|
+ phy_odt_disb_freq = <333>;
|
|
+ ddr3_drv = <DDR3_DS_40ohm>;
|
|
+ ddr3_odt = <DDR3_ODT_120ohm>;
|
|
+ lpddr3_drv = <LP3_DS_34ohm>;
|
|
+ lpddr3_odt = <LP3_ODT_240ohm>;
|
|
+ lpddr2_drv = <LP2_DS_34ohm>;
|
|
+ /* lpddr2 not supported odt */
|
|
+ phy_ddr3_clk_drv = <PHY_DDR3_RON_RTT_45ohm>;
|
|
+ phy_ddr3_cmd_drv = <PHY_DDR3_RON_RTT_45ohm>;
|
|
+ phy_ddr3_dqs_drv = <PHY_DDR3_RON_RTT_34ohm>;
|
|
+ phy_ddr3_odt = <PHY_DDR3_RON_RTT_225ohm>;
|
|
+ phy_lp23_clk_drv = <PHY_LP23_RON_RTT_43ohm>;
|
|
+ phy_lp23_cmd_drv = <PHY_LP23_RON_RTT_34ohm>;
|
|
+ phy_lp23_dqs_drv = <PHY_LP23_RON_RTT_34ohm>;
|
|
+ phy_lp3_odt = <PHY_LP23_RON_RTT_240ohm>;
|
|
+ };
|
|
+
|
|
arm-pmu {
|
|
compatible = "arm,cortex-a7-pmu";
|
|
interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
|
|
@@ -673,17 +736,17 @@ gpu_opp_table: opp-table2 {
|
|
|
|
opp-200000000 {
|
|
opp-hz = /bits/ 64 <200000000>;
|
|
- opp-microvolt = <1050000>;
|
|
+ opp-microvolt = <1050000 1000000 1200000>;
|
|
};
|
|
|
|
opp-300000000 {
|
|
opp-hz = /bits/ 64 <300000000>;
|
|
- opp-microvolt = <1050000>;
|
|
+ opp-microvolt = <1050000 1000000 1200000>;
|
|
};
|
|
|
|
opp-500000000 {
|
|
opp-hz = /bits/ 64 <500000000>;
|
|
- opp-microvolt = <1150000>;
|
|
+ opp-microvolt = <1150000 1000000 1200000>;
|
|
};
|
|
};
|
|
|
|
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
|
|
index 37dc40d1f..5f864a855 100644
|
|
--- a/drivers/devfreq/Kconfig
|
|
+++ b/drivers/devfreq/Kconfig
|
|
@@ -131,6 +131,18 @@ config ARM_TEGRA20_DEVFREQ
|
|
It reads Memory Controller counters and adjusts the operating
|
|
frequencies and voltages with OPP support.
|
|
|
|
+config ARM_RK3228_DMC_DEVFREQ
|
|
+ tristate "ARM RK3228 DMC DEVFREQ Driver"
|
|
+ depends on ARCH_ROCKCHIP
|
|
+ select DEVFREQ_EVENT_ROCKCHIP_DFI
|
|
+ select DEVFREQ_GOV_SIMPLE_ONDEMAND
|
|
+ select PM_DEVFREQ_EVENT
|
|
+ select PM_OPP
|
|
+ help
|
|
+ This adds the DEVFREQ driver for the RK3228 DMC(Dynamic Memory Controller).
|
|
+ It sets the frequency for the memory controller and reads the usage counts
|
|
+ from hardware.
|
|
+
|
|
config ARM_RK3399_DMC_DEVFREQ
|
|
tristate "ARM RK3399 DMC DEVFREQ Driver"
|
|
depends on (ARCH_ROCKCHIP && HAVE_ARM_SMCCC) || \
|
|
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
|
|
index bf40d04928d..059712bfe5f 100644
|
|
--- a/drivers/devfreq/Makefile
|
|
+++ b/drivers/devfreq/Makefile
|
|
@@ -13,6 +13,7 @@ obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ) += imx-bus.o
|
|
obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ) += imx8m-ddrc.o
|
|
obj-$(CONFIG_ARM_MEDIATEK_CCI_DEVFREQ) += mtk-cci-devfreq.o
|
|
obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o
|
|
+obj-$(CONFIG_ARM_RK3228_DMC_DEVFREQ) += rk3228_dmc.o
|
|
obj-$(CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ) += sun8i-a33-mbus.o
|
|
obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra30-devfreq.o
|
|
|
|
diff --git a/include/dt-bindings/clock/rockchip-ddr.h b/include/dt-bindings/clock/rockchip-ddr.h
|
|
new file mode 100644
|
|
index 000000000..b065432e7
|
|
--- /dev/null
|
|
+++ b/include/dt-bindings/clock/rockchip-ddr.h
|
|
@@ -0,0 +1,63 @@
|
|
+/*
|
|
+ *
|
|
+ * Copyright (C) 2017 ROCKCHIP, Inc.
|
|
+ *
|
|
+ * This software is licensed under the terms of the GNU General Public
|
|
+ * License version 2, as published by the Free Software Foundation, and
|
|
+ * may be copied, distributed, and modified under those terms.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef _DT_BINDINGS_CLOCK_ROCKCHIP_DDR_H
|
|
+#define _DT_BINDINGS_CLOCK_ROCKCHIP_DDR_H
|
|
+
|
|
+#define DDR2_DEFAULT (0)
|
|
+
|
|
+#define DDR3_800D (0) /* 5-5-5 */
|
|
+#define DDR3_800E (1) /* 6-6-6 */
|
|
+#define DDR3_1066E (2) /* 6-6-6 */
|
|
+#define DDR3_1066F (3) /* 7-7-7 */
|
|
+#define DDR3_1066G (4) /* 8-8-8 */
|
|
+#define DDR3_1333F (5) /* 7-7-7 */
|
|
+#define DDR3_1333G (6) /* 8-8-8 */
|
|
+#define DDR3_1333H (7) /* 9-9-9 */
|
|
+#define DDR3_1333J (8) /* 10-10-10 */
|
|
+#define DDR3_1600G (9) /* 8-8-8 */
|
|
+#define DDR3_1600H (10) /* 9-9-9 */
|
|
+#define DDR3_1600J (11) /* 10-10-10 */
|
|
+#define DDR3_1600K (12) /* 11-11-11 */
|
|
+#define DDR3_1866J (13) /* 10-10-10 */
|
|
+#define DDR3_1866K (14) /* 11-11-11 */
|
|
+#define DDR3_1866L (15) /* 12-12-12 */
|
|
+#define DDR3_1866M (16) /* 13-13-13 */
|
|
+#define DDR3_2133K (17) /* 11-11-11 */
|
|
+#define DDR3_2133L (18) /* 12-12-12 */
|
|
+#define DDR3_2133M (19) /* 13-13-13 */
|
|
+#define DDR3_2133N (20) /* 14-14-14 */
|
|
+#define DDR3_DEFAULT (21)
|
|
+#define DDR_DDR2 (22)
|
|
+#define DDR_LPDDR (23)
|
|
+#define DDR_LPDDR2 (24)
|
|
+
|
|
+#define DDR4_1600J (0) /* 10-10-10 */
|
|
+#define DDR4_1600K (1) /* 11-11-11 */
|
|
+#define DDR4_1600L (2) /* 12-12-12 */
|
|
+#define DDR4_1866L (3) /* 12-12-12 */
|
|
+#define DDR4_1866M (4) /* 13-13-13 */
|
|
+#define DDR4_1866N (5) /* 14-14-14 */
|
|
+#define DDR4_2133N (6) /* 14-14-14 */
|
|
+#define DDR4_2133P (7) /* 15-15-15 */
|
|
+#define DDR4_2133R (8) /* 16-16-16 */
|
|
+#define DDR4_2400P (9) /* 15-15-15 */
|
|
+#define DDR4_2400R (10) /* 16-16-16 */
|
|
+#define DDR4_2400U (11) /* 18-18-18 */
|
|
+#define DDR4_DEFAULT (12)
|
|
+
|
|
+#define PAUSE_CPU_STACK_SIZE 16
|
|
+
|
|
+#endif
|
|
diff --git a/include/dt-bindings/memory/rockchip,rk322x.h b/include/dt-bindings/memory/rockchip,rk322x.h
|
|
new file mode 100644
|
|
index 000000000..1ab3317d7
|
|
--- /dev/null
|
|
+++ b/include/dt-bindings/memory/rockchip,rk322x.h
|
|
@@ -0,0 +1,90 @@
|
|
+/*
|
|
+ * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
|
|
+ *
|
|
+ * SPDX-License-Identifier: GPL-2.0+
|
|
+ */
|
|
+
|
|
+#ifndef _DT_BINDINGS_DRAM_ROCKCHIP_RK322X_H
|
|
+#define _DT_BINDINGS_DRAM_ROCKCHIP_RK322X_H
|
|
+
|
|
+#define DDR3_DS_34ohm (1 << 1)
|
|
+#define DDR3_DS_40ohm (0x0)
|
|
+
|
|
+#define LP2_DS_34ohm (0x1)
|
|
+#define LP2_DS_40ohm (0x2)
|
|
+#define LP2_DS_48ohm (0x3)
|
|
+#define LP2_DS_60ohm (0x4)
|
|
+#define LP2_DS_68_6ohm (0x5)/* optional */
|
|
+#define LP2_DS_80ohm (0x6)
|
|
+#define LP2_DS_120ohm (0x7)/* optional */
|
|
+
|
|
+#define LP3_DS_34ohm (0x1)
|
|
+#define LP3_DS_40ohm (0x2)
|
|
+#define LP3_DS_48ohm (0x3)
|
|
+#define LP3_DS_60ohm (0x4)
|
|
+#define LP3_DS_80ohm (0x6)
|
|
+#define LP3_DS_34D_40U (0x9)
|
|
+#define LP3_DS_40D_48U (0xa)
|
|
+#define LP3_DS_34D_48U (0xb)
|
|
+
|
|
+#define DDR3_ODT_DIS (0)
|
|
+#define DDR3_ODT_40ohm ((1 << 2) | (1 << 6))
|
|
+#define DDR3_ODT_60ohm (1 << 2)
|
|
+#define DDR3_ODT_120ohm (1 << 6)
|
|
+
|
|
+#define LP3_ODT_DIS (0)
|
|
+#define LP3_ODT_60ohm (1)
|
|
+#define LP3_ODT_120ohm (2)
|
|
+#define LP3_ODT_240ohm (3)
|
|
+
|
|
+#define PHY_DDR3_RON_RTT_DISABLE (0)
|
|
+#define PHY_DDR3_RON_RTT_451ohm (1)
|
|
+#define PHY_DDR3_RON_RTT_225ohm (2)
|
|
+#define PHY_DDR3_RON_RTT_150ohm (3)
|
|
+#define PHY_DDR3_RON_RTT_112ohm (4)
|
|
+#define PHY_DDR3_RON_RTT_90ohm (5)
|
|
+#define PHY_DDR3_RON_RTT_75ohm (6)
|
|
+#define PHY_DDR3_RON_RTT_64ohm (7)
|
|
+#define PHY_DDR3_RON_RTT_56ohm (16)
|
|
+#define PHY_DDR3_RON_RTT_50ohm (17)
|
|
+#define PHY_DDR3_RON_RTT_45ohm (18)
|
|
+#define PHY_DDR3_RON_RTT_41ohm (19)
|
|
+#define PHY_DDR3_RON_RTT_37ohm (20)
|
|
+#define PHY_DDR3_RON_RTT_34ohm (21)
|
|
+#define PHY_DDR3_RON_RTT_33ohm (22)
|
|
+#define PHY_DDR3_RON_RTT_30ohm (23)
|
|
+#define PHY_DDR3_RON_RTT_28ohm (24)
|
|
+#define PHY_DDR3_RON_RTT_26ohm (25)
|
|
+#define PHY_DDR3_RON_RTT_25ohm (26)
|
|
+#define PHY_DDR3_RON_RTT_23ohm (27)
|
|
+#define PHY_DDR3_RON_RTT_22ohm (28)
|
|
+#define PHY_DDR3_RON_RTT_21ohm (29)
|
|
+#define PHY_DDR3_RON_RTT_20ohm (30)
|
|
+#define PHY_DDR3_RON_RTT_19ohm (31)
|
|
+
|
|
+#define PHY_LP23_RON_RTT_DISABLE (0)
|
|
+#define PHY_LP23_RON_RTT_480ohm (1)
|
|
+#define PHY_LP23_RON_RTT_240ohm (2)
|
|
+#define PHY_LP23_RON_RTT_160ohm (3)
|
|
+#define PHY_LP23_RON_RTT_120ohm (4)
|
|
+#define PHY_LP23_RON_RTT_96ohm (5)
|
|
+#define PHY_LP23_RON_RTT_80ohm (6)
|
|
+#define PHY_LP23_RON_RTT_68ohm (7)
|
|
+#define PHY_LP23_RON_RTT_60ohm (16)
|
|
+#define PHY_LP23_RON_RTT_53ohm (17)
|
|
+#define PHY_LP23_RON_RTT_48ohm (18)
|
|
+#define PHY_LP23_RON_RTT_43ohm (19)
|
|
+#define PHY_LP23_RON_RTT_40ohm (20)
|
|
+#define PHY_LP23_RON_RTT_37ohm (21)
|
|
+#define PHY_LP23_RON_RTT_34ohm (22)
|
|
+#define PHY_LP23_RON_RTT_32ohm (23)
|
|
+#define PHY_LP23_RON_RTT_30ohm (24)
|
|
+#define PHY_LP23_RON_RTT_28ohm (25)
|
|
+#define PHY_LP23_RON_RTT_26ohm (26)
|
|
+#define PHY_LP23_RON_RTT_25ohm (27)
|
|
+#define PHY_LP23_RON_RTT_24ohm (28)
|
|
+#define PHY_LP23_RON_RTT_22ohm (29)
|
|
+#define PHY_LP23_RON_RTT_21ohm (30)
|
|
+#define PHY_LP23_RON_RTT_20ohm (31)
|
|
+
|
|
+#endif /* _DT_BINDINGS_DRAM_ROCKCHIP_RK322X_H */
|
|
|
|
diff --git a/drivers/devfreq/rk3228_dmc.c b/drivers/devfreq/rk3228_dmc.c
|
|
new file mode 100644
|
|
index 00000000000..e8106f36404
|
|
--- /dev/null
|
|
+++ b/drivers/devfreq/rk3228_dmc.c
|
|
@@ -0,0 +1,709 @@
|
|
+// SPDX-License-Identifier: GPL-2.0-only
|
|
+/*
|
|
+ * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd.
|
|
+ * Author: Lin Huang <hl@rock-chips.com>
|
|
+ */
|
|
+
|
|
+#include <linux/arm-smccc.h>
|
|
+#include <linux/clk.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/devfreq.h>
|
|
+#include <linux/devfreq-event.h>
|
|
+#include <linux/devfreq_cooling.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/mfd/syscon.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/pm_opp.h>
|
|
+#include <linux/regmap.h>
|
|
+#include <linux/regulator/consumer.h>
|
|
+#include <linux/rwsem.h>
|
|
+#include <linux/suspend.h>
|
|
+
|
|
+#include <soc/rockchip/rockchip_sip.h>
|
|
+
|
|
+#define DTS_PAR_OFFSET (4096)
|
|
+
|
|
+#define RK3228_GRF_OS_REG2 0x5d0
|
|
+#define DDR_PCTL_MCFG 0x80
|
|
+#define DDR_PCTL_TCL 0xe8
|
|
+#define DDR_PCTL_TRAS 0xf0
|
|
+#define DDR_PCTL_TRCD 0xf8
|
|
+#define DDR_PCTL_TRP 0xdc
|
|
+
|
|
+/* MCFG */
|
|
+#define MDDR_LPDDR2_CLK_STOP_IDLE_SHIFT 24
|
|
+#define PD_IDLE_SHIFT 8
|
|
+#define MDDR_EN (2 << 22)
|
|
+#define LPDDR2_EN (3 << 22)
|
|
+#define LPDDR3_EN (1 << 22)
|
|
+#define DDR2_EN (0 << 5)
|
|
+#define DDR3_EN (1 << 5)
|
|
+#define LPDDR2_S2 (0 << 6)
|
|
+#define LPDDR2_S4 (1 << 6)
|
|
+#define MDDR_LPDDR2_BL_2 (0 << 20)
|
|
+#define MDDR_LPDDR2_BL_4 (1 << 20)
|
|
+#define MDDR_LPDDR2_BL_8 (2 << 20)
|
|
+#define MDDR_LPDDR2_BL_16 (3 << 20)
|
|
+#define DDR2_DDR3_BL_4 0
|
|
+#define DDR2_DDR3_BL_8 1
|
|
+#define TFAW_SHIFT 18
|
|
+#define PD_EXIT_SLOW (0 << 17)
|
|
+#define PD_EXIT_FAST (1 << 17)
|
|
+#define PD_TYPE_SHIFT 16
|
|
+#define BURSTLENGTH_SHIFT 20
|
|
+
|
|
+#define MCFG_CR_2T_BIT(x) ((x & (1 << 3)) >> 3)
|
|
+#define MCFG_DDR_MASK 0x60
|
|
+#define MCFG_DDR_SHIFT 5
|
|
+#define MCFG_LPDDR_MASK 0xC00000
|
|
+#define MCFG_LPDDR_SHIFT 22
|
|
+
|
|
+#define MCFG_LPDDR2_S2 0x0
|
|
+#define MCFG_DDR3 0x1
|
|
+#define MCFG_LPDDR2_S4 0x2
|
|
+
|
|
+#define READ_DRAMTYPE_INFO(n) (((n) >> 13) & 0x7)
|
|
+
|
|
+enum {
|
|
+ DDR4 = 0,
|
|
+ DDR2 = 2,
|
|
+ DDR3 = 3,
|
|
+ LPDDR2 = 5,
|
|
+ LPDDR3 = 6,
|
|
+ LPDDR4 = 7,
|
|
+ UNUSED = 0xFF
|
|
+};
|
|
+
|
|
+struct share_params {
|
|
+ u32 hz;
|
|
+ u32 lcdc_type;
|
|
+ u32 vop;
|
|
+ u32 vop_dclk_mode;
|
|
+ u32 sr_idle_en;
|
|
+ u32 addr_mcu_el3;
|
|
+ /*
|
|
+ * 1: need to wait flag1
|
|
+ * 0: never wait flag1
|
|
+ */
|
|
+ u32 wait_flag1;
|
|
+ /*
|
|
+ * 1: need to wait flag1
|
|
+ * 0: never wait flag1
|
|
+ */
|
|
+ u32 wait_flag0;
|
|
+ u32 complt_hwirq;
|
|
+ /* if need, add parameter after */
|
|
+};
|
|
+
|
|
+static struct share_params *ddr_psci_param = NULL;
|
|
+
|
|
+static const char * const rk3228_dts_timing[] = {
|
|
+ "dram_spd_bin",
|
|
+ "sr_idle",
|
|
+ "pd_idle",
|
|
+ "dram_dll_disb_freq",
|
|
+ "phy_dll_disb_freq",
|
|
+ "dram_odt_disb_freq",
|
|
+ "phy_odt_disb_freq",
|
|
+ "ddr3_drv",
|
|
+ "ddr3_odt",
|
|
+ "lpddr3_drv",
|
|
+ "lpddr3_odt",
|
|
+ "lpddr2_drv",
|
|
+ "phy_ddr3_clk_drv",
|
|
+ "phy_ddr3_cmd_drv",
|
|
+ "phy_ddr3_dqs_drv",
|
|
+ "phy_ddr3_odt",
|
|
+ "phy_lp23_clk_drv",
|
|
+ "phy_lp23_cmd_drv",
|
|
+ "phy_lp23_dqs_drv",
|
|
+ "phy_lp3_odt"
|
|
+};
|
|
+
|
|
+struct rk3228_ddr_dts_config_timing {
|
|
+ u32 dram_spd_bin;
|
|
+ u32 sr_idle;
|
|
+ u32 pd_idle;
|
|
+ u32 dram_dll_dis_freq;
|
|
+ u32 phy_dll_dis_freq;
|
|
+ u32 dram_odt_dis_freq;
|
|
+ u32 phy_odt_dis_freq;
|
|
+ u32 ddr3_drv;
|
|
+ u32 ddr3_odt;
|
|
+ u32 lpddr3_drv;
|
|
+ u32 lpddr3_odt;
|
|
+ u32 lpddr2_drv;
|
|
+ u32 phy_ddr3_clk_drv;
|
|
+ u32 phy_ddr3_cmd_drv;
|
|
+ u32 phy_ddr3_dqs_drv;
|
|
+ u32 phy_ddr3_odt;
|
|
+ u32 phy_lp23_clk_drv;
|
|
+ u32 phy_lp23_cmd_drv;
|
|
+ u32 phy_lp23_dqs_drv;
|
|
+ u32 phy_lp3_odt;
|
|
+};
|
|
+
|
|
+struct rk3228_devfreq {
|
|
+ struct devfreq *devfreq;
|
|
+ struct thermal_cooling_device *cooling;
|
|
+};
|
|
+
|
|
+struct rk3228_dmc {
|
|
+ struct device *dev;
|
|
+ void __iomem *iomem;
|
|
+
|
|
+ int rate;
|
|
+ struct devfreq_simple_ondemand_data ondemand_data;
|
|
+ struct devfreq_event_dev *edev;
|
|
+ struct clk *dmc_clk;
|
|
+ struct rk3228_devfreq devfreq;
|
|
+
|
|
+ uint32_t dram_type;
|
|
+
|
|
+ //struct mutex lock;
|
|
+
|
|
+ int (*set_auto_self_refresh)(u32 en);
|
|
+};
|
|
+
|
|
+static uint32_t of_get_rk3228_timings(struct device *dev,
|
|
+ struct device_node *np, uint32_t *timing)
|
|
+{
|
|
+ struct device_node *np_tim;
|
|
+ uint32_t offset;
|
|
+ int ret = 0;
|
|
+ u32 idx;
|
|
+
|
|
+ // first 4kb page is reserved for interface parameters, we calculate an offset
|
|
+ // after which the timing parameters start
|
|
+ offset = DTS_PAR_OFFSET / sizeof(uint32_t);
|
|
+
|
|
+ np_tim = of_parse_phandle(np, "rockchip,dram_timing", 0);
|
|
+
|
|
+ if (!np_tim) {
|
|
+ ret = -EINVAL;
|
|
+ goto end;
|
|
+ }
|
|
+
|
|
+ for (idx = 0; idx < ARRAY_SIZE(rk3228_dts_timing); idx++)
|
|
+ ret |= of_property_read_u32(np_tim, rk3228_dts_timing[idx], &timing[offset + idx]);
|
|
+
|
|
+end:
|
|
+ if (ret)
|
|
+ dev_err(dev, "of_get_ddr_timings: fail\n");
|
|
+
|
|
+ of_node_put(np_tim);
|
|
+
|
|
+ return ret;
|
|
+
|
|
+}
|
|
+
|
|
+static int rockchip_ddr_set_auto_self_refresh(uint32_t en)
|
|
+{
|
|
+ struct arm_smccc_res res;
|
|
+
|
|
+ ddr_psci_param->sr_idle_en = en;
|
|
+
|
|
+ arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ,
|
|
+ SHARE_PAGE_TYPE_DDR, 0, ROCKCHIP_SIP_CONFIG_DRAM_SET_AT_SR,
|
|
+ 0, 0, 0, 0, &res);
|
|
+
|
|
+ return res.a0;
|
|
+}
|
|
+
|
|
+static int rk3228_dmc_target(struct device *dev, unsigned long *freq,
|
|
+ u32 flags)
|
|
+{
|
|
+
|
|
+ struct rk3228_dmc *rdev = dev_get_drvdata(dev);
|
|
+ struct dev_pm_opp *opp;
|
|
+ int err;
|
|
+
|
|
+ opp = devfreq_recommended_opp(dev, freq, flags);
|
|
+ if (IS_ERR(opp))
|
|
+ return PTR_ERR(opp);
|
|
+ dev_pm_opp_put(opp);
|
|
+
|
|
+ err = dev_pm_opp_set_rate(dev, *freq);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ rdev->rate = *freq;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+}
|
|
+
|
|
+static int rk3228_dmc_get_dev_status(struct device *dev,
|
|
+ struct devfreq_dev_status *stat)
|
|
+{
|
|
+ struct rk3228_dmc *rdev = dev_get_drvdata(dev);
|
|
+ struct devfreq_event_data edata;
|
|
+ int ret = 0;
|
|
+
|
|
+ ret = devfreq_event_get_event(rdev->edev, &edata);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ stat->current_frequency = rdev->rate;
|
|
+ stat->busy_time = edata.load_count;
|
|
+ stat->total_time = edata.total_count;
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int rk3228_dmc_get_cur_freq(struct device *dev, unsigned long *freq)
|
|
+{
|
|
+ struct rk3228_dmc *rdev = dev_get_drvdata(dev);
|
|
+
|
|
+ *freq = rdev->rate;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct devfreq_dev_profile rk3228_devfreq_profile = {
|
|
+ .polling_ms = 50,
|
|
+ .target = rk3228_dmc_target,
|
|
+ .get_dev_status = rk3228_dmc_get_dev_status,
|
|
+ .get_cur_freq = rk3228_dmc_get_cur_freq,
|
|
+};
|
|
+
|
|
+void rk3228_devfreq_fini(struct rk3228_dmc *rdev)
|
|
+{
|
|
+ struct rk3228_devfreq *devfreq = &rdev->devfreq;
|
|
+
|
|
+ if (devfreq->cooling) {
|
|
+ devfreq_cooling_unregister(devfreq->cooling);
|
|
+ devfreq->cooling = NULL;
|
|
+ }
|
|
+
|
|
+ if (devfreq->devfreq) {
|
|
+ devm_devfreq_remove_device(rdev->dev, devfreq->devfreq);
|
|
+ devfreq->devfreq = NULL;
|
|
+ }
|
|
+
|
|
+}
|
|
+
|
|
+int rk3228_devfreq_init(struct rk3228_dmc *rdev)
|
|
+{
|
|
+ struct thermal_cooling_device *cooling;
|
|
+ struct device *dev = rdev->dev;
|
|
+ struct devfreq *devfreq;
|
|
+ struct rk3228_devfreq *rdevfreq = &rdev->devfreq;
|
|
+ const char *regulator_names[] = { "logic", NULL };
|
|
+
|
|
+ struct dev_pm_opp *opp;
|
|
+ unsigned long cur_freq;
|
|
+ int ret;
|
|
+
|
|
+ if (!device_property_present(dev, "operating-points-v2"))
|
|
+ /* Optional, continue without devfreq */
|
|
+ return 0;
|
|
+
|
|
+ ret = devm_pm_opp_set_clkname(dev, "ddr_sclk");
|
|
+ if (ret)
|
|
+ goto err_fini;
|
|
+
|
|
+ ret = devm_pm_opp_set_regulators(dev, regulator_names);
|
|
+
|
|
+ /* Continue if the optional regulator is missing */
|
|
+ if (ret && ret != -ENODEV)
|
|
+ goto err_fini;
|
|
+
|
|
+ ret = devm_pm_opp_of_add_table(dev);
|
|
+ if (ret)
|
|
+ goto err_fini;
|
|
+
|
|
+ cur_freq = 0;
|
|
+
|
|
+ opp = devfreq_recommended_opp(dev, &cur_freq, 0);
|
|
+ if (IS_ERR(opp)) {
|
|
+ ret = PTR_ERR(opp);
|
|
+ goto err_fini;
|
|
+ }
|
|
+
|
|
+ rk3228_devfreq_profile.initial_freq = cur_freq;
|
|
+ dev_pm_opp_put(opp);
|
|
+
|
|
+ rdev->ondemand_data.upthreshold = 30;
|
|
+ rdev->ondemand_data.downdifferential = 5;
|
|
+
|
|
+ devfreq = devm_devfreq_add_device(dev, &rk3228_devfreq_profile,
|
|
+ DEVFREQ_GOV_SIMPLE_ONDEMAND, &rdev->ondemand_data);
|
|
+ if (IS_ERR(devfreq)) {
|
|
+ dev_err(dev, "Couldn't initialize GPU devfreq\n");
|
|
+ ret = PTR_ERR(devfreq);
|
|
+ goto err_fini;
|
|
+ }
|
|
+
|
|
+ rdevfreq->devfreq = devfreq;
|
|
+
|
|
+ cooling = of_devfreq_cooling_register(dev->of_node, devfreq);
|
|
+ if (IS_ERR(cooling))
|
|
+ dev_warn(dev, "Failed to register cooling device\n");
|
|
+ else
|
|
+ rdevfreq->cooling = cooling;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+err_fini:
|
|
+ rk3228_devfreq_fini(rdev);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int rk3228_dmc_init(struct platform_device *pdev,
|
|
+ struct rk3228_dmc *rdev)
|
|
+{
|
|
+ struct arm_smccc_res res;
|
|
+ u32 page_num;
|
|
+
|
|
+ // Count of pages to request to trust os, in pages of 4kb
|
|
+ page_num = DIV_ROUND_UP(sizeof(struct rk3228_ddr_dts_config_timing), PAGE_SIZE) + 1;
|
|
+
|
|
+ dev_dbg(&pdev->dev, "trying to allocate %d pages\n", page_num);
|
|
+
|
|
+ // Do request to trust OS. res.a0 contains error code, res.a1 the *physical*
|
|
+ // initial location of pages
|
|
+ arm_smccc_smc(
|
|
+ ROCKCHIP_SIP_SHARE_MEM,
|
|
+ page_num, SHARE_PAGE_TYPE_DDR, 0,
|
|
+ 0, 0, 0, 0, &res
|
|
+ );
|
|
+
|
|
+ if (res.a0) {
|
|
+ dev_err(&pdev->dev, "no ATF memory for init\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ dev_dbg(&pdev->dev, "allocated %d shared memory pages\n", page_num);
|
|
+
|
|
+ // Remap the physical location to kernel space using ioremap
|
|
+ ddr_psci_param = (struct share_params *)ioremap(res.a1, page_num << PAGE_SHIFT);
|
|
+
|
|
+ if (of_get_rk3228_timings(&pdev->dev, pdev->dev.of_node,
|
|
+ (uint32_t *)ddr_psci_param))
|
|
+ return -ENOMEM;
|
|
+
|
|
+ // Reset Hz value
|
|
+ ddr_psci_param->hz = 0;
|
|
+
|
|
+ arm_smccc_smc(
|
|
+ ROCKCHIP_SIP_DRAM_FREQ,
|
|
+ SHARE_PAGE_TYPE_DDR, 0, ROCKCHIP_SIP_CONFIG_DRAM_INIT,
|
|
+ 0, 0, 0, 0, &res
|
|
+ );
|
|
+
|
|
+ if (res.a0) {
|
|
+ dev_err(&pdev->dev, "rockchip_sip_config_dram_init error:%lx\n",
|
|
+ res.a0);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ dev_notice(&pdev->dev, "TEE DRAM configuration initialized\n");
|
|
+
|
|
+ rdev->set_auto_self_refresh = rockchip_ddr_set_auto_self_refresh;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+}
|
|
+
|
|
+static __maybe_unused int rk3228_dmc_suspend(struct device *dev)
|
|
+{
|
|
+ struct rk3228_dmc *rdev = dev_get_drvdata(dev);
|
|
+ int ret = 0;
|
|
+
|
|
+ ret = devfreq_event_disable_edev(rdev->edev);
|
|
+ if (ret < 0) {
|
|
+ dev_err(dev, "failed to disable the devfreq-event devices\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = devfreq_suspend_device(rdev->devfreq.devfreq);
|
|
+ if (ret < 0) {
|
|
+ dev_err(dev, "failed to suspend the devfreq devices\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static __maybe_unused int rk3228_dmc_resume(struct device *dev)
|
|
+{
|
|
+ struct rk3228_dmc *rdev = dev_get_drvdata(dev);
|
|
+ int ret = 0;
|
|
+
|
|
+ ret = devfreq_event_enable_edev(rdev->edev);
|
|
+ if (ret < 0) {
|
|
+ dev_err(dev, "failed to enable the devfreq-event devices\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = devfreq_resume_device(rdev->devfreq.devfreq);
|
|
+ if (ret < 0) {
|
|
+ dev_err(dev, "failed to resume the devfreq devices\n");
|
|
+ return ret;
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static uint32_t rk3228_get_dram_type(struct device *dev, struct device_node *node_grf, struct rk3228_dmc *data)
|
|
+{
|
|
+
|
|
+ struct regmap *regmap_grf;
|
|
+ uint32_t dram_type;
|
|
+ uint32_t val;
|
|
+
|
|
+ dram_type = UNUSED;
|
|
+
|
|
+ regmap_grf = syscon_node_to_regmap(node_grf);
|
|
+
|
|
+ if (IS_ERR(regmap_grf)) {
|
|
+ dev_err(dev, "Cannot map rockchip,grf\n");
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ regmap_read(regmap_grf, RK3228_GRF_OS_REG2, &val);
|
|
+ dram_type = READ_DRAMTYPE_INFO(val);
|
|
+
|
|
+err:
|
|
+
|
|
+ return dram_type;
|
|
+
|
|
+}
|
|
+
|
|
+static SIMPLE_DEV_PM_OPS(rk3228_dmc_pm, rk3228_dmc_suspend,
|
|
+ rk3228_dmc_resume);
|
|
+
|
|
+static int rk3328_dmc_print_info(struct rk3228_dmc *rdev)
|
|
+{
|
|
+
|
|
+ u32 tcl;
|
|
+ u32 tras;
|
|
+ u32 trp;
|
|
+ u32 trcd;
|
|
+
|
|
+ u32 mcfg;
|
|
+ u32 reg_ddr_type1;
|
|
+ u32 reg_ddr_type2;
|
|
+
|
|
+ u32 dram_type;
|
|
+ u32 cr;
|
|
+
|
|
+ const char * const dram_types[] = {
|
|
+ "LPDDR2 S2",
|
|
+ "LPDDR2 S4",
|
|
+ "DDR3",
|
|
+ "LPDDR3",
|
|
+ "Unknown"
|
|
+ };
|
|
+
|
|
+ const char * const cr_types[] = {
|
|
+ "1T",
|
|
+ "2T"
|
|
+ };
|
|
+
|
|
+
|
|
+ tcl = readl(rdev->iomem + DDR_PCTL_TCL) & 0xf;
|
|
+ tras = readl(rdev->iomem + DDR_PCTL_TRAS) & 0x3f;
|
|
+ trp = readl(rdev->iomem + DDR_PCTL_TRP) & 0xf;
|
|
+ trcd = readl(rdev->iomem + DDR_PCTL_TRCD) & 0xf;
|
|
+
|
|
+ mcfg = readl(rdev->iomem + DDR_PCTL_MCFG);
|
|
+
|
|
+ reg_ddr_type1 = (mcfg & MCFG_DDR_MASK) >> MCFG_DDR_SHIFT;
|
|
+ reg_ddr_type2 = (mcfg & MCFG_LPDDR_MASK) >> MCFG_LPDDR_SHIFT;
|
|
+ cr = MCFG_CR_2T_BIT(mcfg);
|
|
+
|
|
+ switch (reg_ddr_type1) {
|
|
+ case MCFG_LPDDR2_S2:
|
|
+ dram_type = 0;
|
|
+ break;
|
|
+ case MCFG_LPDDR2_S4:
|
|
+ dram_type = 1;
|
|
+ break;
|
|
+ case MCFG_DDR3:
|
|
+ dram_type = reg_ddr_type2 == LPDDR3_EN ? 3 : 2;
|
|
+ break;
|
|
+ default:
|
|
+ dram_type = 4;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ dev_info(rdev->dev,
|
|
+ "memory type %s, timings (tCL, tRCD, tRP, tRAS): CL%d-%d-%d-%d command rate: %s (mcfg register: 0x%x)\n",
|
|
+ dram_types[dram_type], tcl, trcd, trp, tras, cr_types[cr], mcfg);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+}
|
|
+
|
|
+static int rk3228_dmc_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct device *dev = &pdev->dev;
|
|
+ struct device_node *np = pdev->dev.of_node;
|
|
+ struct rk3228_dmc *data;
|
|
+ struct device_node *node_grf;
|
|
+ int ret;
|
|
+
|
|
+ data = devm_kzalloc(dev, sizeof(struct rk3228_dmc), GFP_KERNEL);
|
|
+ if (!data)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ //mutex_init(&data->lock);
|
|
+
|
|
+ data->dmc_clk = devm_clk_get(dev, "ddr_sclk");
|
|
+ if (IS_ERR(data->dmc_clk)) {
|
|
+ if (PTR_ERR(data->dmc_clk) == -EPROBE_DEFER)
|
|
+ return -EPROBE_DEFER;
|
|
+
|
|
+ dev_err(dev, "Cannot get the clk dmc_clk\n");
|
|
+ return PTR_ERR(data->dmc_clk);
|
|
+ }
|
|
+
|
|
+ data->edev = devfreq_event_get_edev_by_phandle(dev, "devfreq-events", 0);
|
|
+ if (IS_ERR(data->edev))
|
|
+ return -EPROBE_DEFER;
|
|
+
|
|
+ data->iomem = devm_platform_ioremap_resource(pdev, 0);
|
|
+ if (IS_ERR(data->iomem)) {
|
|
+ dev_err(dev, "fail to ioremap iomem\n");
|
|
+ ret = PTR_ERR(data->iomem);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ data->dev = dev;
|
|
+
|
|
+ rk3328_dmc_print_info(data);
|
|
+
|
|
+ node_grf = of_parse_phandle(np, "rockchip,grf", 0);
|
|
+ if (node_grf) {
|
|
+
|
|
+ data->dram_type = rk3228_get_dram_type(dev, node_grf, data);
|
|
+
|
|
+ if (data->dram_type == LPDDR2) {
|
|
+ dev_warn(dev, "detected LPDDR2 memory\n");
|
|
+ } else if (data->dram_type == DDR2) {
|
|
+ dev_warn(dev, "detected DDR2 memory\n");
|
|
+ } else if (data->dram_type == DDR3) {
|
|
+ dev_info(dev, "detected DDR3 memory\n");
|
|
+ } else if (data->dram_type == LPDDR3) {
|
|
+ dev_info(dev, "detected LPDDR3 memory\n");
|
|
+ } else if (data->dram_type == DDR4) {
|
|
+ dev_info(dev, "detected DDR4 memory\n");
|
|
+ } else if (data->dram_type == LPDDR4) {
|
|
+ dev_info(dev, "detected LPDDR4 memory\n");
|
|
+ } else if (data->dram_type == UNUSED) {
|
|
+ dev_info(dev, "memory type not detected\n");
|
|
+ } else {
|
|
+ dev_info(dev, "unknown memory type: 0x%x\n", data->dram_type);
|
|
+ }
|
|
+
|
|
+ } else {
|
|
+
|
|
+ dev_warn(dev, "Cannot get rockchip,grf\n");
|
|
+ data->dram_type = UNUSED;
|
|
+
|
|
+ }
|
|
+
|
|
+ if (data->dram_type == DDR3 ||
|
|
+ data->dram_type == LPDDR3 ||
|
|
+ data->dram_type == DDR4 ||
|
|
+ data->dram_type == LPDDR4) {
|
|
+
|
|
+ ret = devfreq_event_enable_edev(data->edev);
|
|
+ if (ret < 0) {
|
|
+ dev_err(dev, "failed to enable devfreq-event devices\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = rk3228_dmc_init(pdev, data);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+
|
|
+
|
|
+ ret = rk3228_devfreq_init(data);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ } else {
|
|
+
|
|
+ dev_warn(dev, "detected memory type does not support clock scaling\n");
|
|
+
|
|
+ }
|
|
+
|
|
+ platform_set_drvdata(pdev, data);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+}
|
|
+
|
|
+static int rk3228_dmc_remove(struct platform_device *pdev)
|
|
+{
|
|
+ struct rk3228_dmc *rdev = dev_get_drvdata(&pdev->dev);
|
|
+
|
|
+ /*
|
|
+ * Before remove the opp table we need to unregister the opp notifier.
|
|
+ */
|
|
+ rk3228_devfreq_fini(rdev);
|
|
+
|
|
+ if (ddr_psci_param)
|
|
+ iounmap(ddr_psci_param);
|
|
+
|
|
+ if (rdev->iomem)
|
|
+ iounmap(rdev->iomem);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct of_device_id rk3228_dmc_of_match[] = {
|
|
+ { .compatible = "rockchip,rk3228-dmc" },
|
|
+ { },
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, rk3228_dmc_of_match);
|
|
+
|
|
+static struct platform_driver rk3228_dmc_driver = {
|
|
+ .probe = rk3228_dmc_probe,
|
|
+ .remove = rk3228_dmc_remove,
|
|
+ .driver = {
|
|
+ .name = "rk3228-dmc",
|
|
+ .pm = &rk3228_dmc_pm,
|
|
+ .of_match_table = rk3228_dmc_of_match,
|
|
+ },
|
|
+};
|
|
+module_platform_driver(rk3228_dmc_driver);
|
|
+
|
|
+#ifdef CONFIG_ARM
|
|
+static __init int sip_firmware_init(void)
|
|
+{
|
|
+ struct arm_smccc_res res;
|
|
+
|
|
+ /*
|
|
+ * OP-TEE works on kernel 3.10 and 4.4 and we have different sip
|
|
+ * implement. We should tell OP-TEE the current rockchip sip version.
|
|
+ */
|
|
+
|
|
+ /*
|
|
+ *
|
|
+ * res = __invoke_sip_fn_smc(ROCKCHIP_SIP_SIP_VERSION, ROCKCHIP_SIP_IMPLEMENT_V2,
|
|
+ SECURE_REG_WR, 0);
|
|
+
|
|
+ arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
|
|
+ */
|
|
+
|
|
+ arm_smccc_smc(ROCKCHIP_SIP_SIP_VERSION, ROCKCHIP_SIP_IMPLEMENT_V2, SECURE_REG_WR, 0, 0, 0, 0, 0, &res);
|
|
+
|
|
+ if (res.a0)
|
|
+ pr_err("%s: set rockchip sip version v2 failed\n", __func__);
|
|
+
|
|
+ pr_notice("Rockchip SIP initialized, version 0x%lx\n", res.a1);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+arch_initcall(sip_firmware_init);
|
|
+#endif
|
|
+
|
|
+MODULE_LICENSE("GPL v2");
|
|
+MODULE_AUTHOR("Lin Huang <hl@rock-chips.com>");
|
|
+MODULE_DESCRIPTION("RK3228 dmcfreq driver with devfreq framework");
|
|
|
|
--
|
|
2.25.1
|