// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 Samsung Electronics Co., Ltd.
* Author: Lukasz Luba <l.luba@partner.samsung.com>
*/
#include <linux/clk.h>
#include <linux/devfreq.h>
#include <linux/devfreq-event.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_device.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"
#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)
/**
* struct dmc_opp_table - Operating level desciption
*
* 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
*
* 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 __iomem *base_drexi1;
struct regmap *clk_regmap;
struct mutex lock;
unsigned long curr_rate;
unsigned long curr_volt;
unsigned long bypass_rate;
struct dmc_opp_table *opp;
struct dmc_opp_table opp_bypass;
int opp_count;
u32 timings_arr_size;
u32 *timing_row;
u32 *timing_data;
u32 *timing_power;
const struct lpddr3_timings *timings;
const struct lpddr3_min_tck *min_tck;
u32 bypass_timing_row;
u32 bypass_timing_data;
u32 bypass_timing_power;
struct regulator *vdd_mif;
struct clk *fout_spll;
struct clk *fout_bpll;
struct clk *mout_spll;
struct clk *mout_bpll;
struct clk *mout_mclk_cdrex;
struct clk *mout_mx_mspll_ccore;
struct clk *mx_mspll_ccore_phy;
struct clk *mout_mx_mspll_ccore_phy;
struct devfreq_event_dev **counter;
int num_counters;
};
#define TIMING_FIELD(t_name, t_bit_beg, t_bit_end) \
{ .name = t_name, .bit_beg = t_bit_beg, .bit_end = t_bit_end }
#define TIMING_VAL2REG(timing, t_val) \
({ \
u32 __val; \
__val = (t_val) << (timing)->bit_beg; \
__val; \
})
struct timing_reg {
char *name;
int bit_beg;
int bit_end;
unsigned int val;
};
static const struct timing_reg timing_row[] = {
TIMING_FIELD("tRFC", 24, 31),
TIMING_FIELD("tRRD", 20, 23),
TIMING_FIELD("tRP", 16, 19),
TIMING_FIELD("tRCD", 12, 15),
TIMING_FIELD("tRC", 6