blob: e4af017ffe72c3681d83e214c02e77a3fae501be [file] [log] [blame]
/*
* mck_memorybus: devfreq device driver for MCK memory controller.
*
* Copyright (C) 2013 Marvell International Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __LINUX_MCK_MEMORYBUS_H__
#define __LINUX_MCK_MEMORYBUS_H__
#include <linux/pm_qos.h>
#define DDR_FREQ_MAX 20
#define DEFAULT_MCK_BASE_ADDR (0xc0100000)
#define DEFAULT_MCK_REG_SIZE (SZ_2K)
#define DEFAULT_PERCNT_IN_USE (4)
#define MCK4_VER_SHIFT (12)
#define MCK4_VER_MASK (0xf << MCK4_VER_SHIFT)
#define MCK4_SDRAM_CTRL4 (0x058)
#define MCK4_SDRAM_CTRL4_BL_SHIFT (22)
#define MCK4_SDRAM_CTRL4_BL_MASK (0x3 << MCK4_SDRAM_CTRL4_BL_SHIFT)
#define MCK4_PERF_CONFIG (0x440)
#define MCK4_PERF_STATUS (0x444)
#define MCK4_PERF_CONTRL (0x448)
#define MCK4_PERF_CNT_0 (0x450)
#define MCK4_PERF_CNT_1 (0x454)
#define MCK4_PERF_CNT_2 (0x458)
#define MCK4_PERF_CNT_3 (0x45C)
#define MCK4_PERF_CNT_BASE MCK4_PERF_CNT_0
#define MCK4_INTR_STATUS (0x480)
#define MCK4_INTR_EN (0x484)
#define MCK4_PERCNT_NUM (4)
#define MCK5_VER_SHIFT (24)
#define MCK5_VER_MASK (0xf << MCK5_VER_SHIFT)
#define MCK5_WCB_DRAINING (0x1 << 28)
#define MCK5_WP_STATUS (0x10)
#define MCK5_WCB_DRAIN_REQ (0x1 << 1)
#define MCK5_USER_CMD0 (0x20)
#define MCK5_CH0_SDRAM_CFG1 (0x300)
#define MCK5_CH0_SDRAM_CFG1_BL_SHIFT (20)
#define MCK5_CH0_SDRAM_CFG1_BL_MASK (0x3 << MCK5_CH0_SDRAM_CFG1_BL_SHIFT)
#define MCK5_PERF_CONFIG (0x100)
#define MCK5_PERF_STATUS (0x108)
#define MCK5_PERF_CONTRL (0x10C)
#define MCK5_PERF_CNT_0 (0x110)
#define MCK5_PERF_CNT_1 (0x114)
#define MCK5_PERF_CNT_2 (0x118)
#define MCK5_PERF_CNT_3 (0x11C)
#define MCK5_PERF_CNT_4 (0x120)
#define MCK5_PERF_CNT_5 (0x124)
#define MCK5_PERF_CNT_6 (0x128)
#define MCK5_PERF_CNT_7 (0x12C)
#define MCK5_PERF_CNT_BASE MCK5_PERF_CNT_0
#define MCK5_INTR_STATUS (0x140)
#define MCK5_INTR_EN (0x144)
#define MCK5_PERCNT_NUM (8)
enum mck_version {
MCK_UNKNOWN = 0,
MCK4 = 4,
MCK5 = 5,
};
/* struct of pmu related registers' offset */
struct mck_pmu_regs_offset {
unsigned int cfg; /* PC Configuration register */
unsigned int cnt_stat; /* PC Status register */
unsigned int ctrl; /* PC Control register */
unsigned int cnt_base; /* PC register 0 */
unsigned int intr_stat; /* MCK Interrupt Status register */
unsigned int intr_en; /* MCK Interrupt Enable register*/
};
/*
* reg[0] ddr_totalticks
* reg[1] ddr_DPC_idle
* reg[2] ddr_rw_cmd
* reg[3] ddr_nobus_notidle
*/
struct perf_counters {
#ifdef CONFIG_64BIT
u64 *reg;
#else
u32 *reg;
#endif
};
struct mck_ppmu {
void __iomem *hw_base;
/* the version of mck controller */
unsigned int version;
/* number of performance counters which are used for profiler */
unsigned int pmucnt_in_use;
/* offset of all pmu related registers */
struct mck_pmu_regs_offset mck_regs;
/*
* SW u64 performance counters for each DDR frequencies.
* It can store all events number from SOD without overflow.
* To get a accurate value, please call update before read it.
*/
struct perf_counters ddr_ticks[DDR_FREQ_MAX];
};
struct ddr_stats_data {
/* snapshot of ddr_ticks for ddr stats */
struct perf_counters ddr_ticks_base[DDR_FREQ_MAX];
/* diff value of current ddr_ticks and ddr_ticks_base */
struct perf_counters ddr_ticks_diff[DDR_FREQ_MAX];
/* indicating if ddr stats are working */
int is_ddr_stats_working;
};
/* snapshot of ddr_ticks to get tick diff in profiling window */
struct ddr_profiler_data {
#ifdef CONFIG_64BIT
u64 total_ticks_base[DDR_FREQ_MAX];
u64 data_ticks_base[DDR_FREQ_MAX];
#else
u32 total_ticks_base[DDR_FREQ_MAX];
u32 data_ticks_base[DDR_FREQ_MAX];
#endif
};
struct ddr_devfreq_data {
struct devfreq *devfreq;
struct clk *ddr_clk;
struct mck_ppmu dmc;
unsigned int bst_len; /* ddr burst length */
unsigned long last_polled_at;
spinlock_t lock;
/* ddr upthreshold constraint */
struct notifier_block qos_max_upthrd_nb;
struct pm_qos_request qos_req_upthrd_max;
unsigned int qos_max_upthrd_component;
int max_upthrd_qos_type;
/* notifier block for ddr upthreshold change */
struct notifier_block freq_transition;
/* DDR frequency table used for platform */
unsigned int ddr_freq_tbl[DDR_FREQ_MAX]; /* unit Khz */
unsigned int ddr_freq_tbl_len;
unsigned int cur_ddr_idx;
/* for ddr_profiling file node */
struct ddr_stats_data ddr_stats;
/* for ddr freq profiler */
struct ddr_profiler_data ddr_profiler;
int irq;
struct work_struct overflow_work;
/* used for debug interface */
atomic_t is_disabled;
atomic_t is_stopped;
struct timespec start_ts;
struct timespec stop_ts;
};
extern void get_fc_spinlock(void);
extern void put_fc_spinlock(void);
extern void put_fc_lock(void __iomem *apmu_base);
extern int get_fc_lock(void __iomem *apmu_base, int has_hwdfcwr);
#endif /* __LINUX_MCK_MEMORYBUS_H__ */