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 }
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; }
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; }
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; }