Pull sbs into release branch
[sfrench/cifs-2.6.git] / arch / powerpc / sysdev / qe_lib / ucc.c
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 Semicondutor, 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/init.h>
18 #include <linux/errno.h>
19 #include <linux/slab.h>
20 #include <linux/stddef.h>
21 #include <linux/module.h>
22
23 #include <asm/irq.h>
24 #include <asm/io.h>
25 #include <asm/immap_qe.h>
26 #include <asm/qe.h>
27 #include <asm/ucc.h>
28
29 static DEFINE_SPINLOCK(ucc_lock);
30
31 int ucc_set_qe_mux_mii_mng(int ucc_num)
32 {
33         unsigned long flags;
34
35         spin_lock_irqsave(&ucc_lock, flags);
36         out_be32(&qe_immr->qmx.cmxgcr,
37                  ((in_be32(&qe_immr->qmx.cmxgcr) &
38                    ~QE_CMXGCR_MII_ENET_MNG) |
39                   (ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT)));
40         spin_unlock_irqrestore(&ucc_lock, flags);
41
42         return 0;
43 }
44 EXPORT_SYMBOL(ucc_set_qe_mux_mii_mng);
45
46 int ucc_set_type(int ucc_num, struct ucc_common *regs,
47                  enum ucc_speed_type speed)
48 {
49         u8 guemr = 0;
50
51         /* check if the UCC number is in range. */
52         if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0))
53                 return -EINVAL;
54
55         guemr = regs->guemr;
56         guemr &= ~(UCC_GUEMR_MODE_MASK_RX | UCC_GUEMR_MODE_MASK_TX);
57         switch (speed) {
58         case UCC_SPEED_TYPE_SLOW:
59                 guemr |= (UCC_GUEMR_MODE_SLOW_RX | UCC_GUEMR_MODE_SLOW_TX);
60                 break;
61         case UCC_SPEED_TYPE_FAST:
62                 guemr |= (UCC_GUEMR_MODE_FAST_RX | UCC_GUEMR_MODE_FAST_TX);
63                 break;
64         default:
65                 return -EINVAL;
66         }
67         regs->guemr = guemr;
68
69         return 0;
70 }
71
72 int ucc_init_guemr(struct ucc_common *regs)
73 {
74         u8 guemr = 0;
75
76         if (!regs)
77                 return -EINVAL;
78
79         /* Set bit 3 (which is reserved in the GUEMR register) to 1 */
80         guemr = UCC_GUEMR_SET_RESERVED3;
81
82         regs->guemr = guemr;
83
84         return 0;
85 }
86
87 static void get_cmxucr_reg(int ucc_num, volatile u32 ** p_cmxucr, u8 * reg_num,
88                            u8 * shift)
89 {
90         switch (ucc_num) {
91         case 0: *p_cmxucr = &(qe_immr->qmx.cmxucr1);
92                 *reg_num = 1;
93                 *shift = 16;
94                 break;
95         case 2: *p_cmxucr = &(qe_immr->qmx.cmxucr1);
96                 *reg_num = 1;
97                 *shift = 0;
98                 break;
99         case 4: *p_cmxucr = &(qe_immr->qmx.cmxucr2);
100                 *reg_num = 2;
101                 *shift = 16;
102                 break;
103         case 6: *p_cmxucr = &(qe_immr->qmx.cmxucr2);
104                 *reg_num = 2;
105                 *shift = 0;
106                 break;
107         case 1: *p_cmxucr = &(qe_immr->qmx.cmxucr3);
108                 *reg_num = 3;
109                 *shift = 16;
110                 break;
111         case 3: *p_cmxucr = &(qe_immr->qmx.cmxucr3);
112                 *reg_num = 3;
113                 *shift = 0;
114                 break;
115         case 5: *p_cmxucr = &(qe_immr->qmx.cmxucr4);
116                 *reg_num = 4;
117                 *shift = 16;
118                 break;
119         case 7: *p_cmxucr = &(qe_immr->qmx.cmxucr4);
120                 *reg_num = 4;
121                 *shift = 0;
122                 break;
123         default:
124                 break;
125         }
126 }
127
128 int ucc_mux_set_grant_tsa_bkpt(int ucc_num, int set, u32 mask)
129 {
130         volatile u32 *p_cmxucr;
131         u8 reg_num;
132         u8 shift;
133
134         /* check if the UCC number is in range. */
135         if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0))
136                 return -EINVAL;
137
138         get_cmxucr_reg(ucc_num, &p_cmxucr, &reg_num, &shift);
139
140         if (set)
141                 out_be32(p_cmxucr, in_be32(p_cmxucr) | (mask << shift));
142         else
143                 out_be32(p_cmxucr, in_be32(p_cmxucr) & ~(mask << shift));
144
145         return 0;
146 }
147
148 int ucc_set_qe_mux_rxtx(int ucc_num, enum qe_clock clock, enum comm_dir mode)
149 {
150         volatile u32 *p_cmxucr;
151         u8 reg_num;
152         u8 shift;
153         u32 clock_bits;
154         u32 clock_mask;
155         int source = -1;
156
157         /* check if the UCC number is in range. */
158         if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0))
159                 return -EINVAL;
160
161         if (!((mode == COMM_DIR_RX) || (mode == COMM_DIR_TX))) {
162                 printk(KERN_ERR
163                        "ucc_set_qe_mux_rxtx: bad comm mode type passed.");
164                 return -EINVAL;
165         }
166
167         get_cmxucr_reg(ucc_num, &p_cmxucr, &reg_num, &shift);
168
169         switch (reg_num) {
170         case 1:
171                 switch (clock) {
172                 case QE_BRG1:   source = 1; break;
173                 case QE_BRG2:   source = 2; break;
174                 case QE_BRG7:   source = 3; break;
175                 case QE_BRG8:   source = 4; break;
176                 case QE_CLK9:   source = 5; break;
177                 case QE_CLK10:  source = 6; break;
178                 case QE_CLK11:  source = 7; break;
179                 case QE_CLK12:  source = 8; break;
180                 case QE_CLK15:  source = 9; break;
181                 case QE_CLK16:  source = 10; break;
182                 default:        source = -1; break;
183                 }
184                 break;
185         case 2:
186                 switch (clock) {
187                 case QE_BRG5:   source = 1; break;
188                 case QE_BRG6:   source = 2; break;
189                 case QE_BRG7:   source = 3; break;
190                 case QE_BRG8:   source = 4; break;
191                 case QE_CLK13:  source = 5; break;
192                 case QE_CLK14:  source = 6; break;
193                 case QE_CLK19:  source = 7; break;
194                 case QE_CLK20:  source = 8; break;
195                 case QE_CLK15:  source = 9; break;
196                 case QE_CLK16:  source = 10; break;
197                 default:        source = -1; break;
198                 }
199                 break;
200         case 3:
201                 switch (clock) {
202                 case QE_BRG9:   source = 1; break;
203                 case QE_BRG10:  source = 2; break;
204                 case QE_BRG15:  source = 3; break;
205                 case QE_BRG16:  source = 4; break;
206                 case QE_CLK3:   source = 5; break;
207                 case QE_CLK4:   source = 6; break;
208                 case QE_CLK17:  source = 7; break;
209                 case QE_CLK18:  source = 8; break;
210                 case QE_CLK7:   source = 9; break;
211                 case QE_CLK8:   source = 10; break;
212                 case QE_CLK16:  source = 11; break;
213                 default:        source = -1; break;
214                 }
215                 break;
216         case 4:
217                 switch (clock) {
218                 case QE_BRG13:  source = 1; break;
219                 case QE_BRG14:  source = 2; break;
220                 case QE_BRG15:  source = 3; break;
221                 case QE_BRG16:  source = 4; break;
222                 case QE_CLK5:   source = 5; break;
223                 case QE_CLK6:   source = 6; break;
224                 case QE_CLK21:  source = 7; break;
225                 case QE_CLK22:  source = 8; break;
226                 case QE_CLK7:   source = 9; break;
227                 case QE_CLK8:   source = 10; break;
228                 case QE_CLK16:  source = 11; break;
229                 default:        source = -1; break;
230                 }
231                 break;
232         default:
233                 source = -1;
234                 break;
235         }
236
237         if (source == -1) {
238                 printk(KERN_ERR
239                      "ucc_set_qe_mux_rxtx: Bad combination of clock and UCC.");
240                 return -ENOENT;
241         }
242
243         clock_bits = (u32) source;
244         clock_mask = QE_CMXUCR_TX_CLK_SRC_MASK;
245         if (mode == COMM_DIR_RX) {
246                 clock_bits <<= 4;  /* Rx field is 4 bits to left of Tx field */
247                 clock_mask <<= 4;  /* Rx field is 4 bits to left of Tx field */
248         }
249         clock_bits <<= shift;
250         clock_mask <<= shift;
251
252         out_be32(p_cmxucr, (in_be32(p_cmxucr) & ~clock_mask) | clock_bits);
253
254         return 0;
255 }