blob: ac209e2a3cd098c012fd47ddff92454fedefef9b (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
/*
* Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
/*!
* @file busfreq_lpddr2.c
*
* @brief iMX6 LPDDR2 frequency change specific file.
*
* @ingroup PM
*/
#include <asm/cacheflush.h>
#include <asm/fncpy.h>
#include <asm/io.h>
#include <asm/mach/map.h>
#include <asm/mach-types.h>
#include <asm/tlb.h>
#include <linux/clk.h>
#include <linux/cpumask.h>
#include <linux/delay.h>
#include <linux/genalloc.h>
#include <linux/interrupt.h>
#include <linux/irqchip/arm-gic.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include "hardware.h"
static struct device *busfreq_dev;
static void *ddr_freq_change_iram_base;
static int curr_ddr_rate;
unsigned long ddr_freq_change_iram_paddr;
void (*mx6_change_lpddr2_freq)(u32 ddr_freq, int bus_freq_mode) = NULL;
extern unsigned int ddr_normal_rate;
extern int low_bus_freq_mode;
extern int ultra_low_bus_freq_mode;
extern void mx6_lpddr2_freq_change(u32 freq, int bus_freq_mode);
extern unsigned long save_ttbr1(void);
extern void restore_ttbr1(unsigned long ttbr1);
/* change the DDR frequency. */
int update_lpddr2_freq(int ddr_rate)
{
unsigned long ttbr1;
if (ddr_rate == curr_ddr_rate)
return 0;
dev_dbg(busfreq_dev, "\nBus freq set to %d start...\n", ddr_rate);
/*
* Flush the TLB, to ensure no TLB maintenance occurs
* when DDR is in self-refresh.
*/
ttbr1 = save_ttbr1();
/* Now change DDR frequency. */
mx6_change_lpddr2_freq(ddr_rate,
(low_bus_freq_mode | ultra_low_bus_freq_mode));
restore_ttbr1(ttbr1);
curr_ddr_rate = ddr_rate;
dev_dbg(busfreq_dev, "\nBus freq set to %d done...\n", ddr_rate);
return 0;
}
int init_mmdc_lpddr2_settings(struct platform_device *busfreq_pdev)
{
busfreq_dev = &busfreq_pdev->dev;
ddr_freq_change_iram_paddr = MX6SL_LPDDR2_FREQ_ADDR;
/* Calculate the virtual address of the code */
ddr_freq_change_iram_base =
(void *)IMX_IO_P2V(MX6Q_IRAM_TLB_BASE_ADDR) +
(ddr_freq_change_iram_paddr - MX6Q_IRAM_TLB_BASE_ADDR);
mx6_change_lpddr2_freq = (void *)fncpy(ddr_freq_change_iram_base,
&mx6_lpddr2_freq_change, LPDDR2_FREQ_CODE_SIZE);
curr_ddr_rate = ddr_normal_rate;
return 0;
}
|