示例#1
0
文件: cache.c 项目: srgmzk/linux
/*
 * Read the Cache Build Confuration Registers, Decode them and save into
 * the cpuinfo structure for later use.
 * No Validation done here, simply read/convert the BCRs
 */
static void read_decode_cache_bcr_arcv2(int cpu)
{
	struct cpuinfo_arc_cache *p_slc = &cpuinfo_arc700[cpu].slc;
	struct bcr_generic sbcr;

	struct bcr_slc_cfg {
#ifdef CONFIG_CPU_BIG_ENDIAN
		unsigned int pad:24, way:2, lsz:2, sz:4;
#else
		unsigned int sz:4, lsz:2, way:2, pad:24;
#endif
	} slc_cfg;

	struct bcr_clust_cfg {
#ifdef CONFIG_CPU_BIG_ENDIAN
		unsigned int pad:7, c:1, num_entries:8, num_cores:8, ver:8;
#else
		unsigned int ver:8, num_cores:8, num_entries:8, c:1, pad:7;
#endif
	} cbcr;

	READ_BCR(ARC_REG_SLC_BCR, sbcr);
	if (sbcr.ver) {
		READ_BCR(ARC_REG_SLC_CFG, slc_cfg);
		p_slc->ver = sbcr.ver;
		p_slc->sz_k = 128 << slc_cfg.sz;
		l2_line_sz = p_slc->line_len = (slc_cfg.lsz == 0) ? 128 : 64;
	}

	READ_BCR(ARC_REG_CLUSTER_BCR, cbcr);
	if (cbcr.c && ioc_enable)
		ioc_exists = 1;
}
示例#2
0
文件: cache_arc700.c 项目: 3CTO/linux
/*
 * Read the Cache Build Confuration Registers, Decode them and save into
 * the cpuinfo structure for later use.
 * No Validation done here, simply read/convert the BCRs
 */
void read_decode_cache_bcr(void)
{
	struct cpuinfo_arc_cache *p_ic, *p_dc;
	unsigned int cpu = smp_processor_id();
	struct bcr_cache {
#ifdef CONFIG_CPU_BIG_ENDIAN
		unsigned int pad:12, line_len:4, sz:4, config:4, ver:8;
#else
		unsigned int ver:8, config:4, sz:4, line_len:4, pad:12;
#endif
	} ibcr, dbcr;

	p_ic = &cpuinfo_arc700[cpu].icache;
	READ_BCR(ARC_REG_IC_BCR, ibcr);

	BUG_ON(ibcr.config != 3);
	p_ic->assoc = 2;		/* Fixed to 2w set assoc */
	p_ic->line_len = 8 << ibcr.line_len;
	p_ic->sz = 0x200 << ibcr.sz;
	p_ic->ver = ibcr.ver;

	p_dc = &cpuinfo_arc700[cpu].dcache;
	READ_BCR(ARC_REG_DC_BCR, dbcr);

	BUG_ON(dbcr.config != 2);
	p_dc->assoc = 4;		/* Fixed to 4w set assoc */
	p_dc->line_len = 16 << dbcr.line_len;
	p_dc->sz = 0x200 << dbcr.sz;
	p_dc->ver = dbcr.ver;
}
示例#3
0
文件: cache.c 项目: srgmzk/linux
void read_decode_cache_bcr(void)
{
	struct cpuinfo_arc_cache *p_ic, *p_dc;
	unsigned int cpu = smp_processor_id();
	struct bcr_cache {
#ifdef CONFIG_CPU_BIG_ENDIAN
		unsigned int pad:12, line_len:4, sz:4, config:4, ver:8;
#else
		unsigned int ver:8, config:4, sz:4, line_len:4, pad:12;
#endif
	} ibcr, dbcr;

	p_ic = &cpuinfo_arc700[cpu].icache;
	READ_BCR(ARC_REG_IC_BCR, ibcr);

	if (!ibcr.ver)
		goto dc_chk;

	if (ibcr.ver <= 3) {
		BUG_ON(ibcr.config != 3);
		p_ic->assoc = 2;		/* Fixed to 2w set assoc */
	} else if (ibcr.ver >= 4) {
		p_ic->assoc = 1 << ibcr.config;	/* 1,2,4,8 */
	}

	p_ic->line_len = 8 << ibcr.line_len;
	p_ic->sz_k = 1 << (ibcr.sz - 1);
	p_ic->ver = ibcr.ver;
	p_ic->vipt = 1;
	p_ic->alias = p_ic->sz_k/p_ic->assoc/TO_KB(PAGE_SIZE) > 1;

dc_chk:
	p_dc = &cpuinfo_arc700[cpu].dcache;
	READ_BCR(ARC_REG_DC_BCR, dbcr);

	if (!dbcr.ver)
		goto slc_chk;

	if (dbcr.ver <= 3) {
		BUG_ON(dbcr.config != 2);
		p_dc->assoc = 4;		/* Fixed to 4w set assoc */
		p_dc->vipt = 1;
		p_dc->alias = p_dc->sz_k/p_dc->assoc/TO_KB(PAGE_SIZE) > 1;
	} else if (dbcr.ver >= 4) {
		p_dc->assoc = 1 << dbcr.config;	/* 1,2,4,8 */
		p_dc->vipt = 0;
		p_dc->alias = 0;		/* PIPT so can't VIPT alias */
	}

	p_dc->line_len = 16 << dbcr.line_len;
	p_dc->sz_k = 1 << (dbcr.sz - 1);
	p_dc->ver = dbcr.ver;

slc_chk:
	if (is_isa_arcv2())
                read_decode_cache_bcr_arcv2(cpu);
}
示例#4
0
static char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
{
	int n = 0;
	struct cpuinfo_arc *cpu = &cpuinfo_arc700[cpu_id];

	FIX_PTR(cpu);

	n += scnprintf(buf + n, len - n, "Vector Table\t: %#x\n", cpu->vec_base);

	if (cpu->extn.fpu_sp || cpu->extn.fpu_dp)
		n += scnprintf(buf + n, len - n, "FPU\t\t: %s%s\n",
			       IS_AVAIL1(cpu->extn.fpu_sp, "SP "),
			       IS_AVAIL1(cpu->extn.fpu_dp, "DP "));

	if (cpu->extn.ap_num | cpu->extn.smart | cpu->extn.rtt) {
		n += scnprintf(buf + n, len - n, "DEBUG\t\t: %s%s",
			       IS_AVAIL1(cpu->extn.smart, "smaRT "),
			       IS_AVAIL1(cpu->extn.rtt, "RTT "));
		if (cpu->extn.ap_num) {
			n += scnprintf(buf + n, len - n, "ActionPoint %d/%s",
				       cpu->extn.ap_num,
				       cpu->extn.ap_full ? "full":"min");
		}
		n += scnprintf(buf + n, len - n, "\n");
	}

	if (cpu->dccm.sz || cpu->iccm.sz)
		n += scnprintf(buf + n, len - n, "Extn [CCM]\t: DCCM @ %x, %d KB / ICCM: @ %x, %d KB\n",
			       cpu->dccm.base_addr, TO_KB(cpu->dccm.sz),
			       cpu->iccm.base_addr, TO_KB(cpu->iccm.sz));

	if (is_isa_arcv2()) {

		/* Error Protection: ECC/Parity */
		struct bcr_erp erp;
		READ_BCR(ARC_REG_ERP_BUILD, erp);

		if (erp.ver) {
			struct  ctl_erp ctl;
			READ_BCR(ARC_REG_ERP_CTRL, ctl);

			/* inverted bits: 0 means enabled */
			n += scnprintf(buf + n, len - n, "Extn [ECC]\t: %s%s%s%s%s%s\n",
				IS_AVAIL3(erp.ic,  !ctl.dpi, "IC "),
				IS_AVAIL3(erp.dc,  !ctl.dpd, "DC "),
				IS_AVAIL3(erp.mmu, !ctl.mpd, "MMU "));
		}
	}

	n += scnprintf(buf + n, len - n, "OS ABI [v%d]\t: %s\n",
			EF_ARC_OSABI_CURRENT >> 8,
			EF_ARC_OSABI_CURRENT == EF_ARC_OSABI_V3 ?
			"no-legacy-syscalls" : "64-bit data any register aligned");

	return buf;
}
示例#5
0
文件: arc_timer.c 项目: dznm/linux
static int __init arc_cs_setup_rtc(struct device_node *node)
{
	struct bcr_timer timer;
	int ret;

	READ_BCR(ARC_REG_TIMERS_BCR, timer);
	if (!timer.rtc) {
		pr_warn("Local-64-bit-Ctr clocksource not detected");
		return -ENXIO;
	}

	/* Local to CPU hence not usable in SMP */
	if (IS_ENABLED(CONFIG_SMP)) {
		pr_warn("Local-64-bit-Ctr not usable in SMP");
		return -EINVAL;
	}

	ret = arc_get_timer_clk(node);
	if (ret)
		return ret;

	write_aux_reg(AUX_RTC_CTRL, 1);

	return clocksource_register_hz(&arc_counter_rtc, arc_timer_freq);
}
static int __init
init_onchip_IRQ(struct device_node *intc, struct device_node *parent)
{
	struct irq_domain *root_domain;
	struct bcr_irq_arcv2 irq_bcr;
	unsigned int nr_cpu_irqs;

	READ_BCR(ARC_REG_IRQ_BCR, irq_bcr);
	nr_cpu_irqs = irq_bcr.irqs + NR_EXCEPTIONS;

	if (parent)
		panic("DeviceTree incore intc not a root irq controller\n");

	root_domain = irq_domain_add_linear(intc, nr_cpu_irqs, &arcv2_irq_ops, NULL);
	if (!root_domain)
		panic("root irq domain not avail\n");

	/*
	 * Needed for primary domain lookup to succeed
	 * This is a primary irqchip, and can never have a parent
	 */
	irq_set_default_host(root_domain);

#ifdef CONFIG_SMP
	irq_create_mapping(root_domain, IPI_IRQ);
#endif
	irq_create_mapping(root_domain, SOFTIRQ_IRQ);

	return 0;
}
示例#7
0
/*
 * Early Hardware specific Interrupt setup
 * -Called very early (start_kernel -> setup_arch -> setup_processor)
 * -Platform Independent (must for any ARC Core)
 * -Needed for each CPU (hence not foldable into init_IRQ)
 */
