diff options
-rw-r--r-- | Documentation/devicetree/bindings/arm/msm/qcom,osm.txt | 5 | ||||
-rw-r--r-- | drivers/clk/qcom/Kconfig | 12 | ||||
-rw-r--r-- | drivers/clk/qcom/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/qcom/clk-cpu-osm.c | 1139 | ||||
-rw-r--r-- | drivers/clk/qcom/common.h | 1 | ||||
-rw-r--r-- | include/dt-bindings/clock/qcom,cpu-osm.h | 23 |
6 files changed, 619 insertions, 562 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt index a8334e1cfde7..be8f27d87738 100644 --- a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt +++ b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt @@ -9,8 +9,9 @@ Properties: - compatible Usage: required Value type: <string> - Definition: must be "qcom,cpu-clock-osm-msm8998-v1" or - "qcom,cpu-clock-osm-msm8998-v2". + Definition: must be "qcom,cpu-clock-osm-msm8998-v1", + "qcom,cpu-clock-osm-msm8998-v2" or + "qcom,clk-cpu-osm". - reg Usage: required diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 2148dad33e87..b5dd556b3f96 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -219,4 +219,16 @@ config QCOM_A53 Say Y if you want to support CPU frequency scaling on devices such as MSM8916. +config CLOCK_CPU_OSM + tristate "OSM CPU Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the osm clock controller. + Operating State Manager (OSM) is a hardware engine used by some + Qualcomm Technologies, Inc. (QTI) SoCs to manage frequency and + voltage scaling in hardware. OSM is capable of controlling + frequency and voltage requests for multiple clusters via the + existence of multiple OSM domains. + Say Y if you want to support osm clocks. + source "drivers/clk/qcom/mdss/Kconfig" diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 176dc3103cdb..a63065c97319 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -37,5 +37,6 @@ obj-$(CONFIG_KRAITCC) += krait-cc.o obj-$(CONFIG_QCOM_A53) += clk-a53.o obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o +obj-$(CONFIG_CLOCK_CPU_OSM) += clk-cpu-osm.o obj-y += mdss/ diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c index f97cd1b03c81..ab6a1384ffbd 100644 --- a/drivers/clk/qcom/clk-cpu-osm.c +++ b/drivers/clk/qcom/clk-cpu-osm.c @@ -22,9 +22,7 @@ #include <linux/err.h> #include <linux/errno.h> #include <linux/clk.h> -#include <linux/clk/msm-clk-provider.h> -#include <linux/clk/msm-clk.h> -#include <linux/clk/msm-clock-generic.h> +#include <linux/clk-provider.h> #include <linux/cpu.h> #include <linux/platform_device.h> #include <linux/of_platform.h> @@ -32,18 +30,20 @@ #include <linux/pm_qos.h> #include <linux/interrupt.h> #include <linux/regulator/driver.h> +#include <linux/regmap.h> #include <linux/uaccess.h> #include <linux/sched.h> - #include <soc/qcom/scm.h> -#include <soc/qcom/clock-pll.h> -#include <soc/qcom/clock-local2.h> -#include <soc/qcom/clock-alpha-pll.h> +#include <dt-bindings/clock/qcom,cpu-osm.h> -#include <dt-bindings/clock/msm-clocks-hwio-cobalt.h> -#include <dt-bindings/clock/msm-clocks-cobalt.h> +#include "common.h" +#include "clk-regmap.h" +#include "clk-rcg.h" -#include "clock.h" +enum { + LMH_LITE_CLK_SRC, + P_XO, +}; enum clk_osm_bases { OSM_BASE, @@ -74,210 +74,192 @@ enum clk_osm_trace_packet_id { TRACE_PACKET3, }; -#define SEQ_REG(n) (0x300 + (n) * 4) -#define MEM_ACC_SEQ_REG_CFG_START(n) (SEQ_REG(12 + (n))) -#define MEM_ACC_SEQ_CONST(n) (n) -#define MEM_ACC_INSTR_COMP(n) (0x67 + ((n) * 0x40)) -#define MEM_ACC_SEQ_REG_VAL_START(n) (SEQ_REG(60 + (n))) -#define SEQ_REG1_MSMCOBALT_V2 0x1048 -#define VERSION_REG 0x0 -#define VERSION_1P1 0x00010100 - -#define OSM_TABLE_SIZE 40 -#define MAX_CLUSTER_CNT 2 -#define MAX_CONFIG 4 -#define LLM_SW_OVERRIDE_CNT 3 - -#define ENABLE_REG 0x1004 -#define INDEX_REG 0x1150 -#define FREQ_REG 0x1154 -#define VOLT_REG 0x1158 -#define OVERRIDE_REG 0x115C -#define SPARE_REG 0x1164 - -#define OSM_CYCLE_COUNTER_CTRL_REG 0x1F00 -#define OSM_CYCLE_COUNTER_STATUS_REG 0x1F04 -#define DCVS_PERF_STATE_DESIRED_REG 0x1F10 -#define DCVS_PERF_STATE_DEVIATION_INTR_STAT 0x1F14 -#define DCVS_PERF_STATE_DEVIATION_INTR_EN 0x1F18 -#define DCVS_PERF_STATE_DEVIATION_INTR_CLEAR 0x1F1C -#define DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_STAT 0x1F20 -#define DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_EN 0x1F24 -#define DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_CLEAR 0x1F28 -#define DCVS_PERF_STATE_MET_INTR_STAT 0x1F2C -#define DCVS_PERF_STATE_MET_INTR_EN 0x1F30 -#define DCVS_PERF_STATE_MET_INTR_CLR 0x1F34 -#define OSM_CORE_TABLE_SIZE 8192 -#define OSM_REG_SIZE 32 - -#define WDOG_DOMAIN_PSTATE_STATUS 0x1c00 -#define WDOG_PROGRAM_COUNTER 0x1c74 - -#define OSM_CYCLE_COUNTER_USE_XO_EDGE_EN BIT(8) -#define PLL_MODE 0x0 -#define PLL_L_VAL 0x4 -#define PLL_USER_CTRL 0xC -#define PLL_CONFIG_CTL_LO 0x10 -#define PLL_TEST_CTL_HI 0x1C -#define PLL_STATUS 0x2C -#define PLL_LOCK_DET_MASK BIT(16) -#define PLL_WAIT_LOCK_TIME_US 10 -#define PLL_WAIT_LOCK_TIME_NS (PLL_WAIT_LOCK_TIME_US * 1000) -#define PLL_MIN_LVAL 43 - -#define CC_ZERO_BEHAV_CTRL 0x100C -#define SPM_CC_DCVS_DISABLE 0x1020 -#define SPM_CC_CTRL 0x1028 -#define SPM_CC_HYSTERESIS 0x101C -#define SPM_CORE_RET_MAPPING 0x1024 -#define CFG_DELAY_VAL_3 0x12C - -#define LLM_FREQ_VOTE_HYSTERESIS 0x102C -#define LLM_VOLT_VOTE_HYSTERESIS 0x1030 -#define LLM_INTF_DCVS_DISABLE 0x1034 - -#define ENABLE_OVERRIDE BIT(0) - -#define ITM_CL0_DISABLE_CL1_ENABLED 0x2 -#define ITM_CL0_ENABLED_CL1_DISABLE 0x1 - -#define APM_MX_MODE 0 -#define APM_APC_MODE BIT(1) -#define APM_MODE_SWITCH_MASK (BVAL(4, 2, 7) | BVAL(1, 0, 3)) -#define APM_MX_MODE_VAL 0 -#define APM_APC_MODE_VAL 0x3 - -#define GPLL_SEL 0x400 -#define PLL_EARLY_SEL 0x500 -#define PLL_MAIN_SEL 0x300 -#define RCG_UPDATE 0x3 -#define RCG_UPDATE_SUCCESS 0x2 -#define PLL_POST_DIV1 0x1F -#define PLL_POST_DIV2 0x11F - -#define LLM_SW_OVERRIDE_REG 0x1038 -#define VMIN_REDUC_ENABLE_REG 0x103C -#define VMIN_REDUC_TIMER_REG 0x1040 -#define PDN_FSM_CTRL_REG 0x1070 -#define CC_BOOST_TIMER_REG0 0x1074 -#define CC_BOOST_TIMER_REG1 0x1078 -#define CC_BOOST_TIMER_REG2 0x107C -#define CC_BOOST_EN_MASK BIT(0) -#define PS_BOOST_EN_MASK BIT(1) -#define DCVS_BOOST_EN_MASK BIT(2) -#define PC_RET_EXIT_DROOP_EN_MASK BIT(3) -#define WFX_DROOP_EN_MASK BIT(4) -#define DCVS_DROOP_EN_MASK BIT(5) -#define LMH_PS_EN_MASK BIT(6) -#define IGNORE_PLL_LOCK_MASK BIT(15) -#define SAFE_FREQ_WAIT_NS 5000 -#define DEXT_DECREMENT_WAIT_NS 1000 -#define DCVS_BOOST_TIMER_REG0 0x1084 -#define DCVS_BOOST_TIMER_REG1 0x1088 -#define DCVS_BOOST_TIMER_REG2 0x108C -#define PS_BOOST_TIMER_REG0 0x1094 -#define PS_BOOST_TIMER_REG1 0x1098 -#define PS_BOOST_TIMER_REG2 0x109C -#define BOOST_PROG_SYNC_DELAY_REG 0x10A0 -#define DROOP_CTRL_REG 0x10A4 -#define DROOP_RELEASE_TIMER_CTRL 0x10A8 -#define DROOP_PROG_SYNC_DELAY_REG 0x10BC -#define DROOP_UNSTALL_TIMER_CTRL_REG 0x10AC -#define DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG 0x10B0 -#define DROOP_WAIT_TO_RELEASE_TIMER_CTRL1_REG 0x10B4 -#define OSM_PLL_SW_OVERRIDE_EN 0x10C0 - -#define PLL_SW_OVERRIDE_DROOP_EN BIT(0) -#define DCVS_DROOP_TIMER_CTRL 0x10B8 -#define SEQ_MEM_ADDR 0x500 -#define SEQ_CFG_BR_ADDR 0x170 -#define MAX_INSTRUCTIONS 256 -#define MAX_BR_INSTRUCTIONS 49 - -#define MAX_MEM_ACC_LEVELS 3 -#define MAX_MEM_ACC_VAL_PER_LEVEL 3 -#define MAX_MEM_ACC_VALUES (MAX_MEM_ACC_LEVELS * \ - MAX_MEM_ACC_VAL_PER_LEVEL) -#define MEM_ACC_APM_READ_MASK 0xff - -#define TRACE_CTRL 0x1F38 -#define TRACE_CTRL_EN_MASK BIT(0) -#define TRACE_CTRL_ENABLE 1 -#define TRACE_CTRL_DISABLE 0 -#define TRACE_CTRL_ENABLE_WDOG_STATUS BIT(30) -#define TRACE_CTRL_PACKET_TYPE_MASK BVAL(2, 1, 3) -#define TRACE_CTRL_PACKET_TYPE_SHIFT 1 -#define TRACE_CTRL_PERIODIC_TRACE_EN_MASK BIT(3) -#define TRACE_CTRL_PERIODIC_TRACE_ENABLE BIT(3) -#define PERIODIC_TRACE_TIMER_CTRL 0x1F3C -#define PERIODIC_TRACE_MIN_NS 1000 -#define PERIODIC_TRACE_MAX_NS 21474836475 -#define PERIODIC_TRACE_DEFAULT_NS 1000000 - -#define PLL_DD_USER_CTL_LO_ENABLE 0x0f04c408 -#define PLL_DD_USER_CTL_LO_DISABLE 0x1f04c41f -#define PLL_DD_D0_USER_CTL_LO 0x17916208 -#define PLL_DD_D1_USER_CTL_LO 0x17816208 - -#define PWRCL_EFUSE_SHIFT 0 -#define PWRCL_EFUSE_MASK 0 -#define PERFCL_EFUSE_SHIFT 29 -#define PERFCL_EFUSE_MASK 0x7 - -#define MSMCOBALTV1_PWRCL_BOOT_RATE 1478400000 -#define MSMCOBALTV1_PERFCL_BOOT_RATE 1536000000 -#define MSMCOBALTV2_PWRCL_BOOT_RATE 1555200000 -#define MSMCOBALTV2_PERFCL_BOOT_RATE 1728000000 +#define SEQ_REG(n) (0x300 + (n) * 4) +#define MEM_ACC_SEQ_REG_CFG_START(n) (SEQ_REG(12 + (n))) +#define MEM_ACC_SEQ_CONST(n) (n) +#define MEM_ACC_INSTR_COMP(n) (0x67 + ((n) * 0x40)) +#define MEM_ACC_SEQ_REG_VAL_START(n) (SEQ_REG(60 + (n))) +#define SEQ_REG1_OFFSET 0x1048 +#define VERSION_REG 0x0 + +#define OSM_TABLE_SIZE 40 +#define MAX_CLUSTER_CNT 2 +#define LLM_SW_OVERRIDE_CNT 3 +#define CORE_COUNT_VAL(val) ((val & GENMASK(18, 16)) >> 16) +#define SINGLE_CORE 1 +#define MAX_CORE_COUNT 4 + +#define ENABLE_REG 0x1004 +#define INDEX_REG 0x1150 +#define FREQ_REG 0x1154 +#define VOLT_REG 0x1158 +#define OVERRIDE_REG 0x115C +#define SPARE_REG 0x1164 + +#define OSM_CYCLE_COUNTER_CTRL_REG 0x1F00 +#define OSM_CYCLE_COUNTER_STATUS_REG 0x1F04 +#define DCVS_PERF_STATE_DESIRED_REG 0x1F10 +#define DCVS_PERF_STATE_DEVIATION_INTR_STAT 0x1F14 +#define DCVS_PERF_STATE_DEVIATION_INTR_EN 0x1F18 +#define DCVS_PERF_STATE_DEVIATION_INTR_CLEAR 0x1F1C +#define DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_STAT 0x1F20 +#define DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_EN 0x1F24 +#define DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_CLEAR 0x1F28 +#define DCVS_PERF_STATE_MET_INTR_STAT 0x1F2C +#define DCVS_PERF_STATE_MET_INTR_EN 0x1F30 +#define DCVS_PERF_STATE_MET_INTR_CLR 0x1F34 +#define OSM_CORE_TABLE_SIZE 8192 +#define OSM_REG_SIZE 32 + +#define WDOG_DOMAIN_PSTATE_STATUS 0x1c00 +#define WDOG_PROGRAM_COUNTER 0x1c74 + +#define OSM_CYCLE_COUNTER_USE_XO_EDGE_EN BIT(8) + +#define PLL_MODE 0x0 +#define PLL_L_VAL 0x4 +#define PLL_USER_CTRL 0xC +#define PLL_CONFIG_CTL_LO 0x10 +#define PLL_TEST_CTL_HI 0x1C +#define PLL_STATUS 0x2C +#define PLL_LOCK_DET_MASK BIT(16) +#define PLL_WAIT_LOCK_TIME_US 10 +#define PLL_WAIT_LOCK_TIME_NS (PLL_WAIT_LOCK_TIME_US * 1000) +#define PLL_MIN_LVAL 43 +#define L_VAL(freq_data) ((freq_data) & GENMASK(7, 0)) + +#define CC_ZERO_BEHAV_CTRL 0x100C +#define SPM_CC_DCVS_DISABLE 0x1020 +#define SPM_CC_CTRL 0x1028 +#define SPM_CC_HYSTERESIS 0x101C +#define SPM_CORE_RET_MAPPING 0x1024 +#define CFG_DELAY_VAL_3 0x12C + +#define LLM_FREQ_VOTE_HYSTERESIS 0x102C +#define LLM_VOLT_VOTE_HYSTERESIS 0x1030 +#define LLM_INTF_DCVS_DISABLE 0x1034 + +#define ENABLE_OVERRIDE BIT(0) + +#define ITM_CL0_DISABLE_CL1_ENABLED 0x2 +#define ITM_CL0_ENABLED_CL1_DISABLE 0x1 + +#define APM_MX_MODE 0 +#define APM_APC_MODE BIT(1) +#define APM_MODE_SWITCH_MASK (BVAL(4, 2, 7) | BVAL(1, 0, 3)) +#define APM_MX_MODE_VAL 0 +#define APM_APC_MODE_VAL 0x3 + +#define GPLL_SEL 0x400 +#define PLL_EARLY_SEL 0x500 +#define PLL_MAIN_SEL 0x300 +#define RCG_UPDATE 0x3 +#define RCG_UPDATE_SUCCESS 0x2 +#define PLL_POST_DIV1 0x1F +#define PLL_POST_DIV2 0x11F + +#define LLM_SW_OVERRIDE_REG 0x1038 +#define VMIN_REDUC_ENABLE_REG 0x103C +#define VMIN_REDUC_TIMER_REG 0x1040 +#define PDN_FSM_CTRL_REG 0x1070 +#define CC_BOOST_TIMER_REG0 0x1074 +#define CC_BOOST_TIMER_REG1 0x1078 +#define CC_BOOST_TIMER_REG2 0x107C +#define CC_BOOST_EN_MASK BIT(0) +#define PS_BOOST_EN_MASK BIT(1) +#define DCVS_BOOST_EN_MASK BIT(2) +#define PC_RET_EXIT_DROOP_EN_MASK BIT(3) +#define WFX_DROOP_EN_MASK BIT(4) +#define DCVS_DROOP_EN_MASK BIT(5) +#define LMH_PS_EN_MASK BIT(6) +#define IGNORE_PLL_LOCK_MASK BIT(15) +#define SAFE_FREQ_WAIT_NS 5000 +#define DEXT_DECREMENT_WAIT_NS 1000 +#define DCVS_BOOST_TIMER_REG0 0x1084 +#define DCVS_BOOST_TIMER_REG1 0x1088 +#define DCVS_BOOST_TIMER_REG2 0x108C +#define PS_BOOST_TIMER_REG0 0x1094 +#define PS_BOOST_TIMER_REG1 0x1098 +#define PS_BOOST_TIMER_REG2 0x109C +#define BOOST_PROG_SYNC_DELAY_REG 0x10A0 +#define DROOP_CTRL_REG 0x10A4 +#define DROOP_RELEASE_TIMER_CTRL 0x10A8 +#define DROOP_PROG_SYNC_DELAY_REG 0x10BC +#define DROOP_UNSTALL_TIMER_CTRL_REG 0x10AC +#define DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG 0x10B0 +#define DROOP_WAIT_TO_RELEASE_TIMER_CTRL1_REG 0x10B4 +#define OSM_PLL_SW_OVERRIDE_EN 0x10C0 + +#define PLL_SW_OVERRIDE_DROOP_EN BIT(0) +#define DCVS_DROOP_TIMER_CTRL 0x10B8 +#define SEQ_MEM_ADDR 0x500 +#define SEQ_CFG_BR_ADDR 0x170 +#define MAX_INSTRUCTIONS 256 +#define MAX_BR_INSTRUCTIONS 49 + +#define MAX_MEM_ACC_LEVELS 3 +#define MAX_MEM_ACC_VAL_PER_LEVEL 3 +#define MAX_MEM_ACC_VALUES (MAX_MEM_ACC_LEVELS * \ + MAX_MEM_ACC_VAL_PER_LEVEL) +#define MEM_ACC_APM_READ_MASK 0xff + +#define TRACE_CTRL 0x1F38 +#define TRACE_CTRL_EN_MASK BIT(0) +#define TRACE_CTRL_ENABLE 1 +#define TRACE_CTRL_DISABLE 0 +#define TRACE_CTRL_ENABLE_WDOG_STATUS BIT(30) +#define TRACE_CTRL_PACKET_TYPE_MASK BVAL(2, 1, 3) +#define TRACE_CTRL_PACKET_TYPE_SHIFT 1 +#define TRACE_CTRL_PERIODIC_TRACE_EN_MASK BIT(3) +#define TRACE_CTRL_PERIODIC_TRACE_ENABLE BIT(3) +#define PERIODIC_TRACE_TIMER_CTRL 0x1F3C +#define PERIODIC_TRACE_MIN_NS 1000 +#define PERIODIC_TRACE_MAX_NS 21474836475ULL +#define PERIODIC_TRACE_DEFAULT_NS 1000000 + +#define PLL_DD_USER_CTL_LO_ENABLE 0x0f04c408 +#define PLL_DD_USER_CTL_LO_DISABLE 0x1f04c41f +#define PLL_DD_D0_USER_CTL_LO 0x17916208 +#define PLL_DD_D1_USER_CTL_LO 0x17816208 + +#define PWRCL_EFUSE_SHIFT 0 +#define PWRCL_EFUSE_MASK 0 +#define PERFCL_EFUSE_SHIFT 29 +#define PERFCL_EFUSE_MASK 0x7 /* ACD registers */ -#define ACD_HW_VERSION 0x0 -#define ACDCR 0x4 -#define ACDTD 0x8 -#define ACDSSCR 0x28 -#define ACD_EXTINT_CFG 0x30 -#define ACD_DCVS_SW 0x34 -#define ACD_GFMUX_CFG 0x3c -#define ACD_READOUT_CFG 0x48 -#define ACD_AUTOXFER_CFG 0x80 -#define ACD_AUTOXFER 0x84 -#define ACD_AUTOXFER_CTL 0x88 -#define ACD_AUTOXFER_STATUS 0x8c -#define ACD_WRITE_CTL 0x90 -#define ACD_WRITE_STATUS 0x94 -#define ACD_READOUT 0x98 - -#define ACD_MASTER_ONLY_REG_ADDR 0x80 -#define ACD_WRITE_CTL_UPDATE_EN BIT(0) -#define ACD_WRITE_CTL_SELECT_SHIFT 1 -#define ACD_GFMUX_CFG_SELECT BIT(0) -#define ACD_AUTOXFER_START_CLEAR 0 -#define ACD_AUTOXFER_START_SET BIT(0) -#define AUTO_XFER_DONE_MASK BIT(0) -#define ACD_DCVS_SW_DCVS_IN_PRGR_SET BIT(0) -#define ACD_DCVS_SW_DCVS_IN_PRGR_CLEAR 0 -#define ACD_LOCAL_TRANSFER_TIMEOUT_NS 500 - -static void __iomem *virt_base; -static void __iomem *debug_base; - -#define lmh_lite_clk_src_source_val 1 - -#define ACD_REG_RELATIVE_ADDR(addr) (addr / 4) +#define ACD_HW_VERSION 0x0 +#define ACDCR 0x4 +#define ACDTD 0x8 +#define ACDSSCR 0x28 +#define ACD_EXTINT_CFG 0x30 +#define ACD_DCVS_SW 0x34 +#define ACD_GFMUX_CFG 0x3c +#define ACD_READOUT_CFG 0x48 +#define ACD_AUTOXFER_CFG 0x80 +#define ACD_AUTOXFER 0x84 +#define ACD_AUTOXFER_CTL 0x88 +#define ACD_AUTOXFER_STATUS 0x8c +#define ACD_WRITE_CTL 0x90 +#define ACD_WRITE_STATUS 0x94 +#define ACD_READOUT 0x98 + +#define ACD_MASTER_ONLY_REG_ADDR 0x80 +#define ACD_WRITE_CTL_UPDATE_EN BIT(0) +#define ACD_WRITE_CTL_SELECT_SHIFT 1 +#define ACD_GFMUX_CFG_SELECT BIT(0) +#define ACD_AUTOXFER_START_CLEAR 0 +#define ACD_AUTOXFER_START_SET BIT(0) +#define AUTO_XFER_DONE_MASK BIT(0) +#define ACD_DCVS_SW_DCVS_IN_PRGR_SET BIT(0) +#define ACD_DCVS_SW_DCVS_IN_PRGR_CLEAR 0 +#define ACD_LOCAL_TRANSFER_TIMEOUT_NS 500 + +#define ACD_REG_RELATIVE_ADDR(addr) (addr / 4) #define ACD_REG_RELATIVE_ADDR_BITMASK(addr) \ - (1 << (ACD_REG_RELATIVE_ADDR(addr))) - -#define FIXDIV(div) (div ? (2 * (div) - 1) : (0)) + (1 << (ACD_REG_RELATIVE_ADDR(addr))) -#define F(f, s, div, m, n) \ - { \ - .freq_hz = (f), \ - .src_clk = &s.c, \ - .m_val = (m), \ - .n_val = ~((n)-(m)) * !!(n), \ - .d_val = ~(n),\ - .div_src_val = BVAL(4, 0, (int)FIXDIV(div)) \ - | BVAL(10, 8, s##_source_val), \ - } +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } static u32 seq_instr[] = { 0xc2005000, 0x2c9e3b21, 0xc0ab2cdc, 0xc2882525, 0x359dc491, @@ -325,10 +307,6 @@ static u32 seq_br_instr[] = { 0x20c, }; -DEFINE_EXT_CLK(xo_ao, NULL); -DEFINE_EXT_CLK(sys_apcsaux_clk_gcc, NULL); -DEFINE_EXT_CLK(lmh_lite_clk_src, NULL); - struct osm_entry { u16 virtual_corner; u16 open_loop_volt; @@ -338,10 +316,20 @@ struct osm_entry { long frequency; }; +static void __iomem *virt_base; static struct dentry *osm_debugfs_base; +static struct regulator *vdd_pwrcl; +static struct regulator *vdd_perfcl; + +static const struct regmap_config osm_qcom_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .fast_io = true, +}; struct clk_osm { - struct clk c; + struct clk_hw hw; struct osm_entry osm_table[OSM_TABLE_SIZE]; struct dentry *debugfs; struct regulator *vdd_reg; @@ -350,13 +338,14 @@ struct clk_osm { unsigned long pbases[NUM_BASES]; spinlock_t lock; - u32 version; u32 cpu_reg_mask; u32 num_entries; u32 cluster_num; u32 irq; u32 apm_crossover_vc; u32 apm_threshold_vc; + u32 mem_acc_crossover_vc; + u32 mem_acc_threshold_vc; u32 cycle_counter_reads; u32 cycle_counter_delay; u32 cycle_counter_factor; @@ -399,9 +388,6 @@ struct clk_osm { bool wdog_trace_en; }; -static bool msmcobalt_v1; -static bool msmcobalt_v2; - static inline void clk_osm_masked_write_reg(struct clk_osm *c, u32 val, u32 offset, u32 mask) { @@ -600,63 +586,86 @@ static inline int clk_osm_count_ns(struct clk_osm *c, u64 nsec) return temp; } -static inline struct clk_osm *to_clk_osm(struct clk *c) +static inline struct clk_osm *to_clk_osm(struct clk_hw *_hw) { - return container_of(c, struct clk_osm, c); + return container_of(_hw, struct clk_osm, hw); } -static enum handoff clk_osm_handoff(struct clk *c) +static long clk_osm_list_rate(struct clk_hw *hw, unsigned n, + unsigned long rate_max) { - return HANDOFF_DISABLED_CLK; + if (n >= hw->init->num_rate_max) + return -ENXIO; + return hw->init->rate_max[n]; } -static long clk_osm_list_rate(struct clk *c, unsigned n) +static inline bool is_better_rate(unsigned long req, unsigned long best, + unsigned long new) { - if (n >= c->num_fmax) - return -ENXIO; - return c->fmax[n]; + if (IS_ERR_VALUE(new)) + return false; + + return (req <= new && new < best) || (best < req && best < new); } -static long clk_osm_round_rate(struct clk *c, unsigned long rate) +static long clk_osm_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) { int i; unsigned long rrate = 0; /* - * If the rate passed in is 0, return the first frequency in - * the FMAX table. + * If the rate passed in is 0, return the first frequency in the + * FMAX table. */ if (!rate) - return c->fmax[0]; + return hw->init->rate_max[0]; - for (i = 0; i < c->num_fmax; i++) { - if (is_better_rate(rate, rrate, c->fmax[i])) { - rrate = c->fmax[i]; - if (rrate == rate) + for (i = 0; i < hw->init->num_rate_max; i++) { + if (is_better_rate(rate, rrate, hw->init->rate_max[i])) { + rrate = hw->init->rate_max[i]; + if (rate == rrate) break; } } + pr_debug("%s: rate %lu, rrate %ld, Rate max %ld\n", __func__, rate, + rrate, hw->init->rate_max[i]); + return rrate; } static int clk_osm_search_table(struct osm_entry *table, int entries, long rate) { - int i; + int quad_core_index, single_core_index = 0; + int core_count; + + for (quad_core_index = 0; quad_core_index < entries; + quad_core_index++) { + core_count = CORE_COUNT_VAL(table[quad_core_index].freq_data); + if (rate == table[quad_core_index].frequency && + core_count == SINGLE_CORE) { + single_core_index = quad_core_index; + continue; + } + if (rate == table[quad_core_index].frequency && + core_count == MAX_CORE_COUNT) + return quad_core_index; + } + if (single_core_index) + return single_core_index; - for (i = 0; i < entries; i++) - if (rate == table[i].frequency) - return i; return -EINVAL; } -static int clk_osm_set_rate(struct clk *c, unsigned long rate) +static int clk_osm_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) { - struct clk_osm *cpuclk = to_clk_osm(c); + struct clk_osm *cpuclk = to_clk_osm(hw); int index = 0; unsigned long r_rate; - r_rate = clk_osm_round_rate(c, rate); + r_rate = clk_osm_round_rate(hw, rate, NULL); if (rate != r_rate) { pr_err("invalid rate requested rate=%ld\n", rate); @@ -675,9 +684,9 @@ static int clk_osm_set_rate(struct clk *c, unsigned long rate) if (cpuclk->llm_sw_overr[0]) { clk_osm_write_reg(cpuclk, cpuclk->llm_sw_overr[0], - LLM_SW_OVERRIDE_REG); + LLM_SW_OVERRIDE_REG); clk_osm_write_reg(cpuclk, cpuclk->llm_sw_overr[1], - LLM_SW_OVERRIDE_REG); + LLM_SW_OVERRIDE_REG); udelay(1); } @@ -687,7 +696,7 @@ static int clk_osm_set_rate(struct clk *c, unsigned long rate) if (cpuclk->llm_sw_overr[0]) { udelay(1); clk_osm_write_reg(cpuclk, cpuclk->llm_sw_overr[2], - LLM_SW_OVERRIDE_REG); + LLM_SW_OVERRIDE_REG); } /* Make sure the write goes through before proceeding */ @@ -696,9 +705,9 @@ static int clk_osm_set_rate(struct clk *c, unsigned long rate) return 0; } -static int clk_osm_enable(struct clk *c) +static int clk_osm_enable(struct clk_hw *hw) { - struct clk_osm *cpuclk = to_clk_osm(c); + struct clk_osm *cpuclk = to_clk_osm(hw); clk_osm_write_reg(cpuclk, 1, ENABLE_REG); @@ -713,95 +722,108 @@ static int clk_osm_enable(struct clk *c) return 0; } +static unsigned long clk_osm_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_osm *cpuclk = to_clk_osm(hw); + int index = 0; + + index = clk_osm_read_reg(cpuclk, DCVS_PERF_STATE_DESIRED_REG); + + pr_debug("%s: Index %d, freq %ld\n", __func__, index, + cpuclk->osm_table[index].frequency); + + /* Convert index to frequency. + * The frequency corresponding to the index requested might not + * be what the clock is actually running at. + * There are other inputs into OSM(acd, LMH, sequencer) + * which might decide the final rate. + */ + return cpuclk->osm_table[index].frequency; +} + static struct clk_ops clk_ops_cpu_osm = { .enable = clk_osm_enable, .set_rate = clk_osm_set_rate, .round_rate = clk_osm_round_rate, .list_rate = clk_osm_list_rate, - .handoff = clk_osm_handoff, + .recalc_rate = clk_osm_recalc_rate, }; -static struct regulator *vdd_pwrcl; -static struct regulator *vdd_perfcl; +static const struct parent_map gcc_parent_map_1[] = { + { P_XO, 0 }, + { LMH_LITE_CLK_SRC, 1 }, +}; -static struct clk_freq_tbl ftbl_osm_clk_src[] = { - F( 200000000, lmh_lite_clk_src, 1.5, 0, 0), - F_END +static const char * const gcc_parent_names_1[] = { + "xo", + "hmss_gpll0_clk_src", }; -static struct rcg_clk osm_clk_src = { - .cmd_rcgr_reg = APCS_COMMON_LMH_CMD_RCGR, - .set_rate = set_rate_hid, +static struct freq_tbl ftbl_osm_clk_src[] = { + F(200000000, LMH_LITE_CLK_SRC, 3, 0, 0), + { } +}; + +/* APCS_COMMON_LMH_CMD_RCGR */ +static struct clk_rcg2 osm_clk_src = { + .cmd_rcgr = 0x0012c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_1, .freq_tbl = ftbl_osm_clk_src, - .current_freq = &rcg_dummy_freq, - .base = &virt_base, - .c = { - .dbg_name = "osm_clk_src", - .ops = &clk_ops_rcg, - CLK_INIT(osm_clk_src.c), + .clkr.hw.init = &(struct clk_init_data){ + .name = "osm_clk_src", + .parent_names = gcc_parent_names_1, + .num_parents = 2, + .ops = &clk_rcg2_ops, }, }; -static struct clk_osm pwrcl_clk = { - .cluster_num = 0, - .cpu_reg_mask = 0x3, - .c = { - .dbg_name = "pwrcl_clk", - .ops = &clk_ops_cpu_osm, - .parent = &xo_ao.c, - CLK_INIT(pwrcl_clk.c), +static struct clk_fixed_factor sys_apcsaux_clk_gcc = { + .div = 1, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "sys_apcsaux_clk_gcc", + .parent_names = (const char *[]){ "hmss_gpll0_clk_src" }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, }, }; -static struct clk_osm perfcl_clk = { - .cluster_num = 1, - .cpu_reg_mask = 0x103, - .c = { - .dbg_name = "perfcl_clk", +static struct clk_init_data osm_clks_init[] = { + [0] = { + .name = "pwrcl_clk", + .parent_names = (const char *[]){ "cxo_a" }, + .num_parents = 1, + .ops = &clk_ops_cpu_osm, + }, + [1] = { + .name = "perfcl_clk", + .parent_names = (const char *[]){ "cxo_a" }, + .num_parents = 1, .ops = &clk_ops_cpu_osm, - .parent = &xo_ao.c, - CLK_INIT(perfcl_clk.c), }, }; -static struct clk_ops clk_ops_cpu_dbg_mux; - -static struct mux_clk cpu_debug_mux = { - .offset = 0x0, - .mask = 0x3, - .shift = 8, - .ops = &mux_reg_ops, - MUX_SRC_LIST( - { &pwrcl_clk.c, 0x00 }, - { &perfcl_clk.c, 0x01 }, - ), - .base = &debug_base, - .c = { - .dbg_name = "cpu_debug_mux", - .ops = &clk_ops_cpu_dbg_mux, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(cpu_debug_mux.c), - }, +static struct clk_osm pwrcl_clk = { + .cluster_num = 0, + .cpu_reg_mask = 0x3, + .hw.init = &osm_clks_init[0], }; -static struct clk_lookup cpu_clocks_osm[] = { - CLK_LIST(pwrcl_clk), - CLK_LIST(perfcl_clk), - CLK_LIST(sys_apcsaux_clk_gcc), - CLK_LIST(xo_ao), - CLK_LIST(osm_clk_src), - CLK_LIST(cpu_debug_mux), +static struct clk_osm perfcl_clk = { + .cluster_num = 1, + .cpu_reg_mask = 0x103, + .hw.init = &osm_clks_init[1], }; -static unsigned long cpu_dbg_mux_get_rate(struct clk *clk) -{ - /* Account for the divider between the clock and the debug mux */ - if (!strcmp(clk->parent->dbg_name, "pwrcl_clk")) - return clk->rate/4; - else if (!strcmp(clk->parent->dbg_name, "perfcl_clk")) - return clk->rate/8; - return clk->rate; -} +static struct clk_hw *osm_qcom_clk_hws[] = { + [SYS_APCSAUX_CLK_GCC] = &sys_apcsaux_clk_gcc.hw, + [PWRCL_CLK] = &pwrcl_clk.hw, + [PERFCL_CLK] = &perfcl_clk.hw, + [OSM_CLK_SRC] = &osm_clk_src.clkr.hw, +}; static void clk_osm_print_osm_table(struct clk_osm *c) { @@ -813,7 +835,7 @@ static void clk_osm_print_osm_table(struct clk_osm *c) for (i = 0; i < c->num_entries; i++) { pll_src = (table[i].freq_data & GENMASK(27, 26)) >> 26; pll_div = (table[i].freq_data & GENMASK(25, 24)) >> 24; - lval = table[i].freq_data & GENMASK(7, 0); + lval = L_VAL(table[i].freq_data); core_count = (table[i].freq_data & GENMASK(18, 16)) >> 16; pr_debug("%3d, %11lu, %2u, %5u, %2u, %6u, %8u, %7u, %5u\n", @@ -828,18 +850,21 @@ static void clk_osm_print_osm_table(struct clk_osm *c) table[i].spare_data); } pr_debug("APM threshold corner=%d, crossover corner=%d\n", - c->apm_threshold_vc, c->apm_crossover_vc); + c->apm_threshold_vc, c->apm_crossover_vc); + pr_debug("MEM-ACC threshold corner=%d, crossover corner=%d\n", + c->mem_acc_threshold_vc, c->mem_acc_crossover_vc); } static int clk_osm_get_lut(struct platform_device *pdev, struct clk_osm *c, char *prop_name) { - struct clk *clk = &c->c; struct device_node *of = pdev->dev.of_node; int prop_len, total_elems, num_rows, i, j, k; int rc = 0; u32 *array; + u32 *fmax_temp; u32 data; + unsigned long abs_fmax = 0; bool last_entry = false; if (!of_find_property(of, prop_name, &prop_len)) { @@ -855,9 +880,9 @@ static int clk_osm_get_lut(struct platform_device *pdev, num_rows = total_elems / NUM_FIELDS; - clk->fmax = devm_kzalloc(&pdev->dev, num_rows * sizeof(unsigned long), - GFP_KERNEL); - if (!clk->fmax) + fmax_temp = devm_kzalloc(&pdev->dev, num_rows * sizeof(unsigned long), + GFP_KERNEL); + if (!fmax_temp) return -ENOMEM; array = devm_kzalloc(&pdev->dev, prop_len, GFP_KERNEL); @@ -893,18 +918,34 @@ static int clk_osm_get_lut(struct platform_device *pdev, c->osm_table[j].spare_data); data = (array[i + FREQ_DATA] & GENMASK(18, 16)) >> 16; - if (!last_entry) { - clk->fmax[k] = array[i]; + if (!last_entry && data == MAX_CORE_COUNT) { + fmax_temp[k] = array[i]; k++; } if (i < total_elems - NUM_FIELDS) i += NUM_FIELDS; - else + else { + abs_fmax = array[i]; last_entry = true; + } + } + fmax_temp[k] = abs_fmax; + + osm_clks_init[c->cluster_num].rate_max = devm_kzalloc(&pdev->dev, + k * sizeof(unsigned long), + GFP_KERNEL); + if (!osm_clks_init[c->cluster_num].rate_max) { + rc = -ENOMEM; + goto exit; } - clk->num_fmax = k; + + for (i = 0; i < k; i++) + osm_clks_init[c->cluster_num].rate_max[i] = fmax_temp[i]; + + osm_clks_init[c->cluster_num].num_rate_max = k; exit: + devm_kfree(&pdev->dev, fmax_temp); devm_kfree(&pdev->dev, array); return rc; } @@ -1192,7 +1233,6 @@ static int clk_osm_resources_init(struct platform_device *pdev) { struct device_node *node; struct resource *res; - struct clk *c; unsigned long pbase; int i, rc = 0; void *vbase; @@ -1213,9 +1253,9 @@ static int clk_osm_resources_init(struct platform_device *pdev) } perfcl_clk.pbases[OSM_BASE] = pwrcl_clk.pbases[OSM_BASE] + - perfcl_clk.cluster_num * OSM_CORE_TABLE_SIZE; + perfcl_clk.cluster_num * OSM_CORE_TABLE_SIZE; perfcl_clk.vbases[OSM_BASE] = pwrcl_clk.vbases[OSM_BASE] + - perfcl_clk.cluster_num * OSM_CORE_TABLE_SIZE; + perfcl_clk.cluster_num * OSM_CORE_TABLE_SIZE; for (i = 0; i < MAX_CLUSTER_CNT; i++) { res = platform_get_resource_byname(pdev, IORESOURCE_MEM, @@ -1244,22 +1284,6 @@ static int clk_osm_resources_init(struct platform_device *pdev) } } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "debug"); - if (!res) { - dev_err(&pdev->dev, "Failed to get debug mux base\n"); - return -EINVAL; - } - - debug_base = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (!debug_base) { - dev_err(&pdev->dev, "Unable to map in debug mux base\n"); - return -ENOMEM; - } - - clk_ops_cpu_dbg_mux = clk_ops_gen_mux; - clk_ops_cpu_dbg_mux.get_rate = cpu_dbg_mux_get_rate; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apcs_common"); if (!res) { dev_err(&pdev->dev, "Failed to get apcs common base\n"); @@ -1272,6 +1296,13 @@ static int clk_osm_resources_init(struct platform_device *pdev) return -ENOMEM; } + osm_clk_src.clkr.regmap = devm_regmap_init_mmio(&pdev->dev, virt_base, + &osm_qcom_regmap_config); + if (IS_ERR(osm_clk_src.clkr.regmap)) { + dev_err(&pdev->dev, "Couldn't get regmap OSM clock\n"); + return PTR_ERR(osm_clk_src.clkr.regmap); + } + /* efuse speed bin fuses are optional */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwrcl_efuse"); @@ -1381,26 +1412,6 @@ static int clk_osm_resources_init(struct platform_device *pdev) return -EINVAL; } - c = devm_clk_get(&pdev->dev, "aux_clk"); - if (IS_ERR(c)) { - rc = PTR_ERR(c); - if (rc != -EPROBE_DEFER) - dev_err(&pdev->dev, "Unable to get aux_clk, rc=%d\n", - rc); - return rc; - } - sys_apcsaux_clk_gcc.c.parent = c; - - c = devm_clk_get(&pdev->dev, "xo_ao"); - if (IS_ERR(c)) { - rc = PTR_ERR(c); - if (rc != -EPROBE_DEFER) - dev_err(&pdev->dev, "Unable to get xo_ao clk, rc=%d\n", - rc); - return rc; - } - xo_ao.c.parent = c; - return 0; } @@ -1490,20 +1501,27 @@ static int clk_osm_resolve_open_loop_voltages(struct clk_osm *c) } static int clk_osm_resolve_crossover_corners(struct clk_osm *c, - struct platform_device *pdev) + struct platform_device *pdev, + const char *mem_acc_prop) { struct regulator *regulator = c->vdd_reg; - int count, vc, i, threshold, rc = 0; + int count, vc, i, apm_threshold; + int mem_acc_threshold = 0; + int rc = 0; u32 corner_volt; rc = of_property_read_u32(pdev->dev.of_node, "qcom,apm-threshold-voltage", - &threshold); + &apm_threshold); if (rc) { pr_info("qcom,apm-threshold-voltage property not specified\n"); return rc; } + if (mem_acc_prop) + of_property_read_u32(pdev->dev.of_node, mem_acc_prop, + &mem_acc_threshold); + /* Determine crossover virtual corner */ count = regulator_count_voltages(regulator); if (count < 0) { @@ -1511,19 +1529,49 @@ static int clk_osm_resolve_crossover_corners(struct clk_osm *c, return count; } - c->apm_crossover_vc = count - 1; + /* + * CPRh corners (in hardware) are ordered: + * 0 - n-1 - for n functional corners + * APM crossover - required for OSM + * [MEM ACC Crossover] - optional + * + * 'count' corresponds to the total number of corners including n + * functional corners, the APM crossover corner, and potentially the + * MEM ACC cross over corner. + */ + if (mem_acc_threshold) { + c->apm_crossover_vc = count - 2; + c->mem_acc_crossover_vc = count - 1; + } else { + c->apm_crossover_vc = count - 1; + } - /* Determine threshold virtual corner */ + /* Determine APM threshold virtual corner */ for (i = 0; i < OSM_TABLE_SIZE; i++) { vc = c->osm_table[i].virtual_corner + 1; corner_volt = regulator_list_corner_voltage(regulator, vc); - if (corner_volt >= threshold) { + if (corner_volt >= apm_threshold) { c->apm_threshold_vc = c->osm_table[i].virtual_corner; break; } } + /* Determine MEM ACC threshold virtual corner */ + if (mem_acc_threshold) { + for (i = 0; i < OSM_TABLE_SIZE; i++) { + vc = c->osm_table[i].virtual_corner + 1; + corner_volt = + regulator_list_corner_voltage(regulator, vc); + + if (corner_volt >= mem_acc_threshold) { + c->mem_acc_threshold_vc + = c->osm_table[i].virtual_corner; + break; + } + } + } + return 0; } @@ -1777,9 +1825,9 @@ static int clk_osm_set_llm_volt_policy(struct platform_device *pdev) /* Enable or disable LLM VOLT DVCS */ regval = val | clk_osm_read_reg(&pwrcl_clk, LLM_INTF_DCVS_DISABLE); - clk_osm_write_reg(&pwrcl_clk, val, LLM_INTF_DCVS_DISABLE); + clk_osm_write_reg(&pwrcl_clk, regval, LLM_INTF_DCVS_DISABLE); regval = val | clk_osm_read_reg(&perfcl_clk, LLM_INTF_DCVS_DISABLE); - clk_osm_write_reg(&perfcl_clk, val, LLM_INTF_DCVS_DISABLE); + clk_osm_write_reg(&perfcl_clk, regval, LLM_INTF_DCVS_DISABLE); /* Wait for the writes to complete */ clk_osm_mb(&perfcl_clk, OSM_BASE); @@ -1820,8 +1868,10 @@ static void clk_osm_program_apm_regs(struct clk_osm *c) static void clk_osm_program_mem_acc_regs(struct clk_osm *c) { + struct osm_entry *table = c->osm_table; int i, curr_level, j = 0; int mem_acc_level_map[MAX_MEM_ACC_LEVELS] = {0, 0, 0}; + int threshold_vc[4]; curr_level = c->osm_table[0].spare_data; for (i = 0; i < c->num_entries; i++) { @@ -1829,7 +1879,8 @@ static void clk_osm_program_mem_acc_regs(struct clk_osm *c) break; if (c->osm_table[i].spare_data != curr_level) { - mem_acc_level_map[j++] = i - 1; + mem_acc_level_map[j++] = + c->osm_table[i].virtual_corner - 1; curr_level = c->osm_table[i].spare_data; } } @@ -1855,16 +1906,49 @@ static void clk_osm_program_mem_acc_regs(struct clk_osm *c) clk_osm_write_reg(c, c->apcs_mem_acc_cfg[i], MEM_ACC_SEQ_REG_CFG_START(i)); } else { + if (c->mem_acc_crossover_vc) + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(88), + c->mem_acc_crossover_vc); + + threshold_vc[0] = mem_acc_level_map[0]; + threshold_vc[1] = mem_acc_level_map[0] + 1; + threshold_vc[2] = mem_acc_level_map[1]; + threshold_vc[3] = mem_acc_level_map[1] + 1; + + /* + * Use dynamic MEM ACC threshold voltage based value for the + * highest MEM ACC threshold if it is specified instead of the + * fixed mapping in the LUT. + */ + if (c->mem_acc_threshold_vc) { + threshold_vc[2] = c->mem_acc_threshold_vc - 1; + threshold_vc[3] = c->mem_acc_threshold_vc; + if (threshold_vc[1] >= threshold_vc[2]) + threshold_vc[1] = threshold_vc[2] - 1; + if (threshold_vc[0] >= threshold_vc[1]) + threshold_vc[0] = threshold_vc[1] - 1; + } + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(55), - mem_acc_level_map[0]); + threshold_vc[0]); scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(56), - mem_acc_level_map[0] + 1); + threshold_vc[1]); scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(57), - mem_acc_level_map[1]); + threshold_vc[2]); scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(58), - mem_acc_level_map[1] + 1); + threshold_vc[3]); /* SEQ_REG(49) = SEQ_REG(28) init by TZ */ } + + /* + * Program L_VAL corresponding to the first virtual + * corner with MEM ACC level 3. + */ + if (c->mem_acc_threshold_vc) + for (i = 0; i < c->num_entries; i++) + if (c->mem_acc_threshold_vc == table[i].virtual_corner) + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(32), + L_VAL(table[i].freq_data)); } void clk_osm_setup_sequencer(struct clk_osm *c) @@ -1895,93 +1979,13 @@ static void clk_osm_setup_cycle_counters(struct clk_osm *c) /* Setup OSM clock to XO ratio */ do_div(ratio, c->xo_clk_rate); val |= BVAL(5, 1, ratio - 1) | OSM_CYCLE_COUNTER_USE_XO_EDGE_EN; + clk_osm_write_reg(c, val, OSM_CYCLE_COUNTER_CTRL_REG); + c->total_cycle_counter = 0; c->prev_cycle_counter = 0; - pr_debug("OSM to XO clock ratio: %d\n", ratio); -} - -static void clk_osm_setup_osm_was(struct clk_osm *c) -{ - u32 cc_hyst; - u32 val; - - if (msmcobalt_v2) - return; - - val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG); - val |= IGNORE_PLL_LOCK_MASK; - cc_hyst = clk_osm_read_reg(c, SPM_CC_HYSTERESIS); - - if (c->secure_init) { - clk_osm_write_reg(c, val, SEQ_REG(47)); - val &= ~IGNORE_PLL_LOCK_MASK; - clk_osm_write_reg(c, val, SEQ_REG(48)); - - clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(42), - SEQ_REG(40)); - clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(43), - SEQ_REG(41)); - clk_osm_write_reg(c, 0x1, SEQ_REG(44)); - clk_osm_write_reg(c, 0x0, SEQ_REG(45)); - clk_osm_write_reg(c, c->pbases[OSM_BASE] + PDN_FSM_CTRL_REG, - SEQ_REG(46)); - - /* C2D/C3 + D2D workaround */ - clk_osm_write_reg(c, c->pbases[OSM_BASE] + SPM_CC_HYSTERESIS, - SEQ_REG(6)); - clk_osm_write_reg(c, cc_hyst, SEQ_REG(7)); - - /* Droop detector PLL lock detect workaround */ - clk_osm_write_reg(c, PLL_DD_USER_CTL_LO_ENABLE, SEQ_REG(4)); - clk_osm_write_reg(c, PLL_DD_USER_CTL_LO_DISABLE, SEQ_REG(5)); - clk_osm_write_reg(c, c->cluster_num == 0 ? PLL_DD_D0_USER_CTL_LO - : PLL_DD_D1_USER_CTL_LO, SEQ_REG(21)); - - /* PLL lock detect and HMSS AHB clock workaround */ - clk_osm_write_reg(c, 0x640, CFG_DELAY_VAL_3); - - /* DxFSM workaround */ - clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17911200 : - 0x17811200, SEQ_REG(22)); - clk_osm_write_reg(c, 0x80800, SEQ_REG(23)); - clk_osm_write_reg(c, 0x179D1100, SEQ_REG(24)); - clk_osm_write_reg(c, 0x11f, SEQ_REG(25)); - clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17912000 : - 0x17811290, SEQ_REG(26)); - clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17911290 : - 0x17811290, SEQ_REG(20)); - clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17811290 : - 0x17911290, SEQ_REG(32)); - clk_osm_write_reg(c, 0x179D4020, SEQ_REG(35)); - clk_osm_write_reg(c, 0x11f, SEQ_REG(25)); - clk_osm_write_reg(c, 0xa, SEQ_REG(86)); - clk_osm_write_reg(c, 0xe, SEQ_REG(87)); - clk_osm_write_reg(c, 0x00400000, SEQ_REG(88)); - clk_osm_write_reg(c, 0x00700000, SEQ_REG(89)); - } else { - scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(47), val); - val &= ~IGNORE_PLL_LOCK_MASK; - scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(48), val); - - /* C2D/C3 + D2D workaround */ - scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(7), - cc_hyst); - - /* Droop detector PLL lock detect workaround */ - scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(4), - PLL_DD_USER_CTL_LO_ENABLE); - } - - if (c->cluster_num == 0) { - val = readl_relaxed(c->vbases[PLL_BASE] + PLL_TEST_CTL_HI) - | BIT(13); - writel_relaxed(val, c->vbases[PLL_BASE] + - PLL_TEST_CTL_HI); - } - /* Ensure writes complete before returning */ - clk_osm_mb(c, OSM_BASE); + pr_debug("OSM to XO clock ratio: %d\n", ratio); } static void clk_osm_setup_fsms(struct clk_osm *c) @@ -2128,7 +2132,7 @@ static void clk_osm_do_additional_setup(struct clk_osm *c, return; dev_info(&pdev->dev, "Performing additional OSM setup due to lack of TZ for cluster=%d\n", - c->cluster_num); + c->cluster_num); clk_osm_write_reg(c, BVAL(23, 16, 0xF), SPM_CC_CTRL); @@ -2157,7 +2161,7 @@ static void clk_osm_do_additional_setup(struct clk_osm *c, /* ITM to OSM handoff */ clk_osm_setup_itm_to_osm_handoff(); - pr_debug("seq_size: %lu, seqbr_size: %lu\n", ARRAY_SIZE(seq_instr), + pr_debug("seq_size: %zu, seqbr_size: %zu\n", ARRAY_SIZE(seq_instr), ARRAY_SIZE(seq_br_instr)); clk_osm_setup_sequencer(&pwrcl_clk); clk_osm_setup_sequencer(&perfcl_clk); @@ -2175,38 +2179,31 @@ static void clk_osm_apm_vc_setup(struct clk_osm *c) clk_osm_write_reg(c, c->apm_threshold_vc, SEQ_REG(1)); clk_osm_write_reg(c, c->apm_crossover_vc, SEQ_REG(72)); clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(1), - SEQ_REG(8)); - clk_osm_write_reg(c, c->apm_threshold_vc, - SEQ_REG(15)); + SEQ_REG(8)); + clk_osm_write_reg(c, c->apm_threshold_vc, SEQ_REG(15)); clk_osm_write_reg(c, c->apm_threshold_vc != 0 ? - c->apm_threshold_vc - 1 : 0xff, - SEQ_REG(31)); + c->apm_threshold_vc - 1 : 0xff, + SEQ_REG(31)); clk_osm_write_reg(c, 0x3b | c->apm_threshold_vc << 6, - SEQ_REG(73)); + SEQ_REG(73)); clk_osm_write_reg(c, 0x39 | c->apm_threshold_vc << 6, - SEQ_REG(76)); + SEQ_REG(76)); /* Ensure writes complete before returning */ clk_osm_mb(c, OSM_BASE); } else { - if (msmcobalt_v1) { - scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(1), - c->apm_threshold_vc); - scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(73), - 0x3b | c->apm_threshold_vc << 6); - } else if (msmcobalt_v2) { + if (c->apm_threshold_vc) clk_osm_write_reg(c, c->apm_threshold_vc, - SEQ_REG1_MSMCOBALT_V2); - } + SEQ_REG1_OFFSET); scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(72), - c->apm_crossover_vc); + c->apm_crossover_vc); scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(15), - c->apm_threshold_vc); + c->apm_threshold_vc); scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(31), - c->apm_threshold_vc != 0 ? - c->apm_threshold_vc - 1 : 0xff); + c->apm_threshold_vc != 0 ? + c->apm_threshold_vc - 1 : 0xff); scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(76), - 0x39 | c->apm_threshold_vc << 6); + 0x39 | c->apm_threshold_vc << 6); } } @@ -2298,11 +2295,12 @@ static int add_opp(struct clk_osm *c, struct device *dev) u32 uv; long rc; int j = 0; - unsigned long min_rate = c->c.fmax[0]; - unsigned long max_rate = c->c.fmax[c->c.num_fmax - 1]; + unsigned long min_rate = c->hw.init->rate_max[0]; + unsigned long max_rate = + c->hw.init->rate_max[c->hw.init->num_rate_max - 1]; while (1) { - rate = c->c.fmax[j++]; + rate = c->hw.init->rate_max[j++]; uv = find_voltage(c, rate); if (uv <= 0) { pr_warn("No voltage for %lu.\n", rate); @@ -2360,12 +2358,12 @@ static struct clk *logical_cpu_to_clk(int cpu) hwid = of_read_number(cell, of_n_addr_cells(cpu_node)); if ((hwid | pwrcl_clk.cpu_reg_mask) == pwrcl_clk.cpu_reg_mask) { - cpu_clk_map[cpu] = &pwrcl_clk.c; - return &pwrcl_clk.c; + cpu_clk_map[cpu] = pwrcl_clk.hw.clk; + return pwrcl_clk.hw.clk; } if ((hwid | perfcl_clk.cpu_reg_mask) == perfcl_clk.cpu_reg_mask) { - cpu_clk_map[cpu] = &perfcl_clk.c; - return &perfcl_clk.c; + cpu_clk_map[cpu] = perfcl_clk.hw.clk; + return perfcl_clk.hw.clk; } fail: @@ -2378,9 +2376,9 @@ static u64 clk_osm_get_cpu_cycle_counter(int cpu) u32 val; unsigned long flags; - if (logical_cpu_to_clk(cpu) == &pwrcl_clk.c) + if (logical_cpu_to_clk(cpu) == pwrcl_clk.hw.clk) c = &pwrcl_clk; - else if (logical_cpu_to_clk(cpu) == &perfcl_clk.c) + else if (logical_cpu_to_clk(cpu) == perfcl_clk.hw.clk) c = &perfcl_clk; else { pr_err("no clock device for CPU=%d\n", cpu); @@ -2409,11 +2407,11 @@ static void populate_opp_table(struct platform_device *pdev) int cpu; for_each_possible_cpu(cpu) { - if (logical_cpu_to_clk(cpu) == &pwrcl_clk.c) { + if (logical_cpu_to_clk(cpu) == pwrcl_clk.hw.clk) { WARN(add_opp(&pwrcl_clk, get_cpu_device(cpu)), "Failed to add OPP levels for power cluster\n"); } - if (logical_cpu_to_clk(cpu) == &perfcl_clk.c) { + if (logical_cpu_to_clk(cpu) == perfcl_clk.hw.clk) { WARN(add_opp(&perfcl_clk, get_cpu_device(cpu)), "Failed to add OPP levels for perf cluster\n"); } @@ -2456,15 +2454,11 @@ static int debugfs_set_wdog_trace(void *data, u64 val) struct clk_osm *c = data; int regval; - if (c->version >= VERSION_1P1) { - regval = clk_osm_read_reg(c, TRACE_CTRL); - regval = val ? regval | TRACE_CTRL_ENABLE_WDOG_STATUS : + regval = clk_osm_read_reg(c, TRACE_CTRL); + regval = val ? regval | TRACE_CTRL_ENABLE_WDOG_STATUS : regval & ~TRACE_CTRL_ENABLE_WDOG_STATUS; - clk_osm_write_reg(c, regval, TRACE_CTRL); - c->wdog_trace_en = val ? true : false; - } else { - pr_info("wdog status registers enabled by default\n"); - } + clk_osm_write_reg(c, regval, TRACE_CTRL); + c->wdog_trace_en = val ? true : false; return 0; } @@ -2618,7 +2612,7 @@ static int debugfs_set_trace_periodic_timer(void *data, u64 val) struct clk_osm *c = data; if (val < PERIODIC_TRACE_MIN_NS || val > PERIODIC_TRACE_MAX_NS) { - pr_err("supported periodic trace periods=%d-%ld ns\n", + pr_err("supported periodic trace periods=%d-%lld ns\n", PERIODIC_TRACE_MIN_NS, PERIODIC_TRACE_MAX_NS); return 0; } @@ -2760,7 +2754,7 @@ static void populate_debugfs_dir(struct clk_osm *c) } } - c->debugfs = debugfs_create_dir(c->c.dbg_name, osm_debugfs_base); + c->debugfs = debugfs_create_dir(c->hw.init->name, osm_debugfs_base); if (IS_ERR_OR_NULL(c->debugfs)) { pr_err("osm debugfs directory creation failed\n"); return; @@ -2977,31 +2971,60 @@ static int clk_osm_acd_init(struct clk_osm *c) static unsigned long init_rate = 300000000; static unsigned long osm_clk_init_rate = 200000000; +static unsigned long pwrcl_boot_rate = 1401600000; +static unsigned long perfcl_boot_rate = 1747200000; -static int cpu_clock_osm_driver_probe(struct platform_device *pdev) +static int clk_cpu_osm_driver_probe(struct platform_device *pdev) { - int rc, cpu; + int rc, cpu, i; int speedbin = 0, pvs_ver = 0; u32 pte_efuse; - char pwrclspeedbinstr[] = "qcom,pwrcl-speedbin0-v0"; + int num_clks = ARRAY_SIZE(osm_qcom_clk_hws); + struct clk *clk; + struct clk *ext_xo_clk, *ext_hmss_gpll0_clk_src; + struct device *dev = &pdev->dev; + struct clk_onecell_data *clk_data; char perfclspeedbinstr[] = "qcom,perfcl-speedbin0-v0"; + char pwrclspeedbinstr[] = "qcom,pwrcl-speedbin0-v0"; struct cpu_cycle_counter_cb cb = { .get_cpu_cycle_counter = clk_osm_get_cpu_cycle_counter, }; - if (of_find_compatible_node(NULL, NULL, - "qcom,cpu-clock-osm-msmcobalt-v1")) { - msmcobalt_v1 = true; - } else if (of_find_compatible_node(NULL, NULL, - "qcom,cpu-clock-osm-msmcobalt-v2")) { - msmcobalt_v2 = true; + /* + * Require the RPM-XO clock and GCC-HMSS-GPLL0 clocks to be registererd + * before OSM. + */ + ext_xo_clk = devm_clk_get(dev, "xo_a"); + if (IS_ERR(ext_xo_clk)) { + if (PTR_ERR(ext_xo_clk) != -EPROBE_DEFER) + dev_err(dev, "Unable to get xo clock\n"); + return PTR_ERR(ext_xo_clk); + } + + ext_hmss_gpll0_clk_src = devm_clk_get(dev, "aux_clk"); + if (IS_ERR(ext_hmss_gpll0_clk_src)) { + if (PTR_ERR(ext_hmss_gpll0_clk_src) != -EPROBE_DEFER) + dev_err(dev, "Unable to get aux_clk clock\n"); + return PTR_ERR(ext_hmss_gpll0_clk_src); } + clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data), + GFP_KERNEL); + if (!clk_data) + goto exit; + + clk_data->clks = devm_kzalloc(&pdev->dev, (num_clks * + sizeof(struct clk *)), GFP_KERNEL); + if (!clk_data->clks) + goto clk_err; + + clk_data->clk_num = num_clks; + rc = clk_osm_resources_init(pdev); if (rc) { if (rc != -EPROBE_DEFER) dev_err(&pdev->dev, "resources init failed, rc=%d\n", - rc); + rc); return rc; } @@ -3011,17 +3034,11 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) return rc; } - if ((pwrcl_clk.secure_init || perfcl_clk.secure_init) && - msmcobalt_v2) { - pr_err("unsupported configuration for msmcobalt v2\n"); - return -EINVAL; - } - if (pwrcl_clk.vbases[EFUSE_BASE]) { /* Multiple speed-bins are supported */ pte_efuse = readl_relaxed(pwrcl_clk.vbases[EFUSE_BASE]); speedbin = ((pte_efuse >> PWRCL_EFUSE_SHIFT) & - PWRCL_EFUSE_MASK); + PWRCL_EFUSE_MASK); snprintf(pwrclspeedbinstr, ARRAY_SIZE(pwrclspeedbinstr), "qcom,pwrcl-speedbin%d-v%d", speedbin, pvs_ver); } @@ -3029,8 +3046,7 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) dev_info(&pdev->dev, "using pwrcl speed bin %u and pvs_ver %d\n", speedbin, pvs_ver); - rc = clk_osm_get_lut(pdev, &pwrcl_clk, - pwrclspeedbinstr); + rc = clk_osm_get_lut(pdev, &pwrcl_clk, pwrclspeedbinstr); if (rc) { dev_err(&pdev->dev, "Unable to get OSM LUT for power cluster, rc=%d\n", rc); @@ -3041,7 +3057,7 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) /* Multiple speed-bins are supported */ pte_efuse = readl_relaxed(perfcl_clk.vbases[EFUSE_BASE]); speedbin = ((pte_efuse >> PERFCL_EFUSE_SHIFT) & - PERFCL_EFUSE_MASK); + PERFCL_EFUSE_MASK); snprintf(perfclspeedbinstr, ARRAY_SIZE(perfclspeedbinstr), "qcom,perfcl-speedbin%d-v%d", speedbin, pvs_ver); } @@ -3074,13 +3090,14 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) return rc; } - rc = clk_osm_resolve_crossover_corners(&pwrcl_clk, pdev); + rc = clk_osm_resolve_crossover_corners(&pwrcl_clk, pdev, NULL); if (rc) dev_info(&pdev->dev, "No APM crossover corner programmed\n"); - rc = clk_osm_resolve_crossover_corners(&perfcl_clk, pdev); + rc = clk_osm_resolve_crossover_corners(&perfcl_clk, pdev, + "qcom,perfcl-apcs-mem-acc-threshold-voltage"); if (rc) - dev_info(&pdev->dev, "No APM crossover corner programmed\n"); + dev_info(&pdev->dev, "No MEM-ACC crossover corner programmed\n"); clk_osm_setup_cycle_counters(&pwrcl_clk); clk_osm_setup_cycle_counters(&perfcl_clk); @@ -3146,11 +3163,7 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) if (rc) pr_err("Debug IRQ not set for perfcl\n"); - clk_osm_setup_osm_was(&pwrcl_clk); - clk_osm_setup_osm_was(&perfcl_clk); - - if (of_property_read_bool(pdev->dev.of_node, - "qcom,osm-pll-setup")) { + if (of_property_read_bool(pdev->dev.of_node, "qcom,osm-pll-setup")) { clk_osm_setup_cluster_pll(&pwrcl_clk); clk_osm_setup_cluster_pll(&perfcl_clk); } @@ -3176,12 +3189,22 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) atomic_notifier_chain_register(&panic_notifier_list, &perfcl_clk.panic_notifier); - rc = of_msm_clock_register(pdev->dev.of_node, cpu_clocks_osm, - ARRAY_SIZE(cpu_clocks_osm)); + /* Register OSM pwr and perf clocks with Clock Framework */ + for (i = 0; i < num_clks; i++) { + clk = devm_clk_register(&pdev->dev, osm_qcom_clk_hws[i]); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "Unable to register CPU clock at index %d\n", + i); + return PTR_ERR(clk); + } + clk_data->clks[i] = clk; + } + + rc = of_clk_add_provider(pdev->dev.of_node, of_clk_src_onecell_get, + clk_data); if (rc) { - dev_err(&pdev->dev, "Unable to register CPU clocks, rc=%d\n", - rc); - return rc; + dev_err(&pdev->dev, "Unable to register CPU clocks\n"); + goto provider_err; } /* @@ -3189,15 +3212,15 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) * frequency before enabling OSM. LUT index 0 is always sourced from * this clock. */ - rc = clk_set_rate(&sys_apcsaux_clk_gcc.c, init_rate); + rc = clk_set_rate(sys_apcsaux_clk_gcc.hw.clk, init_rate); if (rc) { dev_err(&pdev->dev, "Unable to set init rate on hmss_gpll0, rc=%d\n", rc); return rc; } - clk_prepare_enable(&sys_apcsaux_clk_gcc.c); + clk_prepare_enable(sys_apcsaux_clk_gcc.hw.clk); - rc = clk_set_rate(&osm_clk_src.c, osm_clk_init_rate); + rc = clk_set_rate(osm_clk_src.clkr.hw.clk, osm_clk_init_rate); if (rc) { dev_err(&pdev->dev, "Unable to set init rate on osm_clk, rc=%d\n", rc); @@ -3205,14 +3228,14 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) } /* Make sure index zero is selected */ - rc = clk_set_rate(&pwrcl_clk.c, init_rate); + rc = clk_set_rate(pwrcl_clk.hw.clk, init_rate); if (rc) { dev_err(&pdev->dev, "Unable to set init rate on pwr cluster, rc=%d\n", rc); goto exit2; } - rc = clk_set_rate(&perfcl_clk.c, init_rate); + rc = clk_set_rate(perfcl_clk.hw.clk, init_rate); if (rc) { dev_err(&pdev->dev, "Unable to set init rate on perf cluster, rc=%d\n", rc); @@ -3228,27 +3251,20 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) } /* Set final boot rate */ - rc = clk_set_rate(&pwrcl_clk.c, msmcobalt_v1 ? - MSMCOBALTV1_PWRCL_BOOT_RATE : - MSMCOBALTV2_PWRCL_BOOT_RATE); + rc = clk_set_rate(pwrcl_clk.hw.clk, pwrcl_boot_rate); if (rc) { dev_err(&pdev->dev, "Unable to set boot rate on pwr cluster, rc=%d\n", rc); goto exit2; } - rc = clk_set_rate(&perfcl_clk.c, msmcobalt_v1 ? - MSMCOBALTV1_PERFCL_BOOT_RATE : - MSMCOBALTV2_PERFCL_BOOT_RATE); + rc = clk_set_rate(perfcl_clk.hw.clk, perfcl_boot_rate); if (rc) { dev_err(&pdev->dev, "Unable to set boot rate on perf cluster, rc=%d\n", rc); goto exit2; } - pwrcl_clk.version = clk_osm_read_reg(&pwrcl_clk, VERSION_REG); - perfcl_clk.version = clk_osm_read_reg(&perfcl_clk, VERSION_REG); - populate_opp_table(pdev); populate_debugfs_dir(&pwrcl_clk); populate_debugfs_dir(&perfcl_clk); @@ -3263,39 +3279,42 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) return 0; exit2: - clk_disable_unprepare(&sys_apcsaux_clk_gcc.c); + clk_disable_unprepare(sys_apcsaux_clk_gcc.hw.clk); +provider_err: + if (clk_data) + devm_kfree(&pdev->dev, clk_data->clks); +clk_err: + devm_kfree(&pdev->dev, clk_data); exit: - dev_err(&pdev->dev, "OSM driver failed to initialize, rc=%d\n", - rc); + dev_err(&pdev->dev, "OSM driver failed to initialize, rc=%d\n", rc); panic("Unable to Setup OSM"); } static const struct of_device_id match_table[] = { - { .compatible = "qcom,cpu-clock-osm-msmcobalt-v1" }, - { .compatible = "qcom,cpu-clock-osm-msmcobalt-v2" }, + { .compatible = "qcom,clk-cpu-osm" }, {} }; -static struct platform_driver cpu_clock_osm_driver = { - .probe = cpu_clock_osm_driver_probe, +static struct platform_driver clk_cpu_osm_driver = { + .probe = clk_cpu_osm_driver_probe, .driver = { - .name = "cpu-clock-osm", + .name = "clk-cpu-osm", .of_match_table = match_table, .owner = THIS_MODULE, }, }; -static int __init cpu_clock_osm_init(void) +static int __init clk_cpu_osm_init(void) { - return platform_driver_register(&cpu_clock_osm_driver); + return platform_driver_register(&clk_cpu_osm_driver); } -arch_initcall(cpu_clock_osm_init); +arch_initcall(clk_cpu_osm_init); -static void __exit cpu_clock_osm_exit(void) +static void __exit clk_cpu_osm_exit(void) { - platform_driver_unregister(&cpu_clock_osm_driver); + platform_driver_unregister(&clk_cpu_osm_driver); } -module_exit(cpu_clock_osm_exit); +module_exit(clk_cpu_osm_exit); MODULE_DESCRIPTION("CPU clock driver for OSM"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h index 841367eb21ff..76c010970b51 100644 --- a/drivers/clk/qcom/common.h +++ b/drivers/clk/qcom/common.h @@ -137,6 +137,7 @@ struct clk_debug_mux { }; #define BM(msb, lsb) (((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb) +#define BVAL(msb, lsb, val) (((val) << lsb) & BM(msb, lsb)) #define to_clk_measure(_hw) container_of((_hw), struct clk_debug_mux, hw) diff --git a/include/dt-bindings/clock/qcom,cpu-osm.h b/include/dt-bindings/clock/qcom,cpu-osm.h new file mode 100644 index 000000000000..71745fab287a --- /dev/null +++ b/include/dt-bindings/clock/qcom,cpu-osm.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DT_BINDINGS_CLK_MSM_CPU_OSM_H +#define _DT_BINDINGS_CLK_MSM_CPU_OSM_H + +/* CPU clock IDs */ +#define SYS_APCSAUX_CLK_GCC 0 +#define PWRCL_CLK 1 +#define PERFCL_CLK 2 +#define OSM_CLK_SRC 3 + +#endif |