0001
0002
0003
0004
0005
0006
0007
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
0035
0036
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
0061
0062
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
0071
0072
0073
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
0088
0089
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
0109
0110
0111
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
0132
0133
0134
0135
0136
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
0165
0166
0167
0168
0169
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
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;
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
0217
0218
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
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
0254
0255
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
0265
0266
0267
0268
0269
0270
0271 refresh = (cfg->freq.hclk / 100) * (board->refresh / 10);
0272 refresh = DIV_ROUND_UP(refresh, (1000 * 1000));
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 }