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