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-s3c2412.c (7460B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// Copyright (c) 2006-2008 Simtec Electronics
      4//	http://armlinux.simtec.co.uk/
      5//	Ben Dooks <ben@simtec.co.uk>
      6//
      7// S3C2412/S3C2443 (PL093 based) IO timing support
      8
      9#include <linux/init.h>
     10#include <linux/module.h>
     11#include <linux/interrupt.h>
     12#include <linux/ioport.h>
     13#include <linux/cpufreq.h>
     14#include <linux/seq_file.h>
     15#include <linux/device.h>
     16#include <linux/delay.h>
     17#include <linux/clk.h>
     18#include <linux/err.h>
     19#include <linux/slab.h>
     20
     21#include <linux/amba/pl093.h>
     22
     23#include <asm/mach/arch.h>
     24#include <asm/mach/map.h>
     25
     26#include "cpu.h"
     27#include <linux/soc/samsung/s3c-cpufreq-core.h>
     28
     29#include "s3c2412.h"
     30
     31#define print_ns(x) ((x) / 10), ((x) % 10)
     32
     33/**
     34 * s3c2412_print_timing - print timing information via printk.
     35 * @pfx: The prefix to print each line with.
     36 * @iot: The IO timing information
     37 */
     38static void s3c2412_print_timing(const char *pfx, struct s3c_iotimings *iot)
     39{
     40	struct s3c2412_iobank_timing *bt;
     41	unsigned int bank;
     42
     43	for (bank = 0; bank < MAX_BANKS; bank++) {
     44		bt = iot->bank[bank].io_2412;
     45		if (!bt)
     46			continue;
     47
     48		printk(KERN_DEBUG "%s: %d: idcy=%d.%d wstrd=%d.%d wstwr=%d,%d"
     49		       "wstoen=%d.%d wstwen=%d.%d wstbrd=%d.%d\n", pfx, bank,
     50		       print_ns(bt->idcy),
     51		       print_ns(bt->wstrd),
     52		       print_ns(bt->wstwr),
     53		       print_ns(bt->wstoen),
     54		       print_ns(bt->wstwen),
     55		       print_ns(bt->wstbrd));
     56	}
     57}
     58
     59/**
     60 * to_div - turn a cycle length into a divisor setting.
     61 * @cyc_tns: The cycle time in 10ths of nanoseconds.
     62 * @clk_tns: The clock period in 10ths of nanoseconds.
     63 */
     64static inline unsigned int to_div(unsigned int cyc_tns, unsigned int clk_tns)
     65{
     66	return cyc_tns ? DIV_ROUND_UP(cyc_tns, clk_tns) : 0;
     67}
     68
     69/**
     70 * calc_timing - calculate timing divisor value and check in range.
     71 * @hwtm: The hardware timing in 10ths of nanoseconds.
     72 * @clk_tns: The clock period in 10ths of nanoseconds.
     73 * @err: Pointer to err variable to update in event of failure.
     74 */
     75static unsigned int calc_timing(unsigned int hwtm, unsigned int clk_tns,
     76				unsigned int *err)
     77{
     78	unsigned int ret = to_div(hwtm, clk_tns);
     79
     80	if (ret > 0xf)
     81		*err = -EINVAL;
     82
     83	return ret;
     84}
     85
     86/**
     87 * s3c2412_calc_bank - calculate the bank divisor settings.
     88 * @cfg: The current frequency configuration.
     89 * @bt: The bank timing.
     90 */
     91static int s3c2412_calc_bank(struct s3c_cpufreq_config *cfg,
     92			     struct s3c2412_iobank_timing *bt)
     93{
     94	unsigned int hclk = cfg->freq.hclk_tns;
     95	int err = 0;
     96
     97	bt->smbidcyr = calc_timing(bt->idcy, hclk, &err);
     98	bt->smbwstrd = calc_timing(bt->wstrd, hclk, &err);
     99	bt->smbwstwr = calc_timing(bt->wstwr, hclk, &err);
    100	bt->smbwstoen = calc_timing(bt->wstoen, hclk, &err);
    101	bt->smbwstwen = calc_timing(bt->wstwen, hclk, &err);
    102	bt->smbwstbrd = calc_timing(bt->wstbrd, hclk, &err);
    103
    104	return err;
    105}
    106
    107/**
    108 * s3c2412_iotiming_debugfs - debugfs show io bank timing information
    109 * @seq: The seq_file to write output to using seq_printf().
    110 * @cfg: The current configuration.
    111 * @iob: The IO bank information to decode.
    112*/
    113void s3c2412_iotiming_debugfs(struct seq_file *seq,
    114			      struct s3c_cpufreq_config *cfg,
    115			      union s3c_iobank *iob)
    116{
    117	struct s3c2412_iobank_timing *bt = iob->io_2412;
    118
    119	seq_printf(seq,
    120		   "\tRead: idcy=%d.%d wstrd=%d.%d wstwr=%d,%d"
    121		   "wstoen=%d.%d wstwen=%d.%d wstbrd=%d.%d\n",
    122		   print_ns(bt->idcy),
    123		   print_ns(bt->wstrd),
    124		   print_ns(bt->wstwr),
    125		   print_ns(bt->wstoen),
    126		   print_ns(bt->wstwen),
    127		   print_ns(bt->wstbrd));
    128}
    129
    130/**
    131 * s3c2412_iotiming_calc - calculate all the bank divisor settings.
    132 * @cfg: The current frequency configuration.
    133 * @iot: The bank timing information.
    134 *
    135 * Calculate the timing information for all the banks that are
    136 * configured as IO, using s3c2412_calc_bank().
    137 */
    138int s3c2412_iotiming_calc(struct s3c_cpufreq_config *cfg,
    139			  struct s3c_iotimings *iot)
    140{
    141	struct s3c2412_iobank_timing *bt;
    142	int bank;
    143	int ret;
    144
    145	for (bank = 0; bank < MAX_BANKS; bank++) {
    146		bt = iot->bank[bank].io_2412;
    147		if (!bt)
    148			continue;
    149
    150		ret = s3c2412_calc_bank(cfg, bt);
    151		if (ret) {
    152			printk(KERN_ERR "%s: cannot calculate bank %d io\n",
    153			       __func__, bank);
    154			goto err;
    155		}
    156	}
    157
    158	return 0;
    159 err:
    160	return ret;
    161}
    162
    163/**
    164 * s3c2412_iotiming_set - set the timing information
    165 * @cfg: The current frequency configuration.
    166 * @iot: The bank timing information.
    167 *
    168 * Set the IO bank information from the details calculated earlier from
    169 * calling s3c2412_iotiming_calc().
    170 */
    171void s3c2412_iotiming_set(struct s3c_cpufreq_config *cfg,
    172			  struct s3c_iotimings *iot)
    173{
    174	struct s3c2412_iobank_timing *bt;
    175	void __iomem *regs;
    176	int bank;
    177
    178	/* set the io timings from the specifier */
    179
    180	for (bank = 0; bank < MAX_BANKS; bank++) {
    181		bt = iot->bank[bank].io_2412;
    182		if (!bt)
    183			continue;
    184
    185		regs = S3C2412_SSMC_BANK(bank);
    186
    187		__raw_writel(bt->smbidcyr, regs + SMBIDCYR);
    188		__raw_writel(bt->smbwstrd, regs + SMBWSTRDR);
    189		__raw_writel(bt->smbwstwr, regs + SMBWSTWRR);
    190		__raw_writel(bt->smbwstoen, regs + SMBWSTOENR);
    191		__raw_writel(bt->smbwstwen, regs + SMBWSTWENR);
    192		__raw_writel(bt->smbwstbrd, regs + SMBWSTBRDR);
    193	}
    194}
    195
    196static inline unsigned int s3c2412_decode_timing(unsigned int clock, u32 reg)
    197{
    198	return (reg & 0xf) * clock;
    199}
    200
    201static void s3c2412_iotiming_getbank(struct s3c_cpufreq_config *cfg,
    202				     struct s3c2412_iobank_timing *bt,
    203				     unsigned int bank)
    204{
    205	unsigned long clk = cfg->freq.hclk_tns;  /* ssmc clock??? */
    206	void __iomem *regs = S3C2412_SSMC_BANK(bank);
    207
    208	bt->idcy = s3c2412_decode_timing(clk, __raw_readl(regs + SMBIDCYR));
    209	bt->wstrd = s3c2412_decode_timing(clk, __raw_readl(regs + SMBWSTRDR));
    210	bt->wstoen = s3c2412_decode_timing(clk, __raw_readl(regs + SMBWSTOENR));
    211	bt->wstwen = s3c2412_decode_timing(clk, __raw_readl(regs + SMBWSTWENR));
    212	bt->wstbrd = s3c2412_decode_timing(clk, __raw_readl(regs + SMBWSTBRDR));
    213}
    214
    215/**
    216 * bank_is_io - return true if bank is (possibly) IO.
    217 * @bank: The bank number.
    218 * @bankcfg: The value of S3C2412_EBI_BANKCFG.
    219 */
    220static inline bool bank_is_io(unsigned int bank, u32 bankcfg)
    221{
    222	if (bank < 2)
    223		return true;
    224
    225	return !(bankcfg & (1 << bank));
    226}
    227
    228int s3c2412_iotiming_get(struct s3c_cpufreq_config *cfg,
    229			 struct s3c_iotimings *timings)
    230{
    231	struct s3c2412_iobank_timing *bt;
    232	u32 bankcfg = __raw_readl(S3C2412_EBI_BANKCFG);
    233	unsigned int bank;
    234
    235	/* look through all banks to see what is currently set. */
    236
    237	for (bank = 0; bank < MAX_BANKS; bank++) {
    238		if (!bank_is_io(bank, bankcfg))
    239			continue;
    240
    241		bt = kzalloc(sizeof(*bt), GFP_KERNEL);
    242		if (!bt)
    243			return -ENOMEM;
    244
    245		timings->bank[bank].io_2412 = bt;
    246		s3c2412_iotiming_getbank(cfg, bt, bank);
    247	}
    248
    249	s3c2412_print_timing("get", timings);
    250	return 0;
    251}
    252
    253/* this is in here as it is so small, it doesn't currently warrant a file
    254 * to itself. We expect that any s3c24xx needing this is going to also
    255 * need the iotiming support.
    256 */
    257void s3c2412_cpufreq_setrefresh(struct s3c_cpufreq_config *cfg)
    258{
    259	struct s3c_cpufreq_board *board = cfg->board;
    260	u32 refresh;
    261
    262	WARN_ON(board == NULL);
    263
    264	/* Reduce both the refresh time (in ns) and the frequency (in MHz)
    265	 * down to ensure that we do not overflow 32 bit numbers.
    266	 *
    267	 * This should work for HCLK up to 133MHz and refresh period up
    268	 * to 30usec.
    269	 */
    270
    271	refresh = (cfg->freq.hclk / 100) * (board->refresh / 10);
    272	refresh = DIV_ROUND_UP(refresh, (1000 * 1000)); /* apply scale  */
    273	refresh &= ((1 << 16) - 1);
    274
    275	s3c_freq_dbg("%s: refresh value %u\n", __func__, (unsigned int)refresh);
    276
    277	__raw_writel(refresh, S3C2412_REFRESH);
    278}