xref: /netbsd-src/sys/arch/arm/marvell/mv78xx0.c (revision 75219f3a016dfaad1cb304eb017f9787b1de8292)
1 /*	$NetBSD: mv78xx0.c,v 1.1 2013/09/30 13:07:30 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: mv78xx0.c,v 1.1 2013/09/30 13:07:30 kiyohara Exp $");
30 
31 #define _INTR_PRIVATE
32 
33 #include "mvsocgpp.h"
34 
35 #include <sys/param.h>
36 #include <sys/bus.h>
37 #include <sys/cpu.h>
38 
39 #include <machine/intr.h>
40 
41 #include <arm/pic/picvar.h>
42 #include <arm/pic/picvar.h>
43 
44 #include <arm/marvell/mvsocreg.h>
45 #include <arm/marvell/mvsocvar.h>
46 #include <arm/marvell/mv78xx0reg.h>
47 
48 #include <dev/marvell/marvellreg.h>
49 
50 #define MV78XX0_ICI_MICR(g)	(MV78XX0_ICI_MICLR + ((g) << 2))
51 #define MV78XX0_ICI_IRQIMR(g)	(MV78XX0_ICI_IRQIMLR + ((g) << 2))
52 
53 static void mv78xx0_intr_init(void);
54 
55 static void mv78xx0_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
56 static void mv78xx0_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
57 static void mv78xx0_pic_establish_irq(struct pic_softc *, struct intrsource *);
58 static void mv78xx0_pic_source_name(struct pic_softc *, int, char *, size_t);
59 
60 static int mv78xx0_find_pending_irqs(void);
61 
62 static const char * const sources[64] = {
63     "ErrSum(0)",       "SPI(1)",          "TWSI0(2)",        "TWSI1(3)",
64     "IDMA0(4)",        "IDMA1(5)",        "IDMA2(6)",        "IDMA3(7)",
65     "Timer0(8)",       "Timer1(9)",       "Timer2(10)",      "Timer3(11)",
66     "UART0(12)",       "UART1(13)",       "UART2(14)",       "UART3(15)",
67     "USB0(16)",        "USB1(17)",        "USB2(18)",        "Crypto(19)",
68     "Reserved(20)",    "Reserved(21)",    "XOR0(22)",        "XOR1(23)",
69     "Reserved(24)",    "Reserved(25)",    "SATA(26)",        "TDMI_INT(27)",
70     "Reserved(28)",    "Reserved(29)",    "Reserved(30)",    "Reserved(31)"
71 
72     "PEX00INTA(32)",   "PEX01INTA(33)",   "PEX02INTA(34)",   "PEX03INTA(35)"
73     "PEX10INTA(36)",   "PEX11INTA(37)",   "PEX12INTA(38)",   "PEX13INTA(39)"
74     "GE00Sum(40)",     "GE00Rx(41)",      "GE00Tx(42)",      "GE00Misc(43)"
75     "GE01Sum(44)",     "GE01Rx(45)",      "GE01Tx(46)",      "GE01Misc(47)"
76     "GE10Sum(48)",     "GE10Rx(49)",      "GE10Tx(50)",      "GE10Misc(51)"
77     "GE11Sum(52)",     "GE11Rx(53)",      "GE11Tx(54)",      "GE11Misc(55)"
78     "GPIO0_7(56)",     "GPIO8_15(57)",    "GPIO16_23(58)",   "GPIO24_31(59)"
79     "DB_INT(60)",      "DB_OUT(61)",      "Reserved(62)",    "Reserved(63)"
80 };
81 
82 static struct pic_ops mv78xx0_picops = {
83 	.pic_unblock_irqs = mv78xx0_pic_unblock_irqs,
84 	.pic_block_irqs = mv78xx0_pic_block_irqs,
85 	.pic_establish_irq = mv78xx0_pic_establish_irq,
86 	.pic_source_name = mv78xx0_pic_source_name,
87 };
88 static struct pic_softc mv78xx0_pic = {
89 	.pic_ops = &mv78xx0_picops,
90 	.pic_maxsources = 64,
91 	.pic_name = "mv78xx0_pic",
92 };
93 
94 
95 /*
96  * mv78xx0_intr_bootstrap:
97  *
98  *	Initialize the rest of the interrupt subsystem, making it
99  *	ready to handle interrupts from devices.
100  */
101 void
102 mv78xx0_intr_bootstrap(void)
103 {
104 	extern void (*mvsoc_intr_init)(void);
105 
106 	/* disable all interrupts */
107 	write_mlmbreg(MV78XX0_ICI_IRQIMER, 0);
108 	write_mlmbreg(MV78XX0_ICI_IRQIMLR, 0);
109 	write_mlmbreg(MV78XX0_ICI_IRQIMHR, 0);
110 
111 	/* disable all bridge interrupts */
112 	write_mlmbreg(MVSOC_MLMB_MLMBIMR, 0);
113 
114 	mvsoc_intr_init = mv78xx0_intr_init;
115 
116 	gpp_npins = 32;
117 	gpp_irqbase = 64;	/* Main Low(32) + High(32) */
118 }
119 
120 static void
121 mv78xx0_intr_init(void)
122 {
123 
124 	pic_add(&mv78xx0_pic, 0);
125 
126 	find_pending_irqs = mv78xx0_find_pending_irqs;
127 }
128 
129 /* ARGSUSED */
130 static void
131 mv78xx0_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
132 			 uint32_t irq_mask)
133 {
134 	const size_t group = irqbase / 32;
135 
136 	write_mlmbreg(MV78XX0_ICI_IRQIMR(group),
137 	    read_mlmbreg(MV78XX0_ICI_IRQIMR(group)) | irq_mask);
138 }
139 
140 /* ARGSUSED */
141 static void
142 mv78xx0_pic_block_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask)
143 {
144 	const size_t group = irqbase / 32;
145 
146 	write_mlmbreg(MV78XX0_ICI_IRQIMR(group),
147 	    read_mlmbreg(MV78XX0_ICI_IRQIMR(group)) & ~irq_mask);
148 }
149 
150 /* ARGSUSED */
151 static void
152 mv78xx0_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
153 {
154 	uint32_t mlmbim;
155 
156 	/* Also enable MbusL-Mbus Bridge Interrupt Mask, if irq is TimerX. */
157 	if (is->is_irq == MV78XX0_IRQ_TIMER0 ||
158 	    is->is_irq == MV78XX0_IRQ_TIMER1 ||
159 	    is->is_irq == MV78XX0_IRQ_TIMER2 ||
160 	    is->is_irq == MV78XX0_IRQ_TIMER3) {
161 		mlmbim = read_mlmbreg(MVSOC_MLMB_MLMBIMR);
162 		mlmbim |= TIMER_IRQ2MLMBIMR(is->is_irq);
163 		write_mlmbreg(MVSOC_MLMB_MLMBIMR, mlmbim);
164 	}
165 }
166 
167 static void
168 mv78xx0_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
169 {
170 
171 	strlcpy(buf, sources[pic->pic_irqbase + irq], len);
172 }
173 
174 /*
175  * Called with interrupts disabled
176  */
177 static int
178 mv78xx0_find_pending_irqs(void)
179 {
180 	uint32_t pending;
181 	int ipl = 0;
182 
183 	pending = read_mlmbreg(MV78XX0_ICI_MICR(0)) &
184 	    read_mlmbreg(MV78XX0_ICI_IRQIMR(0));
185 	if (pending != 0)
186 		ipl = pic_mark_pending_sources(&mv78xx0_pic, 0, pending);
187 
188 	pending = read_mlmbreg(MV78XX0_ICI_MICR(1)) &
189 	    read_mlmbreg(MV78XX0_ICI_IRQIMR(1));
190 	if (pending != 0)
191 		ipl |= pic_mark_pending_sources(&mv78xx0_pic, 32, pending);
192 
193 	return ipl;
194 }
195 
196 /*
197  * Clock functions
198  */
199 
200 void
201 mv78xx0_getclks(bus_addr_t iobase)
202 {
203 	const static int sys2cpu_clk_ratio_m[] =	/* Mul constant */
204 	    { 1, 3, 2, 5, 3, 7, 4, 9, 5, 1, 6 };
205 	const static int sys2cpu_clk_ratio_n[] =	/* Div constant */
206 	    { 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1 };
207 	uint32_t reg;
208 	int x;
209 
210 #define MHz	* 1000 * 1000
211 
212 	reg = *(volatile uint32_t *)(iobase + MV78XX0_SAMPLE_AT_RESET_HIGH);
213 	switch (reg & 0x180) {
214 	case 0x000: mvTclk = 166666667; break;
215 	case 0x080: mvTclk =   200 MHz; break;
216 	default:    mvTclk =   200 MHz; break;
217 	}
218 
219 	reg = *(volatile uint32_t *)(iobase + MV78XX0_SAMPLE_AT_RESET_LOW);
220 
221 	switch (reg & 0x0e0) {
222 	case 0x020: mvSysclk =   200 MHz; break;
223 	case 0x040: mvSysclk = 266666667; break;
224 	case 0x060: mvSysclk = 333333334; break;
225 	case 0x080: mvSysclk =   400 MHz; break;
226 	case 0x0a0: mvSysclk =   250 MHz; break;
227 	case 0x0c0: mvSysclk =   300 MHz; break;
228 	default:    mvSysclk = 266666667; break;
229 	}
230 
231 	x = (reg & 0xf00) >> 8;
232 	mvPclk = sys2cpu_clk_ratio_m[x] * mvSysclk / sys2cpu_clk_ratio_n[x];
233 
234 #undef MHz
235 
236 }
237