/* * 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; }
/* * 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; }
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); }
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; }
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; }
/* * 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)); }
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; } } }
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; }
/* * 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)); }
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); }
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); } }
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"); }
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; }
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"; } }
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; }
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; }
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; } }
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; }