summaryrefslogtreecommitdiff
path: root/arch/arm/plat-samsung/include/plat/cpu-freq-core.h
blob: 317c523032888690bb4fb9832c13908edd47204a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
/* arch/arm/plat-samsung/include/plat/cpu-freq-core.h
 *
 * Copyright (c) 2006-2009 Simtec Electronics
 *	http://armlinux.simtec.co.uk/
 *	Ben Dooks <ben@simtec.co.uk>
 *
 * S3C CPU frequency scaling support - core support
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
*/

#include <plat/cpu-freq.h>

struct seq_file;

#define MAX_BANKS (8)
#define S3C2412_MAX_IO	(8)

/**
 * struct s3c2410_iobank_timing - IO bank timings for S3C2410 style timings
 * @bankcon: The cached version of settings in this structure.
 * @tacp:
 * @tacs: Time from address valid to nCS asserted.
 * @tcos: Time from nCS asserted to nOE or nWE asserted.
 * @tacc: Time that nOE or nWE is asserted.
 * @tcoh: Time nCS is held after nOE or nWE are released.
 * @tcah: Time address is held for after
 * @nwait_en: Whether nWAIT is enabled for this bank.
 *
 * This structure represents the IO timings for a S3C2410 style IO bank
 * used by the CPU frequency support if it needs to change the settings
 * of the IO.
 */
struct s3c2410_iobank_timing {
	unsigned long	bankcon;
	unsigned int	tacp;
	unsigned int	tacs;
	unsigned int	tcos;
	unsigned int	tacc;
	unsigned int	tcoh;		/* nCS hold afrer nOE/nWE */
	unsigned int	tcah;		/* Address hold after nCS */
	unsigned char	nwait_en;	/* nWait enabled for bank. */
};

/**
 * struct s3c2412_iobank_timing - io timings for PL092 (S3C2412) style IO
 * @idcy: The idle cycle time between transactions.
 * @wstrd: nCS release to end of read cycle.
 * @wstwr: nCS release to end of write cycle.
 * @wstoen: nCS assertion to nOE assertion time.
 * @wstwen: nCS assertion to nWE assertion time.
 * @wstbrd: Burst ready delay.
 * @smbidcyr: Register cache for smbidcyr value.
 * @smbwstrd: Register cache for smbwstrd value.
 * @smbwstwr: Register cache for smbwstwr value.
 * @smbwstoen: Register cache for smbwstoen value.
 * @smbwstwen: Register cache for smbwstwen value.
 * @smbwstbrd: Register cache for smbwstbrd value.
 *
 * Timing information for a IO bank on an S3C2412 or similar system which
 * uses a PL093 block.
 */
struct s3c2412_iobank_timing {
	unsigned int	idcy;
	unsigned int	wstrd;
	unsigned int	wstwr;
	unsigned int	wstoen;
	unsigned int	wstwen;
	unsigned int	wstbrd;

	/* register cache */
	unsigned char	smbidcyr;
	unsigned char	smbwstrd;
	unsigned char	smbwstwr;
	unsigned char	smbwstoen;
	unsigned char	smbwstwen;
	unsigned char	smbwstbrd;
};

union s3c_iobank {
	struct s3c2410_iobank_timing	*io_2410;
	struct s3c2412_iobank_timing	*io_2412;
};

/**
 * struct s3c_iotimings - Chip IO timings holder
 * @bank: The timings for each IO bank.
 */
struct s3c_iotimings {
	union s3c_iobank	bank[MAX_BANKS];
};

/**
 * struct s3c_plltab - PLL table information.
 * @vals: List of PLL values.
 * @size: Size of the PLL table @vals.
 */
struct s3c_plltab {
	struct s3c_pllval	*vals;
	int			 size;
};

/**
 * struct s3c_cpufreq_config - current cpu frequency configuration
 * @freq: The current settings for the core clocks.
 * @max: Maxium settings, derived from core, board and user settings.
 * @pll: The PLL table entry for the current PLL settings.
 * @divs: The divisor settings for the core clocks.
 * @info: The current core driver information.
 * @board: The information for the board we are running on.
 * @lock_pll: Set if the PLL settings cannot be changed.
 *
 * This is for the core drivers that need to know information about
 * the current settings and values. It should not be needed by any
 * device drivers.
*/
struct s3c_cpufreq_config {
	struct s3c_freq		freq;
	struct s3c_freq		max;
	struct clk		*mpll;
	struct cpufreq_frequency_table pll;
	struct s3c_clkdivs	divs;
	struct s3c_cpufreq_info *info;	/* for core, not drivers */
	struct s3c_cpufreq_board *board;

	unsigned int	lock_pll:1;
};

/**
 * struct s3c_cpufreq_info - Information for the CPU frequency driver.
 * @name: The name of this implementation.
 * @max: The maximum frequencies for the system.
 * @latency: Transition latency to give to cpufreq.
 * @locktime_m: The lock-time in uS for the MPLL.
 * @locktime_u: The lock-time in uS for the UPLL.
 * @locttime_bits: The number of bits each LOCKTIME field.
 * @need_pll: Set if this driver needs to change the PLL values to achieve
 *	any frequency changes. This is really only need by devices like the
 *	S3C2410 where there is no or limited divider between the PLL and the
 *	ARMCLK.
 * @get_iotiming: Get the current IO timing data, mainly for use at start.
 * @set_iotiming: Update the IO timings from the cached copies calculated
 *	from the @calc_iotiming entry when changing the frequency.
 * @calc_iotiming: Calculate and update the cached copies of the IO timings
 *	from the newly calculated frequencies.
 * @calc_freqtable: Calculate (fill in) the given frequency table from the
 *	current frequency configuration. If the table passed in is NULL,
 *	then the return is the number of elements to be filled for allocation
 *	of the table.
 * @set_refresh: Set the memory refresh configuration.
 * @set_fvco: Set the PLL frequencies.
 * @set_divs: Update the clock divisors.
 * @calc_divs: Calculate the clock divisors.
 */
