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

iotiming-s3c2410.c (11753B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// Copyright (c) 2006-2009 Simtec Electronics
      4//	http://armlinux.simtec.co.uk/
      5//	Ben Dooks <ben@simtec.co.uk>
      6//
      7// S3C24XX CPU Frequency scaling - IO timing for S3C2410/S3C2440/S3C2442
      8
      9#include <linux/init.h>
     10#include <linux/kernel.h>
     11#include <linux/errno.h>
     12#include <linux/cpufreq.h>
     13#include <linux/seq_file.h>
     14#include <linux/io.h>
     15#include <linux/slab.h>
     16
     17#include "map.h"
     18#include "regs-clock.h"
     19
     20#include <linux/soc/samsung/s3c-cpufreq-core.h>
     21
     22#include "regs-mem-s3c24xx.h"
     23
     24#define print_ns(x) ((x) / 10), ((x) % 10)
     25
     26/**
     27 * s3c2410_print_timing - print bank timing data for debug purposes
     28 * @pfx: The prefix to put on the output
     29 * @timings: The timing inforamtion to print.
     30*/
     31static void s3c2410_print_timing(const char *pfx,
     32				 struct s3c_iotimings *timings)
     33{
     34	struct s3c2410_iobank_timing *bt;
     35	int bank;
     36
     37	for (bank = 0; bank < MAX_BANKS; bank++) {
     38		bt = timings->bank[bank].io_2410;
     39		if (!bt)
     40			continue;
     41
     42		printk(KERN_DEBUG "%s %d: Tacs=%d.%d, Tcos=%d.%d, Tacc=%d.%d, "
     43		       "Tcoh=%d.%d, Tcah=%d.%d\n", pfx, bank,
     44		       print_ns(bt->tacs),
     45		       print_ns(bt->tcos),
     46		       print_ns(bt->tacc),
     47		       print_ns(bt->tcoh),
     48		       print_ns(bt->tcah));
     49	}
     50}
     51
     52/**
     53 * bank_reg - convert bank number to pointer to the control register.
     54 * @bank: The IO bank number.
     55 */
     56static inline void __iomem *bank_reg(unsigned int bank)
     57{
     58	return S3C2410_BANKCON0 + (bank << 2);
     59}
     60
     61/**
     62 * bank_is_io - test whether bank is used for IO
     63 * @bankcon: The bank control register.
     64 *
     65 * This is a simplistic test to see if any BANKCON[x] is not an IO
     66 * bank. It currently does not take into account whether BWSCON has
     67 * an illegal width-setting in it, or if the pin connected to nCS[x]
     68 * is actually being handled as a chip-select.
     69 */
     70static inline int bank_is_io(unsigned long bankcon)
     71{
     72	return !(bankcon & S3C2410_BANKCON_SDRAM);
     73}
     74
     75/**
     76 * to_div - convert cycle time to divisor
     77 * @cyc: The cycle time, in 10ths of nanoseconds.
     78 * @hclk_tns: The cycle time for HCLK, in 10ths of nanoseconds.
     79 *
     80 * Convert the given cycle time into the divisor to use to obtain it from
     81 * HCLK.
     82*/
     83static inline unsigned int to_div(unsigned int cyc, unsigned int hclk_tns)
     84{
     85	if (cyc == 0)
     86		return 0;
     87
     88	return DIV_ROUND_UP(cyc, hclk_tns);
     89}
     90
     91/**
     92 * calc_0124 - calculate divisor control for divisors that do /0, /1. /2 and /4
     93 * @cyc: The cycle time, in 10ths of nanoseconds.
     94 * @hclk_tns: The cycle time for HCLK, in 10ths of nanoseconds.
     95 * @v: Pointer to register to alter.
     96 * @shift: The shift to get to the control bits.
     97 *
     98 * Calculate the divisor, and turn it into the correct control bits to
     99 * set in the result, @v.
    100 */
    101static unsigned int calc_0124(unsigned int cyc, unsigned long hclk_tns,
    102			      unsigned long *v, int shift)
    103{
    104	unsigned int div = to_div(cyc, hclk_tns);
    105	unsigned long val;
    106
    107	s3c_freq_iodbg("%s: cyc=%d, hclk=%lu, shift=%d => div %d\n",
    108		       __func__, cyc, hclk_tns, shift, div);
    109
    110	switch (div) {
    111	case 0:
    112		val = 0;
    113		break;
    114	case 1:
    115		val = 1;
    116		break;
    117	case 2:
    118		val = 2;
    119		break;
    120	case 3:
    121	case 4:
    122		val = 3;
    123		break;
    124	default:
    125		return -1;
    126	}
    127
    128	*v |= val << shift;
    129	return 0;
    130}
    131
    132static int calc_tacp(unsigned int cyc, unsigned long hclk, unsigned long *v)
    133{
    134	/* Currently no support for Tacp calculations. */
    135	return 0;
    136}
    137
    138/**
    139 * calc_tacc - calculate divisor control for tacc.
    140 * @cyc: The cycle time, in 10ths of nanoseconds.
    141 * @nwait_en: IS nWAIT enabled for this bank.
    142 * @hclk_tns: The cycle time for HCLK, in 10ths of nanoseconds.
    143 * @v: Pointer to register to alter.
    144 *
    145 * Calculate the divisor control for tACC, taking into account whether
    146 * the bank has nWAIT enabled. The result is used to modify the value
    147 * pointed to by @v.
    148*/
    149static int calc_tacc(unsigned int cyc, int nwait_en,
    150		     unsigned long hclk_tns, unsigned long *v)
    151{
    152	unsigned int div = to_div(cyc, hclk_tns);
    153	unsigned long val;
    154
    155	s3c_freq_iodbg("%s: cyc=%u, nwait=%d, hclk=%lu => div=%u\n",
    156		       __func__, cyc, nwait_en, hclk_tns, div);
    157
    158	/* if nWait enabled on an bank, Tacc must be at-least 4 cycles. */
    159	if (nwait_en && div < 4)
    160		div = 4;
    161
    162	switch (div) {
    163	case 0:
    164		val = 0;
    165		break;
    166
    167	case 1:
    168	case 2:
    169	case 3:
    170	case 4:
    171		val = div - 1;
    172		break;
    173
    174	case 5:
    175	case 6:
    176		val = 4;
    177		break;
    178
    179	case 7:
    180	case 8:
    181		val = 5;
    182		break;
    183
    184	case 9:
    185	case 10:
    186		val = 6;
    187		break;
    188
    189	case 11:
    190	case 12:
    191	case 13:
    192	case 14:
    193		val = 7;
    194		break;
    195
    196	default:
    197		return -1;
    198	}
    199
    200	*v |= val << 8;
    201	return 0;
    202}
    203
    204/**
    205 * s3c2410_calc_bank - calculate bank timing information
    206 * @cfg: The configuration we need to calculate for.
    207 * @bt: The bank timing information.
    208 *
    209 * Given the cycle timine for a bank @bt, calculate the new BANKCON
    210 * setting for the @cfg timing. This updates the timing information
    211 * ready for the cpu frequency change.
    212 */
    213static int s3c2410_calc_bank(struct s3c_cpufreq_config *cfg,
    214			     struct s3c2410_iobank_timing *bt)
    215{
    216	unsigned long hclk = cfg->freq.hclk_tns;
    217	unsigned long res;
    218	int ret;
    219
    220	res  = bt->bankcon;
    221	res &= (S3C2410_BANKCON_SDRAM | S3C2410_BANKCON_PMC16);
    222
    223	/* tacp: 2,3,4,5 */
    224	/* tcah: 0,1,2,4 */
    225	/* tcoh: 0,1,2,4 */
    226	/* tacc: 1,2,3,4,6,7,10,14 (>4 for nwait) */
    227	/* tcos: 0,1,2,4 */
    228	/* tacs: 0,1,2,4 */
    229
    230	ret  = calc_0124(bt->tacs, hclk, &res, S3C2410_BANKCON_Tacs_SHIFT);
    231	ret |= calc_0124(bt->tcos, hclk, &res, S3C2410_BANKCON_Tcos_SHIFT);
    232	ret |= calc_0124(bt->tcah, hclk, &res, S3C2410_BANKCON_Tcah_SHIFT);
    233	ret |= calc_0124(bt->tcoh, hclk, &res, S3C2410_BANKCON_Tcoh_SHIFT);
    234
    235	if (ret)
    236		return -EINVAL;
    237
    238	ret |= calc_tacp(bt->tacp, hclk, &res);
    239	ret |= calc_tacc(bt->tacc, bt->nwait_en, hclk, &res);
    240
    241	if (ret)
    242		return -EINVAL;
    243
    244	bt->bankcon = res;
    245	return 0;
    246}
    247
    248static const unsigned int tacc_tab[] = {
    249	[0]	= 1,
    250	[1]	= 2,
    251	[2]	= 3,
    252	[3]	= 4,
    253	[4]	= 6,
    254	[5]	= 9,
    255	[6]	= 10,
    256	[7]	= 14,
    257};
    258
    259/**
    260 * get_tacc - turn tACC value into cycle time
    261 * @hclk_tns: The cycle time for HCLK, in 10ths of nanoseconds.
    262 * @val: The bank timing register value, shifted down.
    263 */
    264static unsigned int get_tacc(unsigned long hclk_tns,
    265			     unsigned long val)
    266{
    267	val &= 7;
    268	return hclk_tns * tacc_tab[val];
    269}
    270
    271/**
    272 * get_0124 - turn 0/1/2/4 divider into cycle time
    273 * @hclk_tns: The cycle time for HCLK, in 10ths of nanoseconds.
    274 * @val: The bank timing register value, shifed down.
    275 */
    276static unsigned int get_0124(unsigned long hclk_tns,
    277			     unsigned long val)
    278{
    279	val &= 3;
    280	return hclk_tns * ((val == 3) ? 4 : val);
    281}
    282
    283/**
    284 * s3c2410_iotiming_getbank - turn BANKCON into cycle time information
    285 * @cfg: The frequency configuration
    286 * @bt: The bank timing to fill in (uses cached BANKCON)
    287 *
    288 * Given the BANKCON setting in @bt and the current frequency settings
    289 * in @cfg, update the cycle timing information.
    290 */
    291static void s3c2410_iotiming_getbank(struct s3c_cpufreq_config *cfg,
    292				     struct s3c2410_iobank_timing *bt)
    293{
    294	unsigned long bankcon = bt->bankcon;
    295	unsigned long hclk = cfg->freq.hclk_tns;
    296
    297	bt->tcah = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcah_SHIFT);
    298	bt->tcoh = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcoh_SHIFT);
    299	bt->tcos = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcos_SHIFT);
    300	bt->tacs = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tacs_SHIFT);
    301	bt->tacc = get_tacc(hclk, bankcon >> S3C2410_BANKCON_Tacc_SHIFT);
    302}
    303
    304/**
    305 * s3c2410_iotiming_debugfs - debugfs show io bank timing information
    306 * @seq: The seq_file to write output to using seq_printf().
    307 * @cfg: The current configuration.
    308 * @iob: The IO bank information to decode.
    309 */
    310void s3c2410_iotiming_debugfs(struct seq_file *seq,
    311			      struct s3c_cpufreq_config *cfg,
    312			      union s3c_iobank *iob)
    313{
    314	struct s3c2410_iobank_timing *bt = iob->io_2410;
    315	unsigned long bankcon = bt->bankcon;
    316	unsigned long hclk = cfg->freq.hclk_tns;
    317	unsigned int tacs;
    318	unsigned int tcos;
    319	unsigned int tacc;
    320	unsigned int tcoh;
    321	unsigned int tcah;
    322
    323	seq_printf(seq, "BANKCON=0x%08lx\n", bankcon);
    324
    325	tcah = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcah_SHIFT);
    326	tcoh = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcoh_SHIFT);
    327	tcos = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcos_SHIFT);
    328	tacs = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tacs_SHIFT);
    329	tacc = get_tacc(hclk, bankcon >> S3C2410_BANKCON_Tacc_SHIFT);
    330
    331	seq_printf(seq,
    332		   "\tRead: Tacs=%d.%d, Tcos=%d.%d, Tacc=%d.%d, Tcoh=%d.%d, Tcah=%d.%d\n",
    333		   print_ns(bt->tacs),
    334		   print_ns(bt->tcos),
    335		   print_ns(bt->tacc),
    336		   print_ns(bt->tcoh),
    337		   print_ns(bt->tcah));
    338
    339	seq_printf(seq,
    340		   "\t Set: Tacs=%d.%d, Tcos=%d.%d, Tacc=%d.%d, Tcoh=%d.%d, Tcah=%d.%d\n",
    341		   print_ns(tacs),
    342		   print_ns(tcos),
    343		   print_ns(tacc),
    344		   print_ns(tcoh),
    345		   print_ns(tcah));
    346}
    347
    348/**
    349 * s3c2410_iotiming_calc - Calculate bank timing for frequency change.
    350 * @cfg: The frequency configuration
    351 * @iot: The IO timing information to fill out.
    352 *
    353 * Calculate the new values for the banks in @iot based on the new
    354 * frequency information in @cfg. This is then used by s3c2410_iotiming_set()
    355 * to update the timing when necessary.
    356 */
    357int s3c2410_iotiming_calc(struct s3c_cpufreq_config *cfg,
    358			  struct s3c_iotimings *iot)
    359{
    360	struct s3c2410_iobank_timing *bt;
    361	unsigned long bankcon;
    362	int bank;
    363	int ret;
    364
    365	for (bank = 0; bank < MAX_BANKS; bank++) {
    366		bankcon = __raw_readl(bank_reg(bank));
    367		bt = iot->bank[bank].io_2410;
    368
    369		if (!bt)
    370			continue;
    371
    372		bt->bankcon = bankcon;
    373
    374		ret = s3c2410_calc_bank(cfg, bt);
    375		if (ret) {
    376			printk(KERN_ERR "%s: cannot calculate bank %d io\n",
    377			       __func__, bank);
    378			goto err;
    379		}
    380
    381		s3c_freq_iodbg("%s: bank %d: con=%08lx\n",
    382			       __func__, bank, bt->bankcon);
    383	}
    384
    385	return 0;
    386 err:
    387	return ret;
    388}
    389
    390/**
    391 * s3c2410_iotiming_set - set the IO timings from the given setup.
    392 * @cfg: The frequency configuration
    393 * @iot: The IO timing information to use.
    394 *
    395 * Set all the currently used IO bank timing information generated
    396 * by s3c2410_iotiming_calc() once the core has validated that all
    397 * the new values are within permitted bounds.
    398 */
    399void s3c2410_iotiming_set(struct s3c_cpufreq_config *cfg,
    400			  struct s3c_iotimings *iot)
    401{
    402	struct s3c2410_iobank_timing *bt;
    403	int bank;
    404
    405	/* set the io timings from the specifier */
    406
    407	for (bank = 0; bank < MAX_BANKS; bank++) {
    408		bt = iot->bank[bank].io_2410;
    409		if (!bt)
    410			continue;
    411
    412		__raw_writel(bt->bankcon, bank_reg(bank));
    413	}
    414}
    415
    416/**
    417 * s3c2410_iotiming_get - Get the timing information from current registers.
    418 * @cfg: The frequency configuration
    419 * @timings: The IO timing information to fill out.
    420 *
    421 * Calculate the @timings timing information from the current frequency
    422 * information in @cfg, and the new frequency configuration
    423 * through all the IO banks, reading the state and then updating @iot
    424 * as necessary.
    425 *
    426 * This is used at the moment on initialisation to get the current
    427 * configuration so that boards do not have to carry their own setup
    428 * if the timings are correct on initialisation.
    429 */
    430
    431int s3c2410_iotiming_get(struct s3c_cpufreq_config *cfg,
    432			 struct s3c_iotimings *timings)
    433{
    434	struct s3c2410_iobank_timing *bt;
    435	unsigned long bankcon;
    436	unsigned long bwscon;
    437	int bank;
    438
    439	bwscon = __raw_readl(S3C2410_BWSCON);
    440
    441	/* look through all banks to see what is currently set. */
    442
    443	for (bank = 0; bank < MAX_BANKS; bank++) {
    444		bankcon = __raw_readl(bank_reg(bank));
    445
    446		if (!bank_is_io(bankcon))
    447			continue;
    448
    449		s3c_freq_iodbg("%s: bank %d: con %08lx\n",
    450			       __func__, bank, bankcon);
    451
    452		bt = kzalloc(sizeof(*bt), GFP_KERNEL);
    453		if (!bt)
    454			return -ENOMEM;
    455
    456		/* find out in nWait is enabled for bank. */
    457
    458		if (bank != 0) {
    459			unsigned long tmp  = S3C2410_BWSCON_GET(bwscon, bank);
    460			if (tmp & S3C2410_BWSCON_WS)
    461				bt->nwait_en = 1;
    462		}
    463
    464		timings->bank[bank].io_2410 = bt;
    465		bt->bankcon = bankcon;
    466
    467		s3c2410_iotiming_getbank(cfg, bt);
    468	}
    469
    470	s3c2410_print_timing("get", timings);
    471	return 0;
    472}