Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Copyright (c) 2006-2008 Simtec Electronics
0004 //  http://armlinux.simtec.co.uk/
0005 //  Ben Dooks <ben@simtec.co.uk>
0006 //
0007 // S3C2412/S3C2443 (PL093 based) IO timing support
0008 
0009 #include <linux/init.h>
0010 #include <linux/module.h>
0011 #include <linux/interrupt.h>
0012 #include <linux/ioport.h>
0013 #include <linux/cpufreq.h>
0014 #include <linux/seq_file.h>
0015 #include <linux/device.h>
0016 #include <linux/delay.h>
0017 #include <linux/clk.h>
0018 #include <linux/err.h>
0019 #include <linux/slab.h>
0020 
0021 #include <linux/amba/pl093.h>
0022 
0023 #include <asm/mach/arch.h>
0024 #include <asm/mach/map.h>
0025 
0026 #include "cpu.h"
0027 #include <linux/soc/samsung/s3c-cpufreq-core.h>
0028 
0029 #include "s3c2412.h"
0030 
0031 #define print_ns(x) ((x) / 10), ((x) % 10)
0032 
0033 /**
0034  * s3c2412_print_timing - print timing information via printk.
0035  * @pfx: The prefix to print each line with.
0036  * @iot: The IO timing information
0037  */
0038 static void s3c2412_print_timing(const char *pfx, struct s3c_iotimings *iot)
0039 {
0040     struct s3c2412_iobank_timing *bt;
0041     unsigned int bank;
0042 
0043     for (bank = 0; bank < MAX_BANKS; bank++) {
0044         bt = iot->bank[bank].io_2412;
0045         if (!bt)
0046             continue;
0047 
0048         printk(KERN_DEBUG "%s: %d: idcy=%d.%d wstrd=%d.%d wstwr=%d,%d"
0049                "wstoen=%d.%d wstwen=%d.%d wstbrd=%d.%d\n", pfx, bank,
0050                print_ns(bt->idcy),
0051                print_ns(bt->wstrd),
0052                print_ns(bt->wstwr),
0053                print_ns(bt->wstoen),
0054                print_ns(bt->wstwen),
0055                print_ns(bt->wstbrd));
0056     }
0057 }
0058 
0059 /**
0060  * to_div - turn a cycle length into a divisor setting.
0061  * @cyc_tns: The cycle time in 10ths of nanoseconds.
0062  * @clk_tns: The clock period in 10ths of nanoseconds.
0063  */
0064 static inline unsigned int to_div(unsigned int cyc_tns, unsigned int clk_tns)
0065 {
0066     return cyc_tns ? DIV_ROUND_UP(cyc_tns, clk_tns) : 0;
0067 }
0068 
0069 /**
0070  * calc_timing - calculate timing divisor value and check in range.
0071  * @hwtm: The hardware timing in 10ths of nanoseconds.
0072  * @clk_tns: The clock period in 10ths of nanoseconds.
0073  * @err: Pointer to err variable to update in event of failure.
0074  */
0075 static unsigned int calc_timing(unsigned int hwtm, unsigned int clk_tns,
0076                 unsigned int *err)
0077 {
0078     unsigned int ret = to_div(hwtm, clk_tns);
0079 
0080     if (ret > 0xf)
0081         *err = -EINVAL;
0082 
0083     return ret;
0084 }
0085 
0086 /**
0087  * s3c2412_calc_bank - calculate the bank divisor settings.
0088  * @cfg: The current frequency configuration.
0089  * @bt: The bank timing.
0090  */
0091 static int s3c2412_calc_bank(struct s3c_cpufreq_config *cfg,
0092                  struct s3c2412_iobank_timing *bt)
0093 {
0094     unsigned int hclk = cfg->freq.hclk_tns;
0095     int err = 0;
0096 
0097     bt->smbidcyr = calc_timing(bt->idcy, hclk, &err);
0098     bt->smbwstrd = calc_timing(bt->wstrd, hclk, &err);
0099     bt->smbwstwr = calc_timing(bt->wstwr, hclk, &err);
0100     bt->smbwstoen = calc_timing(bt->wstoen, hclk, &err);
0101     bt->smbwstwen = calc_timing(bt->wstwen, hclk, &err);
0102     bt->smbwstbrd = calc_timing(bt->wstbrd, hclk, &err);
0103 
0104     return err;
0105 }
0106 
0107 /**
0108  * s3c2412_iotiming_debugfs - debugfs show io bank timing information
0109  * @seq: The seq_file to write output to using seq_printf().
0110  * @cfg: The current configuration.
0111  * @iob: The IO bank information to decode.
0112 */
0113 void s3c2412_iotiming_debugfs(struct seq_file *seq,
0114                   struct s3c_cpufreq_config *cfg,
0115                   union s3c_iobank *iob)
0116 {
0117     struct s3c2412_iobank_timing *bt = iob->io_2412;
0118 
0119     seq_printf(seq,
0120            "\tRead: idcy=%d.%d wstrd=%d.%d wstwr=%d,%d"
0121            "wstoen=%d.%d wstwen=%d.%d wstbrd=%d.%d\n",
0122            print_ns(bt->idcy),
0123            print_ns(bt->wstrd),
0124            print_ns(bt->wstwr),
0125            print_ns(bt->wstoen),
0126            print_ns(bt->wstwen),
0127            print_ns(bt->wstbrd));
0128 }
0129 
0130 /**
0131  * s3c2412_iotiming_calc - calculate all the bank divisor settings.
0132  * @cfg: The current frequency configuration.
0133  * @iot: The bank timing information.
0134  *
0135  * Calculate the timing information for all the banks that are
0136  * configured as IO, using s3c2412_calc_bank().
0137  */
0138 int s3c2412_iotiming_calc(struct s3c_cpufreq_config *cfg,
0139               struct s3c_iotimings *iot)
0140 {
0141     struct s3c2412_iobank_timing *bt;
0142     int bank;
0143     int ret;
0144 
0145     for (bank = 0; bank < MAX_BANKS; bank++) {
0146         bt = iot->bank[bank].io_2412;
0147         if (!bt)
0148             continue;
0149 
0150         ret = s3c2412_calc_bank(cfg, bt);
0151         if (ret) {
0152             printk(KERN_ERR "%s: cannot calculate bank %d io\n",
0153                    __func__, bank);
0154             goto err;
0155         }
0156     }
0157 
0158     return 0;
0159  err:
0160     return ret;
0161 }
0162 
0163 /**
0164  * s3c2412_iotiming_set - set the timing information
0165  * @cfg: The current frequency configuration.
0166  * @iot: The bank timing information.
0167  *
0168  * Set the IO bank information from the details calculated earlier from
0169  * calling s3c2412_iotiming_calc().
0170  */
0171 void s3c2412_iotiming_set(struct s3c_cpufreq_config *cfg,
0172               struct s3c_iotimings *iot)
0173 {
0174     struct s3c2412_iobank_timing *bt;
0175     void __iomem *regs;
0176     int bank;
0177 
0178     /* set the io timings from the specifier */
0179 
0180     for (bank = 0; bank < MAX_BANKS; bank++) {
0181         bt = iot->bank[bank].io_2412;
0182         if (!bt)
0183             continue;
0184 
0185         regs = S3C2412_SSMC_BANK(bank);
0186 
0187         __raw_writel(bt->smbidcyr, regs + SMBIDCYR);
0188         __raw_writel(bt->smbwstrd, regs + SMBWSTRDR);
0189         __raw_writel(bt->smbwstwr, regs + SMBWSTWRR);
0190         __raw_writel(bt->smbwstoen, regs + SMBWSTOENR);
0191         __raw_writel(bt->smbwstwen, regs + SMBWSTWENR);
0192         __raw_writel(bt->smbwstbrd, regs + SMBWSTBRDR);
0193     }
0194 }
0195 
0196 static inline unsigned int s3c2412_decode_timing(unsigned int clock, u32 reg)
0197 {
0198     return (reg & 0xf) * clock;
0199 }
0200 
0201 static void s3c2412_iotiming_getbank(struct s3c_cpufreq_config *cfg,
0202                      struct s3c2412_iobank_timing *bt,
0203                      unsigned int bank)
0204 {
0205     unsigned long clk = cfg->freq.hclk_tns;  /* ssmc clock??? */
0206     void __iomem *regs = S3C2412_SSMC_BANK(bank);
0207 
0208     bt->idcy = s3c2412_decode_timing(clk, __raw_readl(regs + SMBIDCYR));
0209     bt->wstrd = s3c2412_decode_timing(clk, __raw_readl(regs + SMBWSTRDR));
0210     bt->wstoen = s3c2412_decode_timing(clk, __raw_readl(regs + SMBWSTOENR));
0211     bt->wstwen = s3c2412_decode_timing(clk, __raw_readl(regs + SMBWSTWENR));
0212     bt->wstbrd = s3c2412_decode_timing(clk, __raw_readl(regs + SMBWSTBRDR));
0213 }
0214 
0215 /**
0216  * bank_is_io - return true if bank is (possibly) IO.
0217  * @bank: The bank number.
0218  * @bankcfg: The value of S3C2412_EBI_BANKCFG.
0219  */
0220 static inline bool bank_is_io(unsigned int bank, u32 bankcfg)
0221 {
0222     if (bank < 2)
0223         return true;
0224 
0225     return !(bankcfg & (1 << bank));
0226 }
0227 
0228 int s3c2412_iotiming_get(struct s3c_cpufreq_config *cfg,
0229              struct s3c_iotimings *timings)
0230 {
0231     struct s3c2412_iobank_timing *bt;
0232     u32 bankcfg = __raw_readl(S3C2412_EBI_BANKCFG);
0233     unsigned int bank;
0234 
0235     /* look through all banks to see what is currently set. */
0236 
0237     for (bank = 0; bank < MAX_BANKS; bank++) {
0238         if (!bank_is_io(bank, bankcfg))
0239             continue;
0240 
0241         bt = kzalloc(sizeof(*bt), GFP_KERNEL);
0242         if (!bt)
0243             return -ENOMEM;
0244 
0245         timings->bank[bank].io_2412 = bt;
0246         s3c2412_iotiming_getbank(cfg, bt, bank);
0247     }
0248 
0249     s3c2412_print_timing("get", timings);
0250     return 0;
0251 }
0252 
0253 /* this is in here as it is so small, it doesn't currently warrant a file
0254  * to itself. We expect that any s3c24xx needing this is going to also
0255  * need the iotiming support.
0256  */
0257 void s3c2412_cpufreq_setrefresh(struct s3c_cpufreq_config *cfg)
0258 {
0259     struct s3c_cpufreq_board *board = cfg->board;
0260     u32 refresh;
0261 
0262     WARN_ON(board == NULL);
0263 
0264     /* Reduce both the refresh time (in ns) and the frequency (in MHz)
0265      * down to ensure that we do not overflow 32 bit numbers.
0266      *
0267      * This should work for HCLK up to 133MHz and refresh period up
0268      * to 30usec.
0269      */
0270 
0271     refresh = (cfg->freq.hclk / 100) * (board->refresh / 10);
0272     refresh = DIV_ROUND_UP(refresh, (1000 * 1000)); /* apply scale  */
0273     refresh &= ((1 << 16) - 1);
0274 
0275     s3c_freq_dbg("%s: refresh value %u\n", __func__, (unsigned int)refresh);
0276 
0277     __raw_writel(refresh, S3C2412_REFRESH);
0278 }