aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/voltage.h
blob: e59f8ad3a06582e0b9b939dfdbeec23618dfbb04 (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
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
/*
 * OMAP Voltage Management Routines
 *
 * Author: Thara Gopinath	<thara@ti.com>
 *
 * Copyright (C) 2009 Texas Instruments, Inc.
 * Thara Gopinath <thara@ti.com>
 *
 * 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.
 */

#ifndef __ARCH_ARM_MACH_OMAP2_VOLTAGE_H
#define __ARCH_ARM_MACH_OMAP2_VOLTAGE_H

#include <linux/notifier.h>
#include <linux/err.h>

struct omap_volt_data;

#include "vc.h"
#include "vp.h"
#include "ldo.h"

struct powerdomain;

/* XXX document */
#define VOLTSCALE_VPFORCEUPDATE		1
#define VOLTSCALE_VCBYPASS		2

/*
 * OMAP3 GENERIC setup times. Revisit to see if these needs to be
 * passed from board or PMIC file
 */
#define OMAP3_CLKSETUP		0xff
#define OMAP3_VOLTOFFSET	0xff
#define OMAP3_VOLTSETUP2	0xff

struct omap_vdd_info;

/**
 * struct omap_vfsm_instance - per-voltage manager FSM register/bitfield
 * data
 * @voltsetup_mask: SETUP_TIME* bitmask of PRM_VOLTSETUP* register(RET/SLEEP)
 * @voltsetup_reg: register offset of PRM_VOLTSETUP from PRM base(RET/SLEEP)
 * @voltsetup_shift: SETUP_TIME* field shift in the PRM_VOLTSETUP* register
 * @voltsetupoff_reg: register offset of PRM_VOLTSETUP*_OFF from PRM base
 *
 * XXX What about VOLTOFFSET/VOLTCTRL?
 * XXX It is not necessary to have both a _mask and a _shift for the same
 *     bitfield - remove one!
 */
struct omap_vfsm_instance {
	u32 voltsetup_mask;
	u8 voltsetup_reg;
	u8 voltsetup_shift;
	u8 voltsetupoff_reg;
};

/* Dynamic nominal voltage margin common for OMAP3630 and OMAP4 */
#define OMAP3PLUS_DYNAMIC_NOMINAL_MARGIN_UV	50000

/**
 * struct voltagedomain - omap voltage domain global structure.
 * @name: Name of the voltage domain which can be used as a unique identifier.
 * @scalable: Whether or not this voltage domain is scalable
 * @node: list_head linking all voltage domains
 * @pwrdm_node: list_head linking all powerdomains in this voltagedomain
 * @vdd: to be removed
 * @pwrdms: powerdomains in this voltagedomain
 * @scale: function used to scale the voltage of the voltagedomain
 * @curr_volt: current nominal voltage for this voltage domain
 * @change_notify_list: notifiers that need to be told on pre and post change
 */
struct voltagedomain {
	char *name;
	bool scalable;
	struct list_head node;
	struct list_head pwrdm_list;
	struct omap_vc_channel *vc;
	const struct omap_vfsm_instance *vfsm;
	struct omap_vp_instance *vp;
	struct omap_voltdm_pmic *pmic;
	struct omap_ldo_abb_instance *abb;

	/* VC/VP register access functions: SoC specific */
	u32 (*read) (u8 offset);
	void (*write) (u32 val, u8 offset);
	u32 (*rmw)(u32 mask, u32 bits, u8 offset);

	union {
		const char *name;
		u32 rate;
	} sys_clk;

	int (*scale) (struct voltagedomain *voltdm,
		      struct omap_volt_data *target_volt);
	struct omap_volt_data *curr_volt;

	struct omap_vdd_info *vdd;
	struct srcu_notifier_head change_notify_list;
	struct dentry *debug_dir;
};

/* Notifier values for voltage changes */
#define OMAP_VOLTAGE_PRECHANGE	1
#define OMAP_VOLTAGE_POSTCHANGE	2

/**
 * struct omap_voltage_notifier - notifier data that is passed along
 * @voltdm:		voltage domain for the notification
 * @target_volt:	what voltage is happening
 * @op_result:		valid only for POSTCHANGE, tells the result of
 *			the operation.
 *
 * This provides notification
 */
struct omap_voltage_notifier {
	struct voltagedomain	*voltdm;
	unsigned long		target_volt;
	int			op_result;
};

/* Flags for various ABB options */
#define OMAP_ABB_NONE		-1
#define OMAP_ABB_NOMINAL_OPP	0
#define OMAP_ABB_FAST_OPP	1
#define OMAP_ABB_SLOW_OPP	3

/**
 * struct omap_volt_data - Omap voltage specific data.
 * @voltage_nominal:	The possible voltage value in uV
 * @voltage_calibrated:	The Calibrated voltage value in uV
 * @voltage_dynamic_nominal:	The run time optimized nominal voltage for
 *			the device. Dynamic nominal is the nominal voltage
 *			specialized for that OPP on the device in uV.
 * @volt_margin:	Additional sofware margin to add to OPP calibrated
 *			voltage
 * @sr_efuse_offs:	The offset of the efuse register(from system
 *			control module base address) from where to read
 *			the n-target value for the smartreflex module.
 * @sr_errminlimit:	Error min limit value for smartreflex. This value
 *			differs at differnet opp and thus is linked
 *			with voltage.
 * @vp_errorgain:	Error gain value for the voltage processor. This
 *			field also differs according to the voltage/opp.
 * @abb_type:		Either OMAP_ABB_NONE - which implies that there is no
 *			usage of ABB; OMAP_ABB_NOMINAL_OPP - which bypasses ABB
 *			LDO; or OMAP_ABB_FAST_OPP, which enables Forward-Body
 *			Bias.
 */
struct omap_volt_data {
	u32	volt_nominal;
	u32	volt_calibrated;
	u32	volt_dynamic_nominal;
	u32	volt_margin;
	u32	sr_efuse_offs;
	u8	sr_errminlimit;
	u8	vp_errgain;
	int	abb_type;
};

/*
 * Introduced in OMAP4, is a concept of a default channel - in OMAP4, this
 * channel is MPU, all other domains such as IVA/CORE, could optionally
 * link their i2c reg configuration to use MPU channel's configuration if
 * required. To do this, mark in the PMIC structure's
 * i2c_slave_addr, volt_reg_addr,cmd_reg_addr with this macro.
 */
#define USE_DEFAULT_CHANNEL_I2C_PARAM  0x8000

/* Min and max voltages from OMAP perspective */
#define OMAP3430_VP1_VLIMITTO_VDDMIN	850000
#define OMAP3430_VP1_VLIMITTO_VDDMAX	1425000
#define OMAP3430_VP2_VLIMITTO_VDDMIN	900000
#define OMAP3430_VP2_VLIMITTO_VDDMAX	1150000

#define OMAP3630_VP1_VLIMITTO_VDDMIN	900000
#define OMAP3630_VP1_VLIMITTO_VDDMAX	1350000
#define OMAP3630_VP2_VLIMITTO_VDDMIN	900000
#define OMAP3630_VP2_VLIMITTO_VDDMAX	1200000

#define OMAP3_VP_CONFIG_ERROROFFSET	0x00
#define OMAP3_VP_VSTEPMIN_VSTEPMIN	0x1
#define OMAP3_VP_VSTEPMAX_VSTEPMAX	0x04
#define OMAP3_VP_VLIMITTO_TIMEOUT_US	200

#define OMAP4_VP_MPU_VLIMITTO_VDDMIN	830000
#define OMAP4_VP_IVA_VLIMITTO_VDDMIN	830000
#define OMAP4_VP_CORE_VLIMITTO_VDDMIN	830000

#define OMAP4430_VP_MPU_VLIMITTO_VDDMAX		1360000
#define OMAP4430_VP_IVA_VLIMITTO_VDDMAX		1240000
#define OMAP4430_VP_CORE_VLIMITTO_VDDMAX	1170000

#define OMAP4460_VP_MPU_VLIMITTO_VDDMAX		1380000
#define OMAP4460_VP_IVA_VLIMITTO_VDDMAX		1375000
#define OMAP4460_VP_CORE_VLIMITTO_VDDMAX	1250000

#define OMAP4_VP_CONFIG_ERROROFFSET	0x00
#define OMAP4_VP_VSTEPMIN_VSTEPMIN	0x01
#define OMAP4_VP_VSTEPMAX_VSTEPMAX	0x04
#define OMAP4_VP_VLIMITTO_TIMEOUT_US	200

/**
 * struct omap_voltdm_pmic - PMIC specific data required by voltage driver.
 * @slew_rate:	PMIC slew rate (in uv/us)
 * @step_size:	PMIC voltage step size (in uv)
 * @i2c_high_speed: whether VC uses I2C high-speed mode to PMIC
 * @i2c_mcode: master code value for I2C high-speed preamble transmission
 * @vsel_to_uv:	PMIC API to convert vsel value to actual voltage in uV.
 * @uv_to_vsel:	PMIC API to convert voltage in uV to vsel value.
 * @i2c_hscll_low: PMIC interface speed config for highspeed mode (T low)
 * @i2c_hscll_high: PMIC interface speed config for highspeed mode (T high)
 * @i2c_scll_low: PMIC interface speed config for fullspeed mode (T low)
 * @i2c_scll_high: PMIC interface speed config for fullspeed mode (T high)
 * @switch_on_time: time taken for switch on the DCDC in uSec
 * @max_volt: Maximum supported voltage in uV (should be contigous till min)
 * @min_volt: Minimum supported voltage in uV (should be contigous till max)
 */
struct omap_voltdm_pmic {
	int slew_rate;
	int step_size;
	u32 on_volt;
	u32 onlp_volt;
	u32 ret_volt;
	u32 off_volt;
	u16 volt_setup_time;
	u16 switch_on_time;
	u8 vp_erroroffset;
	u8 vp_vstepmin;
	u8 vp_vstepmax;
	u32 min_volt;
	u32 max_volt;
	u8 vp_timeout_us;
	u16 i2c_slave_addr;
	u16 volt_reg_addr;
	u16 cmd_reg_addr;
	bool i2c_high_speed;
	u8 i2c_hscll_low;
	u8 i2c_hscll_high;
	u8 i2c_scll_low;
	u8 i2c_scll_high;
	u8 i2c_mcode;
	unsigned long (*vsel_to_uv) (const u8 vsel);
	u8 (*uv_to_vsel) (unsigned long uV);
};

/**
 * struct omap_vdd_dep_volt - Map table for voltage dependencies
 * @main_vdd_volt	: The main vdd voltage
 * @dep_vdd_volt	: The voltage at which the dependent vdd should be
 *			  when the main vdd is at <main_vdd_volt> voltage
 *
 * Table containing the parent vdd voltage and the dependent vdd voltage
 * corresponding to it.
 */
struct omap_vdd_dep_volt {
	u32 main_vdd_volt;
	u32 dep_vdd_volt;
};

/**
 * struct omap_vdd_dep_info -  Dependent vdd info
 * @name		: Dependent vdd name
 * @_dep_voltdm		: internal structure meant to prevent multiple lookups
 * @dep_table		: Table containing the dependent vdd voltage
 *			  corresponding to every main vdd voltage.
 * @nr_dep_entries	: number of dependency voltage entries
 */
struct omap_vdd_dep_info {
	char *name;
	struct voltagedomain *_dep_voltdm;
	struct omap_vdd_dep_volt *dep_table;
	int nr_dep_entries;
};

/**
 * omap_vdd_info - Per Voltage Domain info
 *
 * @volt_data		: Array ending with a 0 terminator containing the
 *			  voltage table with distinct voltages supported
 *			  by the domain and other associated per voltage data.
 * @dep_vdd_info	: Array ending with a 0 terminator for dependency
 *			  voltage information.
 */
struct omap_vdd_info {
	struct omap_volt_data *volt_data;
	struct omap_vdd_dep_info *dep_vdd_info;
};

void omap_voltage_get_volttable(struct voltagedomain *voltdm,
		struct omap_volt_data **volt_data);
struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm,
		unsigned long volt);
