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

📄 prcm_34xx.c

📁 omap3 linux 2.6 用nocc去除了冗余代码
💻 C
📖 第 1 页 / 共 5 页
字号:
 * * Checks whether a specified DPLL is locked or not. * Returns PRCM_TRUE if it is locked, PRCM_FALSE otherwise. */static int is_dpll_locked(u32 dpll_id, int *result){	volatile u32 *addr;	u32 dpll_enbit_mask, dpll_idlest_lock_bit;	addr = get_addr_pll(dpll_id, REG_CLKEN_PLL);	if (!addr)		return PRCM_FAIL;	dpll_enbit_mask = get_dpll_enbitmask(dpll_id);	dpll_idlest_lock_bit = get_idlest_lock_bit(dpll_id);	if ((*addr & (~dpll_enbit_mask)) == (~dpll_enbit_mask))		*result = PRCM_TRUE;	else		*result = PRCM_FALSE;	return PRCM_PASS;}/** * check_accessibility: Is device accessible? * @deviceid: Device id * @clk_type: * * Checks whether a specified device is accessible by probing FCLK and ICLK. * Returns PRCM_TRUE if it is accessible, PRCM_FALSE otherwise. */static int check_accessibility(u32 deviceid, u8 clk_type){	u32 valid = 0, enbit, type, domain;	volatile u32 *addr = 0;	enbit  = DEV_BIT_POS(deviceid);	domain = DOMAIN_ID(deviceid);	type   = DEV_TYPE(deviceid);	if (type == TARGET) {		/* Skip devices without CM_IDLEST register bit support */		addr  = get_addr(domain, REG_IDLEST);		valid = get_val_bits(domain, REG_IDLEST);		if (!(addr) || !(valid & (1 << enbit)))			return PRCM_PASS;		/* Check if FCLK/ICLK is absent or ICLK is ON if present. */		if (clk_type == ICLK) {			addr  = get_addr(domain, REG_FCLKEN);			valid = get_val_bits(domain, REG_FCLKEN);		} else if (clk_type == FCLK) {			addr = get_addr(domain, REG_ICLKEN);			valid = get_val_bits(domain, REG_ICLKEN);		}		if (!(addr) || !(valid & (1 << enbit))		    || (*addr & (1 << enbit))) {			/* FCLK/ICLK present and is ON */			return check_device_status(deviceid, PRCM_ENABLE);		}	} else {		/* type = INITIATOR or INITIATOR+TARGET		 * IDLEST bit cannot be polled,		 * it only specifies the		 * standby status		 * Check if the ICLK is present and ON */		if (clk_type == FCLK) {			addr  = get_addr(domain, REG_ICLKEN);			valid = get_val_bits(domain, REG_ICLKEN);		} else if (clk_type == ICLK) {			addr  = get_addr(domain, REG_FCLKEN);			valid = get_val_bits(domain, REG_FCLKEN);		}		if (!(addr) || !(valid & (1 << enbit))		    || (*addr & (1 << enbit))) {			/* FCLK/ICLK present and is ON			 * Wait for sometime for the clocks to stabilize*/			DPRINTK("Adding delay\n");			omap_udelay(100);			return PRCM_PASS;		}	}	return PRCM_PASS;}/** * calc_dpll_lock_delay: Calculate DPLL lock time. * @dpll_id: dpll ID * @delay: Calculated delay * * Calculates the delay/wait time for a DPLL to relock. * Uses the following formula to calculate the worst possible delay. * delay = 2us + 350Fint_cycles (Fint_cycles = Fref/N+1) */static int calc_dpll_lock_delay(u32 dpll_id, u32 *delay){	u32 f_ref, f_int, m, n;	f_ref = prcm_get_system_clock_speed();	if (f_ref == PRCM_FAIL) {		printk(KERN_INFO "Unable to get system clock\n");		return PRCM_FAIL;	}	if (get_dpll_m_n(dpll_id, &m, &n) == PRCM_FAIL) {		printk(KERN_INFO "Failed to get the M and N values\n");		return PRCM_FAIL;	}	f_int = f_ref / (n + 1);	*delay = (2 + (350*1000)/f_int);	return PRCM_PASS;}/*============================================================================*//*============================================================================*//*======================== CLOCK CONTROL  ====================================*//*============================================================================*//*= This function will either enable or disable the fclk/iclk clock for the  =*//*= specified module.  This command will modify the CM_F/ICLKEN_<DOMAIN>/    =*//*= setting.  The valid parameters for control are PRCM_ENABLE and           =*//*= PRCM_DISABLE. This command will return PRCM_FAIL if the passed parameters=*//*= are not valid,otherwise it will return PRCM_PASS.If the parameter        =*//*= checkaccessibility is PRCM_TRUE, the function waits till the device is   =*//*= accessible before returning (provided both fclk/iclk clock are           =*//*= enabled).                                                                =*//*============================================================================*/int prcm_clock_control(u32 deviceid, u8 clk_type, u8 control,		       u8 checkaccessibility){	u32 domain, omap, valid, enbit;	volatile u32 *addr;	DPRINTK("Clock:%d Control:%d\n", clk_type, control);	omap   = OMAP(deviceid);	enbit  = DEV_BIT_POS(deviceid);	domain = DOMAIN_ID(deviceid);	if (cpu_is_omap3430() && !(omap & (AT_3430|AT_3430_ES2)))		return PRCM_FAIL;	switch (clk_type) {	case ICLK:		addr = get_addr(domain, REG_ICLKEN);		valid = get_val_bits(domain, REG_ICLKEN);		break;	case FCLK:		addr = get_addr(domain, REG_FCLKEN);		valid = get_val_bits(domain, REG_FCLKEN);		break;	default:		return PRCM_FAIL;	}	DPRINTK("Address before: %x\n", *addr);	/* No functional/Interface Clk control for the device */	if (!(addr) || !(valid & (1 << enbit)))		return PRCM_FAIL;	if (control == PRCM_ENABLE)		*addr |= (1 << enbit);	else if (control == PRCM_DISABLE)		*addr &= ~(1 << enbit);	DPRINTK("Address after: %x\n", *addr);	if (checkaccessibility) {		return check_accessibility(deviceid, clk_type);	}	return PRCM_PASS;}/*======================== DEVICE IDLE STATE =================================*//*============================================================================*//*= This function returns the specified module's idle status. It reads the   =*//*= CM_IDLEST_<DOMAIN> register to determine whether the device is accessible=*//*= or not. The result returned is PRCM_TRUE if the device is accessible     =*//*= else PRCM_FALSE. The function returns PRCM_FAIL if the parameters are    =*//*= not valid.                                                               =*//*============================================================================*/int prcm_is_device_accessible(u32 deviceid, u8 *result){	u32 domain, omap, valid, enbit;	volatile u32 *addr;	omap = OMAP(deviceid);	enbit = DEV_BIT_POS(deviceid);	domain = DOMAIN_ID(deviceid);	if (cpu_is_omap3430() && !(omap & (AT_3430|AT_3430_ES2)))		return PRCM_FAIL;	addr = get_addr(domain, REG_IDLEST);	valid = get_val_bits(domain, REG_IDLEST);	if (!(addr) || !(valid & (1 << enbit)))		return PRCM_FAIL;	if (!(*addr & (1 << enbit))) {		*result = PRCM_TRUE;	} else {		*result = PRCM_FALSE;	}	return PRCM_PASS;}/** * prcm_interface_clock_autoidle: * @deviceid: Device ID * @control: One of the control arguments - PRCM_ENABLE or PRCM_DISABLE. * * Enable or Disable the interface clock autoidle. It modifies the * CM_AUTOIDLE_<DOMAIN> setting. * Returns PRCM_PASS on success, PRCM_FAIL otherwise. */int prcm_interface_clock_autoidle(u32 deviceid, u8 control){	u32 domain, omap, valid, enbit;	volatile u32 *addr;	omap   = OMAP(deviceid);	enbit  = DEV_BIT_POS(deviceid);	domain = DOMAIN_ID(deviceid);	if (cpu_is_omap3430() && !(omap & (AT_3430|AT_3430_ES2)))		return PRCM_FAIL;	addr  = get_addr(domain, REG_AUTOIDLE);	valid = get_val_bits(domain, REG_AUTOIDLE);	if (!(addr) || !(valid & (1 << enbit)))		return PRCM_FAIL;	if (control == PRCM_ENABLE)		*addr |= (1 << enbit);	else if (control == PRCM_DISABLE)		*addr &= ~(1 << enbit);	return PRCM_PASS;}/** * prcm_wakeup_event_control: Enable/ Disable the wakeup event for a device * @deviceid: Device ID * @control: One of the control arguments - PRCM_ENABLE or PRCM_DISABLE * * Enable or Disable the wakeup event for specified device. If enabled, * the device can generate a wake-up event. If disabled, the wake-up event * from the device is masked. It modifies the PM_WKEN_<DOMAIN> register. * Returns PRCM_PASS on success, PRCM_FAIL otherwise. */int prcm_wakeup_event_control(u32 deviceid, u8 control){	u32 domain, omap, valid, enbit;	volatile u32 *addr;	omap   = OMAP(deviceid);	enbit  = DEV_BIT_POS(deviceid);	domain = DOMAIN_ID(deviceid);	if (cpu_is_omap3430() && !(omap & (AT_3430|AT_3430_ES2)))		return PRCM_FAIL;	addr = get_addr(domain, REG_WKEN);	valid = get_val_bits(domain, REG_WKEN);	if (!(addr) || !(valid & (1 << enbit)))		return PRCM_FAIL;	if (control == PRCM_ENABLE)		*addr |= (1 << enbit);	else if (control == PRCM_DISABLE)		*addr &= ~(1 << enbit);	return PRCM_PASS;}/*============================================================================*//*======================== ENABLE DPLL =======================================*//*============================================================================*//*= The function enables the specified DPLL and then wait for the DPLL to    =*//*= lock before returning.The function modifies the CM_CLKEN_PLL_<DPLL>      =*//*= setting. The function returns PRCM_FAIL if the dpllid passed is invalid  =*//*============================================================================*/int prcm_enable_dpll(u32 dpll_id){	u32 dpll_idlest_lock_bit, dpll_enbit_mask, delay;	volatile u32 *addr, *addr_auto;	u32 dpll_autoidle;	int ret, enabled;	u32 loop_cnt = 0, retries_cnt = 0;	if (dpll_id > NO_OF_DPLL)		return PRCM_FAIL;	/* Currently, this API does not allow locking of core DPLL */	/* Locking of core DPLL needs to be done without access to SDRAM */	/* This can be done safely if execution is done from SRAM */	if (dpll_id == DPLL3_CORE)		return PRCM_FAIL;	/* Store the DPLL autoidle */	addr_auto = get_addr_pll(dpll_id, REG_AUTOIDLE_PLL);	dpll_autoidle = *addr_auto;	*addr_auto = 0x0;	ret = is_dpll_locked(dpll_id, &enabled);	if (ret != PRCM_PASS) {		*addr_auto = dpll_autoidle;		return ret;	}	if (enabled == PRCM_TRUE) {		DPRINTK("DPLL%d already enabled\n", dpll_id);		*addr_auto = dpll_autoidle;		return PRCM_PASS;	}	addr = get_addr_pll(dpll_id, REG_CLKEN_PLL);	if (!addr) {		*addr_auto = dpll_autoidle;		return PRCM_FAIL;	}	dpll_enbit_mask = get_dpll_enbitmask(dpll_id);	dpll_idlest_lock_bit = get_idlest_lock_bit(dpll_id);	*addr |= ~dpll_enbit_mask;	/* enable DPLL in lock mode */	if (is_sil_rev_equal_to(OMAP3430_REV_ES1_0)) {		/* WORKAROUND FOR SILICON ERRATA 1.56 */		ret = calc_dpll_lock_delay(dpll_id, &delay);		if (ret != PRCM_PASS) {			*addr_auto = dpll_autoidle;			return ret;		}		DPRINTK("SILICON ERRATA 1.56, adding delay of %dus\n", delay);		omap_udelay(delay);	}	ret = calc_dpll_lock_delay(dpll_id, &delay);	if (ret != PRCM_PASS) {		*addr_auto = dpll_autoidle;		return ret;	}	DPRINTK("Waiting for %dus for dpll:%u to relock\n", delay, dpll_id);	while (!(*get_addr_pll(dpll_id, REG_IDLEST_PLL) &						 dpll_idlest_lock_bit)) {		/* wait for DPLL to lock */		ret = loop_wait(&loop_cnt, &retries_cnt, delay/5);		if (ret != PRCM_PASS) {		printk(KERN_INFO "Loop count exceeded in"				"prcm_enable_dpll for dpll:%u\n", dpll_id);			*addr_auto = dpll_autoidle;			return ret;		}	}	/* Restore the autoidle for the DPLL back */	*addr_auto = dpll_autoidle;	return PRCM_PASS;}/*============================================================================*//*======================== CONFIGURE DPLL ====================================*//*============================================================================*//*= This function will set up the multiply and divide fields for the         =*//*= specified DPLL with the passed mult and div values. It also sets the     =*//*= frequency select field for the specified DPLL. The function returns      =*//*= PRCM_FAIL if the parameters passed are not valid.                        =*//*= Note that this function only does the configuration. Locking is done     =*//*= by prcm_enable_dpll() function                                           =*//*============================================================================*/int prcm_configure_dpll(u32 dpll_id, u32 mult, u8 div, u8 freq_sel){	u32 valid;	volatile u32 *addr, *addr_auto;	u32 new_reg_val = 0x0;	int ret, enabled, index;	u32 sys_clkspeed, dpll_autoidle;	if (dpll_id > NO_OF_DPLL)		return PRCM_FAIL;	if (is_sil_rev_equal_to(OMAP3430_REV_ES1_0)) {		/* WORKAROUND FOR Limitation 2.5 */		if (dpll_id == DPLL4_PER)			return PRCM_FAIL;	}	/* Store the DPLL autoidle */	addr_auto = get_addr_pll(dpll_id, REG_AUTOIDLE_PLL);	dpll_autoidle = *addr_auto;	*addr_auto = 0x0;	/* DPLL M,N,FreqSel values should be changed only if the DPLL	 * is in bypass mode. If it is not in bypass mode, return error */	ret = is_dpll_locked(dpll_id, &enabled);	if (enabled == PRCM_TRUE) {		printk(KERN_INFO "Dpll enabled - m,n values cannot be"								"changed\n");		*addr_auto = dpll_autoidle;		return PRCM_FAIL;	}	/* Configure M and N values */	addr = get_addr_pll(dpll_id, REG_CLKSEL1_PLL);	if (!addr)		return PRCM_FAIL;	if (dpll_id == DPLL5_PER2) {		/* get the M/N/freqsel values */		sys_clkspeed = prcm_get_system_clock_speed();		switch (sys_clkspeed) {		case (int)(12000):			index = 0;			break;		case (int)(13000):			index = 1;			break;		case (int)(19200):			index = 2;			break;		case (int)(26000):			index = 3;			break;		case (int)(38400):			index = 4;			break;		default:			return PRCM_FAIL;		}		mult = usb_dpll_param[index].dpll_m;		div = usb_dpll_param[index].dpll_n;		freq_sel = usb_dpll_param[index].dpll_freqsel;	}	valid = get_val_bits_pll(dpll_id, REG_CLKSEL1_PLL);	if (dpll_id == DPLL3_CORE) {		new_reg_val = *addr & valid & DPLL3_N_MASK;		new_reg_val |= (mult << 16) | (div << 8);		*addr = new_reg_val;	} else {		new_reg_val = *addr & valid & DPLL_N_MASK;		new_reg_val |= (mult << 8) | div;		*addr = new_reg_val;	}	/* Configure FreqSel values */	addr = get_addr_pll(dpll_id, REG_CLKEN_PLL);	if (!addr)		return PRCM_FAIL;	valid = get_val_bits_pll(dpll_id, REG_CLKEN_PLL);

⌨️ 快捷键说明

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