cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

s3c24xx-cpufreq.c (15866B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2006-2008 Simtec Electronics
      4 *	http://armlinux.simtec.co.uk/
      5 *	Ben Dooks <ben@simtec.co.uk>
      6 *
      7 * S3C24XX CPU Frequency scaling
      8*/
      9
     10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     11
     12#include <linux/init.h>
     13#include <linux/module.h>
     14#include <linux/interrupt.h>
     15#include <linux/ioport.h>
     16#include <linux/cpufreq.h>
     17#include <linux/cpu.h>
     18#include <linux/clk.h>
     19#include <linux/err.h>
     20#include <linux/io.h>
     21#include <linux/device.h>
     22#include <linux/sysfs.h>
     23#include <linux/slab.h>
     24#include <linux/soc/samsung/s3c-cpufreq-core.h>
     25#include <linux/soc/samsung/s3c-pm.h>
     26
     27#include <asm/mach/arch.h>
     28#include <asm/mach/map.h>
     29
     30/* note, cpufreq support deals in kHz, no Hz */
     31static struct cpufreq_driver s3c24xx_driver;
     32static struct s3c_cpufreq_config cpu_cur;
     33static struct s3c_iotimings s3c24xx_iotiming;
     34static struct cpufreq_frequency_table *pll_reg;
     35static unsigned int last_target = ~0;
     36static unsigned int ftab_size;
     37static struct cpufreq_frequency_table *ftab;
     38
     39static struct clk *_clk_mpll;
     40static struct clk *_clk_xtal;
     41static struct clk *clk_fclk;
     42static struct clk *clk_hclk;
     43static struct clk *clk_pclk;
     44static struct clk *clk_arm;
     45
     46#ifdef CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS
     47struct s3c_cpufreq_config *s3c_cpufreq_getconfig(void)
     48{
     49	return &cpu_cur;
     50}
     51
     52struct s3c_iotimings *s3c_cpufreq_getiotimings(void)
     53{
     54	return &s3c24xx_iotiming;
     55}
     56#endif /* CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS */
     57
     58static void s3c_cpufreq_getcur(struct s3c_cpufreq_config *cfg)
     59{
     60	unsigned long fclk, pclk, hclk, armclk;
     61
     62	cfg->freq.fclk = fclk = clk_get_rate(clk_fclk);
     63	cfg->freq.hclk = hclk = clk_get_rate(clk_hclk);
     64	cfg->freq.pclk = pclk = clk_get_rate(clk_pclk);
     65	cfg->freq.armclk = armclk = clk_get_rate(clk_arm);
     66
     67	cfg->pll.driver_data = s3c24xx_read_mpllcon();
     68	cfg->pll.frequency = fclk;
     69
     70	cfg->freq.hclk_tns = 1000000000 / (cfg->freq.hclk / 10);
     71
     72	cfg->divs.h_divisor = fclk / hclk;
     73	cfg->divs.p_divisor = fclk / pclk;
     74}
     75
     76static inline void s3c_cpufreq_calc(struct s3c_cpufreq_config *cfg)
     77{
     78	unsigned long pll = cfg->pll.frequency;
     79
     80	cfg->freq.fclk = pll;
     81	cfg->freq.hclk = pll / cfg->divs.h_divisor;
     82	cfg->freq.pclk = pll / cfg->divs.p_divisor;
     83
     84	/* convert hclk into 10ths of nanoseconds for io calcs */
     85	cfg->freq.hclk_tns = 1000000000 / (cfg->freq.hclk / 10);
     86}
     87
     88static inline int closer(unsigned int target, unsigned int n, unsigned int c)
     89{
     90	int diff_cur = abs(target - c);
     91	int diff_new = abs(target - n);
     92
     93	return (diff_new < diff_cur);
     94}
     95
     96static void s3c_cpufreq_show(const char *pfx,
     97				 struct s3c_cpufreq_config *cfg)
     98{
     99	s3c_freq_dbg("%s: Fvco=%u, F=%lu, A=%lu, H=%lu (%u), P=%lu (%u)\n",
    100		     pfx, cfg->pll.frequency, cfg->freq.fclk, cfg->freq.armclk,
    101		     cfg->freq.hclk, cfg->divs.h_divisor,
    102		     cfg->freq.pclk, cfg->divs.p_divisor);
    103}
    104
    105/* functions to wrapper the driver info calls to do the cpu specific work */
    106
    107static void s3c_cpufreq_setio(struct s3c_cpufreq_config *cfg)
    108{
    109	if (cfg->info->set_iotiming)
    110		(cfg->info->set_iotiming)(cfg, &s3c24xx_iotiming);
    111}
    112
    113static int s3c_cpufreq_calcio(struct s3c_cpufreq_config *cfg)
    114{
    115	if (cfg->info->calc_iotiming)
    116		return (cfg->info->calc_iotiming)(cfg, &s3c24xx_iotiming);
    117
    118	return 0;
    119}
    120
    121static void s3c_cpufreq_setrefresh(struct s3c_cpufreq_config *cfg)
    122{
    123	(cfg->info->set_refresh)(cfg);
    124}
    125
    126static void s3c_cpufreq_setdivs(struct s3c_cpufreq_config *cfg)
    127{
    128	(cfg->info->set_divs)(cfg);
    129}
    130
    131static int s3c_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg)
    132{
    133	return (cfg->info->calc_divs)(cfg);
    134}
    135
    136static void s3c_cpufreq_setfvco(struct s3c_cpufreq_config *cfg)
    137{
    138	cfg->mpll = _clk_mpll;
    139	(cfg->info->set_fvco)(cfg);
    140}
    141
    142static inline void s3c_cpufreq_updateclk(struct clk *clk,
    143					 unsigned int freq)
    144{
    145	clk_set_rate(clk, freq);
    146}
    147
    148static int s3c_cpufreq_settarget(struct cpufreq_policy *policy,
    149				 unsigned int target_freq,
    150				 struct cpufreq_frequency_table *pll)
    151{
    152	struct s3c_cpufreq_freqs freqs;
    153	struct s3c_cpufreq_config cpu_new;
    154	unsigned long flags;
    155
    156	cpu_new = cpu_cur;  /* copy new from current */
    157
    158	s3c_cpufreq_show("cur", &cpu_cur);
    159
    160	/* TODO - check for DMA currently outstanding */
    161
    162	cpu_new.pll = pll ? *pll : cpu_cur.pll;
    163
    164	if (pll)
    165		freqs.pll_changing = 1;
    166
    167	/* update our frequencies */
    168
    169	cpu_new.freq.armclk = target_freq;
    170	cpu_new.freq.fclk = cpu_new.pll.frequency;
    171
    172	if (s3c_cpufreq_calcdivs(&cpu_new) < 0) {
    173		pr_err("no divisors for %d\n", target_freq);
    174		goto err_notpossible;
    175	}
    176
    177	s3c_freq_dbg("%s: got divs\n", __func__);
    178
    179	s3c_cpufreq_calc(&cpu_new);
    180
    181	s3c_freq_dbg("%s: calculated frequencies for new\n", __func__);
    182
    183	if (cpu_new.freq.hclk != cpu_cur.freq.hclk) {
    184		if (s3c_cpufreq_calcio(&cpu_new) < 0) {
    185			pr_err("%s: no IO timings\n", __func__);
    186			goto err_notpossible;
    187		}
    188	}
    189
    190	s3c_cpufreq_show("new", &cpu_new);
    191
    192	/* setup our cpufreq parameters */
    193
    194	freqs.old = cpu_cur.freq;
    195	freqs.new = cpu_new.freq;
    196
    197	freqs.freqs.old = cpu_cur.freq.armclk / 1000;
    198	freqs.freqs.new = cpu_new.freq.armclk / 1000;
    199
    200	/* update f/h/p clock settings before we issue the change
    201	 * notification, so that drivers do not need to do anything
    202	 * special if they want to recalculate on CPUFREQ_PRECHANGE. */
    203
    204	s3c_cpufreq_updateclk(_clk_mpll, cpu_new.pll.frequency);
    205	s3c_cpufreq_updateclk(clk_fclk, cpu_new.freq.fclk);
    206	s3c_cpufreq_updateclk(clk_hclk, cpu_new.freq.hclk);
    207	s3c_cpufreq_updateclk(clk_pclk, cpu_new.freq.pclk);
    208
    209	/* start the frequency change */
    210	cpufreq_freq_transition_begin(policy, &freqs.freqs);
    211
    212	/* If hclk is staying the same, then we do not need to
    213	 * re-write the IO or the refresh timings whilst we are changing
    214	 * speed. */
    215
    216	local_irq_save(flags);
    217
    218	/* is our memory clock slowing down? */
    219	if (cpu_new.freq.hclk < cpu_cur.freq.hclk) {
    220		s3c_cpufreq_setrefresh(&cpu_new);
    221		s3c_cpufreq_setio(&cpu_new);
    222	}
    223
    224	if (cpu_new.freq.fclk == cpu_cur.freq.fclk) {
    225		/* not changing PLL, just set the divisors */
    226
    227		s3c_cpufreq_setdivs(&cpu_new);
    228	} else {
    229		if (cpu_new.freq.fclk < cpu_cur.freq.fclk) {
    230			/* slow the cpu down, then set divisors */
    231
    232			s3c_cpufreq_setfvco(&cpu_new);
    233			s3c_cpufreq_setdivs(&cpu_new);
    234		} else {
    235			/* set the divisors, then speed up */
    236
    237			s3c_cpufreq_setdivs(&cpu_new);
    238			s3c_cpufreq_setfvco(&cpu_new);
    239		}
    240	}
    241
    242	/* did our memory clock speed up */
    243	if (cpu_new.freq.hclk > cpu_cur.freq.hclk) {
    244		s3c_cpufreq_setrefresh(&cpu_new);
    245		s3c_cpufreq_setio(&cpu_new);
    246	}
    247
    248	/* update our current settings */
    249	cpu_cur = cpu_new;
    250
    251	local_irq_restore(flags);
    252
    253	/* notify everyone we've done this */
    254	cpufreq_freq_transition_end(policy, &freqs.freqs, 0);
    255
    256	s3c_freq_dbg("%s: finished\n", __func__);
    257	return 0;
    258
    259 err_notpossible:
    260	pr_err("no compatible settings for %d\n", target_freq);
    261	return -EINVAL;
    262}
    263
    264/* s3c_cpufreq_target
    265 *
    266 * called by the cpufreq core to adjust the frequency that the CPU
    267 * is currently running at.
    268 */
    269
    270static int s3c_cpufreq_target(struct cpufreq_policy *policy,
    271			      unsigned int target_freq,
    272			      unsigned int relation)
    273{
    274	struct cpufreq_frequency_table *pll;
    275	unsigned int index;
    276
    277	/* avoid repeated calls which cause a needless amout of duplicated
    278	 * logging output (and CPU time as the calculation process is
    279	 * done) */
    280	if (target_freq == last_target)
    281		return 0;
    282
    283	last_target = target_freq;
    284
    285	s3c_freq_dbg("%s: policy %p, target %u, relation %u\n",
    286		     __func__, policy, target_freq, relation);
    287
    288	if (ftab) {
    289		index = cpufreq_frequency_table_target(policy, target_freq,
    290						       relation);
    291
    292		s3c_freq_dbg("%s: adjust %d to entry %d (%u)\n", __func__,
    293			     target_freq, index, ftab[index].frequency);
    294		target_freq = ftab[index].frequency;
    295	}
    296
    297	target_freq *= 1000;  /* convert target to Hz */
    298
    299	/* find the settings for our new frequency */
    300
    301	if (!pll_reg || cpu_cur.lock_pll) {
    302		/* either we've not got any PLL values, or we've locked
    303		 * to the current one. */
    304		pll = NULL;
    305	} else {
    306		struct cpufreq_policy tmp_policy;
    307
    308		/* we keep the cpu pll table in Hz, to ensure we get an
    309		 * accurate value for the PLL output. */
    310
    311		tmp_policy.min = policy->min * 1000;
    312		tmp_policy.max = policy->max * 1000;
    313		tmp_policy.cpu = policy->cpu;
    314		tmp_policy.freq_table = pll_reg;
    315
    316		/* cpufreq_frequency_table_target returns the index
    317		 * of the table entry, not the value of
    318		 * the table entry's index field. */
    319
    320		index = cpufreq_frequency_table_target(&tmp_policy, target_freq,
    321						       relation);
    322		pll = pll_reg + index;
    323
    324		s3c_freq_dbg("%s: target %u => %u\n",
    325			     __func__, target_freq, pll->frequency);
    326
    327		target_freq = pll->frequency;
    328	}
    329
    330	return s3c_cpufreq_settarget(policy, target_freq, pll);
    331}
    332
    333struct clk *s3c_cpufreq_clk_get(struct device *dev, const char *name)
    334{
    335	struct clk *clk;
    336
    337	clk = clk_get(dev, name);
    338	if (IS_ERR(clk))
    339		pr_err("failed to get clock '%s'\n", name);
    340
    341	return clk;
    342}
    343
    344static int s3c_cpufreq_init(struct cpufreq_policy *policy)
    345{
    346	policy->clk = clk_arm;
    347	policy->cpuinfo.transition_latency = cpu_cur.info->latency;
    348	policy->freq_table = ftab;
    349
    350	return 0;
    351}
    352
    353static int __init s3c_cpufreq_initclks(void)
    354{
    355	_clk_mpll = s3c_cpufreq_clk_get(NULL, "mpll");
    356	_clk_xtal = s3c_cpufreq_clk_get(NULL, "xtal");
    357	clk_fclk = s3c_cpufreq_clk_get(NULL, "fclk");
    358	clk_hclk = s3c_cpufreq_clk_get(NULL, "hclk");
    359	clk_pclk = s3c_cpufreq_clk_get(NULL, "pclk");
    360	clk_arm = s3c_cpufreq_clk_get(NULL, "armclk");
    361
    362	if (IS_ERR(clk_fclk) || IS_ERR(clk_hclk) || IS_ERR(clk_pclk) ||
    363	    IS_ERR(_clk_mpll) || IS_ERR(clk_arm) || IS_ERR(_clk_xtal)) {
    364		pr_err("%s: could not get clock(s)\n", __func__);
    365		return -ENOENT;
    366	}
    367
    368	pr_info("%s: clocks f=%lu,h=%lu,p=%lu,a=%lu\n",
    369		__func__,
    370		clk_get_rate(clk_fclk) / 1000,
    371		clk_get_rate(clk_hclk) / 1000,
    372		clk_get_rate(clk_pclk) / 1000,
    373		clk_get_rate(clk_arm) / 1000);
    374
    375	return 0;
    376}
    377
    378#ifdef CONFIG_PM
    379static struct cpufreq_frequency_table suspend_pll;
    380static unsigned int suspend_freq;
    381
    382static int s3c_cpufreq_suspend(struct cpufreq_policy *policy)
    383{
    384	suspend_pll.frequency = clk_get_rate(_clk_mpll);
    385	suspend_pll.driver_data = s3c24xx_read_mpllcon();
    386	suspend_freq = clk_get_rate(clk_arm);
    387
    388	return 0;
    389}
    390
    391static int s3c_cpufreq_resume(struct cpufreq_policy *policy)
    392{
    393	int ret;
    394
    395	s3c_freq_dbg("%s: resuming with policy %p\n", __func__, policy);
    396
    397	last_target = ~0;	/* invalidate last_target setting */
    398
    399	/* whilst we will be called later on, we try and re-set the
    400	 * cpu frequencies as soon as possible so that we do not end
    401	 * up resuming devices and then immediately having to re-set
    402	 * a number of settings once these devices have restarted.
    403	 *
    404	 * as a note, it is expected devices are not used until they
    405	 * have been un-suspended and at that time they should have
    406	 * used the updated clock settings.
    407	 */
    408
    409	ret = s3c_cpufreq_settarget(NULL, suspend_freq, &suspend_pll);
    410	if (ret) {
    411		pr_err("%s: failed to reset pll/freq\n", __func__);
    412		return ret;
    413	}
    414
    415	return 0;
    416}
    417#else
    418#define s3c_cpufreq_resume NULL
    419#define s3c_cpufreq_suspend NULL
    420#endif
    421
    422static struct cpufreq_driver s3c24xx_driver = {
    423	.flags		= CPUFREQ_NEED_INITIAL_FREQ_CHECK,
    424	.target		= s3c_cpufreq_target,
    425	.get		= cpufreq_generic_get,
    426	.init		= s3c_cpufreq_init,
    427	.suspend	= s3c_cpufreq_suspend,
    428	.resume		= s3c_cpufreq_resume,
    429	.name		= "s3c24xx",
    430};
    431
    432
    433int s3c_cpufreq_register(struct s3c_cpufreq_info *info)
    434{
    435	if (!info || !info->name) {
    436		pr_err("%s: failed to pass valid information\n", __func__);
    437		return -EINVAL;
    438	}
    439
    440	pr_info("S3C24XX CPU Frequency driver, %s cpu support\n",
    441		info->name);
    442
    443	/* check our driver info has valid data */
    444
    445	BUG_ON(info->set_refresh == NULL);
    446	BUG_ON(info->set_divs == NULL);
    447	BUG_ON(info->calc_divs == NULL);
    448
    449	/* info->set_fvco is optional, depending on whether there
    450	 * is a need to set the clock code. */
    451
    452	cpu_cur.info = info;
    453
    454	/* Note, driver registering should probably update locktime */
    455
    456	return 0;
    457}
    458
    459int __init s3c_cpufreq_setboard(struct s3c_cpufreq_board *board)
    460{
    461	struct s3c_cpufreq_board *ours;
    462
    463	if (!board) {
    464		pr_info("%s: no board data\n", __func__);
    465		return -EINVAL;
    466	}
    467
    468	/* Copy the board information so that each board can make this
    469	 * initdata. */
    470
    471	ours = kzalloc(sizeof(*ours), GFP_KERNEL);
    472	if (!ours)
    473		return -ENOMEM;
    474
    475	*ours = *board;
    476	cpu_cur.board = ours;
    477
    478	return 0;
    479}
    480
    481static int __init s3c_cpufreq_auto_io(void)
    482{
    483	int ret;
    484
    485	if (!cpu_cur.info->get_iotiming) {
    486		pr_err("%s: get_iotiming undefined\n", __func__);
    487		return -ENOENT;
    488	}
    489
    490	pr_info("%s: working out IO settings\n", __func__);
    491
    492	ret = (cpu_cur.info->get_iotiming)(&cpu_cur, &s3c24xx_iotiming);
    493	if (ret)
    494		pr_err("%s: failed to get timings\n", __func__);
    495
    496	return ret;
    497}
    498
    499/* if one or is zero, then return the other, otherwise return the min */
    500#define do_min(_a, _b) ((_a) == 0 ? (_b) : (_b) == 0 ? (_a) : min(_a, _b))
    501
    502/**
    503 * s3c_cpufreq_freq_min - find the minimum settings for the given freq.
    504 * @dst: The destination structure
    505 * @a: One argument.
    506 * @b: The other argument.
    507 *
    508 * Create a minimum of each frequency entry in the 'struct s3c_freq',
    509 * unless the entry is zero when it is ignored and the non-zero argument
    510 * used.
    511 */
    512static void s3c_cpufreq_freq_min(struct s3c_freq *dst,
    513				 struct s3c_freq *a, struct s3c_freq *b)
    514{
    515	dst->fclk = do_min(a->fclk, b->fclk);
    516	dst->hclk = do_min(a->hclk, b->hclk);
    517	dst->pclk = do_min(a->pclk, b->pclk);
    518	dst->armclk = do_min(a->armclk, b->armclk);
    519}
    520
    521static inline u32 calc_locktime(u32 freq, u32 time_us)
    522{
    523	u32 result;
    524
    525	result = freq * time_us;
    526	result = DIV_ROUND_UP(result, 1000 * 1000);
    527
    528	return result;
    529}
    530
    531static void s3c_cpufreq_update_loctkime(void)
    532{
    533	unsigned int bits = cpu_cur.info->locktime_bits;
    534	u32 rate = (u32)clk_get_rate(_clk_xtal);
    535	u32 val;
    536
    537	if (bits == 0) {
    538		WARN_ON(1);
    539		return;
    540	}
    541
    542	val = calc_locktime(rate, cpu_cur.info->locktime_u) << bits;
    543	val |= calc_locktime(rate, cpu_cur.info->locktime_m);
    544
    545	pr_info("%s: new locktime is 0x%08x\n", __func__, val);
    546	s3c24xx_write_locktime(val);
    547}
    548
    549static int s3c_cpufreq_build_freq(void)
    550{
    551	int size, ret;
    552
    553	kfree(ftab);
    554
    555	size = cpu_cur.info->calc_freqtable(&cpu_cur, NULL, 0);
    556	size++;
    557
    558	ftab = kcalloc(size, sizeof(*ftab), GFP_KERNEL);
    559	if (!ftab)
    560		return -ENOMEM;
    561
    562	ftab_size = size;
    563
    564	ret = cpu_cur.info->calc_freqtable(&cpu_cur, ftab, size);
    565	s3c_cpufreq_addfreq(ftab, ret, size, CPUFREQ_TABLE_END);
    566
    567	return 0;
    568}
    569
    570static int __init s3c_cpufreq_initcall(void)
    571{
    572	int ret = 0;
    573
    574	if (cpu_cur.info && cpu_cur.board) {
    575		ret = s3c_cpufreq_initclks();
    576		if (ret)
    577			goto out;
    578
    579		/* get current settings */
    580		s3c_cpufreq_getcur(&cpu_cur);
    581		s3c_cpufreq_show("cur", &cpu_cur);
    582
    583		if (cpu_cur.board->auto_io) {
    584			ret = s3c_cpufreq_auto_io();
    585			if (ret) {
    586				pr_err("%s: failed to get io timing\n",
    587				       __func__);
    588				goto out;
    589			}
    590		}
    591
    592		if (cpu_cur.board->need_io && !cpu_cur.info->set_iotiming) {
    593			pr_err("%s: no IO support registered\n", __func__);
    594			ret = -EINVAL;
    595			goto out;
    596		}
    597
    598		if (!cpu_cur.info->need_pll)
    599			cpu_cur.lock_pll = 1;
    600
    601		s3c_cpufreq_update_loctkime();
    602
    603		s3c_cpufreq_freq_min(&cpu_cur.max, &cpu_cur.board->max,
    604				     &cpu_cur.info->max);
    605
    606		if (cpu_cur.info->calc_freqtable)
    607			s3c_cpufreq_build_freq();
    608
    609		ret = cpufreq_register_driver(&s3c24xx_driver);
    610	}
    611
    612 out:
    613	return ret;
    614}
    615
    616late_initcall(s3c_cpufreq_initcall);
    617
    618/**
    619 * s3c_plltab_register - register CPU PLL table.
    620 * @plls: The list of PLL entries.
    621 * @plls_no: The size of the PLL entries @plls.
    622 *
    623 * Register the given set of PLLs with the system.
    624 */
    625int s3c_plltab_register(struct cpufreq_frequency_table *plls,
    626			       unsigned int plls_no)
    627{
    628	struct cpufreq_frequency_table *vals;
    629	unsigned int size;
    630
    631	size = sizeof(*vals) * (plls_no + 1);
    632
    633	vals = kzalloc(size, GFP_KERNEL);
    634	if (vals) {
    635		memcpy(vals, plls, size);
    636		pll_reg = vals;
    637
    638		/* write a terminating entry, we don't store it in the
    639		 * table that is stored in the kernel */
    640		vals += plls_no;
    641		vals->frequency = CPUFREQ_TABLE_END;
    642
    643		pr_info("%d PLL entries\n", plls_no);
    644	} else
    645		pr_err("no memory for PLL tables\n");
    646
    647	return vals ? 0 : -ENOMEM;
    648}