xref: /netbsd/sys/arch/arm/marvell/orion.c (revision 6550d01e)
1 /*	$NetBSD: orion.c,v 1.1 2010/10/03 05:49:24 kiyohara Exp $	*/
2 /*
3  * Copyright (c) 2010 KIYOHARA Takashi
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: orion.c,v 1.1 2010/10/03 05:49:24 kiyohara Exp $");
30 
31 #define _INTR_PRIVATE
32 
33 #include "mvsocgpp.h"
34 
35 #include <sys/param.h>
36 #include <sys/bus.h>
37 
38 #include <machine/intr.h>
39 
40 #include <arm/pic/picvar.h>
41 #include <arm/pic/picvar.h>
42 
43 #include <arm/marvell/mvsocreg.h>
44 #include <arm/marvell/mvsocvar.h>
45 #include <arm/marvell/orionreg.h>
46 
47 #include <dev/marvell/marvellreg.h>
48 
49 
50 static void orion_intr_init(void);
51 
52 static void orion_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
53 static void orion_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
54 static void orion_pic_establish_irq(struct pic_softc *, struct intrsource *);
55 static void orion_pic_source_name(struct pic_softc *, int, char *, size_t);
56 
57 static int orion_find_pending_irqs(void);
58 
59 static const char * const sources[64] = {
60     "Bridge(0)",       "Host2CPU DB(1)",  "CPU2Host DB(2)",  "UART0(3)",
61     "UART1(4)",        "TWSI(5)",         "GPIO7_0(6)",      "GPIO15_8(7)",
62     "GPIO23_16(8)",    "GPIO31_24(9)",    "PEX0Err(10)",     "PEX0INT(11)",
63     "PEX1Err/USBCnt1", "PEX1INT(13)",     "DEVErr(14)",      "PCIErr(15)",
64     "USBBr(16)",       "USBCnt0(17)",     "GbERx(18)",       "GbETx(19)",
65     "GbEMisc(20)",     "GbESum(21)",      "GbEErr(22)",      "DMAErr(23)",
66     "IDMA0(24)",       "IDMA1(25)",       "IDMA2(26)",       "IDMA3(27)",
67     "SecIntr(28)",     "SataIntr(29)",    "XOR0(30)",        "XOR1(31)"
68 };
69 
70 static struct pic_ops orion_picops = {
71 	.pic_unblock_irqs = orion_pic_unblock_irqs,
72 	.pic_block_irqs = orion_pic_block_irqs,
73 	.pic_establish_irq = orion_pic_establish_irq,
74 	.pic_source_name = orion_pic_source_name,
75 };
76 static struct pic_softc orion_pic = {
77 	.pic_ops = &orion_picops,
78 	.pic_maxsources = 32,
79 	.pic_name = "orion_pic",
80 };
81 
82 
83 /*
84  * orion_intr_bootstrap:
85  *
86  *	Initialize the rest of the interrupt subsystem, making it
87  *	ready to handle interrupts from devices.
88  */
89 void
90 orion_intr_bootstrap()
91 {
92 	extern void (*mvsoc_intr_init)(void);
93 
94 	/* disable all interrupts */
95 	write_mlmbreg(ORION_MLMB_MIRQIMR, 0);
96 
97 	/* disable all bridge interrupts */
98 	write_mlmbreg(MVSOC_MLMB_MLMBIMR, 0);
99 
100 	mvsoc_intr_init = orion_intr_init;
101 
102 #if NMVSOCGPP > 0
103 	gpp_npins = 32;
104 	gpp_irqbase = 64;	/* Main(32) + Bridge(32) */
105 #endif
106 }
107 
108 static void
109 orion_intr_init(void)
110 {
111 	extern struct pic_softc mvsoc_bridge_pic;
112 	void *ih;
113 
114 	pic_add(&orion_pic, 0);
115 
116 	pic_add(&mvsoc_bridge_pic, 32);
117 	ih = intr_establish(ORION_IRQ_BRIDGE, IPL_HIGH, IST_LEVEL_HIGH,
118 	    pic_handle_intr, &mvsoc_bridge_pic);
119 	KASSERT(ih != NULL);
120 
121 	find_pending_irqs = orion_find_pending_irqs;
122 }
123 
124 /* ARGSUSED */
125 static void
126 orion_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask)
127 {
128 
129 	write_mlmbreg(ORION_MLMB_MIRQIMR,
130 	    read_mlmbreg(ORION_MLMB_MIRQIMR) | irq_mask);
131 }
132 
133 /* ARGSUSED */
134 static void
135 orion_pic_block_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask)
136 {
137 
138 	write_mlmbreg(ORION_MLMB_MIRQIMR,
139 	    read_mlmbreg(ORION_MLMB_MIRQIMR) & ~irq_mask);
140 }
141 
142 /* ARGSUSED */
143 static void
144 orion_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
145 {
146 	/* Nothing */
147 }
148 
149 static void
150 orion_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
151 {
152 
153 	strlcpy(buf, sources[pic->pic_irqbase + irq], len);
154 }
155 
156 /*
157  * Called with interrupts disabled
158  */
159 static int
160 orion_find_pending_irqs(void)
161 {
162 	uint32_t pending;
163 
164 	pending =
165 	    read_mlmbreg(ORION_MLMB_MICR) & read_mlmbreg(ORION_MLMB_MIRQIMR);
166 	if (pending == 0)
167 		return 0;
168 
169 	return pic_mark_pending_sources(&orion_pic, 0, pending);
170 }
171 
172 /*
173  * Clock functions
174  */
175 
176 void
177 orion_getclks(bus_addr_t iobase)
178 {
179 	static struct {
180 		int armddrclkval;
181 		uint32_t pclk;
182 		uint32_t sysclk;
183 	} sysclktbl[] = {
184 		{ ORION_PMISMPL_ARMDDRCLK_333_167, 333000000, 166666667 },
185 		{ ORION_PMISMPL_ARMDDRCLK_400_200, 400000000, 200000000 },
186 		{ ORION_PMISMPL_ARMDDRCLK_400_133, 400000000, 133333334 },
187 		{ ORION_PMISMPL_ARMDDRCLK_500_167, 500000000, 166666667 },
188 		{ ORION_PMISMPL_ARMDDRCLK_533_133, 533000000, 133333334 },
189 		{ ORION_PMISMPL_ARMDDRCLK_600_200, 600000000, 200000000 },
190 		{ ORION_PMISMPL_ARMDDRCLK_667_167, 667000000, 166666667 },
191 		{ ORION_PMISMPL_ARMDDRCLK_800_200, 800000000, 200000000 },
192 		{ ORION_PMISMPL_ARMDDRCLK_480_160, 480000000, 160000000 },
193 		{ ORION_PMISMPL_ARMDDRCLK_550_183, 550000000, 183333334 },
194 		{ ORION_PMISMPL_ARMDDRCLK_525_175, 525000000, 175000000 },
195 		{ ORION_PMISMPL_ARMDDRCLK_466_233, 466000000, 233000000 },
196 		{ ORION_PMISMPL_ARMDDRCLK_500_250, 500000000, 250000000 },
197 		{ ORION_PMISMPL_ARMDDRCLK_533_266, 533000000, 266000000 },
198 		{ ORION_PMISMPL_ARMDDRCLK_600_300, 600000000, 300000000 },
199 		{ ORION_PMISMPL_ARMDDRCLK_450_150, 450000000, 150000000 },
200 		{ ORION_PMISMPL_ARMDDRCLK_533_178, 533000000, 178000000 },
201 		{ ORION_PMISMPL_ARMDDRCLK_575_192, 575000000, 192000000 },
202 		{ ORION_PMISMPL_ARMDDRCLK_700_175, 700000000, 175000000 },
203 		{ ORION_PMISMPL_ARMDDRCLK_733_183, 733000000, 183333334 },
204 		{ ORION_PMISMPL_ARMDDRCLK_750_187, 750000000, 187000000 },
205 		{ ORION_PMISMPL_ARMDDRCLK_775_194, 775000000, 194000000 },
206 		{ ORION_PMISMPL_ARMDDRCLK_500_125, 500000000, 125000000 },
207 		{ ORION_PMISMPL_ARMDDRCLK_500_100, 500000000, 100000000 },
208 		{ ORION_PMISMPL_ARMDDRCLK_600_150, 600000000, 150000000 },
209 
210 		{ 0, 0, 0 },
211 	};
212 	uint32_t reg, armddrclk, tclk;
213 	uint16_t model;
214 	int armddrclk_shift, tclk_shift, i;
215 
216 	model = mvsoc_model();
217 	if (model == MARVELL_ORION_1_88F1181 ||
218 	    model == MARVELL_ORION_2_88F1281) {
219 		armddrclk_shift = 6;
220 		tclk_shift = 10;
221 	} else {
222 		armddrclk_shift = 4;
223 		tclk_shift = 8;
224 	}
225 
226 	reg = *(volatile uint32_t *)(iobase + ORION_PMI_BASE +
227 	    ORION_PMI_SAMPLE_AT_RESET);
228 	armddrclk = (reg >> armddrclk_shift) & ORION_PMISMPL_ARMDDRCLK_MASK;
229 	if (model == PCI_PRODUCT_MARVELL_88F5281)
230 		if (reg & ORION_PMISMPL_ARMDDRCLK_H_MASK)
231 			armddrclk |= 0x00000010;	/* set to bit4 */
232 	for (i = 0; sysclktbl[i].pclk != 0; i++)
233 		if (armddrclk == sysclktbl[i].armddrclkval) {
234 			mvPclk = sysclktbl[i].pclk;
235 			mvSysclk = sysclktbl[i].sysclk;
236 			break;
237 		}
238 
239 	tclk = (reg >> tclk_shift) & ORION_PMISMPL_TCLK_MASK;
240 	switch (tclk) {
241 	case ORION_PMISMPL_TCLK_133:
242 		mvTclk = 133333334;	/* 133MHz */
243 		break;
244 
245 	case ORION_PMISMPL_TCLK_150:
246 		mvTclk = 150000000;	/* 150MHz */
247 		break;
248 
249 	case ORION_PMISMPL_TCLK_166:
250 		mvTclk = 166666667;	/* 166MHz */
251 		break;
252 
253 	default:
254 		mvTclk = 100000000;	/* 100MHz */
255 		break;
256 	}
257 }
258