^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2006-2009 Simtec Electronics
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * http://armlinux.simtec.co.uk/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Ben Dooks <ben@simtec.co.uk>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Vincent Sanders <vince@simtec.co.uk>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * S3C2440/S3C2442 CPU Frequency scaling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/cpufreq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/soc/samsung/s3c-cpufreq-core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/soc/samsung/s3c-pm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <asm/mach/arch.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <asm/mach/map.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define S3C2440_CLKDIVN_PDIVN (1<<0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define S3C2440_CLKDIVN_HDIVN_MASK (3<<1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define S3C2440_CLKDIVN_HDIVN_1 (0<<1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define S3C2440_CLKDIVN_HDIVN_2 (1<<1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define S3C2440_CLKDIVN_HDIVN_4_8 (2<<1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define S3C2440_CLKDIVN_HDIVN_3_6 (3<<1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define S3C2440_CLKDIVN_UCLK (1<<3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define S3C2440_CAMDIVN_CAMCLK_MASK (0xf<<0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define S3C2440_CAMDIVN_CAMCLK_SEL (1<<4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define S3C2440_CAMDIVN_HCLK3_HALF (1<<8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define S3C2440_CAMDIVN_HCLK4_HALF (1<<9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define S3C2440_CAMDIVN_DVSEN (1<<12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define S3C2442_CAMDIVN_CAMCLK_DIV3 (1<<5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static struct clk *xtal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static struct clk *fclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static struct clk *hclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static struct clk *armclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) /* HDIV: 1, 2, 3, 4, 6, 8 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) static inline int within_khz(unsigned long a, unsigned long b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) long diff = a - b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return (diff >= -1000 && diff <= 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * s3c2440_cpufreq_calcdivs - calculate divider settings
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * @cfg: The cpu frequency settings.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * Calcualte the divider values for the given frequency settings
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * specified in @cfg. The values are stored in @cfg for later use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * by the relevant set routine if the request settings can be reached.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static int s3c2440_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) unsigned int hdiv, pdiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) unsigned long hclk, fclk, armclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) unsigned long hclk_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) fclk = cfg->freq.fclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) armclk = cfg->freq.armclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) hclk_max = cfg->max.hclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) s3c_freq_dbg("%s: fclk is %lu, armclk %lu, max hclk %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) __func__, fclk, armclk, hclk_max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (armclk > fclk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) pr_warn("%s: armclk > fclk\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) armclk = fclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) /* if we are in DVS, we need HCLK to be <= ARMCLK */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (armclk < fclk && armclk < hclk_max)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) hclk_max = armclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) for (hdiv = 1; hdiv < 9; hdiv++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (hdiv == 5 || hdiv == 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) hdiv++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) hclk = (fclk / hdiv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (hclk <= hclk_max || within_khz(hclk, hclk_max))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) s3c_freq_dbg("%s: hclk %lu, div %d\n", __func__, hclk, hdiv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (hdiv > 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) goto invalid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) pdiv = (hclk > cfg->max.pclk) ? 2 : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) if ((hclk / pdiv) > cfg->max.pclk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) pdiv++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) s3c_freq_dbg("%s: pdiv %d\n", __func__, pdiv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (pdiv > 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) goto invalid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) pdiv *= hdiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) /* calculate a valid armclk */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (armclk < hclk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) armclk = hclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /* if we're running armclk lower than fclk, this really means
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * that the system should go into dvs mode, which means that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * armclk is connected to hclk. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (armclk < fclk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) cfg->divs.dvs = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) armclk = hclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) cfg->divs.dvs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) cfg->freq.armclk = armclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) /* store the result, and then return */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) cfg->divs.h_divisor = hdiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) cfg->divs.p_divisor = pdiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) invalid:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) #define CAMDIVN_HCLK_HALF (S3C2440_CAMDIVN_HCLK3_HALF | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) S3C2440_CAMDIVN_HCLK4_HALF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * s3c2440_cpufreq_setdivs - set the cpu frequency divider settings
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * @cfg: The cpu frequency settings.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) * Set the divisors from the settings in @cfg, which where generated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) * during the calculation phase by s3c2440_cpufreq_calcdivs().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) static void s3c2440_cpufreq_setdivs(struct s3c_cpufreq_config *cfg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) unsigned long clkdiv, camdiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) s3c_freq_dbg("%s: divisors: h=%d, p=%d\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) cfg->divs.h_divisor, cfg->divs.p_divisor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) clkdiv = s3c24xx_read_clkdivn();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) camdiv = s3c2440_read_camdivn();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) clkdiv &= ~(S3C2440_CLKDIVN_HDIVN_MASK | S3C2440_CLKDIVN_PDIVN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) camdiv &= ~CAMDIVN_HCLK_HALF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) switch (cfg->divs.h_divisor) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) clkdiv |= S3C2440_CLKDIVN_HDIVN_1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) clkdiv |= S3C2440_CLKDIVN_HDIVN_2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) case 6:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) camdiv |= S3C2440_CAMDIVN_HCLK3_HALF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) case 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) clkdiv |= S3C2440_CLKDIVN_HDIVN_3_6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) camdiv |= S3C2440_CAMDIVN_HCLK4_HALF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) clkdiv |= S3C2440_CLKDIVN_HDIVN_4_8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) BUG(); /* we don't expect to get here. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if (cfg->divs.p_divisor != cfg->divs.h_divisor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) clkdiv |= S3C2440_CLKDIVN_PDIVN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) /* todo - set pclk. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) /* Write the divisors first with hclk intentionally halved so that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) * when we write clkdiv we will under-frequency instead of over. We
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) * then make a short delay and remove the hclk halving if necessary.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) s3c2440_write_camdivn(camdiv | CAMDIVN_HCLK_HALF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) s3c24xx_write_clkdivn(clkdiv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) ndelay(20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) s3c2440_write_camdivn(camdiv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) clk_set_parent(armclk, cfg->divs.dvs ? hclk : fclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) static int run_freq_for(unsigned long max_hclk, unsigned long fclk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) int *divs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) struct cpufreq_frequency_table *table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) size_t table_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) unsigned long freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) int index = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) int div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) for (div = *divs; div > 0; div = *divs++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) freq = fclk / div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) if (freq > max_hclk && div != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) freq /= 1000; /* table is in kHz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) index = s3c_cpufreq_addfreq(table, index, table_size, freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (index < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) return index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) static int hclk_divs[] = { 1, 2, 3, 4, 6, 8, -1 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) static int s3c2440_cpufreq_calctable(struct s3c_cpufreq_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) struct cpufreq_frequency_table *table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) size_t table_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) WARN_ON(cfg->info == NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) WARN_ON(cfg->board == NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) ret = run_freq_for(cfg->info->max.hclk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) cfg->info->max.fclk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) hclk_divs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) table, table_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) s3c_freq_dbg("%s: returning %d\n", __func__, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) static struct s3c_cpufreq_info s3c2440_cpufreq_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) .max = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) .fclk = 400000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) .hclk = 133333333,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) .pclk = 66666666,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) .locktime_m = 300,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) .locktime_u = 300,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) .locktime_bits = 16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) .name = "s3c244x",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) .calc_iotiming = s3c2410_iotiming_calc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) .set_iotiming = s3c2410_iotiming_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) .get_iotiming = s3c2410_iotiming_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) .set_fvco = s3c2410_set_fvco,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) .set_refresh = s3c2410_cpufreq_setrefresh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) .set_divs = s3c2440_cpufreq_setdivs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) .calc_divs = s3c2440_cpufreq_calcdivs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) .calc_freqtable = s3c2440_cpufreq_calctable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) .debug_io_show = s3c_cpufreq_debugfs_call(s3c2410_iotiming_debugfs),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) static int s3c2440_cpufreq_add(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) struct subsys_interface *sif)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) xtal = s3c_cpufreq_clk_get(NULL, "xtal");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) hclk = s3c_cpufreq_clk_get(NULL, "hclk");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) fclk = s3c_cpufreq_clk_get(NULL, "fclk");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) armclk = s3c_cpufreq_clk_get(NULL, "armclk");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if (IS_ERR(xtal) || IS_ERR(hclk) || IS_ERR(fclk) || IS_ERR(armclk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) pr_err("%s: failed to get clocks\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) return s3c_cpufreq_register(&s3c2440_cpufreq_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) static struct subsys_interface s3c2440_cpufreq_interface = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) .name = "s3c2440_cpufreq",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) .subsys = &s3c2440_subsys,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) .add_dev = s3c2440_cpufreq_add,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) static int s3c2440_cpufreq_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) return subsys_interface_register(&s3c2440_cpufreq_interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) /* arch_initcall adds the clocks we need, so use subsys_initcall. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) subsys_initcall(s3c2440_cpufreq_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) static struct subsys_interface s3c2442_cpufreq_interface = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) .name = "s3c2442_cpufreq",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) .subsys = &s3c2442_subsys,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) .add_dev = s3c2440_cpufreq_add,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) static int s3c2442_cpufreq_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) return subsys_interface_register(&s3c2442_cpufreq_interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) subsys_initcall(s3c2442_cpufreq_init);