struct s3c_cpufreq_info {
	const char		*name;
	struct s3c_freq		max;

	unsigned int		latency;

	unsigned int		locktime_m;
	unsigned int		locktime_u;
	unsigned char		locktime_bits;

	unsigned int		need_pll:1;

	/* driver routines */

	int		(*get_iotiming)(struct s3c_cpufreq_config *cfg,
					struct s3c_iotimings *timings);

	void		(*set_iotiming)(struct s3c_cpufreq_config *cfg,
					struct s3c_iotimings *timings);

	int		(*calc_iotiming)(struct s3c_cpufreq_config *cfg,
					 struct s3c_iotimings *timings);

	int		(*calc_freqtable)(struct s3c_cpufreq_config *cfg,
					  struct cpufreq_frequency_table *t,
					  size_t table_size);

	void		(*debug_io_show)(struct seq_file *seq,
					 struct s3c_cpufreq_config *cfg,
					 union s3c_iobank *iob);

	void		(*set_refresh)(struct s3c_cpufreq_config *cfg);
	void		(*set_fvco)(struct s3c_cpufreq_config *cfg);
	void		(*set_divs)(struct s3c_cpufreq_config *cfg);
	int		(*calc_divs)(struct s3c_cpufreq_config *cfg);
};

extern int s3c_cpufreq_register(struct s3c_cpufreq_info *info);

extern int s3c_plltab_register(struct cpufreq_frequency_table *plls,
			       unsigned int plls_no);

/* exports and utilities for debugfs */
extern struct s3c_cpufreq_config *s3c_cpufreq_getconfig(void);
extern struct s3c_iotimings *s3c_cpufreq_getiotimings(void);

#ifdef CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS
#define s3c_cpufreq_debugfs_call(x) x
#else
#define s3c_cpufreq_debugfs_call(x) NULL
#endif

/* Useful utility functions. */

extern struct clk *s3c_cpufreq_clk_get(struct device *, const char *);

/* S3C2410 and compatible exported functions */

extern void s3c2410_cpufreq_setrefresh(struct s3c_cpufreq_config *cfg);
extern void s3c2410_set_fvco(struct s3c_cpufreq_config *cfg);

#ifdef CONFIG_S3C2410_IOTIMING
extern void s3c2410_iotiming_debugfs(struct seq_file *seq,
				     struct s3c_cpufreq_config *cfg,
				     union s3c_iobank *iob);

extern int s3c2410_iotiming_calc(struct s3c_cpufreq_config *cfg,
				 struct s3c_iotimings *iot);

extern int s3c2410_iotiming_get(struct s3c_cpufreq_config *cfg,
				struct s3c_iotimings *timings);

extern void s3c2410_iotiming_set(struct s3c_cpufreq_config *cfg,
				 struct s3c_iotimings *iot);
#else
#define s3c2410_iotiming_debugfs NULL
#define s3c2410_iotiming_calc NULL
#define s3c2410_iotiming_get NULL
#define s3c2410_iotiming_set NULL
#endif /* CONFIG_S3C2410_IOTIMING */

/* S3C2412 compatible routines */

#ifdef CONFIG_S3C2412_IOTIMING
extern void s3c2412_iotiming_debugfs(struct seq_file *seq,
				     struct s3c_cpufreq_config *cfg,
				     union s3c_iobank *iob);

extern int s3c2412_iotiming_get(struct s3c_cpufreq_config *cfg,
				struct s3c_iotimings *timings);

extern int s3c2412_iotiming_calc(struct s3c_cpufreq_config *cfg,
				 struct s3c_iotimings *iot);

extern void s3c2412_iotiming_set(struct s3c_cpufreq_config *cfg,
				 struct s3c_iotimings *iot);
#else
#define s3c2412_iotiming_debugfs NULL
#define s3c2412_iotiming_calc NULL
#define s3c2412_iotiming_get NULL
#define s3c2412_iotiming_set NULL
#endif /* CONFIG_S3C2412_IOTIMING */

#ifdef CONFIG_ARM_S3C24XX_CPUFREQ_DEBUG
#define s3c_freq_dbg(x...) printk(KERN_INFO x)
#else
#define s3c_freq_dbg(x...) do { if (0) printk(x); } while (0)
#endif /* CONFIG_ARM_S3C24XX_CPUFREQ_DEBUG */

#ifdef CONFIG_ARM_S3C24XX_CPUFREQ_IODEBUG
#define s3c_freq_iodbg(x...) printk(KERN_INFO x)
#else
#define s3c_freq_iodbg(x...) do { if (0) printk(x); } while (0)
#endif /* CONFIG_ARM_S3C24XX_CPUFREQ_IODEBUG */

static inline int s3c_cpufreq_addfreq(struct cpufreq_frequency_table *table,
				      int index, size_t table_size,
				      unsigned int freq)
{
	if (index < 0)
		return index;

	if (table) {
		if (index >= table_size)
			return -ENOMEM;

		s3c_freq_dbg("%s: { %d = %u kHz }\n",
			     __func__, index, freq);

		table[index].driver_data = index;
		table[index].frequency = freq;
	}

	return index + 1;
}