Exemple #1
0
static int msenc_setup_ucode_image(struct platform_device *dev,
                                   u32 *ucode_ptr,
                                   const struct firmware *ucode_fw)
{
    struct msenc *m = get_msenc(dev);
    /* image data is little endian. */
    struct msenc_ucode_v1 ucode;
    int w;

    /* copy the whole thing taking into account endianness */
    for (w = 0; w < ucode_fw->size / sizeof(u32); w++)
        ucode_ptr[w] = le32_to_cpu(((u32 *)ucode_fw->data)[w]);

    ucode.bin_header = (struct msenc_ucode_bin_header_v1 *)ucode_ptr;
    /* endian problems would show up right here */
    if (ucode.bin_header->bin_magic != 0x10de) {
        dev_err(&dev->dev,
                "failed to get firmware magic");
        return -EINVAL;
    }
    if (ucode.bin_header->bin_ver != 1) {
        dev_err(&dev->dev,
                "unsupported firmware version");
        return -ENOENT;
    }
    /* shouldn't be bigger than what firmware thinks */
    if (ucode.bin_header->bin_size > ucode_fw->size) {
        dev_err(&dev->dev,
                "ucode image size inconsistency");
        return -EINVAL;
    }

    nvhost_dbg_info("ucode bin header: magic:0x%x ver:%d size:%d",
                    ucode.bin_header->bin_magic,
                    ucode.bin_header->bin_ver,
                    ucode.bin_header->bin_size);
    nvhost_dbg_info("ucode bin header: os bin (header,data) offset size: 0x%x, 0x%x %d",
                    ucode.bin_header->os_bin_header_offset,
                    ucode.bin_header->os_bin_data_offset,
                    ucode.bin_header->os_bin_size);
    ucode.os_header = (struct msenc_ucode_os_header_v1 *)
                      (((void *)ucode_ptr) + ucode.bin_header->os_bin_header_offset);

    nvhost_dbg_info("os ucode header: os code (offset,size): 0x%x, 0x%x",
                    ucode.os_header->os_code_offset,
                    ucode.os_header->os_code_size);
    nvhost_dbg_info("os ucode header: os data (offset,size): 0x%x, 0x%x",
                    ucode.os_header->os_data_offset,
                    ucode.os_header->os_data_size);
    nvhost_dbg_info("os ucode header: num apps: %d",
                    ucode.os_header->num_apps);

    m->os.size = ucode.bin_header->os_bin_size;
    m->os.bin_data_offset = ucode.bin_header->os_bin_data_offset;
    m->os.code_offset = ucode.os_header->os_code_offset;
    m->os.data_offset = ucode.os_header->os_data_offset;
    m->os.data_size   = ucode.os_header->os_data_size;

    return 0;
}
Exemple #2
0
/* Calculate and update M/N/PL as well as pll->freq
    ref_clk_f = clk_in_f / src_div = clk_in_f; (src_div = 1 on gk20a)
    u_f = ref_clk_f / M;
    PLL output = vco_f = u_f * N = ref_clk_f * N / M;
    gpc2clk = target clock frequency = vco_f / PL;
    gpcclk = gpc2clk / 2; */
static int clk_config_pll(struct clk_gk20a *clk, struct pll *pll,
	struct pll_parms *pll_params, u32 *target_freq, bool best_fit)
{
	u32 min_vco_f, max_vco_f;
	u32 best_M, best_N;
	u32 low_PL, high_PL, best_PL;
	u32 m, n, n2;
	u32 target_vco_f, vco_f;
	u32 ref_clk_f, target_clk_f, u_f;
	u32 delta, lwv, best_delta = ~0;
	int pl;

	BUG_ON(target_freq == NULL);

	nvhost_dbg_fn("request target freq %d MHz", *target_freq);

	ref_clk_f = pll->clk_in;
	target_clk_f = *target_freq;
	max_vco_f = pll_params->max_vco;
	min_vco_f = pll_params->min_vco;
	best_M = pll_params->max_M;
	best_N = pll_params->min_N;
	best_PL = pll_params->min_PL;