struct omap_volt_data *omap_voltage_get_curr_vdata(struct voltagedomain *voldm);
#ifdef CONFIG_PM
int omap_voltage_register_pmic(struct voltagedomain *voltdm,
			       struct omap_voltdm_pmic *pmic);
void omap_change_voltscale_method(struct voltagedomain *voltdm,
		int voltscale_method);
int omap_voltage_late_init(void);
#else
static inline int omap_voltage_register_pmic(struct voltagedomain *voltdm,
					     struct omap_voltdm_pmic *pmic)
{
	return -EINVAL;
}
static inline  void omap_change_voltscale_method(struct voltagedomain *voltdm,
		int voltscale_method) {}
static inline int omap_voltage_late_init(void)
{
	return -EINVAL;
}
#endif

extern void omap2xxx_voltagedomains_init(void);
extern void omap3xxx_voltagedomains_init(void);
extern void omap44xx_voltagedomains_init(void);

struct voltagedomain *voltdm_lookup(const char *name);
void voltdm_init(struct voltagedomain **voltdm_list);
int voltdm_add_pwrdm(struct voltagedomain *voltdm, struct powerdomain *pwrdm);
int voltdm_for_each(int (*fn)(struct voltagedomain *voltdm, void *user),
		    void *user);
int voltdm_for_each_pwrdm(struct voltagedomain *voltdm,
			  int (*fn)(struct voltagedomain *voltdm,
				    struct powerdomain *pwrdm));
