Home | History | Annotate | Line # | Download | only in marvell
armadaxp.c revision 1.6
      1 /*	$NetBSD: armadaxp.c,v 1.6 2013/12/23 04:12:09 kiyohara Exp $	*/
      2 /*******************************************************************************
      3 Copyright (C) Marvell International Ltd. and its affiliates
      4 
      5 Developed by Semihalf
      6 
      7 ********************************************************************************
      8 Marvell BSD License
      9 
     10 If you received this File from Marvell, you may opt to use, redistribute and/or
     11 modify this File under the following licensing terms.
     12 Redistribution and use in source and binary forms, with or without modification,
     13 are permitted provided that the following conditions are met:
     14 
     15     *   Redistributions of source code must retain the above copyright notice,
     16             this list of conditions and the following disclaimer.
     17 
     18     *   Redistributions in binary form must reproduce the above copyright
     19         notice, this list of conditions and the following disclaimer in the
     20         documentation and/or other materials provided with the distribution.
     21 
     22     *   Neither the name of Marvell nor the names of its contributors may be
     23         used to endorse or promote products derived from this software without
     24         specific prior written permission.
     25 
     26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     27 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     28 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     29 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
     30 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     31 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     32 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     33 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     34 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     35 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     36 
     37 *******************************************************************************/
     38 
     39 #include <sys/cdefs.h>
     40 __KERNEL_RCSID(0, "$NetBSD: armadaxp.c,v 1.6 2013/12/23 04:12:09 kiyohara Exp $");
     41 
     42 #define _INTR_PRIVATE
     43 
     44 #include "opt_mvsoc.h"
     45 
     46 #include <sys/param.h>
     47 #include <sys/bus.h>
     48 
     49 #include <machine/intr.h>
     50 
     51 #include <arm/pic/picvar.h>
     52 #include <arm/pic/picvar.h>
     53 
     54 #include <arm/armreg.h>
     55 #include <arm/cpu.h>
     56 #include <arm/cpufunc.h>
     57 
     58 #include <arm/marvell/mvsocreg.h>
     59 #include <arm/marvell/mvsocvar.h>
     60 #include <arm/marvell/armadaxpreg.h>
     61 
     62 #include <dev/marvell/marvellreg.h>
     63 
     64 #define EXTRACT_CPU_FREQ_FIELD(sar)	(((0x01 & (sar >> 52)) << 3) | \
     65 					    (0x07 & (sar >> 21)))
     66 #define EXTRACT_FAB_FREQ_FIELD(sar)	(((0x01 & (sar >> 51)) << 4) | \
     67 					    (0x0F & (sar >> 24)))
     68 
     69 #define	MPIC_WRITE(reg, val)		(bus_space_write_4(&mvsoc_bs_tag, \
     70 					    mpic_handle, reg, val))
     71 #define	MPIC_CPU_WRITE(reg, val)	(bus_space_write_4(&mvsoc_bs_tag, \
     72 					    mpic_cpu_handle, reg, val))
     73 
     74 #define	MPIC_READ(reg)			(bus_space_read_4(&mvsoc_bs_tag, \
     75 					    mpic_handle, reg))
     76 #define	MPIC_CPU_READ(reg)		(bus_space_read_4(&mvsoc_bs_tag, \
     77 					    mpic_cpu_handle, reg))
     78 
     79 #define	L2_WRITE(reg, val)		(bus_space_write_4(&mvsoc_bs_tag, \
     80 					    l2_handle, reg, val))
     81 #define	L2_READ(reg)			(bus_space_read_4(&mvsoc_bs_tag, \
     82 					    l2_handle, reg))
     83 bus_space_handle_t mpic_cpu_handle;
     84 static bus_space_handle_t mpic_handle, l2_handle;
     85 int l2cache_state = 0;
     86 int iocc_state = 0;
     87 #define read_miscreg(r)		(*(volatile uint32_t *)(misc_base + (r)))
     88 vaddr_t misc_base;
     89 
     90 extern void (*mvsoc_intr_init)(void);
     91 static void armadaxp_intr_init(void);
     92 
     93 static void armadaxp_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
     94 static void armadaxp_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
     95 static void armadaxp_pic_establish_irq(struct pic_softc *, struct intrsource *);
     96 static void armadaxp_pic_set_priority(struct pic_softc *, int);
     97 
     98 static int armadaxp_find_pending_irqs(void);
     99 static void armadaxp_pic_block_irq(struct pic_softc *, size_t);
    100 void armadaxp_io_coherency_init(void);
    101 int armadaxp_l2_init(bus_addr_t);
    102 
    103 struct vco_freq_ratio {
    104 	uint8_t	vco_cpu;	/* VCO to CLK0(CPU) clock ratio */
    105 	uint8_t	vco_l2c;	/* VCO to NB(L2 cache) clock ratio */
    106 	uint8_t	vco_hcl;	/* VCO to HCLK(DDR controller) clock ratio */
    107 	uint8_t	vco_ddr;	/* VCO to DR(DDR memory) clock ratio */
    108 };
    109 
    110 static struct vco_freq_ratio freq_conf_table[] = {
    111 /*00*/	{ 1, 1,	 4,  2 },
    112 /*01*/	{ 1, 2,	 2,  2 },
    113 /*02*/	{ 2, 2,	 6,  3 },
    114 /*03*/	{ 2, 2,	 3,  3 },
    115 /*04*/	{ 1, 2,	 3,  3 },
    116 /*05*/	{ 1, 2,	 4,  2 },
    117 /*06*/	{ 1, 1,	 2,  2 },
    118 /*07*/	{ 2, 3,	 6,  6 },
    119 /*08*/	{ 2, 3,	 5,  5 },
    120 /*09*/	{ 1, 2,	 6,  3 },
    121 /*10*/	{ 2, 4,	10,  5 },
    122 /*11*/	{ 1, 3,	 6,  6 },
    123 /*12*/	{ 1, 2,	 5,  5 },
    124 /*13*/	{ 1, 3,	 6,  3 },
    125 /*14*/	{ 1, 2,	 5,  5 },
    126 /*15*/	{ 2, 2,	 5,  5 },
    127 /*16*/	{ 1, 1,	 3,  3 },
    128 /*17*/	{ 2, 5,	10, 10 },
    129 /*18*/	{ 1, 3,	 8,  4 },
    130 /*19*/	{ 1, 1,	 2,  1 },
    131 /*20*/	{ 2, 3,	 6,  3 },
    132 /*21*/	{ 1, 2,	 8,  4 },
    133 /*22*/	{ 2, 5,	10,  5 }
    134 };
    135 
    136 static uint16_t	cpu_clock_table[] = {
    137     1000, 1066, 1200, 1333, 1500, 1666, 1800, 2000, 600,  667,  800,  1600,
    138     2133, 2200, 2400 };
    139 
    140 static struct pic_ops armadaxp_picops = {
    141 	.pic_unblock_irqs = armadaxp_pic_unblock_irqs,
    142 	.pic_block_irqs = armadaxp_pic_block_irqs,
    143 	.pic_establish_irq = armadaxp_pic_establish_irq,
    144 	.pic_set_priority = armadaxp_pic_set_priority,
    145 };
    146 
    147 static struct pic_softc armadaxp_pic = {
    148 	.pic_ops = &armadaxp_picops,
    149 	.pic_name = "armadaxp",
    150 };
    151 
    152 static struct {
    153 	bus_size_t offset;
    154 	uint32_t bits;
    155 } clkgatings[]= {
    156 	{ ARMADAXP_GBE3_BASE,	(1 << 1) },
    157 	{ ARMADAXP_GBE2_BASE,	(1 << 2) },
    158 	{ ARMADAXP_GBE1_BASE,	(1 << 3) },
    159 	{ ARMADAXP_GBE0_BASE,	(1 << 4) },
    160 	{ MVSOC_PEX_BASE,	(1 << 5) },
    161 	{ ARMADAXP_PEX01_BASE,	(1 << 6) },
    162 	{ ARMADAXP_PEX02_BASE,	(1 << 7) },
    163 	{ ARMADAXP_PEX03_BASE,	(1 << 8) },
    164 	{ ARMADAXP_PEX10_BASE,	(1 << 9) },
    165 	{ ARMADAXP_PEX11_BASE,	(1 << 10) },
    166 	{ ARMADAXP_PEX12_BASE,	(1 << 11) },
    167 	{ ARMADAXP_PEX13_BASE,	(1 << 12) },
    168 #if 0
    169 	{ NetA, (1 << 13) },
    170 #endif
    171 	{ ARMADAXP_SATAHC_BASE,	(1 << 14) | (1 << 15) | (1 << 29) | (1 << 30) },
    172 	{ ARMADAXP_LCD_BASE,	(1 << 16) },
    173 	{ ARMADAXP_SDIO_BASE,	(1 << 17) },
    174 	{ ARMADAXP_USB1_BASE,	(1 << 19) },
    175 	{ ARMADAXP_USB2_BASE,	(1 << 20) },
    176 	{ ARMADAXP_PEX2_BASE,	(1 << 26) },
    177 	{ ARMADAXP_PEX3_BASE,	(1 << 27) },
    178 #if 0
    179 	{ DDR, (1 << 28) },
    180 #endif
    181 };
    182 
    183 /*
    184  * armadaxp_intr_bootstrap:
    185  *
    186  *	Initialize the rest of the interrupt subsystem, making it
    187  *	ready to handle interrupts from devices.
    188  */
    189 void
    190 armadaxp_intr_bootstrap(bus_addr_t pbase)
    191 {
    192 	int i;
    193 
    194 	/* Map MPIC base and MPIC percpu base registers */
    195 	if (bus_space_map(&mvsoc_bs_tag, pbase + ARMADAXP_MLMB_MPIC_BASE,
    196 	    0x500, 0, &mpic_handle) != 0)
    197 		panic("%s: Could not map MPIC registers", __func__);
    198 	if (bus_space_map(&mvsoc_bs_tag, pbase + ARMADAXP_MLMB_MPIC_CPU_BASE,
    199 	    0x800, 0, &mpic_cpu_handle) != 0)
    200 		panic("%s: Could not map MPIC percpu registers", __func__);
    201 
    202 	/* Disable all interrupts */
    203 	for (i = 0; i < 116; i++)
    204 		MPIC_WRITE(ARMADAXP_MLMB_MPIC_ICE, i);
    205 
    206 	mvsoc_intr_init = armadaxp_intr_init;
    207 }
    208 
    209 static void
    210 armadaxp_intr_init(void)
    211 {
    212 	int ctrl;
    213 
    214 	/* Get max interrupts */
    215 	armadaxp_pic.pic_maxsources =
    216 	    ((MPIC_READ(ARMADAXP_MLMB_MPIC_CTRL) >> 2) & 0x7FF);
    217 
    218 	if (!armadaxp_pic.pic_maxsources)
    219 		armadaxp_pic.pic_maxsources = 116;
    220 
    221 	pic_add(&armadaxp_pic, 0);
    222 
    223 	ctrl = MPIC_READ(ARMADAXP_MLMB_MPIC_CTRL);
    224 	/* Enable IRQ prioritization */
    225 	ctrl |= (1 << 0);
    226 	MPIC_WRITE(ARMADAXP_MLMB_MPIC_CTRL, ctrl);
    227 
    228 	find_pending_irqs = armadaxp_find_pending_irqs;
    229 }
    230 
    231 static void
    232 armadaxp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    233     uint32_t irq_mask)
    234 {
    235 	int n;
    236 
    237 	while (irq_mask != 0) {
    238 		n = ffs(irq_mask) - 1;
    239 		KASSERT(pic->pic_maxsources >= n + irqbase);
    240 		MPIC_WRITE(ARMADAXP_MLMB_MPIC_ISE, n + irqbase);
    241 		MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_ICM, n + irqbase);
    242 		if ((n + irqbase) == 0)
    243 			MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_DOORBELL_MASK,
    244 			    0xffffffff);
    245 		irq_mask &= ~__BIT(n);
    246 	}
    247 }
    248 
    249 static void
    250 armadaxp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    251     uint32_t irq_mask)
    252 {
    253 	int n;
    254 
    255 	while (irq_mask != 0) {
    256 		n = ffs(irq_mask) - 1;
    257 		KASSERT(pic->pic_maxsources >= n + irqbase);
    258 		MPIC_WRITE(ARMADAXP_MLMB_MPIC_ICE, n + irqbase);
    259 		MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_ISM, n + irqbase);
    260 		irq_mask &= ~__BIT(n);
    261 	}
    262 }
    263 
    264 static void
    265 armadaxp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    266 {
    267 	int tmp;
    268 	KASSERT(pic->pic_maxsources >= is->is_irq);
    269 	tmp = MPIC_READ(ARMADAXP_MLMB_MPIC_ISCR_BASE + is->is_irq * 4);
    270 	/* Clear previous priority */
    271 	tmp &= ~(0xf << MPIC_ISCR_SHIFT);
    272 	MPIC_WRITE(ARMADAXP_MLMB_MPIC_ISCR_BASE + is->is_irq * 4,
    273 	    tmp | (is->is_ipl << MPIC_ISCR_SHIFT));
    274 }
    275 
    276 static void
    277 armadaxp_pic_set_priority(struct pic_softc *pic, int ipl)
    278 {
    279 	int ctp;
    280 
    281 	ctp = MPIC_CPU_READ(ARMADAXP_MLMB_MPIC_CTP);
    282 	ctp &= ~(0xf << MPIC_CTP_SHIFT);
    283 	ctp |= (ipl << MPIC_CTP_SHIFT);
    284 	MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_CTP, ctp);
    285 }
    286 
    287 static int
    288 armadaxp_find_pending_irqs(void)
    289 {
    290 	struct intrsource *is;
    291 	int irq;
    292 
    293 	irq = MPIC_CPU_READ(ARMADAXP_MLMB_MPIC_IIACK) & 0x3ff;
    294 
    295 	/* Is it a spurious interrupt ?*/
    296 	if (irq == 0x3ff)
    297 		return 0;
    298 	is = armadaxp_pic.pic_sources[irq];
    299 	if (is == NULL) {
    300 		printf("stray interrupt: %d\n", irq);
    301 		return 0;
    302 	}
    303 
    304 	armadaxp_pic_block_irq(&armadaxp_pic, irq);
    305 	pic_mark_pending(&armadaxp_pic, irq);
    306 
    307 	return is->is_ipl;
    308 }
    309 
    310 static void
    311 armadaxp_pic_block_irq(struct pic_softc *pic, size_t irq)
    312 {
    313 
    314 	KASSERT(pic->pic_maxsources >= irq);
    315 	MPIC_WRITE(ARMADAXP_MLMB_MPIC_ICE, irq);
    316 	MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_ISM, irq);
    317 }
    318 
    319 /*
    320  * Clock functions
    321  */
    322 
    323 void
    324 armadaxp_getclks(void)
    325 {
    326 	uint64_t sar_reg;
    327 	uint8_t  sar_cpu_freq, sar_fab_freq, array_size;
    328 
    329 	if (cputype == CPU_ID_MV88SV584X_V7)
    330 		mvTclk = 250000000; /* 250 MHz */
    331 	else
    332 		mvTclk = 200000000; /* 200 MHz */
    333 
    334 	sar_reg = (read_miscreg(ARMADAXP_MISC_SAR_HI) << 31) |
    335 	    read_miscreg(ARMADAXP_MISC_SAR_LO);
    336 
    337 	sar_cpu_freq = EXTRACT_CPU_FREQ_FIELD(sar_reg);
    338 	sar_fab_freq = EXTRACT_FAB_FREQ_FIELD(sar_reg);
    339 
    340 	/* Check if CPU frequency field has correct value */
    341 	array_size = sizeof(cpu_clock_table) / sizeof(cpu_clock_table[0]);
    342 	if (sar_cpu_freq >= array_size)
    343 		panic("Reserved value in cpu frequency configuration field: "
    344 		    "%d", sar_cpu_freq);
    345 
    346 	/* Check if fabric frequency field has correct value */
    347 	array_size = sizeof(freq_conf_table) / sizeof(freq_conf_table[0]);
    348 	if (sar_fab_freq >= array_size)
    349 		panic("Reserved value in fabric frequency configuration field: "
    350 		    "%d", sar_fab_freq);
    351 
    352 	/* Get CPU clock frequency */
    353 	mvPclk = cpu_clock_table[sar_cpu_freq] *
    354 	    freq_conf_table[sar_fab_freq].vco_cpu;
    355 
    356 	/* Get L2CLK clock frequency and use as system clock (mvSysclk) */
    357 	mvSysclk = mvPclk / freq_conf_table[sar_fab_freq].vco_l2c;
    358 
    359 	/* Round mvSysclk value to integer MHz */
    360 	if (((mvPclk % freq_conf_table[sar_fab_freq].vco_l2c) * 10 /
    361 	    freq_conf_table[sar_fab_freq].vco_l2c) >= 5)
    362 		mvSysclk++;
    363 
    364 	mvPclk = mvPclk * 1000000;
    365 	mvSysclk = mvSysclk * 1000000;
    366 }
    367 
    368 /*
    369  * L2 Cache initialization
    370  */
    371 
    372 int
    373 armadaxp_l2_init(bus_addr_t pbase)
    374 {
    375 	u_int32_t reg;
    376 	int ret;
    377 
    378 	/* Map L2 space */
    379 	ret = bus_space_map(&mvsoc_bs_tag, pbase + ARMADAXP_L2_BASE,
    380 	    0x1000, 0, &l2_handle);
    381 	if (ret) {
    382 		printf("%s: Cannot map L2 register space, ret:%d\n",
    383 		    __func__, ret);
    384 		return (-1);
    385 	}
    386 
    387 	/* Set L2 policy */
    388 	reg = L2_READ(ARMADAXP_L2_AUX_CTRL);
    389 	reg &= ~(L2_WBWT_MODE_MASK);
    390 	reg &= ~(L2_REP_STRAT_MASK);
    391 	reg |= L2_REP_STRAT_SEMIPLRU;
    392 	L2_WRITE(ARMADAXP_L2_AUX_CTRL, reg);
    393 
    394 	/* Invalidate L2 cache */
    395 	L2_WRITE(ARMADAXP_L2_INV_WAY, L2_ALL_WAYS);
    396 
    397 	/* Clear pending L2 interrupts */
    398 	L2_WRITE(ARMADAXP_L2_INT_CAUSE, 0x1ff);
    399 
    400 	/* Enable Cache and TLB maintenance broadcast */
    401 	__asm__ __volatile__ ("mrc p15, 1, %0, c15, c2, 0" : "=r"(reg));
    402 	reg |= (1 << 8);
    403 	__asm__ __volatile__ ("mcr p15, 1, %0, c15, c2, 0" : :"r"(reg));
    404 
    405 	/*
    406 	 * Set the Point of Coherency and Point of Unification to DRAM.
    407 	 * This is a reset value but anyway, configure this just in case.
    408 	 */
    409 	reg = read_mlmbreg(ARMADAXP_L2_CFU);
    410 	reg |= (1 << 17) | (1 << 18);
    411 	write_mlmbreg(ARMADAXP_L2_CFU, reg);
    412 
    413 	/* Enable L2 cache */
    414 	reg = L2_READ(ARMADAXP_L2_CTRL);
    415 	L2_WRITE(ARMADAXP_L2_CTRL, reg | L2_ENABLE);
    416 
    417 	/* Mark as enabled */
    418 	l2cache_state = 1;
    419 
    420 #ifdef DEBUG
    421 	/* Configure and enable counter */
    422 	L2_WRITE(ARMADAXP_L2_CNTR_CONF(0), 0xf0000 | (4 << 2));
    423 	L2_WRITE(ARMADAXP_L2_CNTR_CONF(1), 0xf0000 | (2 << 2));
    424 	L2_WRITE(ARMADAXP_L2_CNTR_CTRL, 0x303);
    425 #endif
    426 
    427 	return (0);
    428 }
    429 
    430 void
    431 armadaxp_io_coherency_init(void)
    432 {
    433 	uint32_t reg;
    434 
    435 	/* set CIB read snoop command to ReadUnique */
    436 	reg = read_mlmbreg(MVSOC_MLMB_CIB_CTRL_CFG);
    437 	reg &= ~(7 << 16);
    438 	reg |= (7 << 16);
    439 	write_mlmbreg(MVSOC_MLMB_CIB_CTRL_CFG, reg);
    440 	/* enable CPUs in SMP group on Fabric coherency */
    441 	reg = read_mlmbreg(MVSOC_MLMB_COHERENCY_FABRIC_CTRL);
    442 	reg &= ~(0x3 << 24);
    443 	reg |= (1 << 24);
    444 	write_mlmbreg(MVSOC_MLMB_COHERENCY_FABRIC_CTRL, reg);
    445 
    446 	reg = read_mlmbreg(MVSOC_MLMB_COHERENCY_FABRIC_CFG);
    447 	reg &= ~(0x3 << 24);
    448 	reg |= (1 << 24);
    449 	write_mlmbreg(MVSOC_MLMB_COHERENCY_FABRIC_CFG, reg);
    450 
    451 	/* Mark as enabled */
    452 	iocc_state = 1;
    453 }
    454 
    455 int
    456 armadaxp_clkgating(struct marvell_attach_args *mva)
    457 {
    458 	uint32_t val;
    459 	int i;
    460 
    461 	for (i = 0; i < __arraycount(clkgatings); i++) {
    462 		if (clkgatings[i].offset == mva->mva_offset) {
    463 			val = read_miscreg(ARMADAXP_MISC_PMCGC);
    464 			if ((val & clkgatings[i].bits) == clkgatings[i].bits)
    465 				/* Clock enabled */
    466 				return 0;
    467 			return 1;
    468 		}
    469 	}
    470 	/* Clock Gating not support */
    471 	return 0;
    472 }
    473