	target_vco_f = target_clk_f + target_clk_f / 50;
	if (max_vco_f < target_vco_f)
		max_vco_f = target_vco_f;

	high_PL = (max_vco_f + target_vco_f - 1) / target_vco_f;
	high_PL = min(high_PL, pll_params->max_PL);
	high_PL = max(high_PL, pll_params->min_PL);

	low_PL = min_vco_f / target_vco_f;
	low_PL = min(low_PL, pll_params->max_PL);
	low_PL = max(low_PL, pll_params->min_PL);

	/* Find Indices of high_PL and low_PL */
	for (pl = 0; pl < 14; pl++) {
		if (pl_to_div[pl] >= low_PL) {
			low_PL = pl;
			break;
		}
	}
	for (pl = 0; pl < 14; pl++) {
		if (pl_to_div[pl] >= high_PL) {
			high_PL = pl;
			break;
		}
	}
	nvhost_dbg_info("low_PL %d(div%d), high_PL %d(div%d)",
			low_PL, pl_to_div[low_PL], high_PL, pl_to_div[high_PL]);

	for (pl = low_PL; pl <= high_PL; pl++) {
		target_vco_f = target_clk_f * pl_to_div[pl];

		for (m = pll_params->min_M; m <= pll_params->max_M; m++) {
			u_f = ref_clk_f / m;

			if (u_f < pll_params->min_u)
				break;
			if (u_f > pll_params->max_u)
				continue;

			n = (target_vco_f * m) / ref_clk_f;
			n2 = ((target_vco_f * m) + (ref_clk_f - 1)) / ref_clk_f;

			if (n > pll_params->max_N)
				break;

			for (; n <= n2; n++) {
				if (n < pll_params->min_N)
					continue;
				if (n > pll_params->max_N)
					break;

				vco_f = ref_clk_f * n / m;

				if (vco_f >= min_vco_f && vco_f <= max_vco_f) {
					lwv = (vco_f + (pl_to_div[pl] / 2))
						/ pl_to_div[pl];
					delta = abs(lwv - target_clk_f);

					if (delta < best_delta) {
						best_delta = delta;
						best_M = m;
						best_N = n;
						best_PL = pl;

						if (best_delta == 0 ||
						    /* 0.45% for non best fit */
						    (!best_fit && (vco_f / best_delta > 218))) {
							goto found_match;
						}

						nvhost_dbg_info("delta %d @ M %d, N %d, PL %d",
							delta, m, n, pl);
					}
				}
			}
		}
	}

found_match:
	BUG_ON(best_delta == ~0);

	if (best_fit && best_delta != 0)
		nvhost_dbg_clk("no best match for target @ %dMHz on gpc_pll",
			target_clk_f);

	pll->M = best_M;
	pll->N = best_N;
	pll->PL = best_PL;

	/* save current frequency */
	pll->freq = ref_clk_f * pll->N / (pll->M * pl_to_div[pll->PL]);

	*target_freq = pll->freq;

	nvhost_dbg_clk("actual target freq %d MHz, M %d, N %d, PL %d(div%d)",
		*target_freq, pll->M, pll->N, pll->PL, pl_to_div[pll->PL]);

	nvhost_dbg_fn("done");

