📄 pm_pmu.c
字号:
/* * File Name : linux/arch/arm/mach-mp200/pm_pmu.c * Function : pm_pmu * Release Version : Ver 1.00 * Release Date : 2006/03/20 * * Copyright (C) NEC Electronics Corporation 2005-2006 * * * This program is free software;you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by Free Softwere Foundation; either version 2 * of License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warrnty 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. * */#include <linux/config.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/slab.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/errno.h>#include <asm/arch/smu.h>#include <asm/arch/pmu.h>#include "uwire.h"#include "time.h"#include "pm.h"static void (*change_flash_read_mode) (struct flash_read_param *);static struct flash_read_param flash_read_param_fullspeed;static struct flash_read_param flash_read_param_economy = { .smu_ab0_cs0readctrl = SMU_AB0_READMODE_SINGLE0, .smu_ab0_cs1readctrl = SMU_AB0_READMODE_SINGLE0, .smu_ab0_flashrcr = SMU_AB0_ASYNC_READ_MODE,};/* #define PM_DEBUG_CLK */#define PLL_KIND_NUM 5static struct pll_data pll_tbl[PLL_KIND_NUM] ={ { .param = { 0x00000001, 0x00090000, 0x00040000 }, .mode = MP200_PLL_248MHZ, .lpj = MP200_LPJ_248MHZ, }, { .param = { 0x00000005, 0x00050000, 0x00020000 }, .mode = MP200_PLL_164MHZ, .lpj = MP200_LPJ_164MHZ, }, { .param = { 0x00000001, 0x01040000, 0x00000000 }, .mode = MP200_PLL_124MHZ, .lpj = MP200_LPJ_124MHZ, }, { .param = { 0x00000001, 0x02020000, 0x00000000 }, .mode = MP200_PLL_83MHZ, .lpj = MP200_LPJ_83MHZ, }, { .param = { 0x00000001, 0x04010000, 0x00000000 }, .mode = MP200_PLL_50MHZ, .lpj = MP200_LPJ_50MHZ, },};void (*mp200_change_pll_on_sram) (struct pll_param *);void (*mp200_change_osc_on_sram) (void);static inline int get_idx(int x) { int i; for(i=0;i<PLL_KIND_NUM;i++) { if(pll_tbl[i].mode == x) {#ifdef PM_DEBUG_CLK printk("get_idx. idx=%d mode=%d \n", i, pll_tbl[i].mode);#endif return i; } } return 0;}void mp200_pm_set_uwire_clock(void){ unsigned int hpll_p_val; unsigned int hpll_m_val; unsigned int hpll_n_val; unsigned int lpll_ctrl1; unsigned int pll1; mp200_pmu_close_clockgate(MP200_CLOCKGATE_MWI_SCLK); mp200_pmu_close_clockgate(MP200_CLOCKGATE_MWI_PCLK); switch (mp200_pm_get_pll()) { case MP200_PLL_12MHZ: outl((DIV_12M - 1), SMU_MWI_SCLK_DIV); break; case MP200_PLL_164MHZ: /* PLL is L */ lpll_ctrl1 = inl(SMU_LPLL_CTRL1); pll1 = ((3750 + lpll_ctrl1*125) * 32768 )/1000; /* 32.768kHz(RTC) */ outl( (pll1 / 3000) - 1, SMU_MWI_SCLK_DIV );#ifdef PM_DEBUG printk(KERN_INFO "%s(): sclk src=%u.%3u, divisor=%u\n", __FUNCTION__, pll1 / 1000, pll1 % 1000, pll1 / 3000);#endif break; case MP200_PLL_248MHZ: case MP200_PLL_124MHZ: case MP200_PLL_83MHZ: case MP200_PLL_50MHZ: /* PLL is H */ hpll_n_val = (inl(SMU_HPLL_CTRL1) & MASK_HPLL_N) + 1; hpll_m_val = (inl(SMU_HPLL_CTRL2) & MASK_HPLL_M) + 1; hpll_p_val = (inl(SMU_HPLL_CTRL3) & MASK_HPLL_P); pll1 = ((12000000/1000) * hpll_n_val) / hpll_m_val; /* OSC(6-12MHz ) */ if( hpll_p_val != 0 ) { pll1 >>= 1; } outl( (pll1 / 3000) - 1, SMU_MWI_SCLK_DIV );#ifdef PM_DEBUG printk(KERN_INFO "%s(): sclk src=%u.%3u, divisor=%u\n", __FUNCTION__, pll1 / 1000, pll1 % 1000, pll1 / 3000);#endif break; default: printk(KERN_INFO "%s(): Unknown SCLK Source\n", __FUNCTION__); outl((DIV_12M - 1), SMU_MWI_SCLK_DIV); break; } mp200_pmu_open_clockgate(MP200_CLOCKGATE_MWI_PCLK);}void mp200_pm_update_lpj(void){ unsigned int mode = mp200_pm_get_pll(); switch (mode) { case MP200_PLL_248MHZ: case MP200_PLL_164MHZ: case MP200_PLL_124MHZ: case MP200_PLL_83MHZ: case MP200_PLL_50MHZ: loops_per_jiffy = pll_tbl[get_idx(mode)].lpj; timer_set_clock_parm(TIMER_FULLSPEED); break; case MP200_PLL_12MHZ: loops_per_jiffy = MP200_LPJ_ECONOMY; timer_set_clock_parm(TIMER_ECONOMY); break; default: loops_per_jiffy = MP200_LPJ_ECONOMY; timer_set_clock_parm(TIMER_ECONOMY); break; }}/* * economy -> fullspeed */void mp200_pm_eco_to_full(unsigned int new){ if (mp200_pm_get_pll() == new) { return; }#ifdef PM_DEBUG_CLK printk("PM: %s(). change clock to [%d] from [%d]\n", __FUNCTION__, new, mp200_pm_get_pll());#endif mp200_change_pll_on_sram(&pll_tbl[get_idx(new)].param); /* update loops_per_jiffy */ mp200_pm_update_lpj(); /* change flash read mode */ change_flash_read_mode(&flash_read_param_fullspeed); /* set uWire clock */ mp200_pm_set_uwire_clock();}/* * fullspeed -> economy */void mp200_pm_full_to_eco(void){ if (mp200_pm_get_pll() == MP200_PLL_12MHZ) { return; } /* change flash read mode */ change_flash_read_mode(&flash_read_param_economy);#ifdef PM_DEBUG_CLK printk("PM: %s(). change to osc from [%d] \n", __FUNCTION__, mp200_pm_get_pll());#endif mp200_change_osc_on_sram(); /* update loops_per_jiffy */ mp200_pm_update_lpj(); /* set uWire clock */ mp200_pm_set_uwire_clock();}unsigned int mp200_pm_get_pll(void){ if ((inl(SMU_PLLSEL) & MASK_SMU_PLLSEL) == SMU_PLLSEL_PLL) { if(inl(SMU_PLLSEL2) & SMU_NRM_CK_SEL) { /* low */ return MP200_PLL_164MHZ; } else { /* high */ int i; unsigned int frq_change = inl(SMU_AUTO_FRQ_CHANGE); for (i = 0;i < PLL_KIND_NUM; i++) { if((frq_change & SMU_PLL_NRM_DIV_MASK) == (pll_tbl[i].param.auto_frq_change & SMU_PLL_NRM_DIV_MASK)) { return pll_tbl[i].mode; } } } } return MP200_PLL_12MHZ;}int mp200_pm_set_pll(unsigned int flag){ unsigned long irq_flags; unsigned int mode; int ret = 0; local_irq_save(irq_flags); switch (flag) { case MP200_PLL_248MHZ: case MP200_PLL_164MHZ: case MP200_PLL_124MHZ: case MP200_PLL_83MHZ: case MP200_PLL_50MHZ: mode = mp200_pm_get_pll(); if(mode != flag) { mp200_pm_eco_to_full(flag); } if(mode == MP200_PLL_12MHZ) { timer_set_clock(TIMER_FULLSPEED); } break; case MP200_PLL_12MHZ: mode = mp200_pm_get_pll(); if(mode != MP200_PLL_12MHZ) { timer_set_clock(TIMER_ECONOMY); mp200_pm_full_to_eco(); } break; default: ret = -EINVAL; break; } local_irq_restore(irq_flags); return ret;}static void change_flash_read_mode_on_flash(struct flash_read_param *param){ unsigned int addr; outl(param->smu_ab0_flashrcr, SMU_AB0_FLASHRCR); outl(param->smu_ab0_flashrcr, SMU_AB0_FLASHCOMADD0); outl(param->smu_ab0_flashrcr | SMU_AB0_VALIDBIT | SMU_AB0_RW, SMU_AB0_FLASHCOMADD1); outl(FLASH_CMD_CONFIGURATION_1ST, SMU_AB0_FLASHCOMDATA0); outl(FLASH_CMD_CONFIGURATION_2ND, SMU_AB0_FLASHCOMDATA1); outl(param->smu_ab0_cs0readctrl, SMU_AB0_CS0READCTRL); outl(AB0_SET_MODE | AB0_CS0, AB0_FLASHCOMSET); outl(param->smu_ab0_cs1readctrl, SMU_AB0_CS1READCTRL); outl(AB0_SET_MODE | AB0_CS1, AB0_FLASHCOMSET); addr = (param->smu_ab0_flashrcr << 1) + param->flash0_addr; outw(FLASH_CMD_CONFIGURATION_1ST, addr); outw(FLASH_CMD_CONFIGURATION_2ND, addr); addr = (param->smu_ab0_flashrcr << 1) + param->flash1_addr; outw(FLASH_CMD_CONFIGURATION_1ST, addr); outw(FLASH_CMD_CONFIGURATION_2ND, addr);}static unsigned long pm_pmu_compute_lpj(unsigned long ref, u_int div, u_int mult){ unsigned long jiffy_l, jiffy_h; jiffy_h = ref / div; jiffy_l = (ref % div) / 100; jiffy_h *= mult; jiffy_l = jiffy_l * mult / div; return jiffy_h + jiffy_l * 100;}/* * init */static int __init mp200_pm_pmu_init(void){ void *saddr; void *daddr; void *flash_addr; int i; saddr = (void *)change_flash_read_mode_on_flash; daddr = kmalloc(CHANGE_FLASH_READ_MODE_SIZE, GFP_KERNEL); if (daddr == NULL) { return -ENOMEM; } memcpy(daddr, saddr, CHANGE_FLASH_READ_MODE_SIZE); change_flash_read_mode = (void (*)(struct flash_read_param *))daddr; flash_addr = ioremap(FLASH0_BASE, FLASH_SIZE); if (flash_addr == NULL) { kfree(daddr); return -EIO; } flash_read_param_fullspeed.flash0_addr = (unsigned int)flash_addr; flash_read_param_economy.flash0_addr = (unsigned int)flash_addr; flash_addr = ioremap(FLASH1_BASE, FLASH_SIZE); if (flash_addr == NULL) { iounmap((void *)flash_read_param_fullspeed.flash0_addr); kfree(daddr); return -EIO; } flash_read_param_fullspeed.flash1_addr = (unsigned int)flash_addr; flash_read_param_economy.flash1_addr = (unsigned int)flash_addr; flash_read_param_fullspeed.smu_ab0_cs0readctrl = inl(SMU_AB0_CS0READCTRL); flash_read_param_fullspeed.smu_ab0_cs1readctrl = inl(SMU_AB0_CS1READCTRL); flash_read_param_fullspeed.smu_ab0_flashrcr = inl(SMU_AB0_FLASHRCR); for (i = 0;i < PLL_KIND_NUM; i++) { pll_tbl[i].lpj = pm_pmu_compute_lpj(loops_per_jiffy, mp200_pm_get_pll(), pll_tbl[i].mode);#ifdef PM_DEBUG_CLK printk("PM: %s(). clock[%d] - lpj[0x%08x]\n", __FUNCTION__, pll_tbl[i].mode, pll_tbl[i].lpj);#endif }#ifdef PM_DEBUG printk(KERN_INFO "[flash_read_param_fullspeed]\n"); printk(KERN_INFO " flash0_addr = 0x%08x\n", flash_read_param_fullspeed.flash0_addr); printk(KERN_INFO " flash1_addr = 0x%08x\n", flash_read_param_fullspeed.flash1_addr); printk(KERN_INFO " smu_ab0_cs0readctrl = 0x%08x\n", flash_read_param_fullspeed.smu_ab0_cs0readctrl); printk(KERN_INFO " smu_ab0_cs1readctrl = 0x%08x\n", flash_read_param_fullspeed.smu_ab0_cs1readctrl); printk(KERN_INFO " smu_ab0_flashrcr = 0x%08x\n", flash_read_param_fullspeed.smu_ab0_flashrcr); printk(KERN_INFO "[flash_read_param_economy]\n"); printk(KERN_INFO " flash0_addr = 0x%08x\n", flash_read_param_economy.flash0_addr); printk(KERN_INFO " flash1_addr = 0x%08x\n", flash_read_param_economy.flash1_addr); printk(KERN_INFO " smu_ab0_cs0readctrl = 0x%08x\n", flash_read_param_economy.smu_ab0_cs0readctrl); printk(KERN_INFO " smu_ab0_cs1readctrl = 0x%08x\n", flash_read_param_economy.smu_ab0_cs1readctrl); printk(KERN_INFO " smu_ab0_flashrcr = 0x%08x\n", flash_read_param_economy.smu_ab0_flashrcr);#endif return 0;}__initcall(mp200_pm_pmu_init);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -