aboutsummaryrefslogblamecommitdiffstats
path: root/arch/arm/mach-imx/busfreq_lpddr2.c
blob: e71b22f037b6c1aab72b8352ab24b2262187e24a (plain) (tree)
1
2
  
                                                                             








































                                                                     
 
                                  
                         
                                  
 
                                                                       

                                    
                                   
                                                                
                                                                   
                                               

                                                                                        


                                    
                                   

                                      
                                                                          
                                             


                                                             
                             
                                       
                                        
                                                               
                                 
                                                  
 
                                                                         




                                                                   
                                    
                                         
 
                                                                                          
 
                                                       
                                                          
                                                                
                                                       
                                                          
                                                                   



                                        
/*
 * 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 int curr_ddr_rate;
static DEFINE_SPINLOCK(freq_lock);

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 void imx6sx_lpddr2_freq_change(u32 freq, int bus_freq_mode);
extern unsigned long save_ttbr1(void);
extern void restore_ttbr1(unsigned long ttbr1);
extern unsigned long ddr_freq_change_iram_base;
extern unsigned long imx6_lpddr2_freq_change_start asm("imx6_lpddr2_freq_change_start");
extern unsigned long imx6_lpddr2_freq_change_end asm("imx6_lpddr2_freq_change_end");

/* change the DDR frequency. */
int update_lpddr2_freq(int ddr_rate)
{
	unsigned long ttbr1, flags;

	if (ddr_rate == curr_ddr_rate)
		return 0;

	dev_dbg(busfreq_dev, "\nBus freq set to %d start...\n", ddr_rate);

	spin_lock_irqsave(&freq_lock, flags);
	/*
	 * 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;
	spin_unlock_irqrestore(&freq_lock, flags);

	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)
{
	unsigned long ddr_code_size;
	busfreq_dev = &busfreq_pdev->dev;

	ddr_code_size = (&imx6_lpddr2_freq_change_end -&imx6_lpddr2_freq_change_start) *4;

	if (cpu_is_imx6sl())
		mx6_change_lpddr2_freq = (void *)fncpy(
			(void *)ddr_freq_change_iram_base,
			&mx6_lpddr2_freq_change, ddr_code_size);
	else if (cpu_is_imx6sx())
		mx6_change_lpddr2_freq = (void *)fncpy(
			(void *)ddr_freq_change_iram_base,
			&imx6sx_lpddr2_freq_change, ddr_code_size);

	curr_ddr_rate = ddr_normal_rate;

	return 0;
}