void __init prom_init()

in cavium-octeon/setup.c [656:901]


void __init prom_init(void)
{
	struct cvmx_sysinfo *sysinfo;
	const char *arg;
	char *p;
	int i;
	u64 t;
	int argc;

	/*
	 * The bootloader passes a pointer to the boot descriptor in
	 * $a3, this is available as fw_arg3.
	 */
	octeon_boot_desc_ptr = (struct octeon_boot_descriptor *)fw_arg3;
	octeon_bootinfo =
		cvmx_phys_to_ptr(octeon_boot_desc_ptr->cvmx_desc_vaddr);
	cvmx_bootmem_init(cvmx_phys_to_ptr(octeon_bootinfo->phy_mem_desc_addr));

	sysinfo = cvmx_sysinfo_get();
	memset(sysinfo, 0, sizeof(*sysinfo));
	sysinfo->system_dram_size = octeon_bootinfo->dram_size << 20;
	sysinfo->phy_mem_desc_addr = (u64)phys_to_virt(octeon_bootinfo->phy_mem_desc_addr);

	if ((octeon_bootinfo->major_version > 1) ||
	    (octeon_bootinfo->major_version == 1 &&
	     octeon_bootinfo->minor_version >= 4))
		cvmx_coremask_copy(&sysinfo->core_mask,
				   &octeon_bootinfo->ext_core_mask);
	else
		cvmx_coremask_set64(&sysinfo->core_mask,
				    octeon_bootinfo->core_mask);

	/* Some broken u-boot pass garbage in upper bits, clear them out */
	if (!OCTEON_IS_MODEL(OCTEON_CN78XX))
		for (i = 512; i < 1024; i++)
			cvmx_coremask_clear_core(&sysinfo->core_mask, i);

	sysinfo->exception_base_addr = octeon_bootinfo->exception_base_addr;
	sysinfo->cpu_clock_hz = octeon_bootinfo->eclock_hz;
	sysinfo->dram_data_rate_hz = octeon_bootinfo->dclock_hz * 2;
	sysinfo->board_type = octeon_bootinfo->board_type;
	sysinfo->board_rev_major = octeon_bootinfo->board_rev_major;
	sysinfo->board_rev_minor = octeon_bootinfo->board_rev_minor;
	memcpy(sysinfo->mac_addr_base, octeon_bootinfo->mac_addr_base,
	       sizeof(sysinfo->mac_addr_base));
	sysinfo->mac_addr_count = octeon_bootinfo->mac_addr_count;
	memcpy(sysinfo->board_serial_number,
	       octeon_bootinfo->board_serial_number,
	       sizeof(sysinfo->board_serial_number));
	sysinfo->compact_flash_common_base_addr =
		octeon_bootinfo->compact_flash_common_base_addr;
	sysinfo->compact_flash_attribute_base_addr =
		octeon_bootinfo->compact_flash_attribute_base_addr;
	sysinfo->led_display_base_addr = octeon_bootinfo->led_display_base_addr;
	sysinfo->dfa_ref_clock_hz = octeon_bootinfo->dfa_ref_clock_hz;
	sysinfo->bootloader_config_flags = octeon_bootinfo->config_flags;

	if (OCTEON_IS_OCTEON2()) {
		/* I/O clock runs at a different rate than the CPU. */
		union cvmx_mio_rst_boot rst_boot;
		rst_boot.u64 = cvmx_read_csr(CVMX_MIO_RST_BOOT);
		octeon_io_clock_rate = 50000000 * rst_boot.s.pnr_mul;
	} else if (OCTEON_IS_OCTEON3()) {
		/* I/O clock runs at a different rate than the CPU. */
		union cvmx_rst_boot rst_boot;
		rst_boot.u64 = cvmx_read_csr(CVMX_RST_BOOT);
		octeon_io_clock_rate = 50000000 * rst_boot.s.pnr_mul;
	} else {
		octeon_io_clock_rate = sysinfo->cpu_clock_hz;
	}

	t = read_c0_cvmctl();
	if ((t & (1ull << 27)) == 0) {
		/*
		 * Setup the multiplier save/restore code if
		 * CvmCtl[NOMUL] clear.
		 */
		void *save;
		void *save_end;
		void *restore;
		void *restore_end;
		int save_len;
		int restore_len;
		int save_max = (char *)octeon_mult_save_end -
			(char *)octeon_mult_save;
		int restore_max = (char *)octeon_mult_restore_end -
			(char *)octeon_mult_restore;
		if (current_cpu_data.cputype == CPU_CAVIUM_OCTEON3) {
			save = octeon_mult_save3;
			save_end = octeon_mult_save3_end;
			restore = octeon_mult_restore3;
			restore_end = octeon_mult_restore3_end;
		} else {
			save = octeon_mult_save2;
			save_end = octeon_mult_save2_end;
			restore = octeon_mult_restore2;
			restore_end = octeon_mult_restore2_end;
		}
		save_len = (char *)save_end - (char *)save;
		restore_len = (char *)restore_end - (char *)restore;
		if (!WARN_ON(save_len > save_max ||
				restore_len > restore_max)) {
			memcpy(octeon_mult_save, save, save_len);
			memcpy(octeon_mult_restore, restore, restore_len);
		}
	}

	/*
	 * Only enable the LED controller if we're running on a CN38XX, CN58XX,
	 * or CN56XX. The CN30XX and CN31XX don't have an LED controller.
	 */
	if (!octeon_is_simulation() &&
	    octeon_has_feature(OCTEON_FEATURE_LED_CONTROLLER)) {
		cvmx_write_csr(CVMX_LED_EN, 0);
		cvmx_write_csr(CVMX_LED_PRT, 0);
		cvmx_write_csr(CVMX_LED_DBG, 0);
		cvmx_write_csr(CVMX_LED_PRT_FMT, 0);
		cvmx_write_csr(CVMX_LED_UDD_CNTX(0), 32);
		cvmx_write_csr(CVMX_LED_UDD_CNTX(1), 32);
		cvmx_write_csr(CVMX_LED_UDD_DATX(0), 0);
		cvmx_write_csr(CVMX_LED_UDD_DATX(1), 0);
		cvmx_write_csr(CVMX_LED_EN, 1);
	}

#ifdef CONFIG_CAVIUM_OCTEON_LOCK_L2
	if (cvmx_read_csr(CVMX_L2D_FUS3) & (3ull << 34)) {
		pr_info("Skipping L2 locking due to reduced L2 cache size\n");
	} else {
		uint32_t __maybe_unused ebase = read_c0_ebase() & 0x3ffff000;
#ifdef CONFIG_CAVIUM_OCTEON_LOCK_L2_TLB
		/* TLB refill */
		cvmx_l2c_lock_mem_region(ebase, 0x100);
#endif
#ifdef CONFIG_CAVIUM_OCTEON_LOCK_L2_EXCEPTION
		/* General exception */
		cvmx_l2c_lock_mem_region(ebase + 0x180, 0x80);
#endif
#ifdef CONFIG_CAVIUM_OCTEON_LOCK_L2_LOW_LEVEL_INTERRUPT
		/* Interrupt handler */
		cvmx_l2c_lock_mem_region(ebase + 0x200, 0x80);
#endif
#ifdef CONFIG_CAVIUM_OCTEON_LOCK_L2_INTERRUPT
		cvmx_l2c_lock_mem_region(__pa_symbol(handle_int), 0x100);
		cvmx_l2c_lock_mem_region(__pa_symbol(plat_irq_dispatch), 0x80);
#endif
#ifdef CONFIG_CAVIUM_OCTEON_LOCK_L2_MEMCPY
		cvmx_l2c_lock_mem_region(__pa_symbol(memcpy), 0x480);
#endif
	}
#endif

	octeon_check_cpu_bist();

	octeon_uart = octeon_get_boot_uart();

#ifdef CONFIG_SMP
	octeon_write_lcd("LinuxSMP");
#else
	octeon_write_lcd("Linux");
#endif

	octeon_setup_delays();

	/*
	 * BIST should always be enabled when doing a soft reset. L2
	 * Cache locking for instance is not cleared unless BIST is
	 * enabled.  Unfortunately due to a chip errata G-200 for
	 * Cn38XX and CN31XX, BIST must be disabled on these parts.
	 */
	if (OCTEON_IS_MODEL(OCTEON_CN38XX_PASS2) ||
	    OCTEON_IS_MODEL(OCTEON_CN31XX))
		cvmx_write_csr(CVMX_CIU_SOFT_BIST, 0);
	else
		cvmx_write_csr(CVMX_CIU_SOFT_BIST, 1);

	/* Default to 64MB in the simulator to speed things up */
	if (octeon_is_simulation())
		max_memory = 64ull << 20;

	arg = strstr(arcs_cmdline, "mem=");
	if (arg) {
		max_memory = memparse(arg + 4, &p);
		if (max_memory == 0)
			max_memory = 32ull << 30;
		if (*p == '@')
			reserve_low_mem = memparse(p + 1, &p);
	}

	arcs_cmdline[0] = 0;
	argc = octeon_boot_desc_ptr->argc;
	for (i = 0; i < argc; i++) {
		const char *arg =
			cvmx_phys_to_ptr(octeon_boot_desc_ptr->argv[i]);
		if ((strncmp(arg, "MEM=", 4) == 0) ||
		    (strncmp(arg, "mem=", 4) == 0)) {
			max_memory = memparse(arg + 4, &p);
			if (max_memory == 0)
				max_memory = 32ull << 30;
			if (*p == '@')
				reserve_low_mem = memparse(p + 1, &p);
#ifdef CONFIG_KEXEC
		} else if (strncmp(arg, "crashkernel=", 12) == 0) {
			crashk_size = memparse(arg+12, &p);
			if (*p == '@')
				crashk_base = memparse(p+1, &p);
			strcat(arcs_cmdline, " ");
			strcat(arcs_cmdline, arg);
			/*
			 * To do: switch parsing to new style, something like:
			 * parse_crashkernel(arg, sysinfo->system_dram_size,
			 *		  &crashk_size, &crashk_base);
			 */
#endif
		} else if (strlen(arcs_cmdline) + strlen(arg) + 1 <
			   sizeof(arcs_cmdline) - 1) {
			strcat(arcs_cmdline, " ");
			strcat(arcs_cmdline, arg);
		}
	}

	if (strstr(arcs_cmdline, "console=") == NULL) {
		if (octeon_uart == 1)
			strcat(arcs_cmdline, " console=ttyS1,115200");
		else
			strcat(arcs_cmdline, " console=ttyS0,115200");
	}

	mips_hpt_frequency = octeon_get_clock_rate();

	octeon_init_cvmcount();

	_machine_restart = octeon_restart;
	_machine_halt = octeon_halt;

#ifdef CONFIG_KEXEC
	_machine_kexec_shutdown = octeon_shutdown;
	_machine_crash_shutdown = octeon_crash_shutdown;
	_machine_kexec_prepare = octeon_kexec_prepare;
#ifdef CONFIG_SMP
	_crash_smp_send_stop = octeon_crash_smp_send_stop;
#endif
#endif

	octeon_user_io_init();
	octeon_setup_smp();
}