1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  cmu.c, Clock Mask Unit routines for the NEC VR4100 series.
4  *
5  *  Copyright (C) 2001-2002  MontaVista Software Inc.
6  *    Author: Yoichi Yuasa <source@mvista.com>
7  *  Copyright (C) 2003-2005  Yoichi Yuasa <yuasa@linux-mips.org>
8  */
9 /*
10  * Changes:
11  *  MontaVista Software Inc. <source@mvista.com>
12  *  - New creation, NEC VR4122 and VR4131 are supported.
13  *  - Added support for NEC VR4111 and VR4121.
14  *
15  *  Yoichi Yuasa <yuasa@linux-mips.org>
16  *  - Added support for NEC VR4133.
17  */
18 #include <linux/export.h>
19 #include <linux/init.h>
20 #include <linux/ioport.h>
21 #include <linux/smp.h>
22 #include <linux/spinlock.h>
23 #include <linux/types.h>
24 
25 #include <asm/cpu.h>
26 #include <asm/io.h>
27 #include <asm/vr41xx/vr41xx.h>
28 
29 #define CMU_TYPE1_BASE	0x0b000060UL
30 #define CMU_TYPE1_SIZE	0x4
31 
32 #define CMU_TYPE2_BASE	0x0f000060UL
33 #define CMU_TYPE2_SIZE	0x4
34 
35 #define CMU_TYPE3_BASE	0x0f000060UL
36 #define CMU_TYPE3_SIZE	0x8
37 
38 #define CMUCLKMSK	0x0
39  #define MSKPIU		0x0001
40  #define MSKSIU		0x0002
41  #define MSKAIU		0x0004
42  #define MSKKIU		0x0008
43  #define MSKFIR		0x0010
44  #define MSKDSIU	0x0820
45  #define MSKCSI		0x0040
46  #define MSKPCIU	0x0080
47  #define MSKSSIU	0x0100
48  #define MSKSHSP	0x0200
49  #define MSKFFIR	0x0400
50  #define MSKSCSI	0x1000
51  #define MSKPPCIU	0x2000
52 #define CMUCLKMSK2	0x4
53  #define MSKCEU		0x0001
54  #define MSKMAC0	0x0002
55  #define MSKMAC1	0x0004
56 
57 static void __iomem *cmu_base;
58 static uint16_t cmuclkmsk, cmuclkmsk2;
59 static DEFINE_SPINLOCK(cmu_lock);
60 
61 #define cmu_read(offset)		readw(cmu_base + (offset))
62 #define cmu_write(offset, value)	writew((value), cmu_base + (offset))
63 
vr41xx_supply_clock(vr41xx_clock_t clock)64 void vr41xx_supply_clock(vr41xx_clock_t clock)
65 {
66 	spin_lock_irq(&cmu_lock);
67 
68 	switch (clock) {
69 	case PIU_CLOCK:
70 		cmuclkmsk |= MSKPIU;
71 		break;
72 	case SIU_CLOCK:
73 		cmuclkmsk |= MSKSIU | MSKSSIU;
74 		break;
75 	case AIU_CLOCK:
76 		cmuclkmsk |= MSKAIU;
77 		break;
78 	case KIU_CLOCK:
79 		cmuclkmsk |= MSKKIU;
80 		break;
81 	case FIR_CLOCK:
82 		cmuclkmsk |= MSKFIR | MSKFFIR;
83 		break;
84 	case DSIU_CLOCK:
85 		if (current_cpu_type() == CPU_VR4111 ||
86 		    current_cpu_type() == CPU_VR4121)
87 			cmuclkmsk |= MSKDSIU;
88 		else
89 			cmuclkmsk |= MSKSIU | MSKDSIU;
90 		break;
91 	case CSI_CLOCK:
92 		cmuclkmsk |= MSKCSI | MSKSCSI;
93 		break;
94 	case PCIU_CLOCK:
95 		cmuclkmsk |= MSKPCIU;
96 		break;
97 	case HSP_CLOCK:
98 		cmuclkmsk |= MSKSHSP;
99 		break;
100 	case PCI_CLOCK:
101 		cmuclkmsk |= MSKPPCIU;
102 		break;
103 	case CEU_CLOCK:
104 		cmuclkmsk2 |= MSKCEU;
105 		break;
106 	case ETHER0_CLOCK:
107 		cmuclkmsk2 |= MSKMAC0;
108 		break;
109 	case ETHER1_CLOCK:
110 		cmuclkmsk2 |= MSKMAC1;
111 		break;
112 	default:
113 		break;
114 	}
115 
116 	if (clock == CEU_CLOCK || clock == ETHER0_CLOCK ||
117 	    clock == ETHER1_CLOCK)
118 		cmu_write(CMUCLKMSK2, cmuclkmsk2);
119 	else
120 		cmu_write(CMUCLKMSK, cmuclkmsk);
121 
122 	spin_unlock_irq(&cmu_lock);
123 }
124 
125 EXPORT_SYMBOL_GPL(vr41xx_supply_clock);
126 
vr41xx_mask_clock(vr41xx_clock_t clock)127 void vr41xx_mask_clock(vr41xx_clock_t clock)
128 {
129 	spin_lock_irq(&cmu_lock);
130 
131 	switch (clock) {
132 	case PIU_CLOCK:
133 		cmuclkmsk &= ~MSKPIU;
134 		break;
135 	case SIU_CLOCK:
136 		if (current_cpu_type() == CPU_VR4111 ||
137 		    current_cpu_type() == CPU_VR4121) {
138 			cmuclkmsk &= ~(MSKSIU | MSKSSIU);
139 		} else {
140 			if (cmuclkmsk & MSKDSIU)
141 				cmuclkmsk &= ~MSKSSIU;
142 			else
143 				cmuclkmsk &= ~(MSKSIU | MSKSSIU);
144 		}
145 		break;
146 	case AIU_CLOCK:
147 		cmuclkmsk &= ~MSKAIU;
148 		break;
149 	case KIU_CLOCK:
150 		cmuclkmsk &= ~MSKKIU;
151 		break;
152 	case FIR_CLOCK:
153 		cmuclkmsk &= ~(MSKFIR | MSKFFIR);
154 		break;
155 	case DSIU_CLOCK:
156 		if (current_cpu_type() == CPU_VR4111 ||
157 		    current_cpu_type() == CPU_VR4121) {
158 			cmuclkmsk &= ~MSKDSIU;
159 		} else {
160 			if (cmuclkmsk & MSKSSIU)
161 				cmuclkmsk &= ~MSKDSIU;
162 			else
163 				cmuclkmsk &= ~(MSKSIU | MSKDSIU);
164 		}
165 		break;
166 	case CSI_CLOCK:
167 		cmuclkmsk &= ~(MSKCSI | MSKSCSI);
168 		break;
169 	case PCIU_CLOCK:
170 		cmuclkmsk &= ~MSKPCIU;
171 		break;
172 	case HSP_CLOCK:
173 		cmuclkmsk &= ~MSKSHSP;
174 		break;
175 	case PCI_CLOCK:
176 		cmuclkmsk &= ~MSKPPCIU;
177 		break;
178 	case CEU_CLOCK:
179 		cmuclkmsk2 &= ~MSKCEU;
180 		break;
181 	case ETHER0_CLOCK:
182 		cmuclkmsk2 &= ~MSKMAC0;
183 		break;
184 	case ETHER1_CLOCK:
185 		cmuclkmsk2 &= ~MSKMAC1;
186 		break;
187 	default:
188 		break;
189 	}
190 
191 	if (clock == CEU_CLOCK || clock == ETHER0_CLOCK ||
192 	    clock == ETHER1_CLOCK)
193 		cmu_write(CMUCLKMSK2, cmuclkmsk2);
194 	else
195 		cmu_write(CMUCLKMSK, cmuclkmsk);
196 
197 	spin_unlock_irq(&cmu_lock);
198 }
199 
200 EXPORT_SYMBOL_GPL(vr41xx_mask_clock);
201 
vr41xx_cmu_init(void)202 static int __init vr41xx_cmu_init(void)
203 {
204 	unsigned long start, size;
205 
206 	switch (current_cpu_type()) {
207 	case CPU_VR4111:
208 	case CPU_VR4121:
209 		start = CMU_TYPE1_BASE;
210 		size = CMU_TYPE1_SIZE;
211 		break;
212 	case CPU_VR4122:
213 	case CPU_VR4131:
214 		start = CMU_TYPE2_BASE;
215 		size = CMU_TYPE2_SIZE;
216 		break;
217 	case CPU_VR4133:
218 		start = CMU_TYPE3_BASE;
219 		size = CMU_TYPE3_SIZE;
220 		break;
221 	default:
222 		panic("Unexpected CPU of NEC VR4100 series");
223 		break;
224 	}
225 
226 	if (request_mem_region(start, size, "CMU") == NULL)
227 		return -EBUSY;
228 
229 	cmu_base = ioremap(start, size);
230 	if (cmu_base == NULL) {
231 		release_mem_region(start, size);
232 		return -EBUSY;
233 	}
234 
235 	cmuclkmsk = cmu_read(CMUCLKMSK);
236 	if (current_cpu_type() == CPU_VR4133)
237 		cmuclkmsk2 = cmu_read(CMUCLKMSK2);
238 
239 	spin_lock_init(&cmu_lock);
240 
241 	return 0;
242 }
243 
244 core_initcall(vr41xx_cmu_init);
245