Exemplo n.º 1
0
void restart_dvfs_per()
{
	u32 reg;

	if (clk_get_rate(main_bus_clk) == 24000000)
		cur_setpoint = 2;
	else
		cur_setpoint = 0;

	/* Remove weights. */
	__raw_writel(0, MXC_DVFS_PER_LTR3);
	reg = __raw_readl(MXC_DVFS_PER_PMCR1);
	reg &= ~0xf;
	__raw_writel(reg, MXC_DVFS_PER_PMCR1);

	dvfs_per_load_config();

	/*Unmask GPC1 IRQ */
	reg = __raw_readl(MXC_GPC_CNTR);
	reg &= ~MXC_GPCCNTR_GPCIRQM;
	__raw_writel(reg, MXC_GPC_CNTR);

	reg = __raw_readl(MXC_DVFS_PER_PMCR0);
	/* Enable FVFS interrupt */
	/* FSVAIM=0 */
	reg &= ~MXC_DVFSPMCR0_FSVAI_MASK;
	reg |= FSVAI_FREQ_NOCHANGE;
	reg = (reg & ~MXC_DVFSPMCR0_FSVAIM);
	reg |= MXC_DVFSPMCR0_DVFEN;
	__raw_writel(reg, MXC_DVFS_PER_PMCR0);
	dvfs_per_is_active = 1;

}
Exemplo n.º 2
0
/*!
 * This function is called for module initialization.
 * It sets up the DVFS hardware.
 * It sets default values for DVFS thresholds and counters. The default
 * values was chosen from a set of different reasonable values. They was tested
 * and the default values in the driver gave the best results.
 * More work should be done to find optimal values.
 *
 * @return   0 if successful; non-zero otherwise.
 *
 */
static int init_dvfs_per_controller(void)
{
	u32 reg;

	reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTR0);
	/* DIV3CLK */
	reg &= ~dvfsper_plt_data->div3_mask;
	reg |= (dvfsper_plt_data->div3_div <<
		  dvfsper_plt_data->div3_offset);
	__raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_LTR0);

	reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTR1);
	/* Set load tracking buffer register source */
	reg &= ~MXC_DVFSLTR1_LTBRSR;
	reg |= MXC_DVFSLTR1_LTBRSR;
	reg &= ~MXC_DVFSLTR1_LTBRSH;
	__raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_LTR1);

	/* Enable all the peripheral signals, but VPU and IPU panic*/
	__raw_writel(0x30000, dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR1);
	/* Disable weighted load tracking signals */
	__raw_writel(0, dvfsper_plt_data->membase + MXC_DVFS_PER_LTR3);

	reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0);
	reg &= ~MXC_DVFSPMCR0_DVFEV;
	reg |= MXC_DVFSPMCR0_LBMI;
	__raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0);

	/* DVFS loading config */
	dvfs_per_load_config();
	return 0;
}
Exemplo n.º 3
0
static void dvfs_per_handler(struct work_struct *work)
{
	u32 fsvai;
	u32 reg;
	u32 ret;
	unsigned long flags;
	int retry = 20;

	/* Check DVFS frequency adjustment interrupt status */
	reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0);
	fsvai = (reg & MXC_DVFSPMCR0_FSVAI_MASK) >> MXC_DVFSPMCR0_FSVAI_OFFSET;
	/* Check FSVAI, FSVAI=0 is error */
	if (fsvai == FSVAI_FREQ_NOCHANGE) {
		/* Do nothing. Freq change is not required */
		goto END;
	}

#if DVFS_PER_DEBUG
	dump_dvfs_per_regs();
