ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / mips / vr41xx / common / cmu.c
1 /*
2  *  cmu.c, Clock Mask Unit routines for the NEC VR4100 series.
3  *
4  *  Copyright (C) 2001-2002  MontaVista Software Inc.
5  *    Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
6  *  Copuright (C) 2003-2004  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22 /*
23  * Changes:
24  *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
25  *  - New creation, NEC VR4122 and VR4131 are supported.
26  *  - Added support for NEC VR4111 and VR4121.
27  *
28  *  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
29  *  - Added support for NEC VR4133.
30  */
31 #include <linux/init.h>
32 #include <linux/smp.h>
33 #include <linux/spinlock.h>
34 #include <linux/types.h>
35
36 #include <asm/cpu.h>
37 #include <asm/io.h>
38 #include <asm/vr41xx/vr41xx.h>
39
40 #define CMUCLKMSK_TYPE1 KSEG1ADDR(0x0b000060)
41 #define CMUCLKMSK_TYPE2 KSEG1ADDR(0x0f000060)
42  #define MSKPIU         0x0001
43  #define MSKSIU         0x0002
44  #define MSKAIU         0x0004
45  #define MSKKIU         0x0008
46  #define MSKFIR         0x0010
47  #define MSKDSIU        0x0820
48  #define MSKCSI         0x0040
49  #define MSKPCIU        0x0080
50  #define MSKSSIU        0x0100
51  #define MSKSHSP        0x0200
52  #define MSKFFIR        0x0400
53  #define MSKSCSI        0x1000
54  #define MSKPPCIU       0x2000
55 #define CMUCLKMSK2      KSEG1ADDR(0x0f000064)
56  #define MSKCEU         0x0001
57  #define MSKMAC0        0x0002
58  #define MSKMAC1        0x0004
59
60 static uint32_t cmu_base;
61 static uint16_t cmuclkmsk, cmuclkmsk2;
62 static spinlock_t cmu_lock;
63
64 #define read_cmuclkmsk()        readw(cmu_base)
65 #define read_cmuclkmsk2()       readw(CMUCLKMSK2)
66 #define write_cmuclkmsk()       writew(cmuclkmsk, cmu_base)
67 #define write_cmuclkmsk2()      writew(cmuclkmsk2, CMUCLKMSK2)
68
69 void vr41xx_supply_clock(vr41xx_clock_t clock)
70 {
71         spin_lock_irq(&cmu_lock);
72
73         switch (clock) {
74         case PIU_CLOCK:
75                 cmuclkmsk |= MSKPIU;
76                 break;
77         case SIU_CLOCK:
78                 cmuclkmsk |= MSKSIU | MSKSSIU;
79                 break;
80         case AIU_CLOCK:
81                 cmuclkmsk |= MSKAIU;
82                 break;
83         case KIU_CLOCK:
84                 cmuclkmsk |= MSKKIU;
85                 break;
86         case FIR_CLOCK:
87                 cmuclkmsk |= MSKFIR | MSKFFIR;
88                 break;
89         case DSIU_CLOCK:
90                 if (current_cpu_data.cputype == CPU_VR4111 ||
91                     current_cpu_data.cputype == CPU_VR4121)
92                         cmuclkmsk |= MSKDSIU;
93                 else
94                         cmuclkmsk |= MSKSIU | MSKDSIU;
95                 break;
96         case CSI_CLOCK:
97                 cmuclkmsk |= MSKCSI | MSKSCSI;
98                 break;
99         case PCIU_CLOCK:
100                 cmuclkmsk |= MSKPCIU;
101                 break;
102         case HSP_CLOCK:
103                 cmuclkmsk |= MSKSHSP;
104                 break;
105         case PCI_CLOCK:
106                 cmuclkmsk |= MSKPPCIU;
107                 break;
108         case CEU_CLOCK:
109                 cmuclkmsk2 |= MSKCEU;
110                 break;
111         case ETHER0_CLOCK:
112                 cmuclkmsk2 |= MSKMAC0;
113                 break;
114         case ETHER1_CLOCK:
115                 cmuclkmsk2 |= MSKMAC1;
116                 break;
117         default:
118                 break;
119         }
120
121         if (clock == CEU_CLOCK || clock == ETHER0_CLOCK ||
122             clock == ETHER1_CLOCK)
123                 write_cmuclkmsk2();
124         else
125                 write_cmuclkmsk();
126
127         spin_unlock_irq(&cmu_lock);
128 }
129
130 void vr41xx_mask_clock(vr41xx_clock_t clock)
131 {
132         spin_lock_irq(&cmu_lock);
133
134         switch (clock) {
135         case PIU_CLOCK:
136                 cmuclkmsk &= ~MSKPIU;
137                 break;
138         case SIU_CLOCK:
139                 if (current_cpu_data.cputype == CPU_VR4111 ||
140                     current_cpu_data.cputype == CPU_VR4121) {
141                         cmuclkmsk &= ~(MSKSIU | MSKSSIU);
142                 } else {
143                         if (cmuclkmsk & MSKDSIU)
144                                 cmuclkmsk &= ~MSKSSIU;
145                         else
146                                 cmuclkmsk &= ~(MSKSIU | MSKSSIU);
147                 }
148                 break;
149         case AIU_CLOCK:
150                 cmuclkmsk &= ~MSKAIU;
151                 break;
152         case KIU_CLOCK:
153                 cmuclkmsk &= ~MSKKIU;
154                 break;
155         case FIR_CLOCK:
156                 cmuclkmsk &= ~(MSKFIR | MSKFFIR);
157                 break;
158         case DSIU_CLOCK:
159                 if (current_cpu_data.cputype == CPU_VR4111 ||
160                     current_cpu_data.cputype == CPU_VR4121) {
161                         cmuclkmsk &= ~MSKDSIU;
162                 } else {
163                         if (cmuclkmsk & MSKSIU)
164                                 cmuclkmsk &= ~MSKDSIU;
165                         else
166                                 cmuclkmsk &= ~(MSKSIU | MSKDSIU);
167                 }
168                 break;
169         case CSI_CLOCK:
170                 cmuclkmsk &= ~(MSKCSI | MSKSCSI);
171                 break;
172         case PCIU_CLOCK:
173                 cmuclkmsk &= ~MSKPCIU;
174                 break;
175         case HSP_CLOCK:
176                 cmuclkmsk &= ~MSKSHSP;
177                 break;
178         case PCI_CLOCK:
179                 cmuclkmsk &= ~MSKPPCIU;
180                 break;
181         case CEU_CLOCK:
182                 cmuclkmsk2 &= ~MSKCEU;
183                 break;
184         case ETHER0_CLOCK:
185                 cmuclkmsk2 &= ~MSKMAC0;
186                 break;
187         case ETHER1_CLOCK:
188                 cmuclkmsk2 &= ~MSKMAC1;
189                 break;
190         default:
191                 break;
192         }
193
194         if (clock == CEU_CLOCK || clock == ETHER0_CLOCK ||
195             clock == ETHER1_CLOCK)
196                 write_cmuclkmsk2();
197         else
198                 write_cmuclkmsk();
199
200         spin_unlock_irq(&cmu_lock);
201 }
202
203 void __init vr41xx_cmu_init(void)
204 {
205         switch (current_cpu_data.cputype) {
206         case CPU_VR4111:
207         case CPU_VR4121:
208                 cmu_base = CMUCLKMSK_TYPE1;
209                 break;
210         case CPU_VR4122:
211         case CPU_VR4131:
212                 cmu_base = CMUCLKMSK_TYPE2;
213                 break;
214         case CPU_VR4133:
215                 cmu_base = CMUCLKMSK_TYPE2;
216                 cmuclkmsk2 = read_cmuclkmsk2();
217                 break;
218         default:
219                 panic("Unexpected CPU of NEC VR4100 series");
220                 break;
221         }
222
223         cmuclkmsk = read_cmuclkmsk();
224
225         spin_lock_init(&cmu_lock);
226 }