pm_34xx.c

来自「omap3 linux 2.6 用nocc去除了冗余代码」· C语言 代码 · 共 1,647 行 · 第 1/3 页

C
1,647
字号
static struct subsys_attribute domain_print = {	.attr = {		.name = __stringify(debug_domain),		.mode = 0644,		},	.show  = omap_pm_domain_show,	.store = omap_pm_domain_store,};/*sysfs interface to chg the frame buffer timer*/static ssize_t omap_pm_fb_timeout_show(struct kset *subsys, char *buf){	return sprintf(buf, "%hu\n", fb_timeout_val);}static ssize_t omap_pm_fb_timeout_store(struct kset *subsys,					const char *buf, size_t n){	unsigned short value;	if (sscanf(buf, "%hu", &value) != 1) {		printk(KERN_ERR "fb_timeout_store: Invalid value\n");		return -EINVAL;	}	fb_timeout_val = value;	set_blank_interval(fb_timeout_val);	return n;}static struct subsys_attribute fb_timeout = {	.attr = {		.name = __stringify(fb_timeout_value),		.mode = 0644,		},	.show  = omap_pm_fb_timeout_show,	.store = omap_pm_fb_timeout_store,};/* Sysfs interface to set the opp for vdd1 and vdd2 */static ssize_t omap_pm_vdd1_opp_show(struct kset *subsys, char *buf){	return sprintf(buf, "%x\n", (unsigned int)get_opp_no(							current_vdd1_opp));}static ssize_t omap_pm_vdd1_opp_store(struct kset *subsys,						const char *buf, size_t n){	sscanf(buf, "%u", &target_opp_no);	if ((target_opp_no < 1) || (target_opp_no > 5))	{		printk(KERN_ERR "\nError : Invalid OPP value for VDD1.\n");		return -EINVAL;	}	if (target_opp_no == get_opp_no(current_vdd1_opp)) {		DPRINTK("Target and current opp values are same\n");	} else {		if (target_opp_no != 1) {			if (vdd1_opp_co == NULL)				vdd1_opp_co = constraint_get("pm_fwk",								&cnstr_id1);			constraint_set(vdd1_opp_co, target_opp_no);		} else {			if (vdd1_opp_co != NULL) {				constraint_remove(vdd1_opp_co);				constraint_put(vdd1_opp_co);				vdd1_opp_co = NULL;			}		}	}	return n;}static struct subsys_attribute vdd1_opp = {	.attr = {		.name = __stringify(vdd1_opp_value),		.mode = 0644,		},	.show  = omap_pm_vdd1_opp_show,	.store = omap_pm_vdd1_opp_store,};static ssize_t omap_pm_vdd2_opp_show(struct kset *subsys, char *buf){	return sprintf(buf, "%x\n", (unsigned int)get_opp_no(current_vdd2_opp));}static ssize_t omap_pm_vdd2_opp_store(struct kset *subsys,						const char *buf, size_t n){	sscanf(buf, "%u", &target_opp_no);	if ((target_opp_no < 1) || (target_opp_no > 3))	{		printk(KERN_ERR "\nError : Invalid OPP value for VDD2.\n");		return -EINVAL;	}	if (target_opp_no == get_opp_no(current_vdd2_opp)) {		DPRINTK("Target and current opp values are same\n");	} else {		if (target_opp_no != 1) {			if (vdd2_opp_co == NULL)				vdd2_opp_co = constraint_get("pm_fwk",								&cnstr_id2);			constraint_set(vdd2_opp_co, target_opp_no);		} else {			if (vdd2_opp_co != NULL) {				constraint_remove(vdd2_opp_co);				constraint_put(vdd2_opp_co);				vdd2_opp_co = NULL;			}		}	}	return n;}static struct subsys_attribute vdd2_opp = {	.attr = {		.name = __stringify(vdd2_opp_value),		.mode = 0644,		},	.show  = omap_pm_vdd2_opp_show,	.store = omap_pm_vdd2_opp_store,};/* PRCM Interrupt Handler */irqreturn_t prcm_interrupt_handler (int irq, void *dev_id){	u32 wkst_wkup = PM_WKST_WKUP;	u32 wkst1_core = PM_WKST1_CORE;	u32 wkst3_core = PM_WKST3_CORE;	u32 wkst_usbhost = PM_WKST_USBHOST;	u32 wkst_per = PM_WKST_PER;	u32 errst_vc = PRM_VC_TIMEOUTERR_ST | PRM_VC_RAERR_ST |							PRM_VC_SAERR_EN;	u32 fclk = 0;	u32 iclk = 0;	if (PM_WKST_WKUP & PM_MPUGRPSEL_WKUP) {		/* Resetting UART1 inactivity timeout, during IO_PAD wakeup */		if (wkst_wkup & 0x100) {			awake_time_end = jiffies +					 msecs_to_jiffies(UART_TIME_OUT);		}		iclk = CM_ICLKEN_WKUP;		fclk = CM_FCLKEN_WKUP;		CM_ICLKEN_WKUP |= wkst_wkup & PM_MPUGRPSEL_WKUP;		CM_FCLKEN_WKUP |= wkst_wkup & PM_MPUGRPSEL_WKUP;		PM_WKST_WKUP = wkst_wkup & PM_MPUGRPSEL_WKUP;		while (PM_WKST_WKUP & PM_MPUGRPSEL_WKUP);		CM_ICLKEN_WKUP = iclk;		CM_FCLKEN_WKUP = fclk;	}	if (PM_WKST1_CORE & PM_MPUGRPSEL1_CORE) {		iclk = CM_ICLKEN1_CORE;		fclk = CM_FCLKEN1_CORE;		CM_ICLKEN1_CORE |= wkst1_core & PM_MPUGRPSEL1_CORE;		CM_FCLKEN1_CORE |= wkst1_core & PM_MPUGRPSEL1_CORE;		PM_WKST1_CORE = wkst1_core & PM_MPUGRPSEL1_CORE;		while (PM_WKST1_CORE & PM_MPUGRPSEL1_CORE);		CM_ICLKEN1_CORE = iclk;		CM_FCLKEN1_CORE = fclk;	}	if (PM_WKST3_CORE & PM_MPUGRPSEL3_CORE) {		iclk = CM_ICLKEN3_CORE;		fclk = CM_FCLKEN3_CORE;		CM_ICLKEN3_CORE |= wkst3_core & PM_MPUGRPSEL3_CORE;		CM_FCLKEN3_CORE |= wkst3_core & PM_MPUGRPSEL3_CORE;		PM_WKST3_CORE = wkst3_core & PM_MPUGRPSEL3_CORE;		while (PM_WKST3_CORE & PM_MPUGRPSEL3_CORE);		CM_ICLKEN3_CORE = iclk;		CM_FCLKEN3_CORE = fclk;	}	if (PM_WKST_USBHOST & PM_MPUGRPSEL_USBHOST) {		iclk = CM_ICLKEN_USBHOST;		fclk = CM_FCLKEN_USBHOST;		CM_ICLKEN_USBHOST |= wkst_usbhost & PM_MPUGRPSEL_USBHOST;		CM_FCLKEN_USBHOST |= wkst_usbhost & PM_MPUGRPSEL_USBHOST;		PM_WKST_USBHOST = wkst_usbhost & PM_MPUGRPSEL_USBHOST;		while (PM_WKST_USBHOST & PM_MPUGRPSEL_USBHOST);		CM_ICLKEN_USBHOST = iclk;		CM_FCLKEN_USBHOST = fclk;	}	if (PM_WKST_PER & PM_MPUGRPSEL_PER) {		iclk = CM_ICLKEN_PER;		fclk = CM_FCLKEN_PER;		CM_ICLKEN_PER |= wkst_per & PM_MPUGRPSEL_PER;		CM_FCLKEN_PER |= wkst_per & PM_MPUGRPSEL_PER;		PM_WKST_PER = wkst_per & PM_MPUGRPSEL_PER;		while (PM_WKST_PER & PM_MPUGRPSEL_PER);		CM_ICLKEN_PER = iclk;		CM_FCLKEN_PER = fclk;	}	if (!(wkst_wkup | wkst1_core | wkst3_core | wkst_usbhost | wkst_per)) {		if (!(PRM_IRQSTATUS_MPU & errst_vc)) {			printk(KERN_ERR "%x,%x,%x,%x\n", PRM_IRQSTATUS_MPU,					wkst_wkup, wkst1_core, wkst_per);			printk(KERN_ERR "Spurious PRCM interrupt\n");		}	}	if (PRM_IRQSTATUS_MPU & PRM_VC_TIMEOUTERR_ST) {		printk(KERN_ERR "PRCM : Voltage Controller timeout\n");		printk(KERN_ERR "PRM_IRQSTATUS_MPU    = 0x%x\n", PRM_IRQSTATUS_MPU) ;		printk(KERN_ERR "PRM_VC_TIMEOUTERR_ST = 0x%x\n", PRM_VC_TIMEOUTERR_ST) ;	}	if (PRM_IRQSTATUS_MPU & PRM_VC_RAERR_ST) {		printk(KERN_ERR "PRCM : Voltage Controller register address "							"acknowledge error\n");	}	if (PRM_IRQSTATUS_MPU & PRM_VC_SAERR_ST) {		printk(KERN_ERR "PRCM : Voltage Controller slave address "							"acknowledge error\n");	}	if (PRM_IRQSTATUS_MPU) {		PRM_IRQSTATUS_MPU |= 0x3;		while (PRM_IRQSTATUS_MPU);	}	return IRQ_HANDLED;}#include <linux/proc_fs.h>#include <linux/seq_file.h>static void *omap_pm_prepwst_start(struct seq_file *m, loff_t *pos){	return *pos < 1 ? (void *)1 : NULL;}static void *omap_pm_prepwst_next(struct seq_file *m, void *v, loff_t *pos){	++*pos;	return NULL;}static void omap_pm_prepwst_stop(struct seq_file *m, void *v){}char *pstates [4] =	{			 "OFF",			 "RET",			 "INACT",			 "ON"			};int omap_pm_prepwst_show(struct seq_file *m, void *v){	u32 arr_rdptr, arr_cnt;	seq_printf(m, "\nPrevious power state for MPU+CORE\n\n");	arr_rdptr = arr_wrptr;	arr_cnt = LAST_IDLE_STATE_ARR_SIZE;	while (arr_cnt--) {		if (arr_rdptr == 0)			arr_rdptr = LAST_IDLE_STATE_ARR_SIZE;		arr_rdptr--;		seq_printf(m,			"MPU = %x - %s, CORE = %x - %s, IVA = %x - %s,"			"fclks: %x, iclks: %x\n",			last_idle_state[arr_wrptr].mpu_state,			pstates [last_idle_state[arr_wrptr].mpu_state & 0x3],			last_idle_state[arr_wrptr].core_state,			pstates [last_idle_state[arr_wrptr].core_state & 0x3],			last_idle_state[arr_wrptr].iva_state,			pstates [last_idle_state[arr_wrptr].iva_state & 0x3],			last_idle_state[arr_wrptr].fclks,			last_idle_state[arr_wrptr].iclks		);	}	seq_printf(m, "\nMPU RET CNT = %d, MPU OFF CNT = %d,"			" CORE RET CNT = %d, CORE OFF CNT = %d\n\n",			mpu_ret_cnt, mpu_off_cnt, core_ret_cnt, core_off_cnt);	return 0;}static struct seq_operations omap_pm_prepwst_op = {	.start = omap_pm_prepwst_start,	.next  = omap_pm_prepwst_next,	.stop  = omap_pm_prepwst_stop,	.show  = omap_pm_prepwst_show};static int omap_pm_prepwst_open(struct inode *inode, struct file *file){	return seq_open(file, &omap_pm_prepwst_op);}static struct file_operations proc_pm_prepwst_ops = {	.open		= omap_pm_prepwst_open,	.read		= seq_read,	.llseek		= seq_lseek,	.release	= seq_release,};/* This API creates a proc entry for shared resources. */int create_pmproc_entry(void){	struct proc_dir_entry *entry;	/* Create a proc entry for shared resources */	entry = create_proc_entry("pm_prepwst", 0, NULL);	if (entry) {		entry->proc_fops = &proc_pm_prepwst_ops;		printk(KERN_ERR "create_proc_entry succeeded\n");		}	else		printk(KERN_ERR "create_proc_entry failed\n");	return 0;}int __init omap3_pm_init(void){	int l, m, ret;	printk(KERN_ERR "Power Management for TI OMAP.\n");	_omap_sram_idle = omap_sram_push(omap34xx_suspend,					omap34xx_suspend_sz);	pm_set_ops(&omap_pm_ops);	/* In case of cold boot, clear scratchpad */	if (RM_RSTST_CORE & 0x1)		clear_scratchpad_contents();	prcm_init();	memret1 = (struct res_handle *)resource_get("corememresret1",							"core_mem1ret");	memret2 = (struct res_handle *)resource_get("corememresret2",							"core_mem2ret");	logret1 = (struct res_handle *)resource_get("corelogicret",							"core_logicret");	/* Registering PRCM Interrupts to MPU, for Wakeup events */	ret = request_irq(PRCM_MPU_IRQ, (irq_handler_t)prcm_interrupt_handler,				IRQF_DISABLED, "prcm", NULL);	if (ret) {		printk(KERN_ERR "request_irq failed to register for 0x%x\n",			PRCM_MPU_IRQ);		return -1;	}	/* Adjust the system OPP based during bootup using	 * KConfig option	 */	if (p_vdd1_clk == NULL) {		p_vdd1_clk = clk_get(NULL, "virt_vdd1_prcm_set");		if (p_vdd1_clk == NULL) {			printk(KERN_ERR "Unable to get the VDD1 clk\n");			return -1;		}	}	if (p_vdd2_clk == NULL) {		p_vdd2_clk = clk_get(NULL, "virt_vdd2_prcm_set");		if (p_vdd2_clk == NULL) {			printk(KERN_ERR "Unable to get the VDD2 clk\n");			return -1;		}	}	/* Configure OPP for VDD1 based on compile time setting */	vdd1_opp_no = PRCM_VDD1_OPP3;	vdd2_opp_no = PRCM_VDD2_OPP3;	prcm_do_voltage_scaling(PRCM_VDD2_OPP3, PRCM_VDD2_OPP2);	/* Request for VDD1 and VDD2 OPP constraints */	/* Currently by default VDD2 OPP level 3 is requested */	if (vdd1_opp_no != PRCM_VDD1_OPP1) {		vdd1_opp_co = constraint_get("pm_fwk", &cnstr_id1);		constraint_set(vdd1_opp_co, get_opp_no(vdd1_opp_no));	}	if (vdd2_opp_no != PRCM_VDD2_OPP1) {		vdd2_opp_co = constraint_get("pm_fwk", &cnstr_id2);		constraint_set(vdd2_opp_co, get_opp_no(vdd2_opp_no));	}	omap_init_power_states();	cpuidle_register_driver(&omap3_idle_driver);	PRM_IRQSTATUS_MPU = 0x3FFFFFD;	PRM_IRQENABLE_MPU = 0x1;	/* Enabling the IO_PAD PRCM interrupts */	PRM_IRQENABLE_MPU |= 0x200;	/* Enabling the VOLTAGE CONTROLLER PRCM interrupts */	PRM_IRQENABLE_MPU |= PRM_VC_TIMEOUTERR_EN | PRM_VC_RAERR_EN|							PRM_VC_SAERR_EN;	l = subsys_create_file(&power_subsys, &sleep_idle_state);	if (l)		printk(KERN_ERR "subsys_create_file failed: %d\n", l);	l = subsys_create_file(&power_subsys, &off_enable);	if (l)		printk(KERN_ERR "subsys_create_file failed for off: %d\n", l);	/*For register dump*/	l = subsys_create_file(&power_subsys, &domain_print);	if (l)		printk(KERN_ERR "subsys_create_file failed for print: %d\n", l);	/* Sysfs entry for setting Display timeout*/	m = subsys_create_file(&power_subsys, &fb_timeout);	if (m)		printk(KERN_ERR "subsys_create_file failed: %d\n", m);	 /* Sysfs entry for setting opp for vdd1 */		m = subsys_create_file(&power_subsys, &vdd1_opp);	if (m)		printk(KERN_ERR "subsys_create_file failed: %d\n", m);	 /* Sysfs entry for setting opp for vdd2 */	m = subsys_create_file(&power_subsys, &vdd2_opp);	if (m)		printk(KERN_ERR "subsys_create_file failed: %d\n", m);	/* Set the default value of frame buffer timeout*/	set_blank_interval(fb_timeout_val);	create_pmproc_entry();	return 0;}/** * clear_scratchpad_contents - Clears the scratchpad contents * * Clears the scratchpad contents in case of cold boot. Called during bootup. */void clear_scratchpad_contents(void){	u32 max_offset = SCRATCHPAD_ROM_OFFSET;	u32 offset = 0;	u32 v_addr = io_p2v(SCRATCHPAD_ROM);	/* Check if it is a cold reboot */	if (PRM_RSTST & 0x1) {		for ( ; offset <= max_offset; offset += 0x4)			__raw_writel(0x0, (v_addr + offset));		PRM_RSTST |= 0x1;	}}/** * save_scratchpad_contents * * Populate the scratchpad structure with restore structure. */void save_scratchpad_contents(void){	u32 *scratchpad_address;	u32 *restore_address;	u32 *sdram_context_address;	/* Get virtual address of SCRATCHPAD */	scratchpad_address = (u32 *) io_p2v(SCRATCHPAD);	/* Get Restore pointer to jump to while waking up from OFF */	restore_address = get_restore_pointer();	/* Convert it to physical address */	restore_address = (u32 *) io_v2p(restore_address);	/* Get address where registers are saved in SDRAM */	sdram_context_address = (u32 *) io_v2p(context_mem);	/* Booting configuration pointer*/	*(scratchpad_address++) = 0x0;	/* Public restore pointer */	/* On ES 2.0, if scratchpad is populated with valid	 * pointer, warm reset does not work	 * So populate scratchpad restore address only in	 * cpuidle and suspend calls	 */	scratchpad_restore_addr = scratchpad_address;	restore_pointer_address = (u32) restore_address;	*(scratchpad_address++) = 0x0;	/* Secure ram restore pointer */	*(scratchpad_address++) = 0x0;	/* SDRC Module semaphore */	*(scratchpad_address++) = 0x0;	/* PRCM Block Offset */	*(scratchpad_address++) = 0x2C;	/* SDRC Block Offset */	*(scratchpad_address++) = 0x64;	/* Empty */	/* Offset 0x8*/	*(scratchpad_address++) = 0x0;	*(scratchpad_address++) = 0x0;	/* Offset 0xC*/	*(scratchpad_address++) = 0x0;	/* Offset 0x10*/	*(scratchpad_address++) = 0x0;	/* Offset 0x14*/	*(scratchpad_address++) = 0x0;	/* Offset 0x18*/	/* PRCM Block */	*(scratchpad_address++) = PRM_CLKSRC_CTRL;	*(scratchpad_address++) = PRM_CLKSEL;	*(scratchpad_address++) = CM_CLKSEL_CORE;	*(scratchpad_address++) = CM_CLKSEL_WKUP;	*(scratchpad_address++) = CM_CLKEN_PLL;	*(scratchpad_address++) = CM_AUTOIDLE_PLL;	*(scratchpad_address++) = CM_CLKSEL1_PLL;	*(scratchpad_address++) = CM_CLKSEL2_PLL;	*(scratchpad_address++) = CM_CLKSEL3_PLL;	*(scratchpad_address++) = CM_CLKEN_PLL_MPU;	*(scratchpad_address++) = CM_AUTOIDLE_PLL_MPU;	*(scratchpad_address++) = CM_CLKSEL1_PLL_MPU;	*(scratchpad_address++) = CM_CLKSEL2_PLL_MPU;	*(scratchpad_address++) = 0x0;	/* SDRC Block */	*(scratchpad_address++) = ((SDRC_CS_CFG & 0xFFFF) << 16) |					(SDRC_SYS_CONFIG & 0xFFFF);	*(scratchpad_address++) = ((SDRC_ERR_TYPE & 0xFFFF) << 16) |					(SDRC_SHARING & 0xFFFF);	*(scratchpad_address++) = SDRC_DLL_A_CTRL;	*(scratchpad_address++) = 0x0;	*(scratchpad_address++) = SDRC_PWR;	*(scratchpad_address++) = 0x0;	*(scratchpad_address++) = SDRC_MCFG_0;	*(scratchpad_address++) = SDRC_MR0 & 0xFFFF;	*(scratchpad_address++) = 0x0;	*(scratchpad_address++) = SDRC_ACTIM_CTRL_A_0;	*(scratchpad_address++) = SDRC_ACTIM_CTRL_B_0;	*(scratchpad_address++) = SDRC_RFR_CTRL_0;	*(scratchpad_address++) = 0x0;	*(scratchpad_address++) = SDRC_MCFG_1;	*(scratchpad_address++) = SDRC_MR1 & 0xFFFF;	*(scratchpad_address++) = 0x0;	*(scratchpad_address++) = SDRC_ACTIM_CTRL_A_1;	*(scratchpad_address++) = SDRC_ACTIM_CTRL_B_1;	*(scratchpad_address++) = SDRC_RFR_CTRL_1;	*(scratchpad_address++) = 0x0;	*(scratchpad_address++) = 0x0;	*(scratchpad_address++) = 0x0;	*(scratchpad_address++) = (u32) sdram_context_address;}__initcall(omap3_pm_init);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?