diff options
Diffstat (limited to 'drivers/soc/qcom/qcom-geni-se.c')
-rw-r--r-- | drivers/soc/qcom/qcom-geni-se.c | 748 |
1 files changed, 748 insertions, 0 deletions
diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c new file mode 100644 index 000000000000..feed3db21c10 --- /dev/null +++ b/drivers/soc/qcom/qcom-geni-se.c | |||
@@ -0,0 +1,748 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | // Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. | ||
3 | |||
4 | #include <linux/clk.h> | ||
5 | #include <linux/slab.h> | ||
6 | #include <linux/dma-mapping.h> | ||
7 | #include <linux/io.h> | ||
8 | #include <linux/module.h> | ||
9 | #include <linux/of.h> | ||
10 | #include <linux/of_platform.h> | ||
11 | #include <linux/pinctrl/consumer.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | #include <linux/qcom-geni-se.h> | ||
14 | |||
15 | /** | ||
16 | * DOC: Overview | ||
17 | * | ||
18 | * Generic Interface (GENI) Serial Engine (SE) Wrapper driver is introduced | ||
19 | * to manage GENI firmware based Qualcomm Universal Peripheral (QUP) Wrapper | ||
20 | * controller. QUP Wrapper is designed to support various serial bus protocols | ||
21 | * like UART, SPI, I2C, I3C, etc. | ||
22 | */ | ||
23 | |||
24 | /** | ||
25 | * DOC: Hardware description | ||
26 | * | ||
27 | * GENI based QUP is a highly-flexible and programmable module for supporting | ||
28 | * a wide range of serial interfaces like UART, SPI, I2C, I3C, etc. A single | ||
29 | * QUP module can provide upto 8 serial interfaces, using its internal | ||
30 | * serial engines. The actual configuration is determined by the target | ||
31 | * platform configuration. The protocol supported by each interface is | ||
32 | * determined by the firmware loaded to the serial engine. Each SE consists | ||
33 | * of a DMA Engine and GENI sub modules which enable serial engines to | ||
34 | * support FIFO and DMA modes of operation. | ||
35 | * | ||
36 | * | ||
37 | * +-----------------------------------------+ | ||
38 | * |QUP Wrapper | | ||
39 | * | +----------------------------+ | | ||
40 | * --QUP & SE Clocks--> | Serial Engine N | +-IO------> | ||
41 | * | | ... | | Interface | ||
42 | * <---Clock Perf.----+ +----+-----------------------+ | | | ||
43 | * State Interface | | Serial Engine 1 | | | | ||
44 | * | | | | | | ||
45 | * | | | | | | ||
46 | * <--------AHB-------> | | | | | ||
47 | * | | +----+ | | ||
48 | * | | | | | ||
49 | * | | | | | ||
50 | * <------SE IRQ------+ +----------------------------+ | | ||
51 | * | | | ||
52 | * +-----------------------------------------+ | ||
53 | * | ||
54 | * Figure 1: GENI based QUP Wrapper | ||
55 | * | ||
56 | * The GENI submodules include primary and secondary sequencers which are | ||
57 | * used to drive TX & RX operations. On serial interfaces that operate using | ||
58 | * master-slave model, primary sequencer drives both TX & RX operations. On | ||
59 | * serial interfaces that operate using peer-to-peer model, primary sequencer | ||
60 | * drives TX operation and secondary sequencer drives RX operation. | ||
61 | */ | ||
62 | |||
63 | /** | ||
64 | * DOC: Software description | ||
65 | * | ||
66 | * GENI SE Wrapper driver is structured into 2 parts: | ||
67 | * | ||
68 | * geni_wrapper represents QUP Wrapper controller. This part of the driver | ||
69 | * manages QUP Wrapper information such as hardware version, clock | ||
70 | * performance table that is common to all the internal serial engines. | ||
71 | * | ||
72 | * geni_se represents serial engine. This part of the driver manages serial | ||
73 | * engine information such as clocks, containing QUP Wrapper, etc. This part | ||
74 | * of driver also supports operations (eg. initialize the concerned serial | ||
75 | * engine, select between FIFO and DMA mode of operation etc.) that are | ||
76 | * common to all the serial engines and are independent of serial interfaces. | ||
77 | */ | ||
78 | |||
79 | #define MAX_CLK_PERF_LEVEL 32 | ||
80 | #define NUM_AHB_CLKS 2 | ||
81 | |||
82 | /** | ||
83 | * @struct geni_wrapper - Data structure to represent the QUP Wrapper Core | ||
84 | * @dev: Device pointer of the QUP wrapper core | ||
85 | * @base: Base address of this instance of QUP wrapper core | ||
86 | * @ahb_clks: Handle to the primary & secondary AHB clocks | ||
87 | */ | ||
88 | struct geni_wrapper { | ||
89 | struct device *dev; | ||
90 | void __iomem *base; | ||
91 | struct clk_bulk_data ahb_clks[NUM_AHB_CLKS]; | ||
92 | }; | ||
93 | |||
94 | #define QUP_HW_VER_REG 0x4 | ||
95 | |||
96 | /* Common SE registers */ | ||
97 | #define GENI_INIT_CFG_REVISION 0x0 | ||
98 | #define GENI_S_INIT_CFG_REVISION 0x4 | ||
99 | #define GENI_OUTPUT_CTRL 0x24 | ||
100 | #define GENI_CGC_CTRL 0x28 | ||
101 | #define GENI_CLK_CTRL_RO 0x60 | ||
102 | #define GENI_IF_DISABLE_RO 0x64 | ||
103 | #define GENI_FW_S_REVISION_RO 0x6c | ||
104 | #define SE_GENI_BYTE_GRAN 0x254 | ||
105 | #define SE_GENI_TX_PACKING_CFG0 0x260 | ||
106 | #define SE_GENI_TX_PACKING_CFG1 0x264 | ||
107 | #define SE_GENI_RX_PACKING_CFG0 0x284 | ||
108 | #define SE_GENI_RX_PACKING_CFG1 0x288 | ||
109 | #define SE_GENI_M_GP_LENGTH 0x910 | ||
110 | #define SE_GENI_S_GP_LENGTH 0x914 | ||
111 | #define SE_DMA_TX_PTR_L 0xc30 | ||
112 | #define SE_DMA_TX_PTR_H 0xc34 | ||
113 | #define SE_DMA_TX_ATTR 0xc38 | ||
114 | #define SE_DMA_TX_LEN 0xc3c | ||
115 | #define SE_DMA_TX_IRQ_EN 0xc48 | ||
116 | #define SE_DMA_TX_IRQ_EN_SET 0xc4c | ||
117 | #define SE_DMA_TX_IRQ_EN_CLR 0xc50 | ||
118 | #define SE_DMA_TX_LEN_IN 0xc54 | ||
119 | #define SE_DMA_TX_MAX_BURST 0xc5c | ||
120 | #define SE_DMA_RX_PTR_L 0xd30 | ||
121 | #define SE_DMA_RX_PTR_H 0xd34 | ||
122 | #define SE_DMA_RX_ATTR 0xd38 | ||
123 | #define SE_DMA_RX_LEN 0xd3c | ||
124 | #define SE_DMA_RX_IRQ_EN 0xd48 | ||
125 | #define SE_DMA_RX_IRQ_EN_SET 0xd4c | ||
126 | #define SE_DMA_RX_IRQ_EN_CLR 0xd50 | ||
127 | #define SE_DMA_RX_LEN_IN 0xd54 | ||
128 | #define SE_DMA_RX_MAX_BURST 0xd5c | ||
129 | #define SE_DMA_RX_FLUSH 0xd60 | ||
130 | #define SE_GSI_EVENT_EN 0xe18 | ||
131 | #define SE_IRQ_EN 0xe1c | ||
132 | #define SE_DMA_GENERAL_CFG 0xe30 | ||
133 | |||
134 | /* GENI_OUTPUT_CTRL fields */ | ||
135 | #define DEFAULT_IO_OUTPUT_CTRL_MSK GENMASK(6, 0) | ||
136 | |||
137 | /* GENI_CGC_CTRL fields */ | ||
138 | #define CFG_AHB_CLK_CGC_ON BIT(0) | ||
139 | #define CFG_AHB_WR_ACLK_CGC_ON BIT(1) | ||
140 | #define DATA_AHB_CLK_CGC_ON BIT(2) | ||
141 | #define SCLK_CGC_ON BIT(3) | ||
142 | #define TX_CLK_CGC_ON BIT(4) | ||
143 | #define RX_CLK_CGC_ON BIT(5) | ||
144 | #define EXT_CLK_CGC_ON BIT(6) | ||
145 | #define PROG_RAM_HCLK_OFF BIT(8) | ||
146 | #define PROG_RAM_SCLK_OFF BIT(9) | ||
147 | #define DEFAULT_CGC_EN GENMASK(6, 0) | ||
148 | |||
149 | /* SE_GSI_EVENT_EN fields */ | ||
150 | #define DMA_RX_EVENT_EN BIT(0) | ||
151 | #define DMA_TX_EVENT_EN BIT(1) | ||
152 | #define GENI_M_EVENT_EN BIT(2) | ||
153 | #define GENI_S_EVENT_EN BIT(3) | ||
154 | |||
155 | /* SE_IRQ_EN fields */ | ||
156 | #define DMA_RX_IRQ_EN BIT(0) | ||
157 | #define DMA_TX_IRQ_EN BIT(1) | ||
158 | #define GENI_M_IRQ_EN BIT(2) | ||
159 | #define GENI_S_IRQ_EN BIT(3) | ||
160 | |||
161 | /* SE_DMA_GENERAL_CFG */ | ||
162 | #define DMA_RX_CLK_CGC_ON BIT(0) | ||
163 | #define DMA_TX_CLK_CGC_ON BIT(1) | ||
164 | #define DMA_AHB_SLV_CFG_ON BIT(2) | ||
165 | #define AHB_SEC_SLV_CLK_CGC_ON BIT(3) | ||
166 | #define DUMMY_RX_NON_BUFFERABLE BIT(4) | ||
167 | #define RX_DMA_ZERO_PADDING_EN BIT(5) | ||
168 | #define RX_DMA_IRQ_DELAY_MSK GENMASK(8, 6) | ||
169 | #define RX_DMA_IRQ_DELAY_SHFT 6 | ||
170 | |||
171 | /** | ||
172 | * geni_se_get_qup_hw_version() - Read the QUP wrapper Hardware version | ||
173 | * @se: Pointer to the corresponding serial engine. | ||
174 | * | ||
175 | * Return: Hardware Version of the wrapper. | ||
176 | */ | ||
177 | u32 geni_se_get_qup_hw_version(struct geni_se *se) | ||
178 | { | ||
179 | struct geni_wrapper *wrapper = se->wrapper; | ||
180 | |||
181 | return readl_relaxed(wrapper->base + QUP_HW_VER_REG); | ||
182 | } | ||
183 | EXPORT_SYMBOL(geni_se_get_qup_hw_version); | ||
184 | |||
185 | static void geni_se_io_set_mode(void __iomem *base) | ||
186 | { | ||
187 | u32 val; | ||
188 | |||
189 | val = readl_relaxed(base + SE_IRQ_EN); | ||
190 | val |= GENI_M_IRQ_EN | GENI_S_IRQ_EN; | ||
191 | val |= DMA_TX_IRQ_EN | DMA_RX_IRQ_EN; | ||
192 | writel_relaxed(val, base + SE_IRQ_EN); | ||
193 | |||
194 | val = readl_relaxed(base + SE_GENI_DMA_MODE_EN); | ||
195 | val &= ~GENI_DMA_MODE_EN; | ||
196 | writel_relaxed(val, base + SE_GENI_DMA_MODE_EN); | ||
197 | |||
198 | writel_relaxed(0, base + SE_GSI_EVENT_EN); | ||
199 | } | ||
200 | |||
201 | static void geni_se_io_init(void __iomem *base) | ||
202 | { | ||
203 | u32 val; | ||
204 | |||
205 | val = readl_relaxed(base + GENI_CGC_CTRL); | ||
206 | val |= DEFAULT_CGC_EN; | ||
207 | writel_relaxed(val, base + GENI_CGC_CTRL); | ||
208 | |||
209 | val = readl_relaxed(base + SE_DMA_GENERAL_CFG); | ||
210 | val |= AHB_SEC_SLV_CLK_CGC_ON | DMA_AHB_SLV_CFG_ON; | ||
211 | val |= DMA_TX_CLK_CGC_ON | DMA_RX_CLK_CGC_ON; | ||
212 | writel_relaxed(val, base + SE_DMA_GENERAL_CFG); | ||
213 | |||
214 | writel_relaxed(DEFAULT_IO_OUTPUT_CTRL_MSK, base + GENI_OUTPUT_CTRL); | ||
215 | writel_relaxed(FORCE_DEFAULT, base + GENI_FORCE_DEFAULT_REG); | ||
216 | } | ||
217 | |||
218 | /** | ||
219 | * geni_se_init() - Initialize the GENI serial engine | ||
220 | * @se: Pointer to the concerned serial engine. | ||
221 | * @rx_wm: Receive watermark, in units of FIFO words. | ||
222 | * @rx_rfr_wm: Ready-for-receive watermark, in units of FIFO words. | ||
223 | * | ||
224 | * This function is used to initialize the GENI serial engine, configure | ||
225 | * receive watermark and ready-for-receive watermarks. | ||
226 | */ | ||
227 | void geni_se_init(struct geni_se *se, u32 rx_wm, u32 rx_rfr) | ||
228 | { | ||
229 | u32 val; | ||
230 | |||
231 | geni_se_io_init(se->base); | ||
232 | geni_se_io_set_mode(se->base); | ||
233 | |||
234 | writel_relaxed(rx_wm, se->base + SE_GENI_RX_WATERMARK_REG); | ||
235 | writel_relaxed(rx_rfr, se->base + SE_GENI_RX_RFR_WATERMARK_REG); | ||
236 | |||
237 | val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN); | ||
238 | val |= M_COMMON_GENI_M_IRQ_EN; | ||
239 | writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN); | ||
240 | |||
241 | val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN); | ||
242 | val |= S_COMMON_GENI_S_IRQ_EN; | ||
243 | writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN); | ||
244 | } | ||
245 | EXPORT_SYMBOL(geni_se_init); | ||
246 | |||
247 | static void geni_se_select_fifo_mode(struct geni_se *se) | ||
248 | { | ||
249 | u32 proto = geni_se_read_proto(se); | ||
250 | u32 val; | ||
251 | |||
252 | writel_relaxed(0, se->base + SE_GSI_EVENT_EN); | ||
253 | writel_relaxed(0xffffffff, se->base + SE_GENI_M_IRQ_CLEAR); | ||
254 | writel_relaxed(0xffffffff, se->base + SE_GENI_S_IRQ_CLEAR); | ||
255 | writel_relaxed(0xffffffff, se->base + SE_DMA_TX_IRQ_CLR); | ||
256 | writel_relaxed(0xffffffff, se->base + SE_DMA_RX_IRQ_CLR); | ||
257 | writel_relaxed(0xffffffff, se->base + SE_IRQ_EN); | ||
258 | |||
259 | val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN); | ||
260 | if (proto != GENI_SE_UART) { | ||
261 | val |= M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN; | ||
262 | val |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN; | ||
263 | } | ||
264 | writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN); | ||
265 | |||
266 | val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN); | ||
267 | if (proto != GENI_SE_UART) | ||
268 | val |= S_CMD_DONE_EN; | ||
269 | writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN); | ||
270 | |||
271 | val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN); | ||
272 | val &= ~GENI_DMA_MODE_EN; | ||
273 | writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN); | ||
274 | } | ||
275 | |||
276 | static void geni_se_select_dma_mode(struct geni_se *se) | ||
277 | { | ||
278 | u32 val; | ||
279 | |||
280 | writel_relaxed(0, se->base + SE_GSI_EVENT_EN); | ||
281 | writel_relaxed(0xffffffff, se->base + SE_GENI_M_IRQ_CLEAR); | ||
282 | writel_relaxed(0xffffffff, se->base + SE_GENI_S_IRQ_CLEAR); | ||
283 | writel_relaxed(0xffffffff, se->base + SE_DMA_TX_IRQ_CLR); | ||
284 | writel_relaxed(0xffffffff, se->base + SE_DMA_RX_IRQ_CLR); | ||
285 | writel_relaxed(0xffffffff, se->base + SE_IRQ_EN); | ||
286 | |||
287 | val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN); | ||
288 | val |= GENI_DMA_MODE_EN; | ||
289 | writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN); | ||
290 | } | ||
291 | |||
292 | /** | ||
293 | * geni_se_select_mode() - Select the serial engine transfer mode | ||
294 | * @se: Pointer to the concerned serial engine. | ||
295 | * @mode: Transfer mode to be selected. | ||
296 | */ | ||
297 | void geni_se_select_mode(struct geni_se *se, enum geni_se_xfer_mode mode) | ||
298 | { | ||
299 | WARN_ON(mode != GENI_SE_FIFO && mode != GENI_SE_DMA); | ||
300 | |||
301 | switch (mode) { | ||
302 | case GENI_SE_FIFO: | ||
303 | geni_se_select_fifo_mode(se); | ||
304 | break; | ||
305 | case GENI_SE_DMA: | ||
306 | geni_se_select_dma_mode(se); | ||
307 | break; | ||
308 | case GENI_SE_INVALID: | ||
309 | default: | ||
310 | break; | ||
311 | } | ||
312 | } | ||
313 | EXPORT_SYMBOL(geni_se_select_mode); | ||
314 | |||
315 | /** | ||
316 | * DOC: Overview | ||
317 | * | ||
318 | * GENI FIFO packing is highly configurable. TX/RX packing/unpacking consist | ||
319 | * of up to 4 operations, each operation represented by 4 configuration vectors | ||
320 | * of 10 bits programmed in GENI_TX_PACKING_CFG0 and GENI_TX_PACKING_CFG1 for | ||
321 | * TX FIFO and in GENI_RX_PACKING_CFG0 and GENI_RX_PACKING_CFG1 for RX FIFO. | ||
322 | * Refer to below examples for detailed bit-field description. | ||
323 | * | ||
324 | * Example 1: word_size = 7, packing_mode = 4 x 8, msb_to_lsb = 1 | ||
325 | * | ||
326 | * +-----------+-------+-------+-------+-------+ | ||
327 | * | | vec_0 | vec_1 | vec_2 | vec_3 | | ||
328 | * +-----------+-------+-------+-------+-------+ | ||
329 | * | start | 0x6 | 0xe | 0x16 | 0x1e | | ||
330 | * | direction | 1 | 1 | 1 | 1 | | ||
331 | * | length | 6 | 6 | 6 | 6 | | ||
332 | * | stop | 0 | 0 | 0 | 1 | | ||
333 | * +-----------+-------+-------+-------+-------+ | ||
334 | * | ||
335 | * Example 2: word_size = 15, packing_mode = 2 x 16, msb_to_lsb = 0 | ||
336 | * | ||
337 | * +-----------+-------+-------+-------+-------+ | ||
338 | * | | vec_0 | vec_1 | vec_2 | vec_3 | | ||
339 | * +-----------+-------+-------+-------+-------+ | ||
340 | * | start | 0x0 | 0x8 | 0x10 | 0x18 | | ||
341 | * | direction | 0 | 0 | 0 | 0 | | ||
342 | * | length | 7 | 6 | 7 | 6 | | ||
343 | * | stop | 0 | 0 | 0 | 1 | | ||
344 | * +-----------+-------+-------+-------+-------+ | ||
345 | * | ||
346 | * Example 3: word_size = 23, packing_mode = 1 x 32, msb_to_lsb = 1 | ||
347 | * | ||
348 | * +-----------+-------+-------+-------+-------+ | ||
349 | * | | vec_0 | vec_1 | vec_2 | vec_3 | | ||
350 | * +-----------+-------+-------+-------+-------+ | ||
351 | * | start | 0x16 | 0xe | 0x6 | 0x0 | | ||
352 | * | direction | 1 | 1 | 1 | 1 | | ||
353 | * | length | 7 | 7 | 6 | 0 | | ||
354 | * | stop | 0 | 0 | 1 | 0 | | ||
355 | * +-----------+-------+-------+-------+-------+ | ||
356 | * | ||
357 | */ | ||
358 | |||
359 | #define NUM_PACKING_VECTORS 4 | ||
360 | #define PACKING_START_SHIFT 5 | ||
361 | #define PACKING_DIR_SHIFT 4 | ||
362 | #define PACKING_LEN_SHIFT 1 | ||
363 | #define PACKING_STOP_BIT BIT(0) | ||
364 | #define PACKING_VECTOR_SHIFT 10 | ||
365 | /** | ||
366 | * geni_se_config_packing() - Packing configuration of the serial engine | ||
367 | * @se: Pointer to the concerned serial engine | ||
368 | * @bpw: Bits of data per transfer word. | ||
369 | * @pack_words: Number of words per fifo element. | ||
370 | * @msb_to_lsb: Transfer from MSB to LSB or vice-versa. | ||
371 | * @tx_cfg: Flag to configure the TX Packing. | ||
372 | * @rx_cfg: Flag to configure the RX Packing. | ||
373 | * | ||
374 | * This function is used to configure the packing rules for the current | ||
375 | * transfer. | ||
376 | */ | ||
377 | void geni_se_config_packing(struct geni_se *se, int bpw, int pack_words, | ||
378 | bool msb_to_lsb, bool tx_cfg, bool rx_cfg) | ||
379 | { | ||
380 | u32 cfg0, cfg1, cfg[NUM_PACKING_VECTORS] = {0}; | ||
381 | int len; | ||
382 | int temp_bpw = bpw; | ||
383 | int idx_start = msb_to_lsb ? bpw - 1 : 0; | ||
384 | int idx = idx_start; | ||
385 | int idx_delta = msb_to_lsb ? -BITS_PER_BYTE : BITS_PER_BYTE; | ||
386 | int ceil_bpw = ALIGN(bpw, BITS_PER_BYTE); | ||
387 | int iter = (ceil_bpw * pack_words) / BITS_PER_BYTE; | ||
388 | int i; | ||
389 | |||
390 | if (iter <= 0 || iter > NUM_PACKING_VECTORS) | ||
391 | return; | ||
392 | |||
393 | for (i = 0; i < iter; i++) { | ||
394 | len = min_t(int, temp_bpw, BITS_PER_BYTE) - 1; | ||
395 | cfg[i] = idx << PACKING_START_SHIFT; | ||
396 | cfg[i] |= msb_to_lsb << PACKING_DIR_SHIFT; | ||
397 | cfg[i] |= len << PACKING_LEN_SHIFT; | ||
398 | |||
399 | if (temp_bpw <= BITS_PER_BYTE) { | ||
400 | idx = ((i + 1) * BITS_PER_BYTE) + idx_start; | ||
401 | temp_bpw = bpw; | ||
402 | } else { | ||
403 | idx = idx + idx_delta; | ||
404 | temp_bpw = temp_bpw - BITS_PER_BYTE; | ||
405 | } | ||
406 | } | ||
407 | cfg[iter - 1] |= PACKING_STOP_BIT; | ||
408 | cfg0 = cfg[0] | (cfg[1] << PACKING_VECTOR_SHIFT); | ||
409 | cfg1 = cfg[2] | (cfg[3] << PACKING_VECTOR_SHIFT); | ||
410 | |||
411 | if (tx_cfg) { | ||
412 | writel_relaxed(cfg0, se->base + SE_GENI_TX_PACKING_CFG0); | ||
413 | writel_relaxed(cfg1, se->base + SE_GENI_TX_PACKING_CFG1); | ||
414 | } | ||
415 | if (rx_cfg) { | ||
416 | writel_relaxed(cfg0, se->base + SE_GENI_RX_PACKING_CFG0); | ||
417 | writel_relaxed(cfg1, se->base + SE_GENI_RX_PACKING_CFG1); | ||
418 | } | ||
419 | |||
420 | /* | ||
421 | * Number of protocol words in each FIFO entry | ||
422 | * 0 - 4x8, four words in each entry, max word size of 8 bits | ||
423 | * 1 - 2x16, two words in each entry, max word size of 16 bits | ||
424 | * 2 - 1x32, one word in each entry, max word size of 32 bits | ||
425 | * 3 - undefined | ||
426 | */ | ||
427 | if (pack_words || bpw == 32) | ||
428 | writel_relaxed(bpw / 16, se->base + SE_GENI_BYTE_GRAN); | ||
429 | } | ||
430 | EXPORT_SYMBOL(geni_se_config_packing); | ||
431 | |||
432 | static void geni_se_clks_off(struct geni_se *se) | ||
433 | { | ||
434 | struct geni_wrapper *wrapper = se->wrapper; | ||
435 | |||
436 | clk_disable_unprepare(se->clk); | ||
437 | clk_bulk_disable_unprepare(ARRAY_SIZE(wrapper->ahb_clks), | ||
438 | wrapper->ahb_clks); | ||
439 | } | ||
440 | |||
441 | /** | ||
442 | * geni_se_resources_off() - Turn off resources associated with the serial | ||
443 | * engine | ||
444 | * @se: Pointer to the concerned serial engine. | ||
445 | * | ||
446 | * Return: 0 on success, standard Linux error codes on failure/error. | ||
447 | */ | ||
448 | int geni_se_resources_off(struct geni_se *se) | ||
449 | { | ||
450 | int ret; | ||
451 | |||
452 | ret = pinctrl_pm_select_sleep_state(se->dev); | ||
453 | if (ret) | ||
454 | return ret; | ||
455 | |||
456 | geni_se_clks_off(se); | ||
457 | return 0; | ||
458 | } | ||
459 | EXPORT_SYMBOL(geni_se_resources_off); | ||
460 | |||
461 | static int geni_se_clks_on(struct geni_se *se) | ||
462 | { | ||
463 | int ret; | ||
464 | struct geni_wrapper *wrapper = se->wrapper; | ||
465 | |||
466 | ret = clk_bulk_prepare_enable(ARRAY_SIZE(wrapper->ahb_clks), | ||
467 | wrapper->ahb_clks); | ||
468 | if (ret) | ||
469 | return ret; | ||
470 | |||
471 | ret = clk_prepare_enable(se->clk); | ||
472 | if (ret) | ||
473 | clk_bulk_disable_unprepare(ARRAY_SIZE(wrapper->ahb_clks), | ||
474 | wrapper->ahb_clks); | ||
475 | return ret; | ||
476 | } | ||
477 | |||
478 | /** | ||
479 | * geni_se_resources_on() - Turn on resources associated with the serial | ||
480 | * engine | ||
481 | * @se: Pointer to the concerned serial engine. | ||
482 | * | ||
483 | * Return: 0 on success, standard Linux error codes on failure/error. | ||
484 | */ | ||
485 | int geni_se_resources_on(struct geni_se *se) | ||
486 | { | ||
487 | int ret; | ||
488 | |||
489 | ret = geni_se_clks_on(se); | ||
490 | if (ret) | ||
491 | return ret; | ||
492 | |||
493 | ret = pinctrl_pm_select_default_state(se->dev); | ||
494 | if (ret) | ||
495 | geni_se_clks_off(se); | ||
496 | |||
497 | return ret; | ||
498 | } | ||
499 | EXPORT_SYMBOL(geni_se_resources_on); | ||
500 | |||
501 | /** | ||
502 | * geni_se_clk_tbl_get() - Get the clock table to program DFS | ||
503 | * @se: Pointer to the concerned serial engine. | ||
504 | * @tbl: Table in which the output is returned. | ||
505 | * | ||
506 | * This function is called by the protocol drivers to determine the different | ||
507 | * clock frequencies supported by serial engine core clock. The protocol | ||
508 | * drivers use the output to determine the clock frequency index to be | ||
509 | * programmed into DFS. | ||
510 | * | ||
511 | * Return: number of valid performance levels in the table on success, | ||
512 | * standard Linux error codes on failure. | ||
513 | */ | ||
514 | int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl) | ||
515 | { | ||
516 | unsigned long freq = 0; | ||
517 | int i; | ||
518 | |||
519 | if (se->clk_perf_tbl) { | ||
520 | *tbl = se->clk_perf_tbl; | ||
521 | return se->num_clk_levels; | ||
522 | } | ||
523 | |||
524 | se->clk_perf_tbl = devm_kcalloc(se->dev, MAX_CLK_PERF_LEVEL, | ||
525 | sizeof(*se->clk_perf_tbl), | ||
526 | GFP_KERNEL); | ||
527 | if (!se->clk_perf_tbl) | ||
528 | return -ENOMEM; | ||
529 | |||
530 | for (i = 0; i < MAX_CLK_PERF_LEVEL; i++) { | ||
531 | freq = clk_round_rate(se->clk, freq + 1); | ||
532 | if (!freq || freq == se->clk_perf_tbl[i - 1]) | ||
533 | break; | ||
534 | se->clk_perf_tbl[i] = freq; | ||
535 | } | ||
536 | se->num_clk_levels = i; | ||
537 | *tbl = se->clk_perf_tbl; | ||
538 | return se->num_clk_levels; | ||
539 | } | ||
540 | EXPORT_SYMBOL(geni_se_clk_tbl_get); | ||
541 | |||
542 | /** | ||
543 | * geni_se_clk_freq_match() - Get the matching or closest SE clock frequency | ||
544 | * @se: Pointer to the concerned serial engine. | ||
545 | * @req_freq: Requested clock frequency. | ||
546 | * @index: Index of the resultant frequency in the table. | ||
547 | * @res_freq: Resultant frequency which matches or is closer to the | ||
548 | * requested frequency. | ||
549 | * @exact: Flag to indicate exact multiple requirement of the requested | ||
550 | * frequency. | ||
551 | * | ||
552 | * This function is called by the protocol drivers to determine the matching | ||
553 | * or exact multiple of the requested frequency, as provided by the serial | ||
554 | * engine clock in order to meet the performance requirements. If there is | ||
555 | * no matching or exact multiple of the requested frequency found, then it | ||
556 | * selects the closest floor frequency, if exact flag is not set. | ||
557 | * | ||
558 | * Return: 0 on success, standard Linux error codes on failure. | ||
559 | */ | ||
560 | int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq, | ||
561 | unsigned int *index, unsigned long *res_freq, | ||
562 | bool exact) | ||
563 | { | ||
564 | unsigned long *tbl; | ||
565 | int num_clk_levels; | ||
566 | int i; | ||
567 | |||
568 | num_clk_levels = geni_se_clk_tbl_get(se, &tbl); | ||
569 | if (num_clk_levels < 0) | ||
570 | return num_clk_levels; | ||
571 | |||
572 | if (num_clk_levels == 0) | ||
573 | return -EINVAL; | ||
574 | |||
575 | *res_freq = 0; | ||
576 | for (i = 0; i < num_clk_levels; i++) { | ||
577 | if (!(tbl[i] % req_freq)) { | ||
578 | *index = i; | ||
579 | *res_freq = tbl[i]; | ||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | if (!(*res_freq) || ((tbl[i] > *res_freq) && | ||
584 | (tbl[i] < req_freq))) { | ||
585 | *index = i; | ||
586 | *res_freq = tbl[i]; | ||
587 | } | ||
588 | } | ||
589 | |||
590 | if (exact) | ||
591 | return -EINVAL; | ||
592 | |||
593 | return 0; | ||
594 | } | ||
595 | EXPORT_SYMBOL(geni_se_clk_freq_match); | ||
596 | |||
597 | #define GENI_SE_DMA_DONE_EN BIT(0) | ||
598 | #define GENI_SE_DMA_EOT_EN BIT(1) | ||
599 | #define GENI_SE_DMA_AHB_ERR_EN BIT(2) | ||
600 | #define GENI_SE_DMA_EOT_BUF BIT(0) | ||
601 | /** | ||
602 | * geni_se_tx_dma_prep() - Prepare the serial engine for TX DMA transfer | ||
603 | * @se: Pointer to the concerned serial engine. | ||
604 | * @buf: Pointer to the TX buffer. | ||
605 | * @len: Length of the TX buffer. | ||
606 | * @iova: Pointer to store the mapped DMA address. | ||
607 | * | ||
608 | * This function is used to prepare the buffers for DMA TX. | ||
609 | * | ||
610 | * Return: 0 on success, standard Linux error codes on failure. | ||
611 | */ | ||
612 | int geni_se_tx_dma_prep(struct geni_se *se, void *buf, size_t len, | ||
613 | dma_addr_t *iova) | ||
614 | { | ||
615 | struct geni_wrapper *wrapper = se->wrapper; | ||
616 | u32 val; | ||
617 | |||
618 | *iova = dma_map_single(wrapper->dev, buf, len, DMA_TO_DEVICE); | ||
619 | if (dma_mapping_error(wrapper->dev, *iova)) | ||
620 | return -EIO; | ||
621 | |||
622 | val = GENI_SE_DMA_DONE_EN; | ||
623 | val |= GENI_SE_DMA_EOT_EN; | ||
624 | val |= GENI_SE_DMA_AHB_ERR_EN; | ||
625 | writel_relaxed(val, se->base + SE_DMA_TX_IRQ_EN_SET); | ||
626 | writel_relaxed(lower_32_bits(*iova), se->base + SE_DMA_TX_PTR_L); | ||
627 | writel_relaxed(upper_32_bits(*iova), se->base + SE_DMA_TX_PTR_H); | ||
628 | writel_relaxed(GENI_SE_DMA_EOT_BUF, se->base + SE_DMA_TX_ATTR); | ||
629 | writel_relaxed(len, se->base + SE_DMA_TX_LEN); | ||
630 | return 0; | ||
631 | } | ||
632 | EXPORT_SYMBOL(geni_se_tx_dma_prep); | ||
633 | |||
634 | /** | ||
635 | * geni_se_rx_dma_prep() - Prepare the serial engine for RX DMA transfer | ||
636 | * @se: Pointer to the concerned serial engine. | ||
637 | * @buf: Pointer to the RX buffer. | ||
638 | * @len: Length of the RX buffer. | ||
639 | * @iova: Pointer to store the mapped DMA address. | ||
640 | * | ||
641 | * This function is used to prepare the buffers for DMA RX. | ||
642 | * | ||
643 | * Return: 0 on success, standard Linux error codes on failure. | ||
644 | */ | ||
645 | int geni_se_rx_dma_prep(struct geni_se *se, void *buf, size_t len, | ||
646 | dma_addr_t *iova) | ||
647 | { | ||
648 | struct geni_wrapper *wrapper = se->wrapper; | ||
649 | u32 val; | ||
650 | |||
651 | *iova = dma_map_single(wrapper->dev, buf, len, DMA_FROM_DEVICE); | ||
652 | if (dma_mapping_error(wrapper->dev, *iova)) | ||
653 | return -EIO; | ||
654 | |||
655 | val = GENI_SE_DMA_DONE_EN; | ||
656 | val |= GENI_SE_DMA_EOT_EN; | ||
657 | val |= GENI_SE_DMA_AHB_ERR_EN; | ||
658 | writel_relaxed(val, se->base + SE_DMA_RX_IRQ_EN_SET); | ||
659 | writel_relaxed(lower_32_bits(*iova), se->base + SE_DMA_RX_PTR_L); | ||
660 | writel_relaxed(upper_32_bits(*iova), se->base + SE_DMA_RX_PTR_H); | ||
661 | /* RX does not have EOT buffer type bit. So just reset RX_ATTR */ | ||
662 | writel_relaxed(0, se->base + SE_DMA_RX_ATTR); | ||
663 | writel_relaxed(len, se->base + SE_DMA_RX_LEN); | ||
664 | return 0; | ||
665 | } | ||
666 | EXPORT_SYMBOL(geni_se_rx_dma_prep); | ||
667 | |||
668 | /** | ||
669 | * geni_se_tx_dma_unprep() - Unprepare the serial engine after TX DMA transfer | ||
670 | * @se: Pointer to the concerned serial engine. | ||
671 | * @iova: DMA address of the TX buffer. | ||
672 | * @len: Length of the TX buffer. | ||
673 | * | ||
674 | * This function is used to unprepare the DMA buffers after DMA TX. | ||
675 | */ | ||
676 | void geni_se_tx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len) | ||
677 | { | ||
678 | struct geni_wrapper *wrapper = se->wrapper; | ||
679 | |||
680 | if (iova && !dma_mapping_error(wrapper->dev, iova)) | ||
681 | dma_unmap_single(wrapper->dev, iova, len, DMA_TO_DEVICE); | ||
682 | } | ||
683 | EXPORT_SYMBOL(geni_se_tx_dma_unprep); | ||
684 | |||
685 | /** | ||
686 | * geni_se_rx_dma_unprep() - Unprepare the serial engine after RX DMA transfer | ||
687 | * @se: Pointer to the concerned serial engine. | ||
688 | * @iova: DMA address of the RX buffer. | ||
689 | * @len: Length of the RX buffer. | ||
690 | * | ||
691 | * This function is used to unprepare the DMA buffers after DMA RX. | ||
692 | */ | ||
693 | void geni_se_rx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len) | ||
694 | { | ||
695 | struct geni_wrapper *wrapper = se->wrapper; | ||
696 | |||
697 | if (iova && !dma_mapping_error(wrapper->dev, iova)) | ||
698 | dma_unmap_single(wrapper->dev, iova, len, DMA_FROM_DEVICE); | ||
699 | } | ||
700 | EXPORT_SYMBOL(geni_se_rx_dma_unprep); | ||
701 | |||
702 | static int geni_se_probe(struct platform_device *pdev) | ||
703 | { | ||
704 | struct device *dev = &pdev->dev; | ||
705 | struct resource *res; | ||
706 | struct geni_wrapper *wrapper; | ||
707 | int ret; | ||
708 | |||
709 | wrapper = devm_kzalloc(dev, sizeof(*wrapper), GFP_KERNEL); | ||
710 | if (!wrapper) | ||
711 | return -ENOMEM; | ||
712 | |||
713 | wrapper->dev = dev; | ||
714 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
715 | wrapper->base = devm_ioremap_resource(dev, res); | ||
716 | if (IS_ERR(wrapper->base)) | ||
717 | return PTR_ERR(wrapper->base); | ||
718 | |||
719 | wrapper->ahb_clks[0].id = "m-ahb"; | ||
720 | wrapper->ahb_clks[1].id = "s-ahb"; | ||
721 | ret = devm_clk_bulk_get(dev, NUM_AHB_CLKS, wrapper->ahb_clks); | ||
722 | if (ret) { | ||
723 | dev_err(dev, "Err getting AHB clks %d\n", ret); | ||
724 | return ret; | ||
725 | } | ||
726 | |||
727 | dev_set_drvdata(dev, wrapper); | ||
728 | dev_dbg(dev, "GENI SE Driver probed\n"); | ||
729 | return devm_of_platform_populate(dev); | ||
730 | } | ||
731 | |||
732 | static const struct of_device_id geni_se_dt_match[] = { | ||
733 | { .compatible = "qcom,geni-se-qup", }, | ||
734 | {} | ||
735 | }; | ||
736 | MODULE_DEVICE_TABLE(of, geni_se_dt_match); | ||
737 | |||
738 | static struct platform_driver geni_se_driver = { | ||
739 | .driver = { | ||
740 | .name = "geni_se_qup", | ||
741 | .of_match_table = geni_se_dt_match, | ||
742 | }, | ||
743 | .probe = geni_se_probe, | ||
744 | }; | ||
745 | module_platform_driver(geni_se_driver); | ||
746 | |||
747 | MODULE_DESCRIPTION("GENI Serial Engine Driver"); | ||
748 | MODULE_LICENSE("GPL v2"); | ||