File Index
Files and directories
Sign in
FILE

ucc.c

File preview with syntax highlighting.

linux-6.19.14/drivers/soc/fsl/qe/ucc.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * arch/powerpc/sysdev/qe_lib/ucc.c
  4 *
  5 * QE UCC API Set - UCC specific routines implementations.
  6 *
  7 * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved.
  8 *
  9 * Authors: 	Shlomi Gridish <gridish@freescale.com>
 10 * 		Li Yang <leoli@freescale.com>
 11 */
 12#include <linux/kernel.h>
 13#include <linux/errno.h>
 14#include <linux/stddef.h>
 15#include <linux/spinlock.h>
 16#include <linux/export.h>
 17
 18#include <asm/io.h>
 19#include <soc/fsl/qe/immap_qe.h>
 20#include <soc/fsl/qe/qe.h>
 21#include <soc/fsl/qe/ucc.h>
 22
 23#define UCC_TDM_NUM 8
 24#define RX_SYNC_SHIFT_BASE 30
 25#define TX_SYNC_SHIFT_BASE 14
 26#define RX_CLK_SHIFT_BASE 28
 27#define TX_CLK_SHIFT_BASE 12
 28
 29int ucc_set_qe_mux_mii_mng(unsigned int ucc_num)
 30{
 31	unsigned long flags;
 32
 33	if (ucc_num > UCC_MAX_NUM - 1)
 34		return -EINVAL;
 35
 36	spin_lock_irqsave(&cmxgcr_lock, flags);
 37	qe_clrsetbits_be32(&qe_immr->qmx.cmxgcr, QE_CMXGCR_MII_ENET_MNG,
 38			   ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT);
 39	spin_unlock_irqrestore(&cmxgcr_lock, flags);
 40
 41	return 0;
 42}
 43EXPORT_SYMBOL(ucc_set_qe_mux_mii_mng);
 44
 45/* Configure the UCC to either Slow or Fast.
 46 *
 47 * A given UCC can be figured to support either "slow" devices (e.g. UART)
 48 * or "fast" devices (e.g. Ethernet).
 49 *
 50 * 'ucc_num' is the UCC number, from 0 - 7.
 51 *
 52 * This function also sets the UCC_GUEMR_SET_RESERVED3 bit because that bit
 53 * must always be set to 1.
 54 */
 55int ucc_set_type(unsigned int ucc_num, enum ucc_speed_type speed)
 56{
 57	u8 __iomem *guemr;
 58
 59	/* The GUEMR register is at the same location for both slow and fast
 60	   devices, so we just use uccX.slow.guemr. */
 61	switch (ucc_num) {
 62	case 0: guemr = &qe_immr->ucc1.slow.guemr;
 63		break;
 64	case 1: guemr = &qe_immr->ucc2.slow.guemr;
 65		break;
 66	case 2: guemr = &qe_immr->ucc3.slow.guemr;
 67		break;
 68	case 3: guemr = &qe_immr->ucc4.slow.guemr;
 69		break;
 70	case 4: guemr = &qe_immr->ucc5.slow.guemr;
 71		break;
 72	case 5: guemr = &qe_immr->ucc6.slow.guemr;
 73		break;
 74	case 6: guemr = &qe_immr->ucc7.slow.guemr;
 75		break;
 76	case 7: guemr = &qe_immr->ucc8.slow.guemr;
 77		break;
 78	default:
 79		return -EINVAL;
 80	}
 81
 82	qe_clrsetbits_8(guemr, UCC_GUEMR_MODE_MASK,
 83			UCC_GUEMR_SET_RESERVED3 | speed);
 84
 85	return 0;
 86}
 87
 88static void get_cmxucr_reg(unsigned int ucc_num, __be32 __iomem **cmxucr,
 89	unsigned int *reg_num, unsigned int *shift)
 90{
 91	unsigned int cmx = ((ucc_num & 1) << 1) + (ucc_num > 3);
 92
 93	*reg_num = cmx + 1;
 94	*cmxucr = &qe_immr->qmx.cmxucr[cmx];
 95	*shift = 16 - 8 * (ucc_num & 2);
 96}
 97
 98int ucc_mux_set_grant_tsa_bkpt(unsigned int ucc_num, int set, u32 mask)
 99{
100	__be32 __iomem *cmxucr;
101	unsigned int reg_num;
102	unsigned int shift;
103
104	/* check if the UCC number is in range. */
105	if (ucc_num > UCC_MAX_NUM - 1)
106		return -EINVAL;
107
108	get_cmxucr_reg(ucc_num, &cmxucr, &reg_num, &shift);
109
110	if (set)
111		qe_setbits_be32(cmxucr, mask << shift);
112	else
113		qe_clrbits_be32(cmxucr, mask << shift);
114
115	return 0;
116}
117EXPORT_SYMBOL(ucc_mux_set_grant_tsa_bkpt);
118
119int ucc_set_qe_mux_rxtx(unsigned int ucc_num, enum qe_clock clock,
120	enum comm_dir mode)
121{
122	__be32 __iomem *cmxucr;
123	unsigned int reg_num;
124	unsigned int shift;
125	u32 clock_bits = 0;
126
127	/* check if the UCC number is in range. */
128	if (ucc_num > UCC_MAX_NUM - 1)
129		return -EINVAL;
130
131	/* The communications direction must be RX or TX */
132	if (!((mode == COMM_DIR_RX) || (mode == COMM_DIR_TX)))
133		return -EINVAL;
134
135	get_cmxucr_reg(ucc_num, &cmxucr, &reg_num, &shift);
136
137	switch (reg_num) {
138	case 1:
139		switch (clock) {
140		case QE_BRG1:	clock_bits = 1; break;
141		case QE_BRG2:	clock_bits = 2; break;
142		case QE_BRG7:	clock_bits = 3; break;
143		case QE_BRG8:	clock_bits = 4; break;
144		case QE_CLK9:	clock_bits = 5; break;
145		case QE_CLK10:	clock_bits = 6; break;
146		case QE_CLK11:	clock_bits = 7; break;
147		case QE_CLK12:	clock_bits = 8; break;
148		case QE_CLK15:	clock_bits = 9; break;
149		case QE_CLK16:	clock_bits = 10; break;
150		default: break;
151		}
152		break;
153	case 2:
154		switch (clock) {
155		case QE_BRG5:	clock_bits = 1; break;
156		case QE_BRG6:	clock_bits = 2; break;
157		case QE_BRG7:	clock_bits = 3; break;
158		case QE_BRG8:	clock_bits = 4; break;
159		case QE_CLK13:	clock_bits = 5; break;
160		case QE_CLK14:	clock_bits = 6; break;
161		case QE_CLK19:	clock_bits = 7; break;
162		case QE_CLK20:	clock_bits = 8; break;
163		case QE_CLK15:	clock_bits = 9; break;
164		case QE_CLK16:	clock_bits = 10; break;
165		default: break;
166		}
167		break;
168	case 3:
169		switch (clock) {
170		case QE_BRG9:	clock_bits = 1; break;
171		case QE_BRG10:	clock_bits = 2; break;
172		case QE_BRG15:	clock_bits = 3; break;
173		case QE_BRG16:	clock_bits = 4; break;
174		case QE_CLK3:	clock_bits = 5; break;
175		case QE_CLK4:	clock_bits = 6; break;
176		case QE_CLK17:	clock_bits = 7; break;
177		case QE_CLK18:	clock_bits = 8; break;
178		case QE_CLK7:	clock_bits = 9; break;
179		case QE_CLK8:	clock_bits = 10; break;
180		case QE_CLK16:	clock_bits = 11; break;
181		default: break;
182		}
183		break;
184	case 4:
185		switch (clock) {
186		case QE_BRG13:	clock_bits = 1; break;
187		case QE_BRG14:	clock_bits = 2; break;
188		case QE_BRG15:	clock_bits = 3; break;
189		case QE_BRG16:	clock_bits = 4; break;
190		case QE_CLK5:	clock_bits = 5; break;
191		case QE_CLK6:	clock_bits = 6; break;
192		case QE_CLK21:	clock_bits = 7; break;
193		case QE_CLK22:	clock_bits = 8; break;
194		case QE_CLK7:	clock_bits = 9; break;
195		case QE_CLK8:	clock_bits = 10; break;
196		case QE_CLK16:	clock_bits = 11; break;
197		default: break;
198		}
199		break;
200	default: break;
201	}
202
203	/* Check for invalid combination of clock and UCC number */
204	if (!clock_bits)
205		return -ENOENT;
206
207	if (mode == COMM_DIR_RX)
208		shift += 4;
209
210	qe_clrsetbits_be32(cmxucr, QE_CMXUCR_TX_CLK_SRC_MASK << shift,
211			   clock_bits << shift);
212
213	return 0;
214}
215
216static int ucc_get_tdm_common_clk(u32 tdm_num, enum qe_clock clock)
217{
218	int clock_bits = -EINVAL;
219
220	/*
221	 * for TDM[0, 1, 2, 3], TX and RX use  common
222	 * clock source BRG3,4 and CLK1,2
223	 * for TDM[4, 5, 6, 7], TX and RX use  common
224	 * clock source BRG12,13 and CLK23,24
225	 */
226	switch (tdm_num) {
227	case 0:
228	case 1:
229	case 2:
230	case 3:
231		switch (clock) {
232		case QE_BRG3:
233			clock_bits = 1;
234			break;
235		case QE_BRG4:
236			clock_bits = 2;
237			break;
238		case QE_CLK1:
239			clock_bits = 4;
240			break;
241		case QE_CLK2:
242			clock_bits = 5;
243			break;
244		default:
245			break;
246		}
247		break;
248	case 4:
249	case 5:
250	case 6:
251	case 7:
252		switch (clock) {
253		case QE_BRG12:
254			clock_bits = 1;
255			break;
256		case QE_BRG13:
257			clock_bits = 2;
258			break;
259		case QE_CLK23:
260			clock_bits = 4;
261			break;
262		case QE_CLK24:
263			clock_bits = 5;
264			break;
265		default:
266			break;
267		}
268		break;
269	default:
270		break;
271	}
272
273	return clock_bits;
274}
275
276static int ucc_get_tdm_rx_clk(u32 tdm_num, enum qe_clock clock)
277{
278	int clock_bits = -EINVAL;
279
280	switch (tdm_num) {
281	case 0:
282		switch (clock) {
283		case QE_CLK3:
284			clock_bits = 6;
285			break;
286		case QE_CLK8:
287			clock_bits = 7;
288			break;
289		default:
290			break;
291		}
292		break;
293	case 1:
294		switch (clock) {
295		case QE_CLK5:
296			clock_bits = 6;
297			break;
298		case QE_CLK10:
299			clock_bits = 7;
300			break;
301		default:
302			break;
303		}
304		break;
305	case 2:
306		switch (clock) {
307		case QE_CLK7:
308			clock_bits = 6;
309			break;
310		case QE_CLK12:
311			clock_bits = 7;
312			break;
313		default:
314			break;
315		}
316		break;
317	case 3:
318		switch (clock) {
319		case QE_CLK9:
320			clock_bits = 6;
321			break;
322		case QE_CLK14:
323			clock_bits = 7;
324			break;
325		default:
326			break;
327		}
328		break;
329	case 4:
330		switch (clock) {
331		case QE_CLK11:
332			clock_bits = 6;
333			break;
334		case QE_CLK16:
335			clock_bits = 7;
336			break;
337		default:
338			break;
339		}
340		break;
341	case 5:
342		switch (clock) {
343		case QE_CLK13:
344			clock_bits = 6;
345			break;
346		case QE_CLK18:
347			clock_bits = 7;
348			break;
349		default:
350			break;
351		}
352		break;
353	case 6:
354		switch (clock) {
355		case QE_CLK15:
356			clock_bits = 6;
357			break;
358		case QE_CLK20:
359			clock_bits = 7;
360			break;
361		default:
362			break;
363		}
364		break;
365	case 7:
366		switch (clock) {
367		case QE_CLK17:
368			clock_bits = 6;
369			break;
370		case QE_CLK22:
371			clock_bits = 7;
372			break;
373		default:
374			break;
375		}
376		break;
377	}
378
379	return clock_bits;
380}
381
382static int ucc_get_tdm_tx_clk(u32 tdm_num, enum qe_clock clock)
383{
384	int clock_bits = -EINVAL;
385
386	switch (tdm_num) {
387	case 0:
388		switch (clock) {
389		case QE_CLK4:
390			clock_bits = 6;
391			break;
392		case QE_CLK9:
393			clock_bits = 7;
394			break;
395		default:
396			break;
397		}
398		break;
399	case 1:
400		switch (clock) {
401		case QE_CLK6:
402			clock_bits = 6;
403			break;
404		case QE_CLK11:
405			clock_bits = 7;
406			break;
407		default:
408			break;
409		}
410		break;
411	case 2:
412		switch (clock) {
413		case QE_CLK8:
414			clock_bits = 6;
415			break;
416		case QE_CLK13:
417			clock_bits = 7;
418			break;
419		default:
420			break;
421		}
422		break;
423	case 3:
424		switch (clock) {
425		case QE_CLK10:
426			clock_bits = 6;
427			break;
428		case QE_CLK15:
429			clock_bits = 7;
430			break;
431		default:
432			break;
433		}
434		break;
435	case 4:
436		switch (clock) {
437		case QE_CLK12:
438			clock_bits = 6;
439			break;
440		case QE_CLK17:
441			clock_bits = 7;
442			break;
443		default:
444			break;
445		}
446		break;
447	case 5:
448		switch (clock) {
449		case QE_CLK14:
450			clock_bits = 6;
451			break;
452		case QE_CLK19:
453			clock_bits = 7;
454			break;
455		default:
456			break;
457		}
458		break;
459	case 6:
460		switch (clock) {
461		case QE_CLK16:
462			clock_bits = 6;
463			break;
464		case QE_CLK21:
465			clock_bits = 7;
466			break;
467		default:
468			break;
469		}
470		break;
471	case 7:
472		switch (clock) {
473		case QE_CLK18:
474			clock_bits = 6;
475			break;
476		case QE_CLK3:
477			clock_bits = 7;
478			break;
479		default:
480			break;
481		}
482		break;
483	}
484
485	return clock_bits;
486}
487
488/* tdm_num: TDM A-H port num is 0-7 */
489static int ucc_get_tdm_rxtx_clk(enum comm_dir mode, u32 tdm_num,
490				enum qe_clock clock)
491{
492	int clock_bits;
493
494	clock_bits = ucc_get_tdm_common_clk(tdm_num, clock);
495	if (clock_bits > 0)
496		return clock_bits;
497	if (mode == COMM_DIR_RX)
498		clock_bits = ucc_get_tdm_rx_clk(tdm_num, clock);
499	if (mode == COMM_DIR_TX)
500		clock_bits = ucc_get_tdm_tx_clk(tdm_num, clock);
501	return clock_bits;
502}
503
504static u32 ucc_get_tdm_clk_shift(enum comm_dir mode, u32 tdm_num)
505{
506	u32 shift;
507
508	shift = (mode == COMM_DIR_RX) ? RX_CLK_SHIFT_BASE : TX_CLK_SHIFT_BASE;
509	if (tdm_num < 4)
510		shift -= tdm_num * 4;
511	else
512		shift -= (tdm_num - 4) * 4;
513
514	return shift;
515}
516
517int ucc_set_tdm_rxtx_clk(u32 tdm_num, enum qe_clock clock,
518			 enum comm_dir mode)
519{
520	int clock_bits;
521	u32 shift;
522	struct qe_mux __iomem *qe_mux_reg;
523	__be32 __iomem *cmxs1cr;
524
525	qe_mux_reg = &qe_immr->qmx;
526
527	if (tdm_num > 7)
528		return -EINVAL;
529
530	/* The communications direction must be RX or TX */
531	if (mode != COMM_DIR_RX && mode != COMM_DIR_TX)
532		return -EINVAL;
533
534	clock_bits = ucc_get_tdm_rxtx_clk(mode, tdm_num, clock);
535	if (clock_bits < 0)
536		return -EINVAL;
537
538	shift = ucc_get_tdm_clk_shift(mode, tdm_num);
539
540	cmxs1cr = (tdm_num < 4) ? &qe_mux_reg->cmxsi1cr_l :
541				  &qe_mux_reg->cmxsi1cr_h;
542
543	qe_clrsetbits_be32(cmxs1cr, QE_CMXUCR_TX_CLK_SRC_MASK << shift,
544			   clock_bits << shift);
545
546	return 0;
547}
548
549static int ucc_get_tdm_sync_source(u32 tdm_num, enum qe_clock clock,
550				   enum comm_dir mode)
551{
552	int source = -EINVAL;
553
554	if (mode == COMM_DIR_RX && clock == QE_RSYNC_PIN) {
555		source = 0;
556		return source;
557	}
558	if (mode == COMM_DIR_TX && clock == QE_TSYNC_PIN) {
559		source = 0;
560		return source;
561	}
562
563	switch (tdm_num) {
564	case 0:
565	case 1:
566		switch (clock) {
567		case QE_BRG9:
568			source = 1;
569			break;
570		case QE_BRG10:
571			source = 2;
572			break;
573		default:
574			break;
575		}
576		break;
577	case 2:
578	case 3:
579		switch (clock) {
580		case QE_BRG9:
581			source = 1;
582			break;
583		case QE_BRG11:
584			source = 2;
585			break;
586		default:
587			break;
588		}
589		break;
590	case 4:
591	case 5:
592		switch (clock) {
593		case QE_BRG13:
594			source = 1;
595			break;
596		case QE_BRG14:
597			source = 2;
598			break;
599		default:
600			break;
601		}
602		break;
603	case 6:
604	case 7:
605		switch (clock) {
606		case QE_BRG13:
607			source = 1;
608			break;
609		case QE_BRG15:
610			source = 2;
611			break;
612		default:
613			break;
614		}
615		break;
616	}
617
618	return source;
619}
620
621static u32 ucc_get_tdm_sync_shift(enum comm_dir mode, u32 tdm_num)
622{
623	u32 shift;
624
625	shift = (mode == COMM_DIR_RX) ? RX_SYNC_SHIFT_BASE : TX_SYNC_SHIFT_BASE;
626	shift -= tdm_num * 2;
627
628	return shift;
629}
630
631int ucc_set_tdm_rxtx_sync(u32 tdm_num, enum qe_clock clock,
632			  enum comm_dir mode)
633{
634	int source;
635	u32 shift;
636	struct qe_mux __iomem *qe_mux_reg;
637
638	qe_mux_reg = &qe_immr->qmx;
639
640	if (tdm_num >= UCC_TDM_NUM)
641		return -EINVAL;
642
643	/* The communications direction must be RX or TX */
644	if (mode != COMM_DIR_RX && mode != COMM_DIR_TX)
645		return -EINVAL;
646
647	source = ucc_get_tdm_sync_source(tdm_num, clock, mode);
648	if (source < 0)
649		return -EINVAL;
650
651	shift = ucc_get_tdm_sync_shift(mode, tdm_num);
652
653	qe_clrsetbits_be32(&qe_mux_reg->cmxsi1syr,
654			   QE_CMXUCR_TX_CLK_SRC_MASK << shift,
655			   source << shift);
656
657	return 0;
658}
~/ Read-only file preview.