int tegra_bbc_proxy_la_request(struct device *dev, s32 bbcllr_la_bw,
				s32 bbcr_la_bw, s32 bbcw_la_bw)
{
	struct tegra_bbc_proxy *bbc = dev_get_drvdata(dev);

	if (bbcllr_la_bw < 0)
		bbcllr_la_bw = BBCLLR_LA_MAX_BW;
	if (tegra_set_latency_allowance(TEGRA_LA_BBCLLR, bbcllr_la_bw / 1000))
		return -EINVAL;

	if (bbcr_la_bw < 0)
		bbcr_la_bw = (bbc->bw  * BBCR_BW_PERCENTAGE) / 100;
	if (tegra_set_latency_allowance(TEGRA_LA_BBCR, bbcr_la_bw / 1000))
		return -EINVAL;

	if (bbcw_la_bw < 0)
		bbcw_la_bw = (bbc->bw * BBCW_BW_PERCENTAGE) / 100;
	if (tegra_set_latency_allowance(TEGRA_LA_BBCW, bbcw_la_bw / 1000))
		return -EINVAL;

	dev_dbg(dev, "bbc la request - llr_bw: %d r_bw: %d w_bw: %d",
			bbcllr_la_bw, bbcr_la_bw, bbcw_la_bw);

	return 0;
}
/* uses the larger of w->bandwidth or w->new_bandwidth */
static void tegra_dc_set_latency_allowance(struct tegra_dc *dc,
	struct tegra_dc_win *w)
{
	/* windows A, B, C for first and second display */
	static const enum tegra_la_id la_id_tab[2][3] = {
		/* first display */
		{ TEGRA_LA_DISPLAY_0A, TEGRA_LA_DISPLAY_0B,
			TEGRA_LA_DISPLAY_0C },
		/* second display */
		{ TEGRA_LA_DISPLAY_0AB, TEGRA_LA_DISPLAY_0BB,
			TEGRA_LA_DISPLAY_0CB },
	};
#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
	/* window B V-filter tap for first and second display. */
	static const enum tegra_la_id vfilter_tab[2] = {
		TEGRA_LA_DISPLAY_1B, TEGRA_LA_DISPLAY_1BB,
	};
#endif
	unsigned long bw;

	BUG_ON(dc->ndev->id >= ARRAY_SIZE(la_id_tab));
#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
	BUG_ON(dc->ndev->id >= ARRAY_SIZE(vfilter_tab));
#endif
	BUG_ON(w->idx >= ARRAY_SIZE(*la_id_tab));

	bw = max(w->bandwidth, w->new_bandwidth);

#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
	/* tegra_dc_get_bandwidth() treats V filter windows as double
	 * bandwidth, but LA has a seperate client for V filter */
	if (w->idx == 1 && win_use_v_filter(dc, w))
		bw /= 2;
#endif