#endif
	/* If FSVAI indicate freq down. */
	if (fsvai == FSVAI_FREQ_DECREASE) {
		if (cpu_is_mx51()) {
			/*Change the DDR freq to 133Mhz. */
			clk_set_rate(ddr_hf_clk,
				clk_round_rate(ddr_hf_clk, 133000000));
		}

#ifndef DVFS_SW_WORKAROUND
		spin_lock_irqsave(&mxc_dvfs_per_lock, flags);
		reg = __raw_readl(dvfsper_plt_data->membase
				  + MXC_DVFS_PER_PMCR0);
		reg &= ~MXC_DVFSPMCR0_UDCS;
		__raw_writel(reg, dvfsper_plt_data->membase
				  + MXC_DVFS_PER_PMCR0);

		/* Set the peripheral divider */
		reg = __raw_readl(dvfsper_plt_data->gpc_cntr_reg_addr);
		reg &= ~(MXC_GPCCNTR_ADU_MASK | MXC_GPCCNTR_FUPD_MASK);
		reg |= MXC_GPCCNTR_FUPD;
		__raw_writel(reg, dvfsper_plt_data->gpc_cntr_reg_addr);

		reg = __raw_readl(dvfsper_plt_data->gpc_vcr_reg_addr);
		reg &= ~(MXC_GPCVCR_VINC_MASK | MXC_GPCVCR_VCNTU_MASK |
		      MXC_GPCVCR_VCNT_MASK);
		reg |= (1 << MXC_GPCVCR_VCNTU_OFFSET) |
			(1 << MXC_GPCVCR_VCNT_OFFSET);
		__raw_writel(reg, dvfsper_plt_data->gpc_vcr_reg_addr);

		reg = __raw_readl(dvfsper_plt_data->gpc_cntr_reg_addr);
		reg |= MXC_GPCCNTR_STRT;
		__raw_writel(reg, dvfsper_plt_data->gpc_cntr_reg_addr);

		retry = 10;
		while ((__raw_readl(
			dvfsper_plt_data->gpc_cntr_reg_addr) & 0x4000)
			&& retry > 0) {
			udelay(10);
			retry--;
		}
		spin_unlock_irqrestore(&mxc_dvfs_per_lock, flags);
#else
		/*Set the frequencies manually */
		rate = clk_get_rate(axi_b_clk);
		clk_set_rate(axi_b_clk, clk_round_rate(axi_b_clk, rate/2));

		rate = clk_get_rate(ahb_clk);
		clk_set_rate(ahb_clk, clk_round_rate(ahb_clk, rate/2));
#endif
		dvfs_per_low_freq = 1;
		if (clk_get_rate(main_bus_clk) == LOW_BUS_FREQ) {
			cur_setpoint = 2;
		} else {
#if defined(CONFIG_ARCH_MX37)
			dptc_suspend(DPTC_LP_ID);
#endif
			cur_setpoint = 1;
#ifndef DVFS_SW_WORKAROUND
			clk_set_parent(main_bus_clk, clk_get(NULL, "pll2"));
#endif
		}
#ifndef DVFS_SW_WORKAROUND
		/* Drop the LP domain voltage */
		ret = regulator_set_voltage(lp_regulator,
					dvfsper_plt_data->lp_low,
					dvfsper_plt_data->lp_low);
		if (ret < 0) {
			printk(KERN_DEBUG "COULD NOT SET LP VOLTAGE\n");
			return;
		}
		udelay(100);
#endif
		dvfs_per_load_config();
	} else if ((fsvai == FSVAI_FREQ_INCREASE) ||
			(fsvai == FSVAI_FREQ_EMERG)) {
#ifndef DVFS_SW_WORKAROUND
		/* Increase the LP domain voltage first. */
		ret = regulator_set_voltage(lp_regulator,
					dvfsper_plt_data->lp_high,
					dvfsper_plt_data->lp_high);
		if (ret < 0) {
			printk(KERN_DEBUG "COULD NOT SET LP VOLTAGE\n");
			return;
		}
		udelay(100);
#endif

#ifndef DVFS_SW_WORKAROUND
		spin_lock_irqsave(&mxc_dvfs_per_lock, flags);
		reg = __raw_readl(dvfsper_plt_data->membase
				  + MXC_DVFS_PER_PMCR0);
		reg |= MXC_DVFSPMCR0_UDCS;
		__raw_writel(reg, dvfsper_plt_data->membase
				  + MXC_DVFS_PER_PMCR0);

		reg = __raw_readl(dvfsper_plt_data->gpc_cntr_reg_addr);
		reg &= ~(MXC_GPCCNTR_ADU_MASK | MXC_GPCCNTR_FUPD_MASK);
		reg |= MXC_GPCCNTR_FUPD;
		__raw_writel(reg, dvfsper_plt_data->gpc_cntr_reg_addr);

		reg = __raw_readl(dvfsper_plt_data->gpc_vcr_reg_addr);
		reg &= ~(MXC_GPCVCR_VINC_MASK | MXC_GPCVCR_VCNTU_MASK |
		      MXC_GPCVCR_VCNT_MASK);
		reg |= (1 << MXC_GPCVCR_VINC_OFFSET |
			1 << MXC_GPCVCR_VCNTU_OFFSET |
			1 << MXC_GPCVCR_VCNT_OFFSET);
		__raw_writel(reg, dvfsper_plt_data->gpc_vcr_reg_addr);

		reg = __raw_readl(dvfsper_plt_data->gpc_cntr_reg_addr);
		reg &= ~MXC_GPCCNTR_ADU;
		reg |= MXC_GPCCNTR_STRT;
		__raw_writel(reg, dvfsper_plt_data->gpc_cntr_reg_addr);
		retry = 10;
		while ((__raw_readl(
				dvfsper_plt_data->gpc_cntr_reg_addr) & 0x4000)
				&& retry > 0) {
			udelay(10);
			retry--;
		}
		spin_unlock_irqrestore(&mxc_dvfs_per_lock, flags);

	if (retry < 0)
		printk(KERN_ERR "****ERROR- DVFS\n");
#else
		/*Set the frequencies manually */
		rate = clk_get_rate(axi_b_clk);
		clk_set_rate(axi_b_clk, clk_round_rate(axi_b_clk, 130000000));
		rate = clk_get_rate(ahb_clk);
		clk_set_rate(ahb_clk, clk_round_rate(ahb_clk, 130000000));
#endif
		if (cpu_is_mx51()) {
			/*Change the DDR freq to 200Mhz. */
			clk_set_rate(ddr_hf_clk, clk_round_rate(ddr_hf_clk,
						200000000));
		}
		dvfs_per_low_freq = 0;
		if (clk_get_rate(main_bus_clk) == LOW_BUS_FREQ) {
			cur_setpoint = 2;
		} else {
			cur_setpoint = 0;
#if defined(CONFIG_ARCH_MX37)
			dptc_resume(DPTC_LP_ID);
#endif
#ifndef DVFS_SW_WORKAROUND
			clk_set_parent(main_bus_clk, clk_get(NULL, "pll2"));
#endif
		}
		dvfs_per_load_config();
		freq_increased = 1;
	}

