aboutsummaryrefslogtreecommitdiff
path: root/drivers/clk/bcm/clk-iproc.h
blob: d7e5b94bed45181acfd9e649a4f4997633ac1b0c (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
/*
 * Copyright (C) 2014 Broadcom Corporation
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation version 2.
 *
 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
 * kind, whether express or implied; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef _CLK_IPROC_H
#define _CLK_IPROC_H

#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/clk-provider.h>

#define IPROC_CLK_NAME_LEN 25
#define IPROC_CLK_INVALID_OFFSET 0xffffffff
#define bit_mask(width) ((1 << (width)) - 1)

/* clocks that should not be disabled at runtime */
#define IPROC_CLK_AON BIT(0)

/* PLL that requires gating through ASIU */
#define IPROC_CLK_PLL_ASIU BIT(1)

/* PLL that has fractional part of the NDIV */
#define IPROC_CLK_PLL_HAS_NDIV_FRAC BIT(2)

/*
 * Some of the iProc PLL/clocks may have an ASIC bug that requires read back
 * of the same register following the write to flush the write transaction into
 * the intended register
 */
#define IPROC_CLK_NEEDS_READ_BACK BIT(3)

/*
 * Some PLLs require the PLL SW override bit to be set before changes can be
 * applied to the PLL
 */
#define IPROC_CLK_PLL_NEEDS_SW_CFG BIT(4)

/*
 * Some PLLs use a different way to control clock power, via the PWRDWN bit in
 * the PLL control register
 */
#define IPROC_CLK_EMBED_PWRCTRL BIT(5)

/*
 * Some PLLs have separate registers for Status and Control.  Identify this to
 * let the driver know if additional registers need to be used
 */
#define IPROC_CLK_PLL_SPLIT_STAT_CTRL BIT(6)

/*
 * Some PLLs have an additional divide by 2 in master clock calculation;
 * MCLK = VCO_freq / (Mdiv * 2). Identify this to let the driver know
 * of modified calculations
 */
#define IPROC_CLK_MCLK_DIV_BY_2 BIT(7)

/*
 * Some PLLs provide a look up table for the leaf clock frequencies and
 * auto calculates VCO frequency parameters based on the provided leaf
 * clock frequencies. They have a user mode that allows the divider
 * controls to be determined by the user
 */
#define IPROC_CLK_PLL_USER_MODE_ON BIT(8)

/*
 * Some PLLs have an active low reset
 */
#define IPROC_CLK_PLL_RESET_ACTIVE_LOW BIT(9)

/*
 * Calculate the PLL parameters are runtime, instead of using table
 */
#define IPROC_CLK_PLL_CALC_PARAM BIT(10)

/*
 * Parameters for VCO frequency configuration
 *
 * VCO frequency =
 * ((ndiv_int + ndiv_frac / 2^20) * (ref frequency  / pdiv)
 */
struct iproc_pll_vco_param {
	unsigned long rate;
	unsigned int ndiv_int;
	unsigned int ndiv_frac;
	unsigned int pdiv;
};

struct iproc_clk_reg_op {
	unsigned int offset;
	unsigned int shift;
	unsigned int width;
};

/*
 * Clock gating control at the top ASIU level
 */
struct iproc_asiu_gate {
	unsigned int offset;
	unsigned int en_shift;
};

/*
 * Control of powering on/off of a PLL
 *
 * Before powering off a PLL, input isolation (ISO) needs to be enabled
 */
struct iproc_pll_aon_pwr_ctrl {
	unsigned int offset;
	unsigned int pwr_width;
	unsigned int pwr_shift;
	unsigned int iso_shift;
};

/*
 * Control of the PLL reset
 */
struct iproc_pll_reset_ctrl {
	unsigned int offset;
	unsigned int reset_shift;
	unsigned int p_reset_shift;
};

/*
 * Control of the Ki, Kp, and Ka parameters
 */
struct iproc_pll_dig_filter_ctrl {
	unsigned int offset;
	unsigned int ki_shift;
	unsigned int ki_width;
	unsigned int kp_shift;
	unsigned int kp_width;
	unsigned int ka_shift;
	unsigned int ka_width;
};

/*
 * To enable SW control of the PLL
 */
struct iproc_pll_sw_ctrl {
	unsigned int offset;
	unsigned int shift;
};

struct iproc_pll_vco_ctrl {
	unsigned int u_offset;
	unsigned int l_offset;
};

/*
 * Main PLL control parameters
 */
struct iproc_pll_ctrl {
	unsigned long flags;
	struct iproc_pll_aon_pwr_ctrl aon;
	struct iproc_asiu_gate asiu;
	struct iproc_pll_reset_ctrl reset;
	struct iproc_pll_dig_filter_ctrl dig_filter;
	struct iproc_pll_sw_ctrl sw_ctrl;
	struct iproc_clk_reg_op ndiv_int;
	struct iproc_clk_reg_op ndiv_frac;
	struct iproc_clk_reg_op pdiv;
	struct iproc_pll_vco_ctrl vco_ctrl;
	struct iproc_clk_reg_op status;
	struct iproc_clk_reg_op macro_mode;
};

/*
 * Controls enabling/disabling a PLL derived clock
 */
struct iproc_clk_enable_ctrl {
	unsigned int offset;
	unsigned int enable_shift;
	unsigned int hold_shift;
	unsigned int bypass_shift;
};

/*
 * Main clock control parameters for clocks derived from the PLLs
 */
struct iproc_clk_ctrl {
	unsigned int channel;
	unsigned long flags;
	struct iproc_clk_enable_ctrl enable;
	struct iproc_clk_reg_op mdiv;
};

/*
 * Divisor of the ASIU clocks
 */
struct iproc_asiu_div {
	unsigned int offset;
	unsigned int en_shift;
	unsigned int high_shift;
	unsigned int high_width;
	unsigned int low_shift;
	unsigned int low_width;
};

void iproc_armpll_setup(struct device_node *node);
void iproc_pll_clk_setup(struct device_node *node,
			 const struct iproc_pll_ctrl *pll_ctrl,
			 const struct iproc_pll_vco_param *vco,
			 unsigned int num_vco_entries,
			 const struct iproc_clk_ctrl *clk_ctrl,
			 unsigned int num_clks);
void iproc_asiu_setup(struct device_node *node,
		      const struct iproc_asiu_div *div,
		      const struct iproc_asiu_gate *gate,
		      unsigned int num_clks);

#endif /* _CLK_IPROC_H */