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