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