void arc_init_IRQ(void)
{
	unsigned int tmp, irq_prio, i;
	struct bcr_irq_arcv2 irq_bcr;

	struct aux_irq_ctrl {
#ifdef CONFIG_CPU_BIG_ENDIAN
		unsigned int res3:18, save_idx_regs:1, res2:1,
			     save_u_to_u:1, save_lp_regs:1, save_blink:1,
			     res:4, save_nr_gpr_pairs:5;
#else
		unsigned int save_nr_gpr_pairs:5, res:4,
			     save_blink:1, save_lp_regs:1, save_u_to_u:1,
			     res2:1, save_idx_regs:1, res3:18;
#endif
	} ictrl;

	*(unsigned int *)&ictrl = 0;

	ictrl.save_nr_gpr_pairs = 6;	/* r0 to r11 (r12 saved manually) */
	ictrl.save_blink = 1;
	ictrl.save_lp_regs = 1;		/* LP_COUNT, LP_START, LP_END */
	ictrl.save_u_to_u = 0;		/* user ctxt saved on kernel stack */
	ictrl.save_idx_regs = 1;	/* JLI, LDI, EI */

	WRITE_AUX(AUX_IRQ_CTRL, ictrl);

	/*
	 * ARCv2 core intc provides multiple interrupt priorities (upto 16).
	 * Typical builds though have only two levels (0-high, 1-low)
	 * Linux by default uses lower prio 1 for most irqs, reserving 0 for
	 * NMI style interrupts in future (say perf)
	 */

	READ_BCR(ARC_REG_IRQ_BCR, irq_bcr);

	irq_prio = irq_bcr.prio;	/* Encoded as N-1 for N levels */
	pr_info("archs-intc\t: %d priority levels (default %d)%s\n",
		irq_prio + 1, ARCV2_IRQ_DEF_PRIO,
		irq_bcr.firq ? " FIRQ (not used)":"");

	/*
	 * Set a default priority for all available interrupts to prevent
	 * switching of register banks if Fast IRQ and multiple register banks
	 * are supported by CPU.
	 * Also disable all IRQ lines so faulty external hardware won't
	 * trigger interrupt that kernel is not ready to handle.
	 */
	for (i = NR_EXCEPTIONS; i < irq_bcr.irqs + NR_EXCEPTIONS; i++) {
		write_aux_reg(AUX_IRQ_SELECT, i);
		write_aux_reg(AUX_IRQ_PRIORITY, ARCV2_IRQ_DEF_PRIO);
		write_aux_reg(AUX_IRQ_ENABLE, 0);
	}

	/* setup status32, don't enable intr yet as kernel doesn't want */
	tmp = read_aux_reg(ARC_REG_STATUS32);
	tmp |= STATUS_AD_MASK | (ARCV2_IRQ_DEF_PRIO << 1);
	tmp &= ~STATUS_IE_MASK;
	asm volatile("kflag %0	\n"::"r"(tmp));
}
示例#8
0
文件: setup.c 项目: Artox/linux
static void read_decode_ccm_bcr(struct cpuinfo_arc *cpu)
{
	if (is_isa_arcompact()) {
		struct bcr_iccm_arcompact iccm;
		struct bcr_dccm_arcompact dccm;

		READ_BCR(ARC_REG_ICCM_BUILD, iccm);
		if (iccm.ver) {
			cpu->iccm.sz = 4096 << iccm.sz;	/* 8K to 512K */
			cpu->iccm.base_addr = iccm.base << 16;
		}

		READ_BCR(ARC_REG_DCCM_BUILD, dccm);
		if (dccm.ver) {
			unsigned long base;
			cpu->dccm.sz = 2048 << dccm.sz;	/* 2K to 256K */

			base = read_aux_reg(ARC_REG_DCCM_BASE_BUILD);
			cpu->dccm.base_addr = base & ~0xF;
		}
	} else {
		struct bcr_iccm_arcv2 iccm;
		struct bcr_dccm_arcv2 dccm;
		unsigned long region;

		READ_BCR(ARC_REG_ICCM_BUILD, iccm);
		if (iccm.ver) {
			cpu->iccm.sz = 256 << iccm.sz00;	/* 512B to 16M */
			if (iccm.sz00 == 0xF && iccm.sz01 > 0)
				cpu->iccm.sz <<= iccm.sz01;

			region = read_aux_reg(ARC_REG_AUX_ICCM);
			cpu->iccm.base_addr = region & 0xF0000000;
		}

		READ_BCR(ARC_REG_DCCM_BUILD, dccm);
		if (dccm.ver) {
			cpu->dccm.sz = 256 << dccm.sz0;
			if (dccm.sz0 == 0xF && dccm.sz1 > 0)
				cpu->dccm.sz <<= dccm.sz1;

			region = read_aux_reg(ARC_REG_AUX_DCCM);
			cpu->dccm.base_addr = region & 0xF0000000;
		}
	}
}
示例#9
0
static void read_arc_build_cfg_regs(void)
{
	struct bcr_perip uncached_space;
	struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
	FIX_PTR(cpu);

	READ_BCR(AUX_IDENTITY, cpu->core);

	cpu->timers = read_aux_reg(ARC_REG_TIMERS_BCR);
	cpu->vec_base = read_aux_reg(AUX_INTR_VEC_BASE);

	READ_BCR(ARC_REG_D_UNCACH_BCR, uncached_space);
	cpu->uncached_base = uncached_space.start << 24;

	cpu->extn.mul = read_aux_reg(ARC_REG_MUL_BCR);
	cpu->extn.swap = read_aux_reg(ARC_REG_SWAP_BCR);
	cpu->extn.norm = read_aux_reg(ARC_REG_NORM_BCR);
	cpu->extn.minmax = read_aux_reg(ARC_REG_MIXMAX_BCR);
	cpu->extn.barrel = read_aux_reg(ARC_REG_BARREL_BCR);
	READ_BCR(ARC_REG_MAC_BCR, cpu->extn_mac_mul);

	cpu->extn.ext_arith = read_aux_reg(ARC_REG_EXTARITH_BCR);
	cpu->extn.crc = read_aux_reg(ARC_REG_CRC_BCR);

	/* Note that we read the CCM BCRs independent of kernel config
	 * This is to catch the cases where user doesn't know that
	 * CCMs are present in hardware build
	 */
	{
		struct bcr_iccm iccm;
		struct bcr_dccm dccm;
		struct bcr_dccm_base dccm_base;
		unsigned int bcr_32bit_val;

		bcr_32bit_val = read_aux_reg(ARC_REG_ICCM_BCR);
		if (bcr_32bit_val) {
			iccm = *((struct bcr_iccm *)&bcr_32bit_val);
			cpu->iccm.base_addr = iccm.base << 16;
			cpu->iccm.sz = 0x2000 << (iccm.sz - 1);
		}

		bcr_32bit_val = read_aux_reg(ARC_REG_DCCM_BCR);
		if (bcr_32bit_val) {
			dccm = *((struct bcr_dccm *)&bcr_32bit_val);
			cpu->dccm.sz = 0x800 << (dccm.sz);

			READ_BCR(ARC_REG_DCCMBASE_BCR, dccm_base);
			cpu->dccm.base_addr = dccm_base.addr << 8;
		}
	}

	READ_BCR(ARC_REG_XY_MEM_BCR, cpu->extn_xymem);

	read_decode_mmu_bcr();
	read_decode_cache_bcr();

	READ_BCR(ARC_REG_FP_BCR, cpu->fp);
	READ_BCR(ARC_REG_DPFP_BCR, cpu->dpfp);
}
static int __init
idu_of_init(struct device_node *intc, struct device_node *parent)
{
	struct irq_domain *domain;
	int nr_irqs;
	int i, virq;
	struct mcip_bcr mp;
	struct mcip_idu_bcr idu_bcr;

	READ_BCR(ARC_REG_MCIP_BCR, mp);

	if (!mp.idu)
		panic("IDU not detected, but DeviceTree using it");

	READ_BCR(ARC_REG_MCIP_IDU_BCR, idu_bcr);
	nr_irqs = mcip_idu_bcr_to_nr_irqs(idu_bcr);

	pr_info("MCIP: IDU supports %u common irqs\n", nr_irqs);

	domain = irq_domain_add_linear(intc, nr_irqs, &idu_irq_ops, NULL);

	/* Parent interrupts (core-intc) are already mapped */

	for (i = 0; i < nr_irqs; i++) {
		/* Mask all common interrupts by default */
		idu_irq_mask_raw(i);

		/*
		 * Return parent uplink IRQs (towards core intc) 24,25,.....
		 * this step has been done before already
		 * however we need it to get the parent virq and set IDU handler
		 * as first level isr
		 */
		virq = irq_create_mapping(NULL, i + FIRST_EXT_IRQ);
		BUG_ON(!virq);
		irq_set_chained_handler_and_data(virq, idu_cascade_isr, domain);
	}

	__mcip_cmd(CMD_IDU_ENABLE, 0);

	return 0;
}
示例#11
0
文件: intc-arcv2.c 项目: 020gzh/linux
/*
 * Early Hardware specific Interrupt setup
 * -Called very early (start_kernel -> setup_arch -> setup_processor)
 * -Platform Independent (must for any ARC Core)
 * -Needed for each CPU (hence not foldable into init_IRQ)
 */
