Home | History | Annotate | Line # | Download | only in marvell
kirkwood.c revision 1.1
      1 /*	$NetBSD: kirkwood.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: kirkwood.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/kirkwoodreg.h>
     46 
     47 #include <dev/marvell/marvellreg.h>
     48 
     49 
     50 static void kirkwood_intr_init(void);
     51 
     52 static void kirkwood_pic_unblock_low_irqs(struct pic_softc *, size_t, uint32_t);
     53 static void kirkwood_pic_unblock_high_irqs(struct pic_softc *, size_t,
     54 					   uint32_t);
     55 static void kirkwood_pic_block_low_irqs(struct pic_softc *, size_t, uint32_t);
     56 static void kirkwood_pic_block_high_irqs(struct pic_softc *, size_t, uint32_t);
     57 static int kirkwood_pic_find_pending_high_irqs(struct pic_softc *);
     58 static void kirkwood_pic_establish_irq(struct pic_softc *, struct intrsource *);
     59 static void kirkwood_pic_source_name(struct pic_softc *, int, char *, size_t);
     60 
     61 static int kirkwood_find_pending_irqs(void);
     62 
     63 static const char * const sources[64] = {
     64     "MainHighSum(0)",  "Bridge(1)",       "Host2CPU DB(2)",  "CPU2Host DB(3)",
     65     "Reserved_4(4)",   "Xor0Chan0(5)",    "Xor0Chan1(6)",    "Xor1Chan0(7)",
     66     "Xor1Chan1(8)",    "PEX0INT(9)",      "Reserved(10)",    "GbE0Sum(11)",
     67     "GbE0Rx(12)",      "GbE0Tx(13)",      "GbE0Misc(14)",    "GbE1Sum(15)",
     68     "GbE1Rx(16)",      "GbE1Tx(17)",      "GbE1Misc(18)",    "USB0Cnt(19)",
     69     "Reserved(20)",    "Sata(21)",        "SecurityInt(22)", "SPIInt(23)",
     70     "AudioINT(24)",    "Reserved(25)",    "TS0Int(26)",      "Reserved(27)",
     71     "SDIOInt(28)",     "TWSI(29)",        "AVBInt(30)",      "TDMInt(31)"
     72 
     73     "Reserved(32)",    "Uart0Int(33)",    "Uart1Int(34)",    "GPIOLo7_0(35)"
     74     "GPIOLo8_15(36)",  "GPIOLo16_23(37)", "GPIOLo24_31(38)", "GPIOHi7_0(39)"
     75     "GPIOHi8_15(40)",  "GPIOHi16_23(41)", "XOR0Err(42)",     "XOR1Err(43)"
     76     "PEX0Err(44)",     "Reserved(45)",    "GbE0Err(46)",     "GbE1Err(47)"
     77     "USBErr(48)",      "SecurityErr(49)", "AudioErr(50)",    "Reserved(51)"
     78     "Reserved(52)",    "RTCInt(53)",      "Reserved(54)",    "Reserved(55)"
     79     "Reserved(56)",    "Reserved(57)",    "Reserved(58)",    "Reserved(59)"
     80     "Reserved(60)",    "Reserved(61)",    "Reserved(62)",    "Reserved(63)"
     81 };
     82 
     83 static struct pic_ops kirkwood_picops_low = {
     84 	.pic_unblock_irqs = kirkwood_pic_unblock_low_irqs,
     85 	.pic_block_irqs = kirkwood_pic_block_low_irqs,
     86 	.pic_establish_irq = kirkwood_pic_establish_irq,
     87 	.pic_source_name = kirkwood_pic_source_name,
     88 };
     89 static struct pic_ops kirkwood_picops_high = {
     90 	.pic_unblock_irqs = kirkwood_pic_unblock_high_irqs,
     91 	.pic_block_irqs = kirkwood_pic_block_high_irqs,
     92 	.pic_find_pending_irqs = kirkwood_pic_find_pending_high_irqs,
     93 	.pic_establish_irq = kirkwood_pic_establish_irq,
     94 	.pic_source_name = kirkwood_pic_source_name,
     95 };
     96 static struct pic_softc kirkwood_pic_low = {
     97 	.pic_ops = &kirkwood_picops_low,
     98 	.pic_maxsources = 32,
     99 	.pic_name = "kirkwood_low",
    100 };
    101 static struct pic_softc kirkwood_pic_high = {
    102 	.pic_ops = &kirkwood_picops_high,
    103 	.pic_maxsources = 32,
    104 	.pic_name = "kirkwood_high",
    105 };
    106 
    107 
    108 /*
    109  * kirkwood_intr_bootstrap:
    110  *
    111  *	Initialize the rest of the interrupt subsystem, making it
    112  *	ready to handle interrupts from devices.
    113  */
    114 void
    115 kirkwood_intr_bootstrap(void)
    116 {
    117 	extern void (*mvsoc_intr_init)(void);
    118 
    119 	/* disable all interrupts */
    120 	write_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR, 0);
    121 	write_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR, 0);
    122 
    123 	/* disable all bridge interrupts */
    124 	write_mlmbreg(MVSOC_MLMB_MLMBIMR, 0);
    125 
    126 	mvsoc_intr_init = kirkwood_intr_init;
    127 
    128 #if NMVSOCGPP > 0
    129 	switch (mvsoc_model()) {
    130 	case MARVELL_KIRKWOOD_88F6180: gpp_npins = 30; break;
    131 	case MARVELL_KIRKWOOD_88F6192: gpp_npins = 36; break;
    132 	case MARVELL_KIRKWOOD_88F6281: gpp_npins = 50; break;
    133 	}
    134 	gpp_irqbase = 96;	/* Main Low(32) + High(32) + Bridge(32) */
    135 #endif
    136 }
    137 
    138 static void
    139 kirkwood_intr_init(void)
    140 {
    141 	extern struct pic_softc mvsoc_bridge_pic;
    142 	void *ih;
    143 
    144 	pic_add(&kirkwood_pic_low, 0);
    145 
    146 	pic_add(&kirkwood_pic_high, 32);
    147 	ih = intr_establish(KIRKWOOD_IRQ_HIGH, IPL_HIGH, IST_LEVEL_HIGH,
    148 	    pic_handle_intr, &kirkwood_pic_high);
    149 	KASSERT(ih != NULL);
    150 
    151 	pic_add(&mvsoc_bridge_pic, 64);
    152 	ih = intr_establish(KIRKWOOD_IRQ_BRIDGE, IPL_HIGH, IST_LEVEL_HIGH,
    153 	    pic_handle_intr, &mvsoc_bridge_pic);
    154 	KASSERT(ih != NULL);
    155 
    156 	find_pending_irqs = kirkwood_find_pending_irqs;
    157 }
    158 
    159 /* ARGSUSED */
    160 static void
    161 kirkwood_pic_unblock_low_irqs(struct pic_softc *pic, size_t irqbase,
    162 			      uint32_t irq_mask)
    163 {
    164 
    165 	write_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR,
    166 	    read_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR) | irq_mask);
    167 }
    168 
    169 /* ARGSUSED */
    170 static void
    171 kirkwood_pic_unblock_high_irqs(struct pic_softc *pic, size_t irqbase,
    172 			       uint32_t irq_mask)
    173 {
    174 
    175 	write_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR,
    176 	    read_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR) | irq_mask);
    177 }
    178 
    179 /* ARGSUSED */
    180 static void
    181 kirkwood_pic_block_low_irqs(struct pic_softc *pic, size_t irqbase,
    182 			    uint32_t irq_mask)
    183 {
    184 
    185 	write_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR,
    186 	    read_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR) & ~irq_mask);
    187 }
    188 
    189 /* ARGSUSED */
    190 static void
    191 kirkwood_pic_block_high_irqs(struct pic_softc *pic, size_t irqbase,
    192 			     uint32_t irq_mask)
    193 {
    194 
    195 	write_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR,
    196 	    read_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR) & ~irq_mask);
    197 }
    198 
    199 static int
    200 kirkwood_pic_find_pending_high_irqs(struct pic_softc *pic)
    201 {
    202 	uint32_t pending;
    203 
    204 	pending = read_mlmbreg(KIRKWOOD_MLMB_MICHR) &
    205 	    read_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR);
    206 	if (pending == 0)
    207 		return 0;
    208 	pic_mark_pending_sources(pic, 0, pending);
    209 	return 1;
    210 }
    211 
    212 /* ARGSUSED */
    213 static void
    214 kirkwood_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    215 {
    216 	/* Nothing */
    217 }
    218 
    219 static void
    220 kirkwood_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
    221 {
    222 
    223 	strlcpy(buf, sources[pic->pic_irqbase + irq], len);
    224 }
    225 
    226 /*
    227  * Called with interrupts disabled
    228  */
    229 static int
    230 kirkwood_find_pending_irqs(void)
    231 {
    232 	uint32_t pending;
    233 
    234 	pending = read_mlmbreg(KIRKWOOD_MLMB_MICLR) &
    235 	    read_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR);
    236 	if (pending == 0)
    237 		return 0;
    238 
    239 	return pic_mark_pending_sources(&kirkwood_pic_low, 0, pending);
    240 }
    241 
    242 /*
    243  * Clock functions
    244  */
    245 
    246 void
    247 kirkwood_getclks(bus_addr_t iobase)
    248 {
    249 	uint32_t reg;
    250 	uint16_t model;
    251 
    252 #define MHz	* 1000 * 1000
    253 
    254 	model = mvsoc_model();
    255 	if (model == MARVELL_KIRKWOOD_88F6281)
    256 		mvTclk = 200 MHz;
    257 	else		/* 166MHz */
    258 		mvTclk = 166666667;
    259 
    260 	reg = *(volatile uint32_t *)(iobase + KIRKWOOD_MPP_BASE +
    261 	    KIRKWOOD_MPP_SAMPLE_AT_RESET);
    262 	if (model == MARVELL_KIRKWOOD_88F6180) {
    263 		switch (reg & 0x0000001c) {
    264 		case 0x00000014: mvPclk =  600 MHz;
    265 		case 0x00000018: mvPclk =  800 MHz;
    266 		default:
    267 			panic("unknown mvPclk\n");
    268 		}
    269 		mvSysclk = 200 MHz;
    270 	} else {
    271 		switch (reg & 0x0040001a) {
    272 		case 0x00000008: mvPclk =  600 MHz; break;
    273 		case 0x00400008: mvPclk =  800 MHz; break;
    274 		case 0x0040000a: mvPclk = 1000 MHz; break;
    275 		case 0x00000012: mvPclk = 1200 MHz; break;
    276 		case 0x00000018: mvPclk = 1200 MHz; break;
    277 		default:
    278 			panic("unknown mvPclk\n");
    279 		}
    280 
    281 		switch (reg & 0x000001e0) {
    282 		case 0x00000060: mvSysclk = mvPclk * 2 / 5; break;
    283 		case 0x00000080: mvSysclk = mvPclk * 1 / 3; break;
    284 		case 0x000000c0: mvSysclk = mvPclk * 1 / 4; break;
    285 		default:
    286 			panic("unknown mvSysclk\n");
    287 		}
    288 	}
    289 
    290 #undef MHz
    291 
    292 }
    293