⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 prcm_34xx.c

📁 omap3 linux 2.6 用nocc去除了冗余代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (dpll_id == DPLL4_PER) {		new_reg_val = *addr & valid;		new_reg_val |= (freq_sel << 20);		*addr = new_reg_val;	} else {		new_reg_val = *addr & valid;		new_reg_val |= (freq_sel << 4);		*addr = new_reg_val;	}	*addr_auto = dpll_autoidle;	return PRCM_PASS;}/*============================================================================*//*======================== PUT DPLL IN BYPASS ================================*//*============================================================================*//*= This function will put the specified DPLL in various Bypass modes as     =*//*= specified by bypass_mode. The function waits for the DPLL to go into     =*//*= the given bypass_mode before returning                                   =*//*============================================================================*/int prcm_put_dpll_in_bypass(u32 dpll_id, u32 bypass_mode){	u32 new_val;	volatile u32 *addr, *addr_auto;	u32 dpll_autoidle;	u32 loop_cnt = 0, retries_cnt = 0;	int ret = PRCM_FAIL;	if (dpll_id > NO_OF_DPLL)		return ret;	/* Currently, the API does not allow putting CORE dpll in bypass mode	 * To safely put dpll in bypass mode, it is better to execute code	 * from sram so that there is no access to sdram */	if (dpll_id == DPLL3_CORE)		return ret;	DPRINTK("dpllid:%d\n", dpll_id);	addr = get_addr_pll(dpll_id, REG_CLKEN_PLL);	if (!addr)		return ret;	/* This is needed if the condition in while loop returns true the */							/*very first time*/	ret = PRCM_PASS;	/* Store the DPLL autoidle */	addr_auto = get_addr_pll(dpll_id, REG_AUTOIDLE_PLL);	dpll_autoidle = *addr_auto;	*addr_auto = 0x0;	if (dpll_id == DPLL1_MPU) {		new_val = (*addr & DPLL_ENBIT_MASK) | LOW_POWER_BYPASS;		*addr = new_val;		while (*get_addr_pll(dpll_id, REG_IDLEST_PLL) & 0x1) {			ret = loop_wait(&loop_cnt, &retries_cnt, 1000);			if (ret != PRCM_PASS)				break;		}	} else if (dpll_id == DPLL4_PER) {		new_val = (*addr & DPLL4_ENBIT_MASK) | (LOW_POWER_STOP << 16);		*addr = new_val;		while (*get_addr_pll(dpll_id, REG_IDLEST_PLL) & 0x2) {			ret = loop_wait(&loop_cnt, &retries_cnt, 1000);			if (ret != PRCM_PASS)				break;		}	} else {		if ((dpll_id == DPLL5_PER2) && (bypass_mode != LOW_POWER_STOP))			return ret;		new_val = (*addr & DPLL_ENBIT_MASK) | bypass_mode;		*addr = new_val;		while (*get_addr_pll(dpll_id, REG_IDLEST_PLL) & 0x1) {			ret = loop_wait(&loop_cnt, &retries_cnt, 1000);			if (ret != PRCM_PASS)				break;		}	}	if (ret != PRCM_PASS)		printk(KERN_INFO "Loop count exceeded in "			"prcm_put_dpll_in_bypass for dpll:%u\n", dpll_id);	/* Restore the autoidle for the DPLL back */	*addr_auto = dpll_autoidle;	return ret;}/*============================================================================*//*======================== DPLL AUTO CONTROL =================================*//*============================================================================*//*= This function will enable/disable the auto control feature of the        =*//*= specified dpll.                                                          =*//*= The parameter passed as input should be DPLL_AUTOIDLE,DPLL_NO_AUTOIDLE   =*//*= or DPLL_AUTOIDLE_BYPASS						     =*//*============================================================================*/int prcm_dpll_clock_auto_control(u32 dpll_id, u32 control){	u32 valid;	volatile u32 *addr;	u32 setting;	if (dpll_id > NO_OF_DPLL)		return PRCM_FAIL;	addr = get_addr_pll(dpll_id, REG_AUTOIDLE_PLL);	if (!addr)		return PRCM_FAIL;	valid = get_val_bits_pll(dpll_id, REG_AUTOIDLE_PLL);	if (dpll_id == DPLL4_PER)		setting = 1 << 3;	else if (dpll_id == DPLL3_CORE) {		*addr &= ~CORE3_DPLL_MASK;		switch (control) {		case DPLL_AUTOIDLE_BYPASS:			setting = 5;			break;		case DPLL_NO_AUTOIDLE:		case DPLL_AUTOIDLE:			setting = 1;			break;		default:			return PRCM_FAIL;		}	}	else		setting = 1;	switch (control) {	case DPLL_AUTOIDLE:		*addr |= setting;		break;	case DPLL_NO_AUTOIDLE:		*addr &= (~setting);		break;	case DPLL_AUTOIDLE_BYPASS:		*addr |= setting;		break;	default:		return PRCM_FAIL;	}	return PRCM_PASS;}/*============================================================================*//* This function returns the mn output of a dpll                              *//* (without m2,m3,m4,m5,m6 dividers                                           *//* In other words, it returns CLKOUT = (Fref * m)/(n+1)	in case dpll is locked*//* And bypass clock if it is in bypass mode.                                  *//* The frequency value returned in mn_output is in Khz                        *//*============================================================================*/int prcm_get_dpll_mn_output(u32 dpll, u32 *mn_output){	u32 dpll_idlest_lock_bit, clksel1_pll, dpll_id;	u32 sys_clkspeed, core_clkspeed;	int bypassclk_divider;	u32 mult, div;	volatile u32 *addr;	dpll_id = (dpll >> DPLL_NO_POS) & DPLL_NO_MASK;	if (dpll_id > NO_OF_DPLL)		return PRCM_FAIL;	dpll_idlest_lock_bit = get_idlest_lock_bit(dpll_id);	DPRINTK("dpll: %d\n", dpll_id);	addr = get_addr_pll(dpll_id, REG_IDLEST_PLL);	/* Get the sys clock speed */	sys_clkspeed = prcm_get_system_clock_speed();	DPRINTK("SYSCLKSPEED = %d\n", sys_clkspeed);	if (*addr & dpll_idlest_lock_bit) {		/* dpll locked */		get_dpll_m_n(dpll_id, &mult, &div);		DPRINTK("DPLL not in bypass,M=%d, N=%d\n", mult, div);		*mn_output = ((sys_clkspeed * mult) / (div + 1));	} else {		/* dpll is in bypass mode */		DPRINTK("DPLL in bypass\n");		if ((dpll_id == DPLL3_CORE) || (dpll_id == DPLL4_PER)						|| (dpll_id == DPLL5_PER2))			*mn_output = sys_clkspeed;		else {		/* DPLL1 and DPLL2				 * Check if DPLL3 is in bypass */			prcm_get_dpll_rate(PRCM_DPLL3_M2X2_CLK, &core_clkspeed);			DPRINTK("Core clk speed: %d\n", core_clkspeed);			if (dpll_id == DPLL1_MPU)				clksel1_pll = CM_CLKSEL1_PLL_MPU;			else				clksel1_pll = CM_CLKSEL1_PLL_IVA2;			bypassclk_divider = (clksel1_pll >> 19) & 0x3;			*mn_output = core_clkspeed / bypassclk_divider;		}	}	DPRINTK("DPLL_MN_OUTPUT: %d\n", *mn_output);	return PRCM_PASS;}/*============================================================================*//*======================== GET DPLL RATE =====================================*//*============================================================================*//*= This function returns the rate for the specified dpll in KHz. It checks  =*//*= if the DPLL is in locked mode or unlocked mode and accordingly calculates=*//*= the output.                                                              =*//*============================================================================*/int prcm_get_dpll_rate(u32 dpll, u32 *output){	u32 dpll_id, dpll_div, dpll_mxsft, id_type;	u32 mx, omap;	u32 mn_output;	id_type = get_id_type(dpll);	if (!(id_type & ID_DPLL_OP))		return PRCM_FAIL;	/*Not dpll op */	omap = OMAP(dpll);	if (cpu_is_omap3430() && !(omap & (AT_3430|AT_3430_ES2)))		return PRCM_FAIL;	dpll_id = (dpll >> DPLL_NO_POS) & DPLL_NO_MASK;	if (dpll_id > NO_OF_DPLL)		return PRCM_FAIL;	dpll_div = (dpll >> DPLL_DIV_POS) & DPLL_DIV_MASK;	dpll_mxsft = dpll_mx_shift[dpll_id-1][dpll_div];	DPRINTK("dpllmxsft:%d\n", dpll_mxsft);	DPRINTK("Output required:%d\n", dpll_div);	mx = get_dpll_mx(dpll_id, dpll_div, dpll_mxsft);	DPRINTK("MX: %d\n", mx);	prcm_get_dpll_mn_output(dpll, &mn_output);	/* Except for DPLL_M2 all clocks are (mn_output*2)/mx */	if (dpll_div == DPLL_M2)		*output = (mn_output) / mx;	else		*output = (2 * mn_output) / mx;	DPRINTK("Output: %d\n", *output);	return PRCM_PASS;}/*============================================================================*//*======================== CONFIGURE DPLL DIVIDER ============================*//*============================================================================*//*= Each DPLL can have upto six independent output clocks based on various   =*//*= divider values. This function configures the different divider values for=*//*= the specified dpll.                                                      =*//*============================================================================*/int prcm_configure_dpll_divider(u32 dpll, u32 setting){	u32 dpll_id, valid, dpll_mxsft, omap, id_type;	u32 dpll_div, new_val = 0x00000000;	volatile u32 *addr;	id_type = get_id_type(dpll);	if (!(id_type & ID_DPLL_OP))		return PRCM_FAIL;	/*Not DPLL OP */	omap = OMAP(dpll);	if (cpu_is_omap3430() && !(omap & (AT_3430|AT_3430_ES2)))		return PRCM_FAIL;	dpll_id = (dpll >> DPLL_NO_POS) & DPLL_NO_MASK;	if (dpll_id > NO_OF_DPLL)		return PRCM_FAIL;	if (is_sil_rev_equal_to(OMAP3430_REV_ES1_0)) {		/* Workaround for limitation 2.5 */		/* On ES 1.0, DPLL4 dividers cannot be changed */		if (dpll_id == DPLL4_PER)			return PRCM_FAIL;	}	dpll_div = (dpll >> DPLL_DIV_POS) & DPLL_DIV_MASK;	dpll_mxsft = dpll_mx_shift[dpll_id-1][dpll_div];	addr = get_addr_pll(dpll_id, dpll_div + MX_ARRAY_OFFSET);	valid = get_val_bits_pll(dpll_id, dpll_div + MX_ARRAY_OFFSET);	new_val = (*addr & valid) | (setting << dpll_mxsft);	*addr = new_val;	return PRCM_PASS;}/*============================================================================*//*======================== CLOCK DOMAIN STATE  ===============================*//*============================================================================*//*= This function returns the state of the clock domain. It reads the        =*//*= CM_CLKSTST_<DOMAIN> register and returns the result as PRCM_ENABLE if    =*//*= the clock domain is active, else returns PRCM_DISABLE  		     =*//*= a wake up event.  If disabled, it masks the wake up event from the       =*//*= specified module.  This register will modify the PM_WKEN_<DOMAIN>        =*//*= register.  This function will return PRCM_FAIL if the parameters passed  =*//*= are invalid, otherwise it will return PRCM_PASS.  Valid parameters for   =*//*= control are PRCM_ENABLE and PRCM_DISABLE.                                =*//*============================================================================*/int prcm_is_clock_domain_active(u32 domainid, u8 *result){	u32 valid;	volatile u32 *addr;	/* Core domain check is not supported */	if ((domainid == DOM_CORE1) || (domainid == DOM_CORE2)) {		printk(KERN_INFO "Currently prcm_is_clock_domain_active for "			"the following domains (DOM_CORE1/DOM_CORE2) "			"is not supported\n");		return PRCM_FAIL;	}	addr = get_addr(domainid, REG_CLKSTST);	valid = get_val_bits(domainid, REG_CLKSTST);	if (!addr)		return PRCM_FAIL;	if (*addr & valid) {		*result = PRCM_ENABLE;		return PRCM_PASS;	} else {		*result = PRCM_DISABLE;		return PRCM_PASS;	}}/*============================================================================*//*======================== CLOCK DOMAIN STATUS ===============================*//*============================================================================*//* This function waits for the clock domain to transition to the desired state*//* It polls on the clock domain state and times out after a wait of ~500 micro*//* secs. It returns PRCM_PASS id the clock domain transitions to the desired  *//* state within the timeout period, else return PRCM_FAIL		      *//*============================================================================*/static int prcm_check_clock_domain_status(u32 domainid, u8 desired_state){	u8 curr_state;	u32 loop_cnt = 0, retries_cnt = 0;	int ret;	if (domainid > PRCM_NUM_DOMAINS)		return PRCM_FAIL;	/* Core domain check is not supported */	if (   (domainid == DOM_CORE1)	    || (domainid == DOM_CORE2)	    || (domainid == DOM_MPU)) {		printk ("prcm_check_clock_domain_status : "		        "Not currently supported for "			"DOM_CORE1, DOM_CORE2, DOM_MPU\n") ;		return PRCM_FAIL;	}	ret = prcm_is_clock_domain_active(domainid, &curr_state);	if (ret != PRCM_PASS)		return ret;	while (curr_state != desired_state) {		ret = prcm_is_clock_domain_active(domainid, &curr_state);		if (ret != PRCM_PASS)			return ret;		ret = loop_wait(&loop_cnt, &retries_cnt, 100);		if (ret != PRCM_PASS) {			printk (".");/* * Uncomment for debug.			printk (KERN_INFO "prcm_check_clock_domain_status : "			        "Timeout waiting for clock active. "				"(domain 0x%x) (%d) (%d)\n", domainid, curr_state, desired_state) ;*/			return ret;		}	}	return PRCM_PASS;}/*============================================================================*//*======================== SET CLOCK DOMAIN STATE ============================*//*============================================================================*//* This function sets the clock domain state to the 'new_state' specified. In *//* software supervised mode it checks if all the pre-conditions for clock     *//* domain transition are met. If check_accessibility is set to PRCM_TRUE the  *//* function also waits for the clock domain transition to complete            *//*============================================================================*/int prcm_set_clock_domain_state(u32 domainid, u8 new_state,				u8 check_state){	volatile u32 *addr;	u32 fclk_mask = 0, iclk_mask = 0, init_mask, dev_mask;	u32 new_val, valid;	/*	 *  Validate the pre-conditions:	 *  1) Domain is valid.	 *  2) DOM_CORE1, DOM_CORE2 are currently not supported.	 *  3) Domain has a CLKSTCTRL register	 *  4) 'check_state' is valid for requested 'new_state'	 *  5) 'new_state' is valid for requested 'domainid'	 */	if (domainid > PRCM_NUM_DOMAINS)		return PRCM_FAIL;	if (   (domainid == DOM_CORE1)	    || (domainid == DOM_CORE2)) {		printk (KERN_INFO			"prcm_set_clock_domain_state : "		        "DOM_CORE1, DOM_CORE2 currently not supported.\n") ;		return PRCM_FAIL;	}	addr = get_addr(domainid, REG_CLKSTCTRL);	valid = get_val_bits(domainid, REG_CLKSTCTRL);	if (!addr) {		printk (KERN_INFO			"prcm_set_clock_domain_state : "		        "No ClkStCtrl for domain %d\n", domainid) ;		return PRCM_FAIL;	}	/* It is not appropriate to pass check_state = TRUE for states	 * PRCM_NO_AUTO and PRCM_HWSUP_AUTO.	 * In case of PRCM_NO_AUTO, hardware control of clock domain is disabled	 * In case of PRCM_HWSUP_AUTO, the clock domain will transition	 * automatically when conditions are satisfied	 */	if (check_state == PRCM_TRUE) {		if (   (new_state == PRCM_NO_AUTO)		    || (new_state == PRCM_HWSUP_AUTO)) {			printk(KERN_INFO				"prcm_set_clock_domain_state : "			        "Cannot wait for change of state to 0x%x.\n",				new_state) ;			return PRCM_FAIL;		}	}	/* Check preconditions for SWSUP sleep if check_state = TRUE */	if (new_state == PRCM_SWSUP_SLEEP) {		if (domainid == DOM_MPU) {			/* There is no SWSUPERVISED sleep for MPU*/			return PRCM_FAIL;		}		if (check_state == PRCM_TRUE) {			/*			 * Are FCLK and ICLK disabled for the domain?			 */			prcm_get_domain_functional_clocks(domainid, &fclk_mask);			prcm_get_domain_interface_clocks(domainid, &iclk_mask);			if (fclk_mask || iclk_mask) {				printk (KERN_INFO					"prcm_set_clock_domain_state : "					"Pre-condition not met. "					"Domain : 0x%x "

⌨️ 快捷键说明

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