void arc_init_IRQ(void)
{
	unsigned int tmp;

	struct irq_build {
#ifdef CONFIG_CPU_BIG_ENDIAN
		unsigned int pad:3, firq:1, prio:4, exts:8, irqs:8, ver:8;
#else
		unsigned int ver:8, irqs:8, exts:8, prio:4, firq:1, pad:3;
#endif
	} irq_bcr;

	struct aux_irq_ctrl {
#ifdef CONFIG_CPU_BIG_ENDIAN
		unsigned int res3:18, save_idx_regs:1, res2:1,
			     save_u_to_u:1, save_lp_regs:1, save_blink:1,
			     res:4, save_nr_gpr_pairs:5;
#else
		unsigned int save_nr_gpr_pairs:5, res:4,
			     save_blink:1, save_lp_regs:1, save_u_to_u:1,
			     res2:1, save_idx_regs:1, res3:18;
#endif
	} ictrl;

	*(unsigned int *)&ictrl = 0;

	ictrl.save_nr_gpr_pairs = 6;	/* r0 to r11 (r12 saved manually) */
	ictrl.save_blink = 1;
	ictrl.save_lp_regs = 1;		/* LP_COUNT, LP_START, LP_END */
	ictrl.save_u_to_u = 0;		/* user ctxt saved on kernel stack */
	ictrl.save_idx_regs = 1;	/* JLI, LDI, EI */

	WRITE_AUX(AUX_IRQ_CTRL, ictrl);

	/*
	 * ARCv2 core intc provides multiple interrupt priorities (upto 16).
	 * Typical builds though have only two levels (0-high, 1-low)
	 * Linux by default uses lower prio 1 for most irqs, reserving 0 for
	 * NMI style interrupts in future (say perf)
	 */

	READ_BCR(ARC_REG_IRQ_BCR, irq_bcr);

	irq_prio = irq_bcr.prio;	/* Encoded as N-1 for N levels */
	pr_info("archs-intc\t: %d priority levels (default %d)%s\n",
		irq_prio + 1, irq_prio,
		irq_bcr.firq ? " FIRQ (not used)":"");

	/* setup status32, don't enable intr yet as kernel doesn't want */
	tmp = read_aux_reg(0xa);
	tmp |= STATUS_AD_MASK | (irq_prio << 1);
	tmp &= ~STATUS_IE_MASK;
	asm volatile("flag %0	\n"::"r"(tmp));
}
示例#12
0
文件: arc_timer.c 项目: dznm/linux
static int __init arc_cs_setup_gfrc(struct device_node *node)
{
	struct mcip_bcr mp;
	int ret;

	READ_BCR(ARC_REG_MCIP_BCR, mp);
	if (!mp.gfrc) {
		pr_warn("Global-64-bit-Ctr clocksource not detected");
		return -ENXIO;
	}

	ret = arc_get_timer_clk(node);
	if (ret)
		return ret;

	return clocksource_register_hz(&arc_counter_gfrc, arc_timer_freq);
}
示例#13
0
文件: smp.c 项目: 01org/KVMGT-kernel
void iss_model_init_early_smp(void)
{
#define IS_AVAIL1(var, str)    ((var) ? str : "")

	struct bcr_mp mp;

	READ_BCR(ARC_REG_MP_BCR, mp);

	sprintf(smp_cpuinfo_buf, "Extn [ISS-SMP]: v%d, arch(%d) %s %s %s\n",
		mp.ver, mp.mp_arch, IS_AVAIL1(mp.scu, "SCU"),
		IS_AVAIL1(mp.idu, "IDU"), IS_AVAIL1(mp.sdu, "SDU"));

	plat_smp_ops.info = smp_cpuinfo_buf;

	plat_smp_ops.cpu_kick = iss_model_smp_wakeup_cpu;
	plat_smp_ops.ipi_send = iss_model_ipi_send;
	plat_smp_ops.ipi_clear = iss_model_ipi_clear;
}
static void mcip_probe_n_setup(void)
{
	struct mcip_bcr mp;

	READ_BCR(ARC_REG_MCIP_BCR, mp);

	sprintf(smp_cpuinfo_buf,
		"Extn [SMP]\t: ARConnect (v%d): %d cores with %s%s%s%s\n",
		mp.ver, mp.num_cores,
		IS_AVAIL1(mp.ipi, "IPI "),
		IS_AVAIL1(mp.idu, "IDU "),
		IS_AVAIL1(mp.dbg, "DEBUG "),
		IS_AVAIL1(mp.gfrc, "GFRC"));

	cpuinfo_arc700[0].extn.gfrc = mp.gfrc;

	if (mp.dbg) {
		__mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, 0xf);
		__mcip_cmd_data(CMD_DEBUG_SET_MASK, 0xf, 0xf);
	}
}
示例#15
0
文件: mcip.c 项目: causten/linux
void mcip_init_early_smp(void)
{
#define IS_AVAIL1(var, str)    ((var) ? str : "")

    struct mcip_bcr {
#ifdef CONFIG_CPU_BIG_ENDIAN
        unsigned int pad3:8,
                 idu:1, llm:1, num_cores:6,
                 iocoh:1,  grtc:1, dbg:1, pad2:1,
                 msg:1, sem:1, ipi:1, pad:1,
                 ver:8;
#else
        unsigned int ver:8,
                 pad:1, ipi:1, sem:1, msg:1,
                 pad2:1, dbg:1, grtc:1, iocoh:1,
                 num_cores:6, llm:1, idu:1,
                 pad3:8;
#endif
    } mp;

    READ_BCR(ARC_REG_MCIP_BCR, mp);

    sprintf(smp_cpuinfo_buf,
            "Extn [SMP]\t: ARConnect (v%d): %d cores with %s%s%s%s\n",
            mp.ver, mp.num_cores,
            IS_AVAIL1(mp.ipi, "IPI "),
            IS_AVAIL1(mp.idu, "IDU "),
            IS_AVAIL1(mp.dbg, "DEBUG "),
            IS_AVAIL1(mp.grtc, "GRTC"));

    idu_detected = mp.idu;

    if (mp.dbg) {
        __mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, 0xf);
        __mcip_cmd_data(CMD_DEBUG_SET_MASK, 0xf, 0xf);
    }

    if (IS_ENABLED(CONFIG_ARC_HAS_GRTC) && !mp.grtc)
        panic("kernel trying to use non-existent GRTC\n");
}
示例#16
0
static int __init
idu_of_init(struct device_node *intc, struct device_node *parent)
{
	struct irq_domain *domain;
	/* Read IDU BCR to confirm nr_irqs */
	int nr_irqs = of_irq_count(intc);
	int i, virq;
	struct mcip_bcr mp;

	READ_BCR(ARC_REG_MCIP_BCR, mp);

	if (!mp.idu)
		panic("IDU not detected, but DeviceTree using it");

	pr_info("MCIP: IDU referenced from Devicetree %d irqs\n", nr_irqs);

	domain = irq_domain_add_linear(intc, nr_irqs, &idu_irq_ops, NULL);

	/* Parent interrupts (core-intc) are already mapped */

	for (i = 0; i < nr_irqs; i++) {
		/*
		 * Return parent uplink IRQs (towards core intc) 24,25,.....
		 * this step has been done before already
		 * however we need it to get the parent virq and set IDU handler
		 * as first level isr
		 */
		virq = irq_of_parse_and_map(intc, i);
		if (!i)
			idu_first_hwirq = irqd_to_hwirq(irq_get_irq_data(virq));

		irq_set_chained_handler_and_data(virq, idu_cascade_isr, domain);
	}

	__mcip_cmd(CMD_IDU_ENABLE, 0);

	return 0;
}
示例#17
0
文件: setup.c 项目: Artox/linux
static void read_arc_build_cfg_regs(void)
{
	struct bcr_timer timer;
	struct bcr_generic bcr;
	struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
	const struct id_to_str *tbl;

	FIX_PTR(cpu);

	READ_BCR(AUX_IDENTITY, cpu->core);
	READ_BCR(ARC_REG_ISA_CFG_BCR, cpu->isa);

	for (tbl = &arc_cpu_rel[0]; tbl->id != 0; tbl++) {
		if (cpu->core.family == tbl->id) {
			cpu->details = tbl->str;
			break;
		}
	}

	for (tbl = &arc_cpu_nm[0]; tbl->id != 0; tbl++) {
		if ((cpu->core.family & 0xF0) == tbl->id)
			break;
	}
	cpu->name = tbl->str;

	READ_BCR(ARC_REG_TIMERS_BCR, timer);
	cpu->extn.timer0 = timer.t0;
	cpu->extn.timer1 = timer.t1;
	cpu->extn.rtc = timer.rtc;

	cpu->vec_base = read_aux_reg(AUX_INTR_VEC_BASE);

	READ_BCR(ARC_REG_MUL_BCR, cpu->extn_mpy);

	cpu->extn.norm = read_aux_reg(ARC_REG_NORM_BCR) > 1 ? 1 : 0; /* 2,3 */
	cpu->extn.barrel = read_aux_reg(ARC_REG_BARREL_BCR) > 1 ? 1 : 0; /* 2,3 */
	cpu->extn.swap = read_aux_reg(ARC_REG_SWAP_BCR) ? 1 : 0;        /* 1,3 */
	cpu->extn.crc = read_aux_reg(ARC_REG_CRC_BCR) ? 1 : 0;
	cpu->extn.minmax = read_aux_reg(ARC_REG_MIXMAX_BCR) > 1 ? 1 : 0; /* 2 */
	cpu->extn.swape = (cpu->core.family >= 0x34) ? 1 :
				IS_ENABLED(CONFIG_ARC_HAS_SWAPE);

	READ_BCR(ARC_REG_XY_MEM_BCR, cpu->extn_xymem);

	/* Read CCM BCRs for boot reporting even if not enabled in Kconfig */
	read_decode_ccm_bcr(cpu);

	read_decode_mmu_bcr();
	read_decode_cache_bcr();

	if (is_isa_arcompact()) {
		struct bcr_fp_arcompact sp, dp;
		struct bcr_bpu_arcompact bpu;

		READ_BCR(ARC_REG_FP_BCR, sp);
		READ_BCR(ARC_REG_DPFP_BCR, dp);
		cpu->extn.fpu_sp = sp.ver ? 1 : 0;
		cpu->extn.fpu_dp = dp.ver ? 1 : 0;

		READ_BCR(ARC_REG_BPU_BCR, bpu);
		cpu->bpu.ver = bpu.ver;
		cpu->bpu.full = bpu.fam ? 1 : 0;
		if (bpu.ent) {
			cpu->bpu.num_cache = 256 << (bpu.ent - 1);
			cpu->bpu.num_pred = 256 << (bpu.ent - 1);
		}
	} else {
		struct bcr_fp_arcv2 spdp;
		struct bcr_bpu_arcv2 bpu;

		READ_BCR(ARC_REG_FP_V2_BCR, spdp);
		cpu->extn.fpu_sp = spdp.sp ? 1 : 0;
		cpu->extn.fpu_dp = spdp.dp ? 1 : 0;

		READ_BCR(ARC_REG_BPU_BCR, bpu);
		cpu->bpu.ver = bpu.ver;
		cpu->bpu.full = bpu.ft;
		cpu->bpu.num_cache = 256 << bpu.bce;
		cpu->bpu.num_pred = 2048 << bpu.pte;
	}

	READ_BCR(ARC_REG_AP_BCR, bcr);
	cpu->extn.ap = bcr.ver ? 1 : 0;

	READ_BCR(ARC_REG_SMART_BCR, bcr);
	cpu->extn.smart = bcr.ver ? 1 : 0;

	READ_BCR(ARC_REG_RTT_BCR, bcr);
	cpu->extn.rtt = bcr.ver ? 1 : 0;

	cpu->extn.debug = cpu->extn.ap | cpu->extn.smart | cpu->extn.rtt;

	/* some hacks for lack of feature BCR info in old ARC700 cores */
	if (is_isa_arcompact()) {
		if (!cpu->isa.ver)	/* ISA BCR absent, use Kconfig info */
			cpu->isa.atomic = IS_ENABLED(CONFIG_ARC_HAS_LLSC);
		else
			cpu->isa.atomic = cpu->isa.atomic1;

		cpu->isa.be = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN);

		 /* there's no direct way to distinguish 750 vs. 770 */
		if (unlikely(cpu->core.family < 0x34 || cpu->mmu.ver < 3))
			cpu->name = "ARC750";
	}
}
示例#18
0
文件: setup.c 项目: 1059232202/linux
static void read_arc_build_cfg_regs(void)
{
	struct bcr_perip uncached_space;
	struct bcr_timer timer;
	struct bcr_generic bcr;
	struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
	unsigned long perip_space;
	FIX_PTR(cpu);

	READ_BCR(AUX_IDENTITY, cpu->core);
	READ_BCR(ARC_REG_ISA_CFG_BCR, cpu->isa);

	READ_BCR(ARC_REG_TIMERS_BCR, timer);
	cpu->extn.timer0 = timer.t0;
	cpu->extn.timer1 = timer.t1;
	cpu->extn.rtc = timer.rtc;

	cpu->vec_base = read_aux_reg(AUX_INTR_VEC_BASE);

	READ_BCR(ARC_REG_D_UNCACH_BCR, uncached_space);
        if (uncached_space.ver < 3)
		perip_space = uncached_space.start << 24;
	else
		perip_space = read_aux_reg(AUX_NON_VOL) & 0xF0000000;

	BUG_ON(perip_space != ARC_UNCACHED_ADDR_SPACE);

	READ_BCR(ARC_REG_MUL_BCR, cpu->extn_mpy);

	cpu->extn.norm = read_aux_reg(ARC_REG_NORM_BCR) > 1 ? 1 : 0; /* 2,3 */
	cpu->extn.barrel = read_aux_reg(ARC_REG_BARREL_BCR) > 1 ? 1 : 0; /* 2,3 */
	cpu->extn.swap = read_aux_reg(ARC_REG_SWAP_BCR) ? 1 : 0;        /* 1,3 */
	cpu->extn.crc = read_aux_reg(ARC_REG_CRC_BCR) ? 1 : 0;
	cpu->extn.minmax = read_aux_reg(ARC_REG_MIXMAX_BCR) > 1 ? 1 : 0; /* 2 */
	READ_BCR(ARC_REG_XY_MEM_BCR, cpu->extn_xymem);

	/* Read CCM BCRs for boot reporting even if not enabled in Kconfig */
	read_decode_ccm_bcr(cpu);

	read_decode_mmu_bcr();
	read_decode_cache_bcr();

	if (is_isa_arcompact()) {
		struct bcr_fp_arcompact sp, dp;
		struct bcr_bpu_arcompact bpu;

		READ_BCR(ARC_REG_FP_BCR, sp);
		READ_BCR(ARC_REG_DPFP_BCR, dp);
		cpu->extn.fpu_sp = sp.ver ? 1 : 0;
		cpu->extn.fpu_dp = dp.ver ? 1 : 0;

		READ_BCR(ARC_REG_BPU_BCR, bpu);
		cpu->bpu.ver = bpu.ver;
		cpu->bpu.full = bpu.fam ? 1 : 0;
		if (bpu.ent) {
			cpu->bpu.num_cache = 256 << (bpu.ent - 1);
			cpu->bpu.num_pred = 256 << (bpu.ent - 1);
		}
	} else {
		struct bcr_fp_arcv2 spdp;
		struct bcr_bpu_arcv2 bpu;

		READ_BCR(ARC_REG_FP_V2_BCR, spdp);
		cpu->extn.fpu_sp = spdp.sp ? 1 : 0;
		cpu->extn.fpu_dp = spdp.dp ? 1 : 0;

		READ_BCR(ARC_REG_BPU_BCR, bpu);
		cpu->bpu.ver = bpu.ver;
		cpu->bpu.full = bpu.ft;
		cpu->bpu.num_cache = 256 << bpu.bce;
		cpu->bpu.num_pred = 2048 << bpu.pte;
	}

	READ_BCR(ARC_REG_AP_BCR, bcr);
	cpu->extn.ap = bcr.ver ? 1 : 0;

	READ_BCR(ARC_REG_SMART_BCR, bcr);
	cpu->extn.smart = bcr.ver ? 1 : 0;

	READ_BCR(ARC_REG_RTT_BCR, bcr);
	cpu->extn.rtt = bcr.ver ? 1 : 0;

	cpu->extn.debug = cpu->extn.ap | cpu->extn.smart | cpu->extn.rtt;
}
示例#19
0
文件: setup.c 项目: FxIxFxA/linux
static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len)
{
	struct cpuinfo_arc *cpu = &cpuinfo_arc700[cpu_id];
	struct bcr_identity *core = &cpu->core;
	int i, n = 0, ua = 0;

	FIX_PTR(cpu);

	n += scnprintf(buf + n, len - n,
		       "\nIDENTITY\t: ARCVER [%#02x] ARCNUM [%#02x] CHIPID [%#4x]\n",
		       core->family, core->cpu_id, core->chip_id);

	n += scnprintf(buf + n, len - n, "processor [%d]\t: %s %s (%s ISA) %s%s%s\n",
		       cpu_id, cpu->name, cpu->details,
		       is_isa_arcompact() ? "ARCompact" : "ARCv2",
		       IS_AVAIL1(cpu->isa.be, "[Big-Endian]"),
		       IS_AVAIL3(cpu->extn.dual, cpu->extn.dual_enb, " Dual-Issue "));

	n += scnprintf(buf + n, len - n, "Timers\t\t: %s%s%s%s%s%s\nISA Extn\t: ",
		       IS_AVAIL1(cpu->extn.timer0, "Timer0 "),
		       IS_AVAIL1(cpu->extn.timer1, "Timer1 "),
		       IS_AVAIL2(cpu->extn.rtc, "RTC [UP 64-bit] ", CONFIG_ARC_TIMERS_64BIT),
		       IS_AVAIL2(cpu->extn.gfrc, "GFRC [SMP 64-bit] ", CONFIG_ARC_TIMERS_64BIT));

#ifdef __ARC_UNALIGNED__
	ua = 1;
#endif
	n += i = scnprintf(buf + n, len - n, "%s%s%s%s%s%s",
			   IS_AVAIL2(cpu->isa.atomic, "atomic ", CONFIG_ARC_HAS_LLSC),
			   IS_AVAIL2(cpu->isa.ldd, "ll64 ", CONFIG_ARC_HAS_LL64),
			   IS_AVAIL1(cpu->isa.unalign, "unalign "), IS_USED_RUN(ua));

	if (i)
		n += scnprintf(buf + n, len - n, "\n\t\t: ");

	if (cpu->extn_mpy.ver) {
		if (cpu->extn_mpy.ver <= 0x2) {	/* ARCompact */
			n += scnprintf(buf + n, len - n, "mpy ");
		} else {
			int opt = 2;	/* stock MPY/MPYH */

			if (cpu->extn_mpy.dsp)	/* OPT 7-9 */
				opt = cpu->extn_mpy.dsp + 6;

			n += scnprintf(buf + n, len - n, "mpy[opt %d] ", opt);
		}
	}

	n += scnprintf(buf + n, len - n, "%s%s%s%s%s%s%s%s\n",
		       IS_AVAIL1(cpu->isa.div_rem, "div_rem "),
		       IS_AVAIL1(cpu->extn.norm, "norm "),
		       IS_AVAIL1(cpu->extn.barrel, "barrel-shift "),
		       IS_AVAIL1(cpu->extn.swap, "swap "),
		       IS_AVAIL1(cpu->extn.minmax, "minmax "),
		       IS_AVAIL1(cpu->extn.crc, "crc "),
		       IS_AVAIL2(cpu->extn.swape, "swape", CONFIG_ARC_HAS_SWAPE));

	if (cpu->bpu.ver)
		n += scnprintf(buf + n, len - n,
			      "BPU\t\t: %s%s match, cache:%d, Predict Table:%d",
			      IS_AVAIL1(cpu->bpu.full, "full"),
			      IS_AVAIL1(!cpu->bpu.full, "partial"),
			      cpu->bpu.num_cache, cpu->bpu.num_pred);

	if (is_isa_arcv2()) {
		struct bcr_lpb lpb;

		READ_BCR(ARC_REG_LPB_BUILD, lpb);
		if (lpb.ver) {
			unsigned int ctl;
			ctl = read_aux_reg(ARC_REG_LPB_CTRL);

			n += scnprintf(buf + n, len - n, " Loop Buffer:%d %s",
				lpb.entries,
				IS_DISABLED_RUN(!ctl));
		}
	}

	n += scnprintf(buf + n, len - n, "\n");
	return buf;
}
示例#20
0
static void read_arc_build_cfg_regs(void)
{
	struct bcr_timer timer;
	struct bcr_generic bcr;
	struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
	const struct id_to_str *tbl;
	struct bcr_isa_arcv2 isa;
	struct bcr_actionpoint ap;

	FIX_PTR(cpu);

	READ_BCR(AUX_IDENTITY, cpu->core);

	for (tbl = &arc_cpu_rel[0]; tbl->id != 0; tbl++) {
		if (cpu->core.family == tbl->id) {
			cpu->details = tbl->str;
			break;
		}
	}

	for (tbl = &arc_cpu_nm[0]; tbl->id != 0; tbl++) {
		if ((cpu->core.family & 0xF4) == tbl->id)
			break;
	}
	cpu->name = tbl->str;

	READ_BCR(ARC_REG_TIMERS_BCR, timer);
	cpu->extn.timer0 = timer.t0;
	cpu->extn.timer1 = timer.t1;
	cpu->extn.rtc = timer.rtc;

	cpu->vec_base = read_aux_reg(AUX_INTR_VEC_BASE);

	READ_BCR(ARC_REG_MUL_BCR, cpu->extn_mpy);

	cpu->extn.norm = read_aux_reg(ARC_REG_NORM_BCR) > 1 ? 1 : 0; /* 2,3 */
	cpu->extn.barrel = read_aux_reg(ARC_REG_BARREL_BCR) > 1 ? 1 : 0; /* 2,3 */
	cpu->extn.swap = read_aux_reg(ARC_REG_SWAP_BCR) ? 1 : 0;        /* 1,3 */
	cpu->extn.crc = read_aux_reg(ARC_REG_CRC_BCR) ? 1 : 0;
	cpu->extn.minmax = read_aux_reg(ARC_REG_MIXMAX_BCR) > 1 ? 1 : 0; /* 2 */
	cpu->extn.swape = (cpu->core.family >= 0x34) ? 1 :
				IS_ENABLED(CONFIG_ARC_HAS_SWAPE);

	READ_BCR(ARC_REG_XY_MEM_BCR, cpu->extn_xymem);

	/* Read CCM BCRs for boot reporting even if not enabled in Kconfig */
	read_decode_ccm_bcr(cpu);

	read_decode_mmu_bcr();
	read_decode_cache_bcr();

	if (is_isa_arcompact()) {
		struct bcr_fp_arcompact sp, dp;
		struct bcr_bpu_arcompact bpu;

		READ_BCR(ARC_REG_FP_BCR, sp);
		READ_BCR(ARC_REG_DPFP_BCR, dp);
		cpu->extn.fpu_sp = sp.ver ? 1 : 0;
		cpu->extn.fpu_dp = dp.ver ? 1 : 0;

		READ_BCR(ARC_REG_BPU_BCR, bpu);
		cpu->bpu.ver = bpu.ver;
		cpu->bpu.full = bpu.fam ? 1 : 0;
		if (bpu.ent) {
			cpu->bpu.num_cache = 256 << (bpu.ent - 1);
			cpu->bpu.num_pred = 256 << (bpu.ent - 1);
		}
	} else {
		struct bcr_fp_arcv2 spdp;
		struct bcr_bpu_arcv2 bpu;

		READ_BCR(ARC_REG_FP_V2_BCR, spdp);
		cpu->extn.fpu_sp = spdp.sp ? 1 : 0;
		cpu->extn.fpu_dp = spdp.dp ? 1 : 0;

		READ_BCR(ARC_REG_BPU_BCR, bpu);
		cpu->bpu.ver = bpu.ver;
		cpu->bpu.full = bpu.ft;
		cpu->bpu.num_cache = 256 << bpu.bce;
		cpu->bpu.num_pred = 2048 << bpu.pte;
		cpu->bpu.ret_stk = 4 << bpu.rse;

		if (cpu->core.family >= 0x54) {

			struct bcr_uarch_build_arcv2 uarch;

			/*
			 * The first 0x54 core (uarch maj:min 0:1 or 0:2) was
			 * dual issue only (HS4x). But next uarch rev (1:0)
			 * allows it be configured for single issue (HS3x)
			 * Ensure we fiddle with dual issue only on HS4x
			 */
			READ_BCR(ARC_REG_MICRO_ARCH_BCR, uarch);

			if (uarch.prod == 4) {
				unsigned int exec_ctrl;

				/* dual issue hardware always present */
				cpu->extn.dual = 1;

				READ_BCR(AUX_EXEC_CTRL, exec_ctrl);

				/* dual issue hardware enabled ? */
				cpu->extn.dual_enb = !(exec_ctrl & 1);

			}
		}
	}

	READ_BCR(ARC_REG_AP_BCR, ap);
	if (ap.ver) {
		cpu->extn.ap_num = 2 << ap.num;
		cpu->extn.ap_full = !ap.min;
	}

	READ_BCR(ARC_REG_SMART_BCR, bcr);
	cpu->extn.smart = bcr.ver ? 1 : 0;

	READ_BCR(ARC_REG_RTT_BCR, bcr);
	cpu->extn.rtt = bcr.ver ? 1 : 0;

	READ_BCR(ARC_REG_ISA_CFG_BCR, isa);

	/* some hacks for lack of feature BCR info in old ARC700 cores */
	if (is_isa_arcompact()) {
		if (!isa.ver)	/* ISA BCR absent, use Kconfig info */
			cpu->isa.atomic = IS_ENABLED(CONFIG_ARC_HAS_LLSC);
		else {
			/* ARC700_BUILD only has 2 bits of isa info */
			struct bcr_generic bcr = *(struct bcr_generic *)&isa;
			cpu->isa.atomic = bcr.info & 1;
		}

		cpu->isa.be = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN);

		 /* there's no direct way to distinguish 750 vs. 770 */
		if (unlikely(cpu->core.family < 0x34 || cpu->mmu.ver < 3))
			cpu->name = "ARC750";
	} else {
		cpu->isa = isa;
	}
}
示例#21
0
static void read_arc_build_cfg_regs(void)
{
	struct bcr_perip uncached_space;
	struct bcr_generic bcr;
	struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
	unsigned long perip_space;
	FIX_PTR(cpu);

	READ_BCR(AUX_IDENTITY, cpu->core);
	READ_BCR(ARC_REG_ISA_CFG_BCR, cpu->isa);

	READ_BCR(ARC_REG_TIMERS_BCR, cpu->timers);
	cpu->vec_base = read_aux_reg(AUX_INTR_VEC_BASE);

	READ_BCR(ARC_REG_D_UNCACH_BCR, uncached_space);
        if (uncached_space.ver < 3)
		perip_space = uncached_space.start << 24;
	else
		perip_space = read_aux_reg(AUX_NON_VOL) & 0xF0000000;

	BUG_ON(perip_space != ARC_UNCACHED_ADDR_SPACE);

	READ_BCR(ARC_REG_MUL_BCR, cpu->extn_mpy);

	cpu->extn.norm = read_aux_reg(ARC_REG_NORM_BCR) > 1 ? 1 : 0; /* 2,3 */
	cpu->extn.barrel = read_aux_reg(ARC_REG_BARREL_BCR) > 1 ? 1 : 0; /* 2,3 */
	cpu->extn.swap = read_aux_reg(ARC_REG_SWAP_BCR) ? 1 : 0;        /* 1,3 */
	cpu->extn.crc = read_aux_reg(ARC_REG_CRC_BCR) ? 1 : 0;
	cpu->extn.minmax = read_aux_reg(ARC_REG_MIXMAX_BCR) > 1 ? 1 : 0; /* 2 */

	/* Note that we read the CCM BCRs independent of kernel config
	 * This is to catch the cases where user doesn't know that
	 * CCMs are present in hardware build
	 */
	{
		struct bcr_iccm iccm;
		struct bcr_dccm dccm;
		struct bcr_dccm_base dccm_base;
		unsigned int bcr_32bit_val;

		bcr_32bit_val = read_aux_reg(ARC_REG_ICCM_BCR);
		if (bcr_32bit_val) {
			iccm = *((struct bcr_iccm *)&bcr_32bit_val);
			cpu->iccm.base_addr = iccm.base << 16;
			cpu->iccm.sz = 0x2000 << (iccm.sz - 1);
		}

		bcr_32bit_val = read_aux_reg(ARC_REG_DCCM_BCR);
		if (bcr_32bit_val) {
			dccm = *((struct bcr_dccm *)&bcr_32bit_val);
			cpu->dccm.sz = 0x800 << (dccm.sz);

			READ_BCR(ARC_REG_DCCMBASE_BCR, dccm_base);
			cpu->dccm.base_addr = dccm_base.addr << 8;
		}
	}

	READ_BCR(ARC_REG_XY_MEM_BCR, cpu->extn_xymem);

	read_decode_mmu_bcr();
	read_decode_cache_bcr();

	if (is_isa_arcompact()) {
		struct bcr_fp_arcompact sp, dp;
		struct bcr_bpu_arcompact bpu;

		READ_BCR(ARC_REG_FP_BCR, sp);
		READ_BCR(ARC_REG_DPFP_BCR, dp);
		cpu->extn.fpu_sp = sp.ver ? 1 : 0;
		cpu->extn.fpu_dp = dp.ver ? 1 : 0;

		READ_BCR(ARC_REG_BPU_BCR, bpu);
		cpu->bpu.ver = bpu.ver;
		cpu->bpu.full = bpu.fam ? 1 : 0;
		if (bpu.ent) {
			cpu->bpu.num_cache = 256 << (bpu.ent - 1);
			cpu->bpu.num_pred = 256 << (bpu.ent - 1);
		}
	} else {
		struct bcr_fp_arcv2 spdp;
		struct bcr_bpu_arcv2 bpu;

		READ_BCR(ARC_REG_FP_V2_BCR, spdp);
		cpu->extn.fpu_sp = spdp.sp ? 1 : 0;
		cpu->extn.fpu_dp = spdp.dp ? 1 : 0;

		READ_BCR(ARC_REG_BPU_BCR, bpu);
		cpu->bpu.ver = bpu.ver;
		cpu->bpu.full = bpu.ft;
		cpu->bpu.num_cache = 256 << bpu.bce;
		cpu->bpu.num_pred = 2048 << bpu.pte;
	}

	READ_BCR(ARC_REG_AP_BCR, bcr);
	cpu->extn.ap = bcr.ver ? 1 : 0;

	READ_BCR(ARC_REG_SMART_BCR, bcr);
	cpu->extn.smart = bcr.ver ? 1 : 0;

	READ_BCR(ARC_REG_RTT_BCR, bcr);
	cpu->extn.rtt = bcr.ver ? 1 : 0;

	cpu->extn.debug = cpu->extn.ap | cpu->extn.smart | cpu->extn.rtt;
}