Beispiel #1
0
static ssize_t arisc_freq_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t size)
{
	u32 freq = 0;
	u32 pll  = 0;
	u32 mode = 0;
	u32 ret = 0;

	sscanf(buf, "%u %u", &pll, &freq);

#if (defined CONFIG_ARCH_SUN8IW1P1) || (defined CONFIG_ARCH_SUN8IW3P1) || (defined CONFIG_ARCH_SUN8IW5P1)
	if ((pll != 1) || (freq < 0) || (freq > 3000000)) {
		ARISC_WRN("invalid pll [%u] or freq [%u] to set, this platform only support pll1, freq [0, 3000000]KHz\n", pll, freq);
		ARISC_WRN("pls echo like that: echo pll freq > freq\n");
		return size;
	}
#elif (defined CONFIG_ARCH_SUN9IW1P1) || (defined CONFIG_ARCH_SUN8IW6P1)
	if (((pll != 1) && (pll != 2)) || (freq < 0) || (freq > 3000000)) {
		ARISC_WRN("invalid pll [%u] or freq [%u] to set, this platform only support pll1 and pll2, freq [0, 3000000]KHz\n", pll, freq);
		ARISC_WRN("pls echo like that: echo pll freq > freq\n");
		return size;
	}
#endif

	arisc_pll = pll;
	ret = arisc_dvfs_set_cpufreq(freq, pll, mode, NULL, NULL);
	if (ret) {
		ARISC_ERR("pll%u freq set to %u fail\n", pll, freq);
	} else {
		ARISC_LOG("pll%u freq set to %u success\n", pll, freq);
	}

	return size;
}
Beispiel #2
0
static int sun8i_cluster_power_set(unsigned int cluster, bool enable)
{
	unsigned int value;
	int          i;
#ifdef MCPM_WITH_ARISC_DVFS_SUPPORT
	/* cluster operation must wait arisc ready */
	if (!is_arisc_ready()) {
		pr_debug("%s: arisc not ready, can't power-up cluster\n", __func__);
		return -EINVAL;
	}
#endif
	if (enable) {
		pr_debug("sun8i power-up cluster-%d\n", cluster);

		/* assert cluster cores resets */
		value = cpu_cfg_readl(sun8i_cpuxcfg_base + SUNXI_CPU_RST_CTRL(cluster));
#if defined(CONFIG_ARCH_SUN8IW6)
		value &= (~(0xF<<0));   /* Core Reset    */
#elif defined(CONFIG_ARCH_SUN8IW9)
		value &= (~(0x7<<0));   /* Core Reset    */
#endif
		cpu_cfg_writel(value, sun8i_cpuxcfg_base + SUNXI_CPU_RST_CTRL(cluster));
		udelay(10);

		/* assert cluster cores power-on reset */
		value = sunxi_smc_readl(sun8i_cpuscfg_base + SUNXI_CLUSTER_PWRON_RESET(cluster));
#if defined(CONFIG_ARCH_SUN8IW6)
		value &= (~(0xF));
#elif defined(CONFIG_ARCH_SUN8IW9)
		value &= (~(0x7));
#endif
		sunxi_smc_writel(value, sun8i_cpuscfg_base + SUNXI_CLUSTER_PWRON_RESET(cluster));
		udelay(10);

		/* assert cluster resets */
		value = cpu_cfg_readl(sun8i_cpuxcfg_base + SUNXI_CPU_RST_CTRL(cluster));
		value &= (~(0x1<<24));  /* SOC DBG Reset */
#if defined(CONFIG_ARCH_SUN8IW6)
		value &= (~(0xF<<20));  /* ETM Reset     */
		value &= (~(0xF<<16));  /* Debug Reset   */
#elif defined(CONFIG_ARCH_SUN8IW9)
		value &= (~(0x7<<20));  /* ETM Reset     */
		value &= (~(0x7<<16));  /* Debug Reset   */
#endif
		value &= (~(0x1<<12));  /* HReset        */
		value &= (~(0x1<<8));   /* L2 Cache Reset*/
		cpu_cfg_writel(value, sun8i_cpuxcfg_base + SUNXI_CPU_RST_CTRL(cluster));
		udelay(10);

		/* Set L2RSTDISABLE LOW */
		value = cpu_cfg_readl(sun8i_cpuxcfg_base + SUNXI_CLUSTER_CTRL0(cluster));
		value &= (~(0x1<<4));
		cpu_cfg_writel(value, sun8i_cpuxcfg_base + SUNXI_CLUSTER_CTRL0(cluster));

#ifdef MCPM_WITH_ARISC_DVFS_SUPPORT
		/* notify arisc to power-up cluster */
		arisc_dvfs_set_cpufreq(cluster_powerup_freq[cluster], cluster_pll[cluster],
		                       ARISC_MESSAGE_ATTR_SOFTSYN, NULL, NULL);
		mdelay(1);
#endif

#ifdef CONFIG_ARCH_SUN8IW6
		if (soc_version == SUN8IW6P1_REV_A)
			sun8i_cpu_power_switch_set(cluster, 0, 1);
#endif
		/* active ACINACTM */
		value = cpu_cfg_readl(sun8i_cpuxcfg_base + SUNXI_CLUSTER_CTRL1(cluster));
		value |= (1<<0);
		cpu_cfg_writel(value, sun8i_cpuxcfg_base + SUNXI_CLUSTER_CTRL1(cluster));

		/* clear cluster power-off gating */
		value = sunxi_smc_readl(sun8i_prcm_base + SUNXI_CLUSTER_PWROFF_GATING(cluster));
#ifdef CONFIG_ARCH_SUN8IW6
		if (soc_version == SUN8IW6P1_REV_A)
			value &= (~(0x1<<4));
		value &= (~(0x1<<0));
#else
		value &= (~(0x1<<4));
#endif
		sunxi_smc_writel(value, sun8i_prcm_base + SUNXI_CLUSTER_PWROFF_GATING(cluster));
		udelay(20);

		/* de-active ACINACTM */
		value = cpu_cfg_readl(sun8i_cpuxcfg_base + SUNXI_CLUSTER_CTRL1(cluster));
		value &= (~(1<<0));
		cpu_cfg_writel(value, sun8i_cpuxcfg_base + SUNXI_CLUSTER_CTRL1(cluster));

		/* de-assert cores reset */
		value = cpu_cfg_readl(sun8i_cpuxcfg_base + SUNXI_CPU_RST_CTRL(cluster));
		value |= (0x1<<24);  /* SOC DBG Reset */
#if defined(CONFIG_ARCH_SUN8IW6)
		value |= (0xF<<20);  /* ETM Reset     */
		value |= (0xF<<16);  /* Debug Reset   */
#elif defined(CONFIG_ARCH_SUN8IW9)
		value |= (0x7<<20);  /* ETM Reset     */
		value |= (0x7<<16);  /* Debug Reset   */
#endif
		value |= (0x1<<12);  /* HReset        */
		value |= (0x1<<8);   /* L2 Cache Reset*/
		cpu_cfg_writel(value, sun8i_cpuxcfg_base + SUNXI_CPU_RST_CTRL(cluster));
		udelay(20);
		pr_debug("sun8i power-up cluster-%d ok\n", cluster);
	} else {

		pr_debug("sun8i power-down cluster-%d\n", cluster);

		/* active ACINACTM */
		value = cpu_cfg_readl(sun8i_cpuxcfg_base + SUNXI_CLUSTER_CTRL1(cluster));
		value |= (1<<0);
		cpu_cfg_writel(value, sun8i_cpuxcfg_base + SUNXI_CLUSTER_CTRL1(cluster));

		while (1) {
			if (SUN8I_L2CACHE_IS_WFI_MODE(cluster)) {
				break;
			}
			/* maybe should support timeout to avoid deadloop */
		}

		/* assert cluster cores resets */
		value = cpu_cfg_readl(sun8i_cpuxcfg_base + SUNXI_CPU_RST_CTRL(cluster));
#if defined(CONFIG_ARCH_SUN8IW6)
		value &= (~(0xF<<0));   /* Core Reset    */
#elif defined(CONFIG_ARCH_SUN8IW9)
		value &= (~(0x7<<0));   /* Core Reset    */
#endif
		cpu_cfg_writel(value, sun8i_cpuxcfg_base + SUNXI_CPU_RST_CTRL(cluster));
		udelay(10);

		/* assert cluster cores power-on reset */
		value = sunxi_smc_readl(sun8i_cpuscfg_base + SUNXI_CLUSTER_PWRON_RESET(cluster));
#if defined(CONFIG_ARCH_SUN8IW6)
		value &= (~(0xF));
#elif defined(CONFIG_ARCH_SUN8IW9)
		value &= (~(0x7));
#endif
		sunxi_smc_writel(value, sun8i_cpuscfg_base + SUNXI_CLUSTER_PWRON_RESET(cluster));
		udelay(10);

		/* assert cluster resets */
		value = cpu_cfg_readl(sun8i_cpuxcfg_base + SUNXI_CPU_RST_CTRL(cluster));
		value &= (~(0x1<<24));  /* SOC DBG Reset */
#if defined(CONFIG_ARCH_SUN8IW6)
		value &= (~(0xF<<20));  /* ETM Reset     */
		value &= (~(0xF<<16));  /* Debug Reset   */
#elif defined(CONFIG_ARCH_SUN8IW9)
		value &= (~(0x7<<20));  /* ETM Reset     */
		value &= (~(0x7<<16));  /* Debug Reset   */
#endif
		value &= (~(0x1<<12));  /* HReset        */
		value &= (~(0x1<<8));   /* L2 Cache Reset*/
		cpu_cfg_writel(value, sun8i_cpuxcfg_base + SUNXI_CPU_RST_CTRL(cluster));
		udelay(10);

		/* enable cluster and cores power-off gating */
		value = sunxi_smc_readl(sun8i_prcm_base + SUNXI_CLUSTER_PWROFF_GATING(cluster));
		value |= (1<<4);
#if defined(CONFIG_ARCH_SUN8IW6)
		value |= (0xF<<0);
#elif defined(CONFIG_ARCH_SUN8IW9)
		value |= (0x7<<0);
#endif
		sunxi_smc_writel(value, sun8i_prcm_base + SUNXI_CLUSTER_PWROFF_GATING(cluster));
		udelay(20);

		/* disable cluster cores power switch */
		for (i = 0; i < CORES_PER_CLUSTER; i++) {
			sun8i_cpu_power_switch_set(cluster, i, 0);
		}

#ifdef MCPM_WITH_ARISC_DVFS_SUPPORT
		/* notify arisc to power-down cluster,
		 * arisc will disable cluster clock and power-off cpu power domain.
		 */
		arisc_dvfs_set_cpufreq(0, cluster_pll[cluster],
		                       ARISC_MESSAGE_ATTR_SOFTSYN, NULL, NULL);
#endif
		pr_debug("sun8i power-down cluster-%d ok\n", cluster);
	}

	return 0;
}