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