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; }
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; }