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