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