	/* our bandwidth is in kbytes/sec, but LA takes MBps.
	 * round up bandwidth to next 1MBps */
	bw = bw / 1000 + 1;

#ifdef CONFIG_TEGRA_SILICON_PLATFORM
	tegra_set_latency_allowance(la_id_tab[dc->ndev->id][w->idx], bw);
#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
	/* if window B, also set the 1B client for the 2-tap V filter. */
	if (w->idx == 1)
		tegra_set_latency_allowance(vfilter_tab[dc->ndev->id], bw);
#endif
#endif
}
Beispiel #3
0
static int bbc_bw_request_unlocked(struct device *dev, u32 mode, u32 bw,
				u32 lt, u32 margin)
{
	int ret;
	struct tegra_bbc_proxy *bbc = dev_get_drvdata(dev);

	if (bw > MAX_ISO_BW_REQ)
		return -EINVAL;

	if (margin > MAX_ISO_BW_REQ)
		return -EINVAL;

	if (margin != bbc->margin) {
		ret = tegra_isomgr_set_margin(TEGRA_ISO_CLIENT_BBC_0,
			margin, true);
		if (ret) {
			dev_err(dev, "can't margin for bbc bw\n");
			return ret;
		}

		bbc->margin = margin;
	}

	if ((bw != bbc->bw) || (lt != bbc->lt)) {
		ret = tegra_isomgr_reserve(bbc->isomgr_handle, bw, lt);
		if (!ret) {
			dev_err(dev, "can't reserve iso bw\n");
			return ret;
		}
		bbc->bw = bw;

		ret = tegra_isomgr_realize(bbc->isomgr_handle);
		if (!ret) {
			dev_err(dev, "can't realize iso bw\n");
			return ret;
		}
		bbc->lt = lt;

		tegra_set_latency_allowance(TEGRA_LA_BBCR, bw / 1000);
		tegra_set_latency_allowance(TEGRA_LA_BBCW, bw / 1000);
	}

	return 0;
}
static ssize_t la_bbcw_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t size)
{
	unsigned int la_val;

	if (sscanf(buf, "%u", &la_val) != 1)
		return -EINVAL;
	if (la_val > (MAX_ISO_BW_REQ / 1000))
		return -EINVAL;

	tegra_set_latency_allowance(TEGRA_LA_BBCW, la_val);

	return size;
}
Beispiel #5
0
int tegra_camera_set_latency_allowance(struct tegra_camera *camera,
	unsigned long vi_freq)
{
	/*
	 * Assumption is that preview port has YUV422 and video port has
	 * YUV420. Preview port may have Bayer format which has 10 bit per
	 * pixel. Even if preview port has Bayer format, setting latency
	 * allowance with YUV422 format should be OK because BPP of YUV422 is
	 * higher than BPP of Bayer.
	 * When this function gets called, video format is not programmed yet.
	 * That's why we have to assume video format here rather than reading
	 * them from registers.
	 */
	tegra_set_latency_allowance(TEGRA_LA_VI_WSB,
		((vi_freq / 1000000UL) * BPP_YUV422) / 8UL);
	tegra_set_latency_allowance(TEGRA_LA_VI_WU,
		((vi_freq / 1000000UL) * BPP_YUV420_U) / 8UL);
	tegra_set_latency_allowance(TEGRA_LA_VI_WV,
		((vi_freq / 1000000UL) * BPP_YUV420_V) / 8UL);
	tegra_set_latency_allowance(TEGRA_LA_VI_WY,
		((vi_freq / 1000000UL) * BPP_YUV420_Y) / 8UL);

	return 0;
}
Beispiel #6
0
static int tegra_bbc_proxy_probe(struct platform_device *pdev)
{
	struct tegra_bbc_proxy_platform_data *pdata = pdev->dev.platform_data;
	struct tegra_bbc_proxy *bbc;
	struct edp_manager *mgr;
	struct device_attribute **attrs;
	struct device_attribute *attr;
	int ret = 0;

	/* check for platform data */
	if (!pdata) {
		dev_err(&pdev->dev, "platform data not available\n");
		return -ENODEV;
	}

	bbc = kzalloc(sizeof(struct tegra_bbc_proxy), GFP_KERNEL);
	if (!bbc) {
		dev_err(&pdev->dev, "failed to allocate memory\n");
		return -ENOMEM;
	}

	if (pdata->modem_boot_edp_client && pdata->edp_manager_name) {
		mutex_init(&bbc->edp_lock);

		/* register bbc boot client */
		bbc->edp_manager_name = pdata->edp_manager_name;
		mgr = edp_get_manager(pdata->edp_manager_name);
		if (!mgr) {
			dev_err(&pdev->dev, "can't get edp manager\n");
			goto error;
		}

		bbc->modem_boot_edp_client = pdata->modem_boot_edp_client;
		ret = edp_register_client(mgr, bbc->modem_boot_edp_client);
		if (ret) {
			dev_err(&pdev->dev,
				"unable to register bbc boot edp client\n");
			goto error;
		}

		/* request E0 */
		ret = edp_update_client_request(bbc->modem_boot_edp_client,
						0, NULL);
		if (ret) {
			dev_err(&pdev->dev,
				"unable to set e0 state\n");
			goto edp_req_error;
		}

		bbc->edp_boot_client_registered = 1;

		bbc->i_breach_ppm = pdata->i_breach_ppm;
		bbc->i_thresh_3g_adjperiod = pdata->i_thresh_3g_adjperiod;
		bbc->i_thresh_lte_adjperiod = pdata->i_thresh_lte_adjperiod;

		attrs = edp_attributes;
		while ((attr = *attrs++)) {
			ret = device_create_file(&pdev->dev, attr);
			if (ret) {
				dev_err(&pdev->dev,
					"can't create sysfs file\n");
				goto edp_req_error;
			}
		}

		bbc->edp_initialized = 1;
		bbc->ap_name = pdata->ap_name;
	}

	mutex_init(&bbc->iso_lock);

	bbc->isomgr_handle = tegra_isomgr_register(TEGRA_ISO_CLIENT_BBC_0,
		MAX_ISO_BW_REQ, NULL, NULL);
	if (!bbc->isomgr_handle)
		goto iso_error;

	tegra_set_latency_allowance(TEGRA_LA_BBCLLR, 640);

	/* statically margin for bbc bw */
	ret = tegra_isomgr_set_margin(TEGRA_ISO_CLIENT_BBC_0,
		MAX_ISO_BW_REQ, true);
	if (ret)
		dev_err(&pdev->dev, "can't margin for bbc bw\n");
	else
		bbc->margin = MAX_ISO_BW_REQ;

	/* thermal zones from bbc */
	tegra_bbc_thermal_init();

	attrs = mc_attributes;
	while ((attr = *attrs++)) {
		ret = device_create_file(&pdev->dev, attr);
		if (ret) {
			dev_err(&pdev->dev, "can't create sysfs file\n");
			goto mc_error;
		}
	}

	bbc->sim0 = regulator_get(&pdev->dev, "vddio_sim0");
	if (IS_ERR(bbc->sim0)) {
		dev_err(&pdev->dev, "vddio_sim0 regulator get failed\n");
		bbc->sim0 = NULL;
		goto sim_error;
	}

	bbc->sim1 = regulator_get(&pdev->dev, "vddio_sim1");
	if (IS_ERR(bbc->sim1)) {
		dev_err(&pdev->dev, "vddio_sim1 regulator get failed\n");
		bbc->sim1 = NULL;
		goto sim_error;
	}

	attrs = sim_attributes;
	while ((attr = *attrs++)) {
		ret = device_create_file(&pdev->dev, attr);
		if (ret) {
			dev_err(&pdev->dev, "can't create sysfs file\n");
			goto sim_error;
		}
	}

	bbc->rf1v7 = regulator_get(&pdev->dev, "vdd_1v7_rf");
	if (IS_ERR(bbc->rf1v7)) {
		dev_info(&pdev->dev,
			 "vdd_1v7_rf regulator not available\n");
		bbc->rf1v7 = NULL;
	}

	bbc->rf2v65 = regulator_get(&pdev->dev, "vdd_2v65_rf");
	if (IS_ERR(bbc->rf2v65)) {
		dev_info(&pdev->dev,
			 "vdd_2v65_rf regulator not available\n");
		bbc->rf2v65 = NULL;
	}

	if (bbc->rf1v7 && bbc->rf2v65) {
		attrs = rf_attributes;
		while ((attr = *attrs++)) {
			ret = device_create_file(&pdev->dev, attr);
			if (ret) {
				dev_err(&pdev->dev,
					"can't create sysfs file\n");
				goto rf_error;
			}
		}
	}

	dev_set_drvdata(&pdev->dev, bbc);

	return 0;

rf_error:
	regulator_put(bbc->rf1v7);
	regulator_put(bbc->rf2v65);
sim_error:
	regulator_put(bbc->sim0);
	regulator_put(bbc->sim1);

	attrs = mc_attributes;
	while ((attr = *attrs++))
		device_remove_file(&pdev->dev, attr);

mc_error:
	tegra_isomgr_unregister(bbc->isomgr_handle);

iso_error:
	if (bbc->edp_initialized) {
		attrs = edp_attributes;
		while ((attr = *attrs++))
			device_remove_file(&pdev->dev, attr);
	}

edp_req_error:
	if (bbc->edp_boot_client_registered)
		edp_unregister_client(bbc->modem_boot_edp_client);

error:
	kfree(bbc);

	return ret;
}