END:
#if DVFS_PER_DEBUG
	dump_dvfs_per_regs(void)();
#endif
	if (dvfs_per_is_active) {
		reg = __raw_readl(dvfsper_plt_data->membase
				  + MXC_DVFS_PER_PMCR0);
		/* Enable dVFS interrupt */
		/* FSVAIM=0 */
		reg &= ~MXC_DVFSPMCR0_FSVAI_MASK;
		reg |= FSVAI_FREQ_NOCHANGE;
		reg = (reg & ~MXC_DVFSPMCR0_FSVAIM);
		__raw_writel(reg, dvfsper_plt_data->membase
				  + MXC_DVFS_PER_PMCR0);
		/*Unmask GPC1 IRQ */
		reg = __raw_readl(dvfsper_plt_data->gpc_cntr_reg_addr);
		reg &= ~MXC_GPCCNTR_GPCIRQM;
		__raw_writel(reg, dvfsper_plt_data->gpc_cntr_reg_addr);
	}
}
Exemplo n.º 4
0
static void dvfs_per_workqueue_handler(struct work_struct *work)
{
	u32 fsvai;
	u32 reg;
	u32 ret;
	u32 rate;
	/* Check DVFS frequency adjustment interrupt status */
	reg = __raw_readl(MXC_DVFS_PER_PMCR0);
	fsvai = (reg & MXC_DVFSPMCR0_FSVAI_MASK) >> MXC_DVFSPMCR0_FSVAI_OFFSET;
	/* Check FSVAI, FSVAI=0 is error */
	if (fsvai == FSVAI_FREQ_NOCHANGE) {
		/* Do nothing. Freq change is not required */
		goto END;
	}
	/* If FSVAI indicate freq down. */
	if (fsvai == FSVAI_FREQ_DECREASE) {
		reg = __raw_readl(MXC_DVFS_PER_PMCR0);
		reg &= ~MXC_DVFSPMCR0_UDCS;
		__raw_writel(reg, MXC_DVFS_PER_PMCR0);

	if (cpu_is_mx51()) {
		/*Change the DDR freq to 133Mhz. */
		clk_set_rate(ddr_hf_clk, clk_round_rate(ddr_hf_clk, 133000000));
	}

#ifndef DVFS_SW_WORKAROUND
		/* Set the peripheral divider */
		reg = __raw_readl(MXC_GPC_CNTR);
		reg |= MXC_GPCCNTR_FUPD;
		__raw_writel(reg, MXC_GPC_CNTR);
		reg = __raw_readl(MXC_GPC_VCR);
		reg &= ~(MXC_GPCVCR_VINC_MASK | MXC_GPCVCR_VCNTU_MASK |
		      MXC_GPCVCR_VCNT_MASK);
		reg |= (1 << MXC_GPCVCR_VCNTU_OFFSET) |
			(20 << MXC_GPCVCR_VCNT_OFFSET);
		__raw_writel(reg, MXC_GPC_VCR);
		reg = __raw_readl(MXC_GPC_CNTR);
		reg |= MXC_GPCCNTR_STRT;
		__raw_writel(reg, MXC_GPC_CNTR);
		while (__raw_readl(MXC_GPC_CNTR) & 0x4000) {
			udelay(10);
		}
#else
		//Set the frequencies manually
		rate = clk_get_rate(axi_b_clk);
		clk_set_rate(axi_b_clk, clk_round_rate(axi_b_clk, rate/2));

		rate = clk_get_rate(ahb_clk);
		clk_set_rate(ahb_clk, clk_round_rate(ahb_clk, rate/2));
#endif
		if (clk_get_rate(main_bus_clk) == LOW_BUS_FREQ) {
			cur_setpoint = 2;
		} else {
			if (cpu_is_mx37())
				;//dptc_suspend(DPTC_LP_ID);
			cur_setpoint = 1;
#ifndef DVFS_SW_WORKAROUND
			clk_set_parent(main_bus_clk, pll2);
#endif
		}
#ifndef DVFS_SW_WORKAROUND
		/* Drop the LP domain voltage */
		mx37_set_lp_voltage(LP_LOWFREQ_VOLTAGE);
		udelay(100);
#endif
		dvfs_per_load_config();
	} else if ((fsvai == FSVAI_FREQ_INCREASE) ||
			(fsvai == FSVAI_FREQ_EMERG)) {
		reg = __raw_readl(MXC_DVFS_PER_PMCR0);
		reg |= MXC_DVFSPMCR0_UDCS;
		__raw_writel(reg, MXC_DVFS_PER_PMCR0);
#ifndef DVFS_SW_WORKAROUND
		/* Increase the LP domain voltage first. */
		mx37_set_lp_voltage(LP_NORMAL_VOLTAGE);
		udelay(100);
#endif

	if (cpu_is_mx51()) {
		/*Change the DDR freq to 133Mhz. */
		clk_set_rate(ddr_hf_clk, clk_round_rate(ddr_hf_clk, 200000000));
	}

#ifndef DVFS_SW_WORKAROUND
		reg = __raw_readl(MXC_GPC_CNTR);
		reg |= MXC_GPCCNTR_FUPD;
		__raw_writel(reg, MXC_GPC_CNTR);
		reg = __raw_readl(MXC_GPC_VCR);
		reg &= ~(MXC_GPCVCR_VINC_MASK | MXC_GPCVCR_VCNTU_MASK |
		      MXC_GPCVCR_VCNT_MASK);
		reg |= (1 << MXC_GPCVCR_VINC_OFFSET |
			1 << MXC_GPCVCR_VCNTU_OFFSET |
			20 << MXC_GPCVCR_VCNT_OFFSET);
		__raw_writel(reg, MXC_GPC_VCR);
		reg = __raw_readl(MXC_GPC_CNTR);
		reg &= ~MXC_GPCCNTR_ADU;
		reg |= MXC_GPCCNTR_STRT;

		__raw_writel(reg, MXC_GPC_CNTR);
		while (__raw_readl(MXC_GPC_CNTR) & 0x4000) {
			udelay(10);
		}
#else
		//Set the frequencies manually
		rate = clk_get_rate(axi_b_clk);
		clk_set_rate(axi_b_clk, clk_round_rate(axi_b_clk, 130000000));
		rate = clk_get_rate(ahb_clk);
		clk_set_rate(ahb_clk, clk_round_rate(ahb_clk, 130000000));
#endif

		if (clk_get_rate(main_bus_clk) == LOW_BUS_FREQ) {
			cur_setpoint = 2;
		} else {
			cur_setpoint = 0;
			if (cpu_is_mx37())
				;//dptc_resume(DPTC_LP_ID);
#ifndef DVFS_SW_WORKAROUND
			clk_set_parent(main_bus_clk, clk_get(NULL, "pll2"));
#endif
		}
		dvfs_per_load_config();
		freq_increased = 1;
	}

END:
//	dump_dvfs_per_regs();

	if (dvfs_per_is_active) {
		reg = __raw_readl(MXC_DVFS_PER_PMCR0);
		/* Enable dVFS interrupt */
		/* FSVAIM=0 */
		reg &= ~MXC_DVFSPMCR0_FSVAI_MASK;
		reg |= FSVAI_FREQ_NOCHANGE;
		reg = (reg & ~MXC_DVFSPMCR0_FSVAIM);
		__raw_writel(reg, MXC_DVFS_PER_PMCR0);
		/*Unmask GPC1 IRQ */
		reg = __raw_readl(MXC_GPC_CNTR);
		reg &= ~MXC_GPCCNTR_GPCIRQM;
		__raw_writel(reg, MXC_GPC_CNTR);
	}

}