xref: /linux/drivers/soc/fsl/qe/ucc.c (revision 2bc46b3ad3c15165f91459b07ff8682478683194)
1 /*
2  * arch/powerpc/sysdev/qe_lib/ucc.c
3  *
4  * QE UCC API Set - UCC specific routines implementations.
5  *
6  * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved.
7  *
8  * Authors: 	Shlomi Gridish <gridish@freescale.com>
9  * 		Li Yang <leoli@freescale.com>
10  *
11  * This program is free software; you can redistribute  it and/or modify it
12  * under  the terms of  the GNU General  Public License as published by the
13  * Free Software Foundation;  either version 2 of the  License, or (at your
14  * option) any later version.
15  */
16 #include <linux/kernel.h>
17 #include <linux/errno.h>
18 #include <linux/stddef.h>
19 #include <linux/spinlock.h>
20 #include <linux/export.h>
21 
22 #include <asm/irq.h>
23 #include <asm/io.h>
24 #include <soc/fsl/qe/immap_qe.h>
25 #include <soc/fsl/qe/qe.h>
26 #include <soc/fsl/qe/ucc.h>
27 
28 int ucc_set_qe_mux_mii_mng(unsigned int ucc_num)
29 {
30 	unsigned long flags;
31 
32 	if (ucc_num > UCC_MAX_NUM - 1)
33 		return -EINVAL;
34 
35 	spin_lock_irqsave(&cmxgcr_lock, flags);
36 	clrsetbits_be32(&qe_immr->qmx.cmxgcr, QE_CMXGCR_MII_ENET_MNG,
37 		ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT);
38 	spin_unlock_irqrestore(&cmxgcr_lock, flags);
39 
40 	return 0;
41 }
42 EXPORT_SYMBOL(ucc_set_qe_mux_mii_mng);
43 
44 /* Configure the UCC to either Slow or Fast.
45  *
46  * A given UCC can be figured to support either "slow" devices (e.g. UART)
47  * or "fast" devices (e.g. Ethernet).
48  *
49  * 'ucc_num' is the UCC number, from 0 - 7.
50  *
51  * This function also sets the UCC_GUEMR_SET_RESERVED3 bit because that bit
52  * must always be set to 1.
53  */
54 int ucc_set_type(unsigned int ucc_num, enum ucc_speed_type speed)
55 {
56 	u8 __iomem *guemr;
57 
58 	/* The GUEMR register is at the same location for both slow and fast
59 	   devices, so we just use uccX.slow.guemr. */
60 	switch (ucc_num) {
61 	case 0: guemr = &qe_immr->ucc1.slow.guemr;
62 		break;
63 	case 1: guemr = &qe_immr->ucc2.slow.guemr;
64 		break;
65 	case 2: guemr = &qe_immr->ucc3.slow.guemr;
66 		break;
67 	case 3: guemr = &qe_immr->ucc4.slow.guemr;
68 		break;
69 	case 4: guemr = &qe_immr->ucc5.slow.guemr;
70 		break;
71 	case 5: guemr = &qe_immr->ucc6.slow.guemr;
72 		break;
73 	case 6: guemr = &qe_immr->ucc7.slow.guemr;
74 		break;
75 	case 7: guemr = &qe_immr->ucc8.slow.guemr;
76 		break;
77 	default:
78 		return -EINVAL;
79 	}
80 
81 	clrsetbits_8(guemr, UCC_GUEMR_MODE_MASK,
82 		UCC_GUEMR_SET_RESERVED3 | speed);
83 
84 	return 0;
85 }
86 
87 static void get_cmxucr_reg(unsigned int ucc_num, __be32 __iomem **cmxucr,
88 	unsigned int *reg_num, unsigned int *shift)
89 {
90 	unsigned int cmx = ((ucc_num & 1) << 1) + (ucc_num > 3);
91 
92 	*reg_num = cmx + 1;
93 	*cmxucr = &qe_immr->qmx.cmxucr[cmx];
94 	*shift = 16 - 8 * (ucc_num & 2);
95 }
96 
97 int ucc_mux_set_grant_tsa_bkpt(unsigned int ucc_num, int set, u32 mask)
98 {
99 	__be32 __iomem *cmxucr;
100 	unsigned int reg_num;
101 	unsigned int shift;
102 
103 	/* check if the UCC number is in range. */
104 	if (ucc_num > UCC_MAX_NUM - 1)
105 		return -EINVAL;
106 
107 	get_cmxucr_reg(ucc_num, &cmxucr, &reg_num, &shift);
108 
109 	if (set)
110 		setbits32(cmxucr, mask << shift);
111 	else
112 		clrbits32(cmxucr, mask << shift);
113 
114 	return 0;
115 }
116 
117 int ucc_set_qe_mux_rxtx(unsigned int ucc_num, enum qe_clock clock,
118 	enum comm_dir mode)
119 {
120 	__be32 __iomem *cmxucr;
121 	unsigned int reg_num;
122 	unsigned int shift;
123 	u32 clock_bits = 0;
124 
125 	/* check if the UCC number is in range. */
126 	if (ucc_num > UCC_MAX_NUM - 1)
127 		return -EINVAL;
128 
129 	/* The communications direction must be RX or TX */
130 	if (!((mode == COMM_DIR_RX) || (mode == COMM_DIR_TX)))
131 		return -EINVAL;
132 
133 	get_cmxucr_reg(ucc_num, &cmxucr, &reg_num, &shift);
134 
135 	switch (reg_num) {
136 	case 1:
137 		switch (clock) {
138 		case QE_BRG1:	clock_bits = 1; break;
139 		case QE_BRG2:	clock_bits = 2; break;
140 		case QE_BRG7:	clock_bits = 3; break;
141 		case QE_BRG8:	clock_bits = 4; break;
142 		case QE_CLK9:	clock_bits = 5; break;
143 		case QE_CLK10:	clock_bits = 6; break;
144 		case QE_CLK11:	clock_bits = 7; break;
145 		case QE_CLK12:	clock_bits = 8; break;
146 		case QE_CLK15:	clock_bits = 9; break;
147 		case QE_CLK16:	clock_bits = 10; break;
148 		default: break;
149 		}
150 		break;
151 	case 2:
152 		switch (clock) {
153 		case QE_BRG5:	clock_bits = 1; break;
154 		case QE_BRG6:	clock_bits = 2; break;
155 		case QE_BRG7:	clock_bits = 3; break;
156 		case QE_BRG8:	clock_bits = 4; break;
157 		case QE_CLK13:	clock_bits = 5; break;
158 		case QE_CLK14:	clock_bits = 6; break;
159 		case QE_CLK19:	clock_bits = 7; break;
160 		case QE_CLK20:	clock_bits = 8; break;
161 		case QE_CLK15:	clock_bits = 9; break;
162 		case QE_CLK16:	clock_bits = 10; break;
163 		default: break;
164 		}
165 		break;
166 	case 3:
167 		switch (clock) {
168 		case QE_BRG9:	clock_bits = 1; break;
169 		case QE_BRG10:	clock_bits = 2; break;
170 		case QE_BRG15:	clock_bits = 3; break;
171 		case QE_BRG16:	clock_bits = 4; break;
172 		case QE_CLK3:	clock_bits = 5; break;
173 		case QE_CLK4:	clock_bits = 6; break;
174 		case QE_CLK17:	clock_bits = 7; break;
175 		case QE_CLK18:	clock_bits = 8; break;
176 		case QE_CLK7:	clock_bits = 9; break;
177 		case QE_CLK8:	clock_bits = 10; break;
178 		case QE_CLK16:	clock_bits = 11; break;
179 		default: break;
180 		}
181 		break;
182 	case 4:
183 		switch (clock) {
184 		case QE_BRG13:	clock_bits = 1; break;
185 		case QE_BRG14:	clock_bits = 2; break;
186 		case QE_BRG15:	clock_bits = 3; break;
187 		case QE_BRG16:	clock_bits = 4; break;
188 		case QE_CLK5:	clock_bits = 5; break;
189 		case QE_CLK6:	clock_bits = 6; break;
190 		case QE_CLK21:	clock_bits = 7; break;
191 		case QE_CLK22:	clock_bits = 8; break;
192 		case QE_CLK7:	clock_bits = 9; break;
193 		case QE_CLK8:	clock_bits = 10; break;
194 		case QE_CLK16:	clock_bits = 11; break;
195 		default: break;
196 		}
197 		break;
198 	default: break;
199 	}
200 
201 	/* Check for invalid combination of clock and UCC number */
202 	if (!clock_bits)
203 		return -ENOENT;
204 
205 	if (mode == COMM_DIR_RX)
206 		shift += 4;
207 
208 	clrsetbits_be32(cmxucr, QE_CMXUCR_TX_CLK_SRC_MASK << shift,
209 		clock_bits << shift);
210 
211 	return 0;
212 }
213