xref: /netbsd-src/sys/arch/arm/marvell/orion.c (revision 7d0ac4467565b841a7bc4dbb6b1acb8fec22b511)
1*7d0ac446Srin /*	$NetBSD: orion.c,v 1.7 2021/08/30 00:04:30 rin Exp $	*/
252d286fbSkiyohara /*
352d286fbSkiyohara  * Copyright (c) 2010 KIYOHARA Takashi
452d286fbSkiyohara  * All rights reserved.
552d286fbSkiyohara  *
652d286fbSkiyohara  * Redistribution and use in source and binary forms, with or without
752d286fbSkiyohara  * modification, are permitted provided that the following conditions
852d286fbSkiyohara  * are met:
952d286fbSkiyohara  * 1. Redistributions of source code must retain the above copyright
1052d286fbSkiyohara  *    notice, this list of conditions and the following disclaimer.
1152d286fbSkiyohara  * 2. Redistributions in binary form must reproduce the above copyright
1252d286fbSkiyohara  *    notice, this list of conditions and the following disclaimer in the
1352d286fbSkiyohara  *    documentation and/or other materials provided with the distribution.
1452d286fbSkiyohara  *
1552d286fbSkiyohara  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1652d286fbSkiyohara  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1752d286fbSkiyohara  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1852d286fbSkiyohara  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
1952d286fbSkiyohara  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2052d286fbSkiyohara  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2152d286fbSkiyohara  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2252d286fbSkiyohara  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2352d286fbSkiyohara  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
2452d286fbSkiyohara  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2552d286fbSkiyohara  * POSSIBILITY OF SUCH DAMAGE.
2652d286fbSkiyohara  */
2752d286fbSkiyohara 
2852d286fbSkiyohara #include <sys/cdefs.h>
29*7d0ac446Srin __KERNEL_RCSID(0, "$NetBSD: orion.c,v 1.7 2021/08/30 00:04:30 rin Exp $");
3052d286fbSkiyohara 
3152d286fbSkiyohara #define _INTR_PRIVATE
3252d286fbSkiyohara 
3352d286fbSkiyohara #include "mvsocgpp.h"
3452d286fbSkiyohara 
3552d286fbSkiyohara #include <sys/param.h>
3652d286fbSkiyohara #include <sys/bus.h>
3752d286fbSkiyohara 
3852d286fbSkiyohara #include <machine/intr.h>
3952d286fbSkiyohara 
4052d286fbSkiyohara #include <arm/pic/picvar.h>
4152d286fbSkiyohara #include <arm/pic/picvar.h>
4252d286fbSkiyohara 
4352d286fbSkiyohara #include <arm/marvell/mvsocreg.h>
4452d286fbSkiyohara #include <arm/marvell/mvsocvar.h>
4552d286fbSkiyohara #include <arm/marvell/orionreg.h>
4652d286fbSkiyohara 
4752d286fbSkiyohara #include <dev/marvell/marvellreg.h>
4852d286fbSkiyohara 
4952d286fbSkiyohara 
5052d286fbSkiyohara static void orion_intr_init(void);
5152d286fbSkiyohara 
5252d286fbSkiyohara static void orion_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
5352d286fbSkiyohara static void orion_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
5452d286fbSkiyohara static void orion_pic_establish_irq(struct pic_softc *, struct intrsource *);
5552d286fbSkiyohara static void orion_pic_source_name(struct pic_softc *, int, char *, size_t);
5652d286fbSkiyohara 
5752d286fbSkiyohara static int orion_find_pending_irqs(void);
5852d286fbSkiyohara 
59a4c1b5d6Skiyohara static void orion_getclks(vaddr_t);
60a4c1b5d6Skiyohara 
6152d286fbSkiyohara static const char * const sources[64] = {
6252d286fbSkiyohara     "Bridge(0)",       "Host2CPU DB(1)",  "CPU2Host DB(2)",  "UART0(3)",
6352d286fbSkiyohara     "UART1(4)",        "TWSI(5)",         "GPIO7_0(6)",      "GPIO15_8(7)",
6452d286fbSkiyohara     "GPIO23_16(8)",    "GPIO31_24(9)",    "PEX0Err(10)",     "PEX0INT(11)",
6552d286fbSkiyohara     "PEX1Err/USBCnt1", "PEX1INT(13)",     "DEVErr(14)",      "PCIErr(15)",
6652d286fbSkiyohara     "USBBr(16)",       "USBCnt0(17)",     "GbERx(18)",       "GbETx(19)",
6752d286fbSkiyohara     "GbEMisc(20)",     "GbESum(21)",      "GbEErr(22)",      "DMAErr(23)",
6852d286fbSkiyohara     "IDMA0(24)",       "IDMA1(25)",       "IDMA2(26)",       "IDMA3(27)",
6952d286fbSkiyohara     "SecIntr(28)",     "SataIntr(29)",    "XOR0(30)",        "XOR1(31)"
7052d286fbSkiyohara };
7152d286fbSkiyohara 
7252d286fbSkiyohara static struct pic_ops orion_picops = {
7352d286fbSkiyohara 	.pic_unblock_irqs = orion_pic_unblock_irqs,
7452d286fbSkiyohara 	.pic_block_irqs = orion_pic_block_irqs,
7552d286fbSkiyohara 	.pic_establish_irq = orion_pic_establish_irq,
7652d286fbSkiyohara 	.pic_source_name = orion_pic_source_name,
7752d286fbSkiyohara };
7852d286fbSkiyohara static struct pic_softc orion_pic = {
7952d286fbSkiyohara 	.pic_ops = &orion_picops,
8052d286fbSkiyohara 	.pic_maxsources = 32,
8152d286fbSkiyohara 	.pic_name = "orion_pic",
8252d286fbSkiyohara };
8352d286fbSkiyohara 
8452d286fbSkiyohara 
8552d286fbSkiyohara /*
86a4c1b5d6Skiyohara  * orion_bootstrap:
8752d286fbSkiyohara  *
88a4c1b5d6Skiyohara  *	Initialize the rest of the Orion dependences, making it
8952d286fbSkiyohara  *	ready to handle interrupts from devices.
9052d286fbSkiyohara  */
9152d286fbSkiyohara void
orion_bootstrap(vaddr_t iobase)92a4c1b5d6Skiyohara orion_bootstrap(vaddr_t iobase)
9352d286fbSkiyohara {
9452d286fbSkiyohara 
9552d286fbSkiyohara 	/* disable all interrupts */
9652d286fbSkiyohara 	write_mlmbreg(ORION_MLMB_MIRQIMR, 0);
9752d286fbSkiyohara 
9852d286fbSkiyohara 	/* disable all bridge interrupts */
9952d286fbSkiyohara 	write_mlmbreg(MVSOC_MLMB_MLMBIMR, 0);
10052d286fbSkiyohara 
10152d286fbSkiyohara 	mvsoc_intr_init = orion_intr_init;
10252d286fbSkiyohara 
10352d286fbSkiyohara #if NMVSOCGPP > 0
10452d286fbSkiyohara 	gpp_npins = 32;
10552d286fbSkiyohara 	gpp_irqbase = 64;	/* Main(32) + Bridge(32) */
10652d286fbSkiyohara #endif
107a4c1b5d6Skiyohara 
108a4c1b5d6Skiyohara 	orion_getclks(iobase);
10952d286fbSkiyohara }
11052d286fbSkiyohara 
11152d286fbSkiyohara static void
orion_intr_init(void)11252d286fbSkiyohara orion_intr_init(void)
11352d286fbSkiyohara {
11452d286fbSkiyohara 	extern struct pic_softc mvsoc_bridge_pic;
1151de1b806Smartin 	void *ih __diagused;
11652d286fbSkiyohara 
11752d286fbSkiyohara 	pic_add(&orion_pic, 0);
11852d286fbSkiyohara 
11952d286fbSkiyohara 	pic_add(&mvsoc_bridge_pic, 32);
12052d286fbSkiyohara 	ih = intr_establish(ORION_IRQ_BRIDGE, IPL_HIGH, IST_LEVEL_HIGH,
12152d286fbSkiyohara 	    pic_handle_intr, &mvsoc_bridge_pic);
12252d286fbSkiyohara 	KASSERT(ih != NULL);
12352d286fbSkiyohara 
12452d286fbSkiyohara 	find_pending_irqs = orion_find_pending_irqs;
12552d286fbSkiyohara }
12652d286fbSkiyohara 
12752d286fbSkiyohara /* ARGSUSED */
12852d286fbSkiyohara static void
orion_pic_unblock_irqs(struct pic_softc * pic,size_t irqbase,uint32_t irq_mask)12952d286fbSkiyohara orion_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask)
13052d286fbSkiyohara {
13152d286fbSkiyohara 
13252d286fbSkiyohara 	write_mlmbreg(ORION_MLMB_MIRQIMR,
13352d286fbSkiyohara 	    read_mlmbreg(ORION_MLMB_MIRQIMR) | irq_mask);
13452d286fbSkiyohara }
13552d286fbSkiyohara 
13652d286fbSkiyohara /* ARGSUSED */
13752d286fbSkiyohara static void
orion_pic_block_irqs(struct pic_softc * pic,size_t irqbase,uint32_t irq_mask)13852d286fbSkiyohara orion_pic_block_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask)
13952d286fbSkiyohara {
14052d286fbSkiyohara 
14152d286fbSkiyohara 	write_mlmbreg(ORION_MLMB_MIRQIMR,
14252d286fbSkiyohara 	    read_mlmbreg(ORION_MLMB_MIRQIMR) & ~irq_mask);
14352d286fbSkiyohara }
14452d286fbSkiyohara 
14552d286fbSkiyohara /* ARGSUSED */
14652d286fbSkiyohara static void
orion_pic_establish_irq(struct pic_softc * pic,struct intrsource * is)14752d286fbSkiyohara orion_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
14852d286fbSkiyohara {
14952d286fbSkiyohara 	/* Nothing */
15052d286fbSkiyohara }
15152d286fbSkiyohara 
15252d286fbSkiyohara static void
orion_pic_source_name(struct pic_softc * pic,int irq,char * buf,size_t len)15352d286fbSkiyohara orion_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
15452d286fbSkiyohara {
15552d286fbSkiyohara 
15652d286fbSkiyohara 	strlcpy(buf, sources[pic->pic_irqbase + irq], len);
15752d286fbSkiyohara }
15852d286fbSkiyohara 
15952d286fbSkiyohara /*
16052d286fbSkiyohara  * Called with interrupts disabled
16152d286fbSkiyohara  */
16252d286fbSkiyohara static int
orion_find_pending_irqs(void)16352d286fbSkiyohara orion_find_pending_irqs(void)
16452d286fbSkiyohara {
16552d286fbSkiyohara 	uint32_t pending;
16652d286fbSkiyohara 
16752d286fbSkiyohara 	pending =
16852d286fbSkiyohara 	    read_mlmbreg(ORION_MLMB_MICR) & read_mlmbreg(ORION_MLMB_MIRQIMR);
16952d286fbSkiyohara 	if (pending == 0)
17052d286fbSkiyohara 		return 0;
17152d286fbSkiyohara 
17252d286fbSkiyohara 	return pic_mark_pending_sources(&orion_pic, 0, pending);
17352d286fbSkiyohara }
17452d286fbSkiyohara 
17552d286fbSkiyohara /*
17652d286fbSkiyohara  * Clock functions
17752d286fbSkiyohara  */
17852d286fbSkiyohara 
179a4c1b5d6Skiyohara static void
orion_getclks(vaddr_t iobase)180a4c1b5d6Skiyohara orion_getclks(vaddr_t iobase)
18152d286fbSkiyohara {
1826b253b77Sjakllsch 	static const struct {
18352d286fbSkiyohara 		int armddrclkval;
18452d286fbSkiyohara 		uint32_t pclk;
18552d286fbSkiyohara 		uint32_t sysclk;
18652d286fbSkiyohara 	} sysclktbl[] = {
18752d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_333_167, 333000000, 166666667 },
18852d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_400_200, 400000000, 200000000 },
18952d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_400_133, 400000000, 133333334 },
19052d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_500_167, 500000000, 166666667 },
19152d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_533_133, 533000000, 133333334 },
19252d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_600_200, 600000000, 200000000 },
19352d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_667_167, 667000000, 166666667 },
19452d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_800_200, 800000000, 200000000 },
19552d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_480_160, 480000000, 160000000 },
19652d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_550_183, 550000000, 183333334 },
19752d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_525_175, 525000000, 175000000 },
19852d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_466_233, 466000000, 233000000 },
19952d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_500_250, 500000000, 250000000 },
20052d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_533_266, 533000000, 266000000 },
20152d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_600_300, 600000000, 300000000 },
20252d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_450_150, 450000000, 150000000 },
20352d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_533_178, 533000000, 178000000 },
20452d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_575_192, 575000000, 192000000 },
20552d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_700_175, 700000000, 175000000 },
20652d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_733_183, 733000000, 183333334 },
20752d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_750_187, 750000000, 187000000 },
20852d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_775_194, 775000000, 194000000 },
20952d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_500_125, 500000000, 125000000 },
21052d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_500_100, 500000000, 100000000 },
21152d286fbSkiyohara 		{ ORION_PMISMPL_ARMDDRCLK_600_150, 600000000, 150000000 },
21252d286fbSkiyohara 	};
21352d286fbSkiyohara 	uint32_t reg, armddrclk, tclk;
21452d286fbSkiyohara 	uint16_t model;
21552d286fbSkiyohara 	int armddrclk_shift, tclk_shift, i;
21652d286fbSkiyohara 
21752d286fbSkiyohara 	model = mvsoc_model();
21852d286fbSkiyohara 	if (model == MARVELL_ORION_1_88F1181 ||
21952d286fbSkiyohara 	    model == MARVELL_ORION_2_88F1281) {
22052d286fbSkiyohara 		armddrclk_shift = 6;
22152d286fbSkiyohara 		tclk_shift = 10;
22252d286fbSkiyohara 	} else {
22352d286fbSkiyohara 		armddrclk_shift = 4;
22452d286fbSkiyohara 		tclk_shift = 8;
22552d286fbSkiyohara 	}
22652d286fbSkiyohara 
227*7d0ac446Srin 	reg = le32toh(*(volatile uint32_t *)(iobase + ORION_PMI_BASE +
228*7d0ac446Srin 	    ORION_PMI_SAMPLE_AT_RESET));
22952d286fbSkiyohara 	armddrclk = (reg >> armddrclk_shift) & ORION_PMISMPL_ARMDDRCLK_MASK;
23052d286fbSkiyohara 	if (model == PCI_PRODUCT_MARVELL_88F5281)
23152d286fbSkiyohara 		if (reg & ORION_PMISMPL_ARMDDRCLK_H_MASK)
23252d286fbSkiyohara 			armddrclk |= 0x00000010;	/* set to bit4 */
2336b253b77Sjakllsch 	for (i = 0; i < __arraycount(sysclktbl); i++)
23452d286fbSkiyohara 		if (armddrclk == sysclktbl[i].armddrclkval) {
23552d286fbSkiyohara 			mvPclk = sysclktbl[i].pclk;
23652d286fbSkiyohara 			mvSysclk = sysclktbl[i].sysclk;
23752d286fbSkiyohara 			break;
23852d286fbSkiyohara 		}
23952d286fbSkiyohara 
24052d286fbSkiyohara 	tclk = (reg >> tclk_shift) & ORION_PMISMPL_TCLK_MASK;
24152d286fbSkiyohara 	switch (tclk) {
24252d286fbSkiyohara 	case ORION_PMISMPL_TCLK_133:
243c3764b14Sjakllsch 		mvTclk = 133333333;	/* 133MHz */
24452d286fbSkiyohara 		break;
24552d286fbSkiyohara 
24652d286fbSkiyohara 	case ORION_PMISMPL_TCLK_150:
24752d286fbSkiyohara 		mvTclk = 150000000;	/* 150MHz */
24852d286fbSkiyohara 		break;
24952d286fbSkiyohara 
25052d286fbSkiyohara 	case ORION_PMISMPL_TCLK_166:
25152d286fbSkiyohara 		mvTclk = 166666667;	/* 166MHz */
25252d286fbSkiyohara 		break;
25352d286fbSkiyohara 
25452d286fbSkiyohara 	default:
25552d286fbSkiyohara 		mvTclk = 100000000;	/* 100MHz */
25652d286fbSkiyohara 		break;
25752d286fbSkiyohara 	}
25852d286fbSkiyohara }
259