// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 Samsung Electronics Co., Ltd.
* Author: Lukasz Luba <l.luba@partner.samsung.com>
*/
#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/devfreq.h>
#include <linux/devfreq-event.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/of.h>
#include <linux/pm_opp.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include "../jedec_ddr.h"
#include "../of_memory.h"
static int irqmode;
module_param(irqmode, int, 0644);
MODULE_PARM_DESC(irqmode, "Enable IRQ mode (0=off [default], 1=on)");
#define EXYNOS5_DREXI_TIMINGAREF (0x0030)
#define EXYNOS5_DREXI_TIMINGROW0 (0x0034)
#define EXYNOS5_DREXI_TIMINGDATA0 (0x0038)
#define EXYNOS5_DREXI_TIMINGPOWER0 (0x003C)
#define EXYNOS5_DREXI_TIMINGROW1 (0x00E4)
#define EXYNOS5_DREXI_TIMINGDATA1 (0x00E8)
#define EXYNOS5_DREXI_TIMINGPOWER1 (0x00EC)
#define CDREX_PAUSE (0x2091c)
#define CDREX_LPDDR3PHY_CON3 (0x20a20)
#define CDREX_LPDDR3PHY_CLKM_SRC (0x20700)
#define EXYNOS5_TIMING_SET_SWI BIT(28)
#define USE_MX_MSPLL_TIMINGS (1)
#define USE_BPLL_TIMINGS (0)
#define EXYNOS5_AREF_NORMAL (0x2e)
#define DREX_PPCCLKCON (0x0130)
#define DREX_PEREV2CONFIG (0x013c)
#define DREX_PMNC_PPC (0xE000)
#define DREX_CNTENS_PPC (0xE010)
#define DREX_CNTENC_PPC (0xE020)
#define DREX_INTENS_PPC (0xE030)
#define DREX_INTENC_PPC (0xE040)
#define DREX_FLAG_PPC (0xE050)
#define DREX_PMCNT2_PPC (0xE130)
/*
* A value for register DREX_PMNC_PPC which should be written to reset
* the cycle counter CCNT (a reference wall clock). It sets zero to the
* CCNT counter.
*/
#define CC_RESET BIT(2)
/*
* A value for register DREX_PMNC_PPC which does the reset of all performance
* counters to zero.
*/
#define PPC_COUNTER_RESET BIT(1)
/*
* Enables all configured counters (including cycle counter). The value should
* be written to the register DREX_PMNC_PPC.
*/
#define PPC_ENABLE BIT(0)
/* A value for register DREX_PPCCLKCON which enables performance events clock.
* Must be written before first access to the performance counters register
* set, otherwise it could crash.
*/
#define PEREV_CLK_EN BIT(0)
/*
* Values which are used to enable counters, interrupts or configure flags of
* the performance counters. They configure counter 2 and cycle counter.
*/
#define PERF_CNT2 BIT(2)
#define PERF_CCNT BIT(31)
/*
* Performance event types which are used for setting the preferred event
* to track in the counters.
* There is a set of different types, the values are from range 0 to 0x6f.
* These settings should be written to the configuration register which manages
* the type of the event (register DREX_PEREV2CONFIG).
*/
#define READ_TRANSFER_CH0 (0x6d)
#define READ_TRANSFER_CH1 (0x6f)
#define PERF_COUNTER_START_VALUE 0xff000000
#define PERF_EVENT_UP_DOWN_THRESHOLD 900000000ULL
/**
* struct dmc_opp_table - Operating level desciption
* @freq_hz: target frequency in Hz
* @volt_uv: target voltage in uV
*
* Covers frequency and voltage settings of the DMC operating mode.
*/
struct dmc_opp_table {
u32 freq_hz;
u32 volt_uv;
};
/**
* struct exynos5_dmc - main structure describing DMC device
* @dev: DMC device
* @df: devfreq device structure returned by devfreq framework
* @gov_data: configuration of devfreq governor
* @base_drexi0: DREX0 registers mapping
* @base_drexi1: DREX1 registers mapping
* @clk_regmap: regmap for clock controller registers
* @lock: protects curr_rate and frequency/voltage setting section
* @curr_rate: current frequency
* @curr_volt: current voltage
* @opp: OPP table
* @opp_count: number of 'opp' elements
* @timings_arr_size: number of 'timings' elements
* @timing_row: values for timing row register, for each OPP
* @timing_data: values for timing data register, for each OPP
* @timing_power: balues for timing power register, for each OPP
* @timings: DDR memory timings, from device tree
* @min_tck: DDR memory minimum timing values, from device tree
* @bypass_timing_row: value for timing row register for bypass timings
* @bypass_timing_data: value for timing data register for bypass timings
* @bypass_timing_power: value for timing power register for bypass
* timings
* @vdd_mif: Memory interface regulator
* @fout_spll: clock: SPLL
* @fout_bpll: clock: BPLL
* @mout_spll: clock: mux SPLL
* @mout_bpll: clock: mux BPLL
* @mout_mclk_cdrex: clock: mux mclk_cdrex
* @mout_mx_mspll_ccore: clock: mux mx_mspll_ccore
* @counter: devfreq events
* @num_counters: number of 'counter' elements
* @last_overflow_ts: time (in ns) of last overflow of each DREX
* @load: utilization in percents
* @total: total time between devfreq events
* @in_irq_mode: whether running in interrupt mode (true)
* or polling (false)
*
* The main structure for the Dynamic Memory Controller which covers clocks,
* memory regions, HW information, parameters and current operating mode.
*/
struct exynos5_dmc {
struct device *dev;
struct devfreq *df;
struct devfreq_simple_ondemand_data gov_data;
void __iomem *base_drexi0;
void __iome
|