	return 0;
}
static int flcn_setup_ucode_image(struct platform_device *dev,
				   u32 *ucode_ptr,
				   const struct firmware *ucode_fw)
{
	struct flcn *v = get_flcn(dev);
	/* image data is little endian. */
	struct ucode_v1_flcn ucode;
	int w;
	u32 reserved_offset;
	u32 tsec_key_offset;

	nvhost_dbg_fn("");

	/* copy the whole thing taking into account endianness */
	for (w = 0; w < ucode_fw->size/sizeof(u32); w++)
		ucode_ptr[w] = le32_to_cpu(((u32 *)ucode_fw->data)[w]);

	ucode.bin_header = (struct ucode_bin_header_v1_flcn *)ucode_ptr;
	/* endian problems would show up right here */
	if (ucode.bin_header->bin_magic != 0x10de) {
		dev_err(&dev->dev,
			   "failed to get firmware magic");
		return -EINVAL;
	}
	if (ucode.bin_header->bin_ver != 1) {
		dev_err(&dev->dev,
			   "unsupported firmware version");
		return -ENOENT;
	}
	/* shouldn't be bigger than what firmware thinks */
	if (ucode.bin_header->bin_size > ucode_fw->size) {
		dev_err(&dev->dev,
			   "ucode image size inconsistency");
		return -EINVAL;
	}

	nvhost_dbg_info("ucode bin header: magic:0x%x ver:%d size:%d",
			ucode.bin_header->bin_magic,
			ucode.bin_header->bin_ver,
			ucode.bin_header->bin_size);
	nvhost_dbg_info("ucode bin header: os bin (header,data) offset size: 0x%x, 0x%x %d",
			ucode.bin_header->os_bin_header_offset,
			ucode.bin_header->os_bin_data_offset,
			ucode.bin_header->os_bin_size);
	nvhost_dbg_info("ucode bin header: fce bin (header,data) offset size: 0x%x, 0x%x %d",
			ucode.bin_header->fce_bin_header_offset,
			ucode.bin_header->fce_bin_data_offset,
			ucode.bin_header->fce_bin_size);

	ucode.os_header = (struct ucode_os_header_v1_flcn *)
		(((void *)ucode_ptr) + ucode.bin_header->os_bin_header_offset);

	nvhost_dbg_info("os ucode header: os code (offset,size): 0x%x, 0x%x",
			ucode.os_header->os_code_offset,
			ucode.os_header->os_code_size);
	nvhost_dbg_info("os ucode header: os data (offset,size): 0x%x, 0x%x",
			ucode.os_header->os_data_offset,
			ucode.os_header->os_data_size);
	nvhost_dbg_info("os ucode header: num apps: %d", ucode.os_header->num_apps);

	if (ucode.bin_header->fce_bin_header_offset != 0xa5a5a5a5) {
		ucode.fce_header = (struct ucode_fce_header_v1_flcn *)
			(((void *)ucode_ptr) +
			 ucode.bin_header->fce_bin_header_offset);
		nvhost_dbg_info("fce ucode header: offset, buffer_size, size: 0x%x 0x%x 0x%x",
				ucode.fce_header->fce_ucode_offset,
				ucode.fce_header->fce_ucode_buffer_size,
				ucode.fce_header->fce_ucode_size);
		v->fce.size        = ucode.fce_header->fce_ucode_size;
		v->fce.data_offset =
			ucode.bin_header->fce_bin_data_offset;
	}

	/* make space for reserved area - we need 20 bytes, but we move 256
	 * bytes because firmware needs to be 256 byte aligned */
	reserved_offset = ucode.bin_header->os_bin_data_offset;
	memmove(((void *)ucode_ptr) + reserved_offset + FALCON_RESERVE,
			((void *)ucode_ptr) + reserved_offset,
			ucode.bin_header->os_bin_size);
	ucode.bin_header->os_bin_data_offset += FALCON_RESERVE;

	/*  clear 256 bytes before ucode os code */
	memset(((void *)ucode_ptr) + reserved_offset, 0, FALCON_RESERVE);

	/* Copy key to be the 16 bytes before the firmware */
	tsec_key_offset = reserved_offset + TSEC_KEY_OFFSET;
	memcpy(((void *)ucode_ptr) + tsec_key_offset, otf_key, TSEC_KEY_LENGTH);
	v->os.size = ucode.bin_header->os_bin_size;
	v->os.bin_data_offset = ucode.bin_header->os_bin_data_offset;
	v->os.code_offset = ucode.os_header->os_code_offset;
	v->os.data_offset = ucode.os_header->os_data_offset;
	v->os.data_size   = ucode.os_header->os_data_size;

	return 0;
}