Home | History | Annotate | Line # | Download | only in marvell
armadaxp.c revision 1.5
      1 /*	$NetBSD: armadaxp.c,v 1.5 2013/12/23 03:19:43 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.5 2013/12/23 03:19:43 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 /*
    153  * armadaxp_intr_bootstrap:
    154  *
    155  *	Initialize the rest of the interrupt subsystem, making it
    156  *	ready to handle interrupts from devices.
    157  */
    158 void
    159 armadaxp_intr_bootstrap(bus_addr_t pbase)
    160 {
    161 	int i;
    162 
    163 	/* Map MPIC base and MPIC percpu base registers */
    164 	if (bus_space_map(&mvsoc_bs_tag, pbase + ARMADAXP_MLMB_MPIC_BASE,
    165 	    0x500, 0, &mpic_handle) != 0)
    166 		panic("%s: Could not map MPIC registers", __func__);
    167 	if (bus_space_map(&mvsoc_bs_tag, pbase + ARMADAXP_MLMB_MPIC_CPU_BASE,
    168 	    0x800, 0, &mpic_cpu_handle) != 0)
    169 		panic("%s: Could not map MPIC percpu registers", __func__);
    170 
    171 	/* Disable all interrupts */
    172 	for (i = 0; i < 116; i++)
    173 		MPIC_WRITE(ARMADAXP_MLMB_MPIC_ICE, i);
    174 
    175 	mvsoc_intr_init = armadaxp_intr_init;
    176 }
    177 
    178 static void
    179 armadaxp_intr_init(void)
    180 {
    181 	int ctrl;
    182 
    183 	/* Get max interrupts */
    184 	armadaxp_pic.pic_maxsources =
    185 	    ((MPIC_READ(ARMADAXP_MLMB_MPIC_CTRL) >> 2) & 0x7FF);
    186 
    187 	if (!armadaxp_pic.pic_maxsources)
    188 		armadaxp_pic.pic_maxsources = 116;
    189 
    190 	pic_add(&armadaxp_pic, 0);
    191 
    192 	ctrl = MPIC_READ(ARMADAXP_MLMB_MPIC_CTRL);
    193 	/* Enable IRQ prioritization */
    194 	ctrl |= (1 << 0);
    195 	MPIC_WRITE(ARMADAXP_MLMB_MPIC_CTRL, ctrl);
    196 
    197 	find_pending_irqs = armadaxp_find_pending_irqs;
    198 }
    199 
    200 static void
    201 armadaxp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    202     uint32_t irq_mask)
    203 {
    204 	int n;
    205 
    206 	while (irq_mask != 0) {
    207 		n = ffs(irq_mask) - 1;
    208 		KASSERT(pic->pic_maxsources >= n + irqbase);
    209 		MPIC_WRITE(ARMADAXP_MLMB_MPIC_ISE, n + irqbase);
    210 		MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_ICM, n + irqbase);
    211 		if ((n + irqbase) == 0)
    212 			MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_DOORBELL_MASK,
    213 			    0xffffffff);
    214 		irq_mask &= ~__BIT(n);
    215 	}
    216 }
    217 
    218 static void
    219 armadaxp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    220     uint32_t irq_mask)
    221 {
    222 	int n;
    223 
    224 	while (irq_mask != 0) {
    225 		n = ffs(irq_mask) - 1;
    226 		KASSERT(pic->pic_maxsources >= n + irqbase);
    227 		MPIC_WRITE(ARMADAXP_MLMB_MPIC_ICE, n + irqbase);
    228 		MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_ISM, n + irqbase);
    229 		irq_mask &= ~__BIT(n);
    230 	}
    231 }
    232 
    233 static void
    234 armadaxp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    235 {
    236 	int tmp;
    237 	KASSERT(pic->pic_maxsources >= is->is_irq);
    238 	tmp = MPIC_READ(ARMADAXP_MLMB_MPIC_ISCR_BASE + is->is_irq * 4);
    239 	/* Clear previous priority */
    240 	tmp &= ~(0xf << MPIC_ISCR_SHIFT);
    241 	MPIC_WRITE(ARMADAXP_MLMB_MPIC_ISCR_BASE + is->is_irq * 4,
    242 	    tmp | (is->is_ipl << MPIC_ISCR_SHIFT));
    243 }
    244 
    245 static void
    246 armadaxp_pic_set_priority(struct pic_softc *pic, int ipl)
    247 {
    248 	int ctp;
    249 
    250 	ctp = MPIC_CPU_READ(ARMADAXP_MLMB_MPIC_CTP);
    251 	ctp &= ~(0xf << MPIC_CTP_SHIFT);
    252 	ctp |= (ipl << MPIC_CTP_SHIFT);
    253 	MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_CTP, ctp);
    254 }
    255 
    256 static int
    257 armadaxp_find_pending_irqs(void)
    258 {
    259 	struct intrsource *is;
    260 	int irq;
    261 
    262 	irq = MPIC_CPU_READ(ARMADAXP_MLMB_MPIC_IIACK) & 0x3ff;
    263 
    264 	/* Is it a spurious interrupt ?*/
    265 	if (irq == 0x3ff)
    266 		return 0;
    267 	is = armadaxp_pic.pic_sources[irq];
    268 	if (is == NULL) {
    269 		printf("stray interrupt: %d\n", irq);
    270 		return 0;
    271 	}
    272 
    273 	armadaxp_pic_block_irq(&armadaxp_pic, irq);
    274 	pic_mark_pending(&armadaxp_pic, irq);
    275 
    276 	return is->is_ipl;
    277 }
    278 
    279 static void
    280 armadaxp_pic_block_irq(struct pic_softc *pic, size_t irq)
    281 {
    282 
    283 	KASSERT(pic->pic_maxsources >= irq);
    284 	MPIC_WRITE(ARMADAXP_MLMB_MPIC_ICE, irq);
    285 	MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_ISM, irq);
    286 }
    287 
    288 /*
    289  * Clock functions
    290  */
    291 
    292 void
    293 armadaxp_getclks(void)
    294 {
    295 	uint64_t sar_reg;
    296 	uint8_t  sar_cpu_freq, sar_fab_freq, array_size;
    297 
    298 	if (cputype == CPU_ID_MV88SV584X_V7)
    299 		mvTclk = 250000000; /* 250 MHz */
    300 	else
    301 		mvTclk = 200000000; /* 200 MHz */
    302 
    303 	sar_reg = (read_miscreg(ARMADAXP_MISC_SAR_HI) << 31) |
    304 	    read_miscreg(ARMADAXP_MISC_SAR_LO);
    305 
    306 	sar_cpu_freq = EXTRACT_CPU_FREQ_FIELD(sar_reg);
    307 	sar_fab_freq = EXTRACT_FAB_FREQ_FIELD(sar_reg);
    308 
    309 	/* Check if CPU frequency field has correct value */
    310 	array_size = sizeof(cpu_clock_table) / sizeof(cpu_clock_table[0]);
    311 	if (sar_cpu_freq >= array_size)
    312 		panic("Reserved value in cpu frequency configuration field: "
    313 		    "%d", sar_cpu_freq);
    314 
    315 	/* Check if fabric frequency field has correct value */
    316 	array_size = sizeof(freq_conf_table) / sizeof(freq_conf_table[0]);
    317 	if (sar_fab_freq >= array_size)
    318 		panic("Reserved value in fabric frequency configuration field: "
    319 		    "%d", sar_fab_freq);
    320 
    321 	/* Get CPU clock frequency */
    322 	mvPclk = cpu_clock_table[sar_cpu_freq] *
    323 	    freq_conf_table[sar_fab_freq].vco_cpu;
    324 
    325 	/* Get L2CLK clock frequency and use as system clock (mvSysclk) */
    326 	mvSysclk = mvPclk / freq_conf_table[sar_fab_freq].vco_l2c;
    327 
    328 	/* Round mvSysclk value to integer MHz */
    329 	if (((mvPclk % freq_conf_table[sar_fab_freq].vco_l2c) * 10 /
    330 	    freq_conf_table[sar_fab_freq].vco_l2c) >= 5)
    331 		mvSysclk++;
    332 
    333 	mvPclk = mvPclk * 1000000;
    334 	mvSysclk = mvSysclk * 1000000;
    335 }
    336 
    337 /*
    338  * L2 Cache initialization
    339  */
    340 
    341 int
    342 armadaxp_l2_init(bus_addr_t pbase)
    343 {
    344 	u_int32_t reg;
    345 	int ret;
    346 
    347 	/* Map L2 space */
    348 	ret = bus_space_map(&mvsoc_bs_tag, pbase + ARMADAXP_L2_BASE,
    349 	    0x1000, 0, &l2_handle);
    350 	if (ret) {
    351 		printf("%s: Cannot map L2 register space, ret:%d\n",
    352 		    __func__, ret);
    353 		return (-1);
    354 	}
    355 
    356 	/* Set L2 policy */
    357 	reg = L2_READ(ARMADAXP_L2_AUX_CTRL);
    358 	reg &= ~(L2_WBWT_MODE_MASK);
    359 	reg &= ~(L2_REP_STRAT_MASK);
    360 	reg |= L2_REP_STRAT_SEMIPLRU;
    361 	L2_WRITE(ARMADAXP_L2_AUX_CTRL, reg);
    362 
    363 	/* Invalidate L2 cache */
    364 	L2_WRITE(ARMADAXP_L2_INV_WAY, L2_ALL_WAYS);
    365 
    366 	/* Clear pending L2 interrupts */
    367 	L2_WRITE(ARMADAXP_L2_INT_CAUSE, 0x1ff);
    368 
    369 	/* Enable Cache and TLB maintenance broadcast */
    370 	__asm__ __volatile__ ("mrc p15, 1, %0, c15, c2, 0" : "=r"(reg));
    371 	reg |= (1 << 8);
    372 	__asm__ __volatile__ ("mcr p15, 1, %0, c15, c2, 0" : :"r"(reg));
    373 
    374 	/*
    375 	 * Set the Point of Coherency and Point of Unification to DRAM.
    376 	 * This is a reset value but anyway, configure this just in case.
    377 	 */
    378 	reg = read_mlmbreg(ARMADAXP_L2_CFU);
    379 	reg |= (1 << 17) | (1 << 18);
    380 	write_mlmbreg(ARMADAXP_L2_CFU, reg);
    381 
    382 	/* Enable L2 cache */
    383 	reg = L2_READ(ARMADAXP_L2_CTRL);
    384 	L2_WRITE(ARMADAXP_L2_CTRL, reg | L2_ENABLE);
    385 
    386 	/* Mark as enabled */
    387 	l2cache_state = 1;
    388 
    389 #ifdef DEBUG
    390 	/* Configure and enable counter */
    391 	L2_WRITE(ARMADAXP_L2_CNTR_CONF(0), 0xf0000 | (4 << 2));
    392 	L2_WRITE(ARMADAXP_L2_CNTR_CONF(1), 0xf0000 | (2 << 2));
    393 	L2_WRITE(ARMADAXP_L2_CNTR_CTRL, 0x303);
    394 #endif
    395 
    396 	return (0);
    397 }
    398 
    399 void
    400 armadaxp_io_coherency_init(void)
    401 {
    402 	uint32_t reg;
    403 
    404 	/* set CIB read snoop command to ReadUnique */
    405 	reg = read_mlmbreg(MVSOC_MLMB_CIB_CTRL_CFG);
    406 	reg &= ~(7 << 16);
    407 	reg |= (7 << 16);
    408 	write_mlmbreg(MVSOC_MLMB_CIB_CTRL_CFG, reg);
    409 	/* enable CPUs in SMP group on Fabric coherency */
    410 	reg = read_mlmbreg(MVSOC_MLMB_COHERENCY_FABRIC_CTRL);
    411 	reg &= ~(0x3 << 24);
    412 	reg |= (1 << 24);
    413 	write_mlmbreg(MVSOC_MLMB_COHERENCY_FABRIC_CTRL, reg);
    414 
    415 	reg = read_mlmbreg(MVSOC_MLMB_COHERENCY_FABRIC_CFG);
    416 	reg &= ~(0x3 << 24);
    417 	reg |= (1 << 24);
    418 	write_mlmbreg(MVSOC_MLMB_COHERENCY_FABRIC_CFG, reg);
    419 
    420 	/* Mark as enabled */
    421 	iocc_state = 1;
    422 }
    423