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}