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