int voltdm_scale(struct voltagedomain *voltdm,
		 struct omap_volt_data *target_volt);
void voltdm_reset(struct voltagedomain *voltdm);

static inline int voltdm_register_notifier(struct voltagedomain *voltdm,
						struct notifier_block *nb)
{
	return srcu_notifier_chain_register(&voltdm->change_notify_list, nb);
}

static inline int voltdm_unregister_notifier(struct voltagedomain *voltdm,
						struct notifier_block *nb)
{
	return srcu_notifier_chain_unregister(&voltdm->change_notify_list, nb);
}

/* convert volt data to the voltage for the voltage data */
static inline unsigned long omap_get_operation_voltage(
				struct omap_volt_data *vdata)
{
	if (!vdata)
		return 0;
	return (vdata->volt_calibrated) ? vdata->volt_calibrated :
		(vdata->volt_dynamic_nominal) ? vdata->volt_dynamic_nominal :
			vdata->volt_nominal;
}

/* what is my dynamic nominal? */
static inline unsigned long omap_get_dyn_nominal(struct omap_volt_data *vdata)
{
	if (IS_ERR_OR_NULL(vdata))
		return 0;
	if (vdata->volt_calibrated) {
		unsigned long v = vdata->volt_calibrated +
			OMAP3PLUS_DYNAMIC_NOMINAL_MARGIN_UV;
		if (v > vdata->volt_nominal)
			return vdata->volt_nominal;
		return v;
	}
	return vdata->volt_nominal;
}
static inline unsigned long omap_get_nominal_voltage(
				struct omap_volt_data *vdata)
{
	if (IS_ERR_OR_NULL(vdata))
		return 0;
	return vdata->volt_nominal;
}

int omap_voltage_calib_reset(struct voltagedomain *voltdm);

#endif