2012-02-10 03:47:44 +04:00
/*
* arch / arm / mach - tegra / flowctrl . c
*
* functions and macros to control the flowcontroller
*
* Copyright ( c ) 2010 - 2012 , NVIDIA Corporation . All rights reserved .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/io.h>
2012-10-31 13:41:20 +04:00
# include <linux/cpumask.h>
2012-02-10 03:47:44 +04:00
# include "flowctrl.h"
2012-10-05 00:24:09 +04:00
# include "iomap.h"
2013-01-16 02:11:01 +04:00
# include "fuse.h"
2012-02-10 03:47:44 +04:00
2013-01-03 10:27:05 +04:00
static u8 flowctrl_offset_halt_cpu [ ] = {
2012-02-10 03:47:44 +04:00
FLOW_CTRL_HALT_CPU0_EVENTS ,
FLOW_CTRL_HALT_CPU1_EVENTS ,
FLOW_CTRL_HALT_CPU1_EVENTS + 8 ,
FLOW_CTRL_HALT_CPU1_EVENTS + 16 ,
} ;
2013-01-03 10:27:05 +04:00
static u8 flowctrl_offset_cpu_csr [ ] = {
2012-02-10 03:47:44 +04:00
FLOW_CTRL_CPU0_CSR ,
FLOW_CTRL_CPU1_CSR ,
FLOW_CTRL_CPU1_CSR + 8 ,
FLOW_CTRL_CPU1_CSR + 16 ,
} ;
static void flowctrl_update ( u8 offset , u32 value )
{
void __iomem * addr = IO_ADDRESS ( TEGRA_FLOW_CTRL_BASE ) + offset ;
writel ( value , addr ) ;
/* ensure the update has reached the flow controller */
wmb ( ) ;
readl_relaxed ( addr ) ;
}
2012-10-31 13:41:20 +04:00
u32 flowctrl_read_cpu_csr ( unsigned int cpuid )
{
u8 offset = flowctrl_offset_cpu_csr [ cpuid ] ;
void __iomem * addr = IO_ADDRESS ( TEGRA_FLOW_CTRL_BASE ) + offset ;
return readl ( addr ) ;
}
2012-02-10 03:47:44 +04:00
void flowctrl_write_cpu_csr ( unsigned int cpuid , u32 value )
{
2012-05-14 14:27:09 +04:00
return flowctrl_update ( flowctrl_offset_cpu_csr [ cpuid ] , value ) ;
2012-02-10 03:47:44 +04:00
}
void flowctrl_write_cpu_halt ( unsigned int cpuid , u32 value )
{
2012-05-14 14:27:09 +04:00
return flowctrl_update ( flowctrl_offset_halt_cpu [ cpuid ] , value ) ;
2012-02-10 03:47:44 +04:00
}
2012-10-31 13:41:20 +04:00
void flowctrl_cpu_suspend_enter ( unsigned int cpuid )
{
unsigned int reg ;
int i ;
reg = flowctrl_read_cpu_csr ( cpuid ) ;
2013-01-16 02:11:01 +04:00
switch ( tegra_chip_id ) {
case TEGRA20 :
/* clear wfe bitmap */
reg & = ~ TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP ;
/* clear wfi bitmap */
reg & = ~ TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP ;
/* pwr gating on wfe */
reg | = TEGRA20_FLOW_CTRL_CSR_WFE_CPU0 < < cpuid ;
break ;
case TEGRA30 :
/* clear wfe bitmap */
reg & = ~ TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP ;
/* clear wfi bitmap */
reg & = ~ TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP ;
/* pwr gating on wfi */
reg | = TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 < < cpuid ;
break ;
}
2012-10-31 13:41:20 +04:00
reg | = FLOW_CTRL_CSR_INTR_FLAG ; /* clear intr flag */
reg | = FLOW_CTRL_CSR_EVENT_FLAG ; /* clear event flag */
reg | = FLOW_CTRL_CSR_ENABLE ; /* pwr gating */
flowctrl_write_cpu_csr ( cpuid , reg ) ;
for ( i = 0 ; i < num_possible_cpus ( ) ; i + + ) {
if ( i = = cpuid )
continue ;
reg = flowctrl_read_cpu_csr ( i ) ;
reg | = FLOW_CTRL_CSR_EVENT_FLAG ;
reg | = FLOW_CTRL_CSR_INTR_FLAG ;
flowctrl_write_cpu_csr ( i , reg ) ;
}
}
void flowctrl_cpu_suspend_exit ( unsigned int cpuid )
{
unsigned int reg ;
/* Disable powergating via flow controller for CPU0 */
reg = flowctrl_read_cpu_csr ( cpuid ) ;
2013-01-16 02:11:01 +04:00
switch ( tegra_chip_id ) {
case TEGRA20 :
/* clear wfe bitmap */
reg & = ~ TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP ;
/* clear wfi bitmap */
reg & = ~ TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP ;
break ;
case TEGRA30 :
/* clear wfe bitmap */
reg & = ~ TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP ;
/* clear wfi bitmap */
reg & = ~ TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP ;
break ;
}
2012-10-31 13:41:20 +04:00
reg & = ~ FLOW_CTRL_CSR_ENABLE ; /* clear enable */
reg | = FLOW_CTRL_CSR_INTR_FLAG ; /* clear intr */
reg | = FLOW_CTRL_CSR_EVENT_FLAG ; /* clear event */
flowctrl_write_cpu_csr ( cpuid , reg ) ;
}