void __octeon_board_get_clock_info(uint32_t def_ddr_clock_mhz) { uint8_t ee_buf[OCTEON_EEPROM_MAX_TUPLE_LENGTH] __attribute__((unused)); int addr __attribute__((unused)); /* Assume no descriptor is present */ gd->mem_clk = def_ddr_clock_mhz; debug("%s(%u)\n", __func__, def_ddr_clock_mhz); /* Initialize DDR reference frequency if not already set. */ if (!gd->arch.ddr_ref_hertz) gd->arch.ddr_ref_hertz = 50000000; #if USE_EEPROM /* OCTEON I and OCTEON Plus use the old clock descriptor of which * there are two versions. OCTEON II uses a dedicated DDR clock * descriptor instead. */ if (OCTEON_IS_OCTEON1PLUS()) { octeon_eeprom_header_t *header; struct octeon_eeprom_clock_desc_v1 *clock_v1; struct octeon_eeprom_clock_desc_v2 *clock_v2; addr = octeon_tlv_get_tuple_addr(CONFIG_SYS_DEF_EEPROM_ADDR, EEPROM_CLOCK_DESC_TYPE, 0, ee_buf, OCTEON_EEPROM_MAX_TUPLE_LENGTH); if (addr < 0) return; header = (octeon_eeprom_header_t *)ee_buf; switch (header->major_version) { case 1: clock_v1 = (struct octeon_eeprom_clock_desc_v1 *)ee_buf; gd->mem_clk = clock_v1->ddr_clock_mhz; break; case 2: clock_v2 = (struct octeon_eeprom_clock_desc_v2 *)ee_buf; gd->mem_clk = clock_v2->ddr_clock_mhz; break; default: printf("Unknown TLV clock header version %d.%d\n", header->major_version, header->minor_version); } } else { octeon_eeprom_ddr_clock_desc_t *ddr_clock_ptr; addr = octeon_tlv_get_tuple_addr(CONFIG_SYS_DEF_EEPROM_ADDR, EEPROM_DDR_CLOCK_DESC_TYPE, 0, ee_buf, OCTEON_EEPROM_MAX_TUPLE_LENGTH); if (addr < 0) return; ddr_clock_ptr = (octeon_eeprom_ddr_clock_desc_t *)ee_buf; gd->mem_clk = ddr_clock_ptr->ddr_clock_hz / 1000000; } if (gd->mem_clk < 100 || gd->mem_clk > 2000) gd->mem_clk = def_ddr_clock_mhz; #endif }
static int octeon_l2c_probe(struct platform_device *pdev) { struct edac_device_ctl_info *l2c; int num_tads = OCTEON_IS_MODEL(OCTEON_CN68XX) ? 4 : 1; /* 'Tags' are block 0, 'Data' is block 1*/ l2c = edac_device_alloc_ctl_info(0, "l2c", num_tads, "l2c", 2, 0, NULL, 0, edac_device_alloc_index()); if (!l2c) return -ENOMEM; l2c->dev = &pdev->dev; platform_set_drvdata(pdev, l2c); l2c->dev_name = dev_name(&pdev->dev); l2c->mod_name = "octeon-l2c"; l2c->ctl_name = "octeon_l2c_err"; if (OCTEON_IS_OCTEON1PLUS()) { union cvmx_l2t_err l2t_err; union cvmx_l2d_err l2d_err; l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR); l2t_err.s.sec_intena = 0; /* We poll */ l2t_err.s.ded_intena = 0; cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64); l2d_err.u64 = cvmx_read_csr(CVMX_L2D_ERR); l2d_err.s.sec_intena = 0; /* We poll */ l2d_err.s.ded_intena = 0; cvmx_write_csr(CVMX_L2T_ERR, l2d_err.u64); l2c->edac_check = octeon_l2c_poll_oct1; } else { /* OCTEON II */ l2c->edac_check = octeon_l2c_poll_oct2; } if (edac_device_add_device(l2c) > 0) { pr_err("%s: edac_device_add_device() failed\n", __func__); goto err; } return 0; err: edac_device_free_ctl_info(l2c); return -ENXIO; }
/** * Load the QLM JTAG chain with data from all lanes of the QLM. * * @param qlm QLM to program */ void cvmx_helper_qlm_jtag_capture(int qlm) { union cvmx_ciu_qlm_jtgc jtgc; union cvmx_ciu_qlm_jtgd jtgd; jtgc.u64 = cvmx_read_csr(CVMX_CIU_QLM_JTGC); jtgc.s.mux_sel = qlm; if (OCTEON_IS_OCTEON1PLUS()) jtgc.s.bypass = 1 << qlm; cvmx_write_csr(CVMX_CIU_QLM_JTGC, jtgc.u64); cvmx_read_csr(CVMX_CIU_QLM_JTGC); jtgd.u64 = 0; jtgd.s.capture = 1; if (!OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)) jtgd.s.select = 1 << qlm; cvmx_write_csr(CVMX_CIU_QLM_JTGD, jtgd.u64); do { jtgd.u64 = cvmx_read_csr(CVMX_CIU_QLM_JTGD); } while (jtgd.s.capture); }
/** * Write up to 32bits into the QLM jtag chain. Bits are shifted * into the MSB and out the LSB, so you should shift in the low * order bits followed by the high order bits. The JTAG chain for * CN52XX and CN56XX is 4 * 268 bits long, or 1072. The JTAG chain * for CN63XX is 4 * 300 bits long, or 1200. * * @param qlm QLM to shift value into * @param bits Number of bits to shift in (1-32). * @param data Data to shift in. Bit 0 enters the chain first, followed by * bit 1, etc. * * @return The low order bits of the JTAG chain that shifted out of the * circle. */ uint32_t cvmx_helper_qlm_jtag_shift(int qlm, int bits, uint32_t data) { union cvmx_ciu_qlm_jtgc jtgc; union cvmx_ciu_qlm_jtgd jtgd; jtgc.u64 = cvmx_read_csr(CVMX_CIU_QLM_JTGC); jtgc.s.mux_sel = qlm; if (OCTEON_IS_OCTEON1PLUS()) jtgc.s.bypass = 1 << qlm; cvmx_write_csr(CVMX_CIU_QLM_JTGC, jtgc.u64); cvmx_read_csr(CVMX_CIU_QLM_JTGC); jtgd.u64 = 0; jtgd.s.shift = 1; jtgd.s.shft_cnt = bits - 1; jtgd.s.shft_reg = data; if (!OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)) jtgd.s.select = 1 << qlm; cvmx_write_csr(CVMX_CIU_QLM_JTGD, jtgd.u64); do { jtgd.u64 = cvmx_read_csr(CVMX_CIU_QLM_JTGD); } while (jtgd.s.shift); return jtgd.s.shft_reg >> (32 - bits); }
void __octeon_board_create_random_mac_addr(void) { #ifndef CONFIG_OCTEON_SIM uint8_t fuse_buf[128]; cvmx_mio_fus_rcmd_t fus_rcmd; uint32_t poly = 0x04c11db7; uint32_t crc = 0xffffffff; uint64_t *ptr; int ser_len = strlen((char *)gd->arch.board_desc.serial_str); int i; memset(fuse_buf, 0, sizeof(fuse_buf)); fuse_buf[0] = gd->arch.board_desc.board_type; fuse_buf[1] = (gd->arch.board_desc.rev_major << 4) | gd->arch.board_desc.rev_minor; fuse_buf[2] = ser_len; strncpy((char*)(fuse_buf+3), (char*)gd->arch.board_desc.serial_str, sizeof(fuse_buf)-3); /* For a random number we perform a CRC32 using the board type, * revision, serial number length, serial number and for OCTEON 2 and 3 * the fuse settings. */ CVMX_MT_CRC_POLYNOMIAL(poly); CVMX_ES32(crc, crc); CVMX_MT_CRC_IV_REFLECT(crc); ptr = (uint64_t *)fuse_buf; for (i = 0; i < sizeof(fuse_buf); i += 8) CVMX_MT_CRC_DWORD_REFLECT(*ptr++); if (!OCTEON_IS_OCTEON1PLUS()) { fus_rcmd.u64 = 0; fus_rcmd.s.pend = 1; for (i = 0; i < sizeof(fuse_buf); i++) { do { fus_rcmd.u64 = cvmx_read_csr(CVMX_MIO_FUS_RCMD); } while (fus_rcmd.s.pend == 1); fuse_buf[i] = fus_rcmd.s.dat; } for (i = 0; i < sizeof(fuse_buf); i += 8) CVMX_MT_CRC_DWORD_REFLECT(*ptr++); } /* Get the final CRC32 */ CVMX_MF_CRC_IV_REFLECT(crc); crc ^= 0xffffffff; gd->arch.mac_desc.count = 255; gd->arch.mac_desc.mac_addr_base[0] = 0x02; /* locally administered */ gd->arch.mac_desc.mac_addr_base[1] = crc & 0xff; gd->arch.mac_desc.mac_addr_base[2] = (crc >> 8) & 0xff; gd->arch.mac_desc.mac_addr_base[3] = (crc >> 16) & 0xff; gd->arch.mac_desc.mac_addr_base[4] = (crc >> 24) & 0xff; gd->arch.mac_desc.mac_addr_base[5] = 0; debug("Created random MAC address %pM", gd->arch.mac_desc.mac_addr_base); #else gd->arch.mac_desc.mac_addr_base[0] = 2; gd->arch.mac_desc.mac_addr_base[1] = 0x00; gd->arch.mac_desc.mac_addr_base[2] = 0xDE; gd->arch.mac_desc.mac_addr_base[3] = 0xAD; gd->arch.mac_desc.mac_addr_base[4] = 0xBF; gd->arch.mac_desc.mac_addr_base[5] = 0x00; gd->arch.mac_desc.count = 255; #endif }
static int octeon_lmc_edac_probe(struct platform_device *pdev) { struct mem_ctl_info *mci; struct edac_mc_layer layers[1]; int mc = pdev->id; opstate_init(); layers[0].type = EDAC_MC_LAYER_CHANNEL; layers[0].size = 1; layers[0].is_virt_csrow = false; if (OCTEON_IS_OCTEON1PLUS()) { union cvmx_lmcx_mem_cfg0 cfg0; cfg0.u64 = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(0)); if (!cfg0.s.ecc_ena) { dev_info(&pdev->dev, "Disabled (ECC not enabled)\n"); return 0; } mci = edac_mc_alloc(mc, ARRAY_SIZE(layers), layers, sizeof(struct octeon_lmc_pvt)); if (!mci) return -ENXIO; mci->pdev = &pdev->dev; mci->dev_name = dev_name(&pdev->dev); mci->mod_name = "octeon-lmc"; mci->ctl_name = "octeon-lmc-err"; mci->edac_check = octeon_lmc_edac_poll; if (edac_mc_add_mc_with_groups(mci, octeon_dev_groups)) { dev_err(&pdev->dev, "edac_mc_add_mc() failed\n"); edac_mc_free(mci); return -ENXIO; } cfg0.u64 = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(mc)); cfg0.s.intr_ded_ena = 0; /* We poll */ cfg0.s.intr_sec_ena = 0; cvmx_write_csr(CVMX_LMCX_MEM_CFG0(mc), cfg0.u64); } else { /* OCTEON II */ union cvmx_lmcx_int_en en; union cvmx_lmcx_config config; config.u64 = cvmx_read_csr(CVMX_LMCX_CONFIG(0)); if (!config.s.ecc_ena) { dev_info(&pdev->dev, "Disabled (ECC not enabled)\n"); return 0; } mci = edac_mc_alloc(mc, ARRAY_SIZE(layers), layers, sizeof(struct octeon_lmc_pvt)); if (!mci) return -ENXIO; mci->pdev = &pdev->dev; mci->dev_name = dev_name(&pdev->dev); mci->mod_name = "octeon-lmc"; mci->ctl_name = "co_lmc_err"; mci->edac_check = octeon_lmc_edac_poll_o2; if (edac_mc_add_mc_with_groups(mci, octeon_dev_groups)) { dev_err(&pdev->dev, "edac_mc_add_mc() failed\n"); edac_mc_free(mci); return -ENXIO; } en.u64 = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(mc)); en.s.intr_ded_ena = 0; /* We poll */ en.s.intr_sec_ena = 0; cvmx_write_csr(CVMX_LMCX_MEM_CFG0(mc), en.u64); } platform_set_drvdata(pdev, mci); return 0; }
/* Version of octeon_model_get_string() that takes buffer as argument, as ** running early in u-boot static/global variables don't work when running from ** flash */ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer) { const char *family; const char *core_model; char pass[4]; #ifndef CVMX_BUILD_FOR_UBOOT int clock_mhz; #endif const char *suffix; cvmx_l2d_fus3_t fus3; int num_cores; cvmx_mio_fus_dat2_t fus_dat2; cvmx_mio_fus_dat3_t fus_dat3; char fuse_model[10]; char fuse_suffix[4] = {0}; uint64_t fuse_data = 0; fus3.u64 = 0; if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN5XXX)) fus3.u64 = cvmx_read_csr(CVMX_L2D_FUS3); fus_dat2.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT2); fus_dat3.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT3); if (OCTEON_IS_MODEL(OCTEON_CN78XX)) num_cores = cvmx_pop(cvmx_read_csr(CVMX_CIU3_FUSE)); else num_cores = cvmx_pop(cvmx_read_csr(CVMX_CIU_FUSE)); /* Make sure the non existent devices look disabled */ switch ((chip_id >> 8) & 0xff) { case 6: /* CN50XX */ case 2: /* CN30XX */ fus_dat3.s.nodfa_dte = 1; fus_dat3.s.nozip = 1; break; case 4: /* CN57XX or CN56XX */ fus_dat3.s.nodfa_dte = 1; break; default: break; } /* Make a guess at the suffix */ /* NSP = everything */ /* EXP = No crypto */ /* SCP = No DFA, No zip */ /* CP = No DFA, No crypto, No zip */ if (fus_dat3.s.nodfa_dte) { if (fus_dat2.s.nocrypto) suffix = "CP"; else suffix = "SCP"; } else if (fus_dat2.s.nocrypto) suffix = "EXP"; else suffix = "NSP"; /* Assume pass number is encoded using <5:3><2:0>. Exceptions will be fixed later */ sprintf(pass, "%d.%d", (int)((chip_id >> 3) & 7) + 1, (int)chip_id & 7); /* Use the number of cores to determine the last 2 digits of the model number. There are some exceptions that are fixed later */ switch (num_cores) { case 32: core_model = "80"; break; case 24: core_model = "70"; break; case 16: core_model = "60"; break; case 15: core_model = "58"; break; case 14: core_model = "55"; break; case 13: core_model = "52"; break; case 12: core_model = "50"; break; case 11: core_model = "48"; break; case 10: core_model = "45"; break; case 9: core_model = "42"; break; case 8: core_model = "40"; break; case 7: core_model = "38"; break; case 6: core_model = "34"; break; case 5: core_model = "32"; break; case 4: core_model = "30"; break; case 3: core_model = "25"; break; case 2: core_model = "20"; break; case 1: core_model = "10"; break; default: core_model = "XX"; break; } /* Now figure out the family, the first two digits */ switch ((chip_id >> 8) & 0xff) { case 0: /* CN38XX, CN37XX or CN36XX */ if (fus3.cn38xx.crip_512k) { /* For some unknown reason, the 16 core one is called 37 instead of 36 */ if (num_cores >= 16) family = "37"; else family = "36"; } else family = "38"; /* This series of chips didn't follow the standard pass numbering */ switch (chip_id & 0xf) { case 0: strcpy(pass, "1.X"); break; case 1: strcpy(pass, "2.X"); break; case 3: strcpy(pass, "3.X"); break; default: strcpy(pass, "X.X"); break; } break; case 1: /* CN31XX or CN3020 */ if ((chip_id & 0x10) || fus3.cn31xx.crip_128k) family = "30"; else family = "31"; /* This series of chips didn't follow the standard pass numbering */ switch (chip_id & 0xf) { case 0: strcpy(pass, "1.0"); break; case 2: strcpy(pass, "1.1"); break; default: strcpy(pass, "X.X"); break; } break; case 2: /* CN3010 or CN3005 */ family = "30"; /* A chip with half cache is an 05 */ if (fus3.cn30xx.crip_64k) core_model = "05"; /* This series of chips didn't follow the standard pass numbering */ switch (chip_id & 0xf) { case 0: strcpy(pass, "1.0"); break; case 2: strcpy(pass, "1.1"); break; default: strcpy(pass, "X.X"); break; } break; case 3: /* CN58XX */ family = "58"; /* Special case. 4 core, half cache (CP with half cache) */ if ((num_cores == 4) && fus3.cn58xx.crip_1024k && !strncmp(suffix, "CP", 2)) core_model = "29"; /* Pass 1 uses different encodings for pass numbers */ if ((chip_id & 0xFF) < 0x8) { switch (chip_id & 0x3) { case 0: strcpy(pass, "1.0"); break; case 1: strcpy(pass, "1.1"); break; case 3: strcpy(pass, "1.2"); break; default: strcpy(pass, "1.X"); break; } } break; case 4: /* CN57XX, CN56XX, CN55XX, CN54XX */ if (fus_dat2.cn56xx.raid_en) { if (fus3.cn56xx.crip_1024k) family = "55"; else family = "57"; if (fus_dat2.cn56xx.nocrypto) suffix = "SP"; else suffix = "SSP"; } else { if (fus_dat2.cn56xx.nocrypto) suffix = "CP"; else { suffix = "NSP"; if (fus_dat3.s.nozip) suffix = "SCP"; if (fus_dat3.cn56xx.bar2_en) suffix = "NSPB2"; } if (fus3.cn56xx.crip_1024k) family = "54"; else family = "56"; } break; case 6: /* CN50XX */ family = "50"; break; case 7: /* CN52XX */ if (fus3.cn52xx.crip_256k) family = "51"; else family = "52"; break; case 0x93: /* CN61XX/CN60XX */ family = "61"; if (fus_dat3.cn63xx.l2c_crip == 2) family = "60"; if (fus_dat3.cn61xx.nozip) suffix = "SCP"; else suffix = "AAP"; break; case 0x90: /* CN63XX/CN62XX */ family = "63"; if (fus_dat3.s.l2c_crip == 2) family = "62"; if (num_cores == 6) /* Other core counts match generic */ core_model = "35"; if (fus_dat2.cn63xx.nocrypto) suffix = "CP"; else if (fus_dat2.cn63xx.dorm_crypto) suffix = "DAP"; else if (fus_dat3.cn63xx.nozip) suffix = "SCP"; else suffix = "AAP"; break; case 0x92: /* CN66XX */ family = "66"; if (num_cores == 6) /* Other core counts match generic */ core_model = "35"; if (fus_dat2.cn66xx.nocrypto && fus_dat2.cn66xx.dorm_crypto) suffix = "AP"; if (fus_dat2.cn66xx.nocrypto) suffix = "CP"; else if (fus_dat2.cn66xx.dorm_crypto) suffix = "DAP"; else if (fus_dat3.cn66xx.nozip && fus_dat2.cn66xx.raid_en) suffix = "SCP"; else if (!fus_dat2.cn66xx.raid_en) suffix = "HAP"; else suffix = "AAP"; break; case 0x91: /* CN68XX */ family = "68"; if (fus_dat2.cn68xx.nocrypto && fus_dat3.cn68xx.nozip) suffix = "CP"; else if (fus_dat2.cn68xx.dorm_crypto) suffix = "DAP"; else if (fus_dat3.cn68xx.nozip) suffix = "SCP"; else if (fus_dat2.cn68xx.nocrypto) suffix = "SP"; else if (!fus_dat2.cn68xx.raid_en) suffix = "HAP"; else suffix = "AAP"; break; case 0x94: /* CNF71XX */ family = "F71"; if (fus_dat3.cnf71xx.nozip) suffix = "SCP"; else suffix = "AAP"; break; case 0x95: /* CN78XX */ family = "78"; if (fus_dat3.cn70xx.nozip) suffix = "SCP"; else suffix = "AAP"; break; case 0x96: /* CN70XX */ family = "70"; if (cvmx_read_csr(CVMX_MIO_FUS_PDF) & (0x1ULL << 32)) family = "71"; if (fus_dat2.cn70xx.nocrypto) suffix = "CP"; else if (fus_dat3.cn70xx.nodfa_dte) suffix = "SCP"; else suffix = "AAP"; break; default: family = "XX"; core_model = "XX"; strcpy(pass, "X.X"); suffix = "XXX"; break; } #ifndef CVMX_BUILD_FOR_UBOOT clock_mhz = cvmx_clock_get_rate(CVMX_CLOCK_RCLK) / 1000000; #endif if (family[0] != '3') { if (OCTEON_IS_OCTEON1PLUS() || OCTEON_IS_OCTEON2()) { int fuse_base = 384 / 8; if (family[0] == '6' || OCTEON_IS_OCTEON3()) fuse_base = 832 / 8; /* Check for model in fuses, overrides normal decode */ /* This is _not_ valid for Octeon CN3XXX models */ fuse_data |= cvmx_fuse_read_byte(fuse_base + 5); fuse_data = fuse_data << 8; fuse_data |= cvmx_fuse_read_byte(fuse_base + 4); fuse_data = fuse_data << 8; fuse_data |= cvmx_fuse_read_byte(fuse_base + 3); fuse_data = fuse_data << 8; fuse_data |= cvmx_fuse_read_byte(fuse_base + 2); fuse_data = fuse_data << 8; fuse_data |= cvmx_fuse_read_byte(fuse_base + 1); fuse_data = fuse_data << 8; fuse_data |= cvmx_fuse_read_byte(fuse_base); if (fuse_data & 0x7ffff) { int model = fuse_data & 0x3fff; int suffix = (fuse_data >> 14) & 0x1f; if (suffix && model) { /* Have both number and suffix in fuses, so both */ sprintf(fuse_model, "%d%c", model, 'A' + suffix - 1); core_model = ""; family = fuse_model; } else if (suffix && !model) { /* Only have suffix, so add suffix to 'normal' model number */ sprintf(fuse_model, "%s%c", core_model, 'A' + suffix - 1); core_model = fuse_model; } else { /* Don't have suffix, so just use model from fuses */ sprintf(fuse_model, "%d", model); core_model = ""; family = fuse_model; } } } else {