static void scale3d_clocks(unsigned long percent) { unsigned long hz, curr; if (!tegra_is_clk_enabled(scale3d.clk_3d)) return; if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3) if (!tegra_is_clk_enabled(scale3d.clk_3d2)) return; curr = clk_get_rate(scale3d.clk_3d); hz = percent * (curr / 100); if (!(hz >= scale3d.max_rate_3d && curr == scale3d.max_rate_3d)) { if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3) clk_set_rate(scale3d.clk_3d2, 0); clk_set_rate(scale3d.clk_3d, hz); if (scale3d.p_scale_emc) { long after = (long) clk_get_rate(scale3d.clk_3d); hz = after * scale3d.emc_slope + scale3d.emc_offset; if (scale3d.p_emc_dip) hz -= (scale3d.emc_dip_slope * POW2(after / 1000 - scale3d.emc_xmid) + scale3d.emc_dip_offset); clk_set_rate(scale3d.clk_3d_emc, hz); } } }
/* use the larger of dc->emc_clk_rate or dc->new_emc_clk_rate, and copies * dc->new_emc_clk_rate into dc->emc_clk_rate. * calling this function both before and after a flip is sufficient to select * the best possible frequency and latency allowance. * set use_new to true to force dc->new_emc_clk_rate programming. */ void tegra_dc_program_bandwidth(struct tegra_dc *dc, bool use_new) { unsigned i; if (use_new || dc->emc_clk_rate != dc->new_emc_clk_rate) { /* going from 0 to non-zero */ if (!dc->emc_clk_rate && !tegra_is_clk_enabled(dc->emc_clk)) clk_prepare_enable(dc->emc_clk); clk_set_rate(dc->emc_clk, max(dc->emc_clk_rate, dc->new_emc_clk_rate)); dc->emc_clk_rate = dc->new_emc_clk_rate; /* going from non-zero to 0 */ if (!dc->new_emc_clk_rate && tegra_is_clk_enabled(dc->emc_clk)) clk_disable_unprepare(dc->emc_clk); } for (i = 0; i < DC_N_WINDOWS; i++) { struct tegra_dc_win *w = &dc->windows[i]; if ((use_new || w->bandwidth != w->new_bandwidth) && w->new_bandwidth != 0) tegra_dc_set_latency_allowance(dc, w); trace_program_bandwidth(dc); w->bandwidth = w->new_bandwidth; } }
/* use the larger of dc->emc_clk_rate or dc->new_emc_clk_rate, and copies * dc->new_emc_clk_rate into dc->emc_clk_rate. * calling this function both before and after a flip is sufficient to select * the best possible frequency and latency allowance. * set use_new to true to force dc->new_emc_clk_rate programming. */ void tegra_dc_program_bandwidth(struct tegra_dc *dc, bool use_new) { unsigned i; // // int temp_emc_clk; if (use_new || dc->emc_clk_rate != dc->new_emc_clk_rate) { /* going from 0 to non-zero */ if (!dc->emc_clk_rate && !tegra_is_clk_enabled(dc->emc_clk)) clk_enable(dc->emc_clk); // // clk_set_rate(dc->emc_clk, // max(dc->emc_clk_rate, dc->new_emc_clk_rate)); // // clk_set_rate(dc->emc_clk, max(dc->emc_clk_rate, dc->new_emc_clk_rate)); /* */ dc->emc_clk_rate = dc->new_emc_clk_rate; // // // // dc->emc_clk_rate = (dc->emc_clk_rate > 204000000) ? dc->emc_clk_rate : 204000000; //#endif // // /* going from non-zero to 0 */ if (!dc->new_emc_clk_rate && tegra_is_clk_enabled(dc->emc_clk)) clk_disable(dc->emc_clk); } /* */ for (i = 0; i < DC_N_WINDOWS; i++) { struct tegra_dc_win *w = &dc->windows[i]; if ((use_new || w->bandwidth != w->new_bandwidth) && w->new_bandwidth != 0) tegra_dc_set_latency_allowance(dc, w); trace_program_bandwidth(dc); w->bandwidth = w->new_bandwidth; } }
static void scale3d_clocks(unsigned long percent) { unsigned long hz, curr; int i = 0; ktime_t t; if (!tegra_is_clk_enabled(scale3d.clk_3d)) return; if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3) if (!tegra_is_clk_enabled(scale3d.clk_3d2)) return; curr = clk_get_rate(scale3d.clk_3d); hz = percent * (curr / 100); if (!(hz >= scale3d.max_rate_3d && curr == scale3d.max_rate_3d)) { if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3) clk_set_rate(scale3d.clk_3d2, 0); if (is_tegra_camera_on()) clk_set_rate(scale3d.clk_3d, CAMERA_3D_CLK); else clk_set_rate(scale3d.clk_3d, hz); if (scale3d.p_scale_emc) { long after = (long) clk_get_rate(scale3d.clk_3d); hz = after * scale3d.emc_slope + scale3d.emc_offset; if (scale3d.p_emc_dip) hz -= (scale3d.emc_dip_slope * POW2(after / 1000 - scale3d.emc_xmid) + scale3d.emc_dip_offset); if (is_tegra_camera_on()) clk_set_rate(scale3d.clk_3d_emc, CAMERA_3D_EMC_CLK); else clk_set_rate(scale3d.clk_3d_emc, hz); } } t = ktime_get(); hz = clk_get_rate(scale3d.clk_3d); if (hz != curr) { gpu_loading[curr_idx].total_time += ktime_us_delta(t, gpu_loading[curr_idx].last_start); for (i=0 ; i<FREQ_LEVEL ; i++) { if (gpu_loading[i].freq == hz) { curr_idx = i; break; } } gpu_loading[curr_idx].last_start = t; } }
/* to save power, call when display memory clients would be idle */ void tegra_dc_clear_bandwidth(struct tegra_dc *dc) { trace_clear_bandwidth(dc); if (tegra_is_clk_enabled(dc->emc_clk)) clk_disable_unprepare(dc->emc_clk); dc->emc_clk_rate = 0; }
void tegra_dc_clk_disable(struct tegra_dc *dc) { if (tegra_is_clk_enabled(dc->clk)) { clk_disable(dc->clk); tegra_dvfs_set_rate(dc->clk, 0); } }
void tegra_dc_clk_enable(struct tegra_dc *dc) { if (!tegra_is_clk_enabled(dc->clk)) { clk_enable(dc->clk); tegra_dvfs_set_rate(dc->clk, dc->mode.pclk); } }
/* to save power, call when display memory clients would be idle */ void tegra_dc_clear_bandwidth(struct tegra_dc *dc) { trace_printk("%s:%s rate=%d\n", dc->ndev->name, __func__, dc->emc_clk_rate); if (tegra_is_clk_enabled(dc->emc_clk)) clk_disable(dc->emc_clk); dc->emc_clk_rate = 0; }
static void do_scale(int diff) { unsigned long hz, curr; if (!tegra_is_clk_enabled(scale3d.clk_3d)) return; if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3) if (!tegra_is_clk_enabled(scale3d.clk_3d2)) return; curr = clk_get_rate(scale3d.clk_3d); hz = curr + diff; if (hz < scale3d.min_rate_3d) hz = scale3d.min_rate_3d; if (hz > scale3d.max_rate_3d) hz = scale3d.max_rate_3d; if (hz == curr) return; if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3) clk_set_rate(scale3d.clk_3d2, 0); if (is_tegra_camera_on()) clk_set_rate(scale3d.clk_3d, CAMERA_3D_CLK); else clk_set_rate(scale3d.clk_3d, hz); if (scale3d.p_scale_emc) { long after = (long) clk_get_rate(scale3d.clk_3d); hz = after * scale3d.emc_slope + scale3d.emc_offset; if (scale3d.p_emc_dip) hz -= (scale3d.emc_dip_slope * POW2(after / 1000 - scale3d.emc_xmid) + scale3d.emc_dip_offset); if (is_tegra_camera_on()) clk_set_rate(scale3d.clk_3d_emc, CAMERA_3D_EMC_CLK); else clk_set_rate(scale3d.clk_3d_emc, hz); } }
static int nvhost_scale3d_target(struct device *d, unsigned long *freq, u32 flags) { long hz; long after; /* Inform that the clock is disabled */ if (!tegra_is_clk_enabled(power_profile.clk_3d)) { *freq = 0; return 0; } /* Limit the frequency */ if (*freq < power_profile.min_rate_3d) *freq = power_profile.min_rate_3d; else if (*freq > power_profile.max_rate_3d) *freq = power_profile.max_rate_3d; /* Check if we're already running at the desired speed */ if (*freq == clk_get_rate(power_profile.clk_3d)) return 0; /* Set GPU clockrate */ if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3) nvhost_module_set_devfreq_rate(power_profile.dev, clk_to_idx(power_profile.clk_3d2), 0); nvhost_module_set_devfreq_rate(power_profile.dev, clk_to_idx(power_profile.clk_3d), *freq); /* Set EMC clockrate */ after = (long) clk_get_rate(power_profile.clk_3d); after = INT_TO_FX(HZ_TO_MHZ(after)); hz = FXMUL(after, power_profile.emc_slope) + power_profile.emc_offset; hz -= FXMUL(power_profile.emc_dip_slope, FXMUL(after - power_profile.emc_xmid, after - power_profile.emc_xmid)) + power_profile.emc_dip_offset; hz = MHZ_TO_HZ(FX_TO_INT(hz + FX_HALF)); /* round to nearest */ hz = (hz < 0) ? 0 : hz; nvhost_module_set_devfreq_rate(power_profile.dev, clk_to_idx(power_profile.clk_3d_emc), hz); /* Get the new clockrate */ *freq = clk_get_rate(power_profile.clk_3d); return 0; }
static void scale3d_idle_handler(struct work_struct *work) { int notify_idle = 0; mutex_lock(&scale3d.lock); if (scale3d.enable && scale3d.is_idle && tegra_is_clk_enabled(scale3d.clk_3d)) { unsigned long curr = clk_get_rate(scale3d.clk_3d); if (curr > scale3d.min_rate_3d) notify_idle = 1; } mutex_unlock(&scale3d.lock); if (notify_idle) nvhost_scale3d_notify_idle(NULL); }
void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data) { if (!IS_ERR(data->clk_out1)) clk_put(data->clk_out1); clk_put(data->clk_cdev1); /* Just to make sure that clk_cdev1 should turn off in case if it is * switched on by some codec whose hw switch is not registered.*/ if (tegra_is_clk_enabled(data->clk_cdev1)) clk_disable(data->clk_cdev1); if (!IS_ERR(data->clk_pll_a_out0)) clk_put(data->clk_pll_a_out0); if (!IS_ERR(data->clk_pll_a)) clk_put(data->clk_pll_a); if (!IS_ERR(data->clk_pll_p_out1)) clk_put(data->clk_pll_p_out1); }
static void handle_recheck_edid_l(struct tegra_dc_hdmi_data *hdmi) { int match, tgt_state, timeout; tgt_state = HDMI_STATE_RESET; timeout = 0; if (hdmi_recheck_edid(hdmi, &match)) { /* Failed to read EDID. If we still have retry attempts left, * schedule another attempt. Otherwise give up and reset; */ work_state.edid_reads++; if (work_state.edid_reads >= MAX_EDID_READ_ATTEMPTS) { pr_info("Failed to read EDID after %d times. Giving up.\n", work_state.edid_reads); } else { tgt_state = HDMI_STATE_DONE_RECHECK_EDID; timeout = CHECK_EDID_DELAY_MS; } } else { /* Successful read! If the EDID is unchanged, just go back to * the DONE_ENABLED state and do nothing. If something changed, * just reset the whole system. */ if (match) { pr_info("No EDID change after HPD bounce, taking no action.\n"); tgt_state = HDMI_STATE_DONE_ENABLED; if (tegra_is_clk_enabled(hdmi->dc->clk)) { tegra_nvhdcp_set_plug(hdmi->nvhdcp, 0); tegra_nvhdcp_set_plug(hdmi->nvhdcp, 1); } else { pr_info("dc powergated, skipping hdcp reset\n"); } timeout = -1; } else { pr_info("EDID change after HPD bounce, resetting\n"); } } hdmi_state_machine_set_state_l(tgt_state, timeout); }
static int nvhost_scale_target(struct device *dev, unsigned long *freq, u32 flags) { struct nvhost_device_data *pdata = dev_get_drvdata(dev); struct nvhost_device_profile *profile = pdata->power_profile; if (!tegra_is_clk_enabled(profile->clk)) { *freq = profile->devfreq_profile.freq_table[0]; return 0; } *freq = clk_round_rate(clk_get_parent(profile->clk), *freq); if (clk_get_rate(profile->clk) == *freq) return 0; nvhost_module_set_devfreq_rate(profile->pdev, 0, *freq); if (pdata->scaling_post_cb) pdata->scaling_post_cb(profile, *freq); *freq = clk_get_rate(profile->clk); return 0; }
int is_partition_clk_disabled(struct powergate_partition_info *pg_info) { u32 idx; struct clk *clk; struct partition_clk_info *clk_info; int ret = 0; for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) { clk_info = &pg_info->clk_info[idx]; clk = clk_info->clk_ptr; if (!clk) break; if (clk_info->clk_type != RST_ONLY) { if (tegra_is_clk_enabled(clk)) { ret = -1; break; } } } return ret; }
static void handle_check_edid_l(struct tegra_dc_hdmi_data *hdmi) { struct fb_monspecs specs; #ifdef CONFIG_SWITCH int state; #endif memset(&specs, 0, sizeof(specs)); #ifdef CONFIG_FRAMEBUFFER_CONSOLE /* Set default videomode on dc before enabling it*/ tegra_dc_set_default_videomode(hdmi->dc); #endif if (!tegra_dc_hpd(work_state.hdmi->dc)) { /* hpd dropped - stop EDID read */ pr_info("hpd == 0, aborting EDID read\n"); goto end_disabled; } if (tegra_edid_get_monspecs(hdmi->edid, &specs)) { /* Failed to read EDID. If we still have retry attempts left, * schedule another attempt. Otherwise give up and just go to * the disabled state. */ work_state.edid_reads++; if (work_state.edid_reads >= MAX_EDID_READ_ATTEMPTS) { pr_info("Failed to read EDID after %d times. Giving up.\n", work_state.edid_reads); goto end_disabled; } else { hdmi_state_machine_set_state_l(HDMI_STATE_CHECK_EDID, CHECK_EDID_DELAY_MS); } return; } if (tegra_edid_get_eld(hdmi->edid, &hdmi->eld) < 0) { pr_err("error populating eld\n"); goto end_disabled; } hdmi->eld_retrieved = true; pr_info("panel size %d by %d\n", specs.max_x, specs.max_y); /* monitors like to lie about these but they are still useful for * detecting aspect ratios */ hdmi->dc->out->h_size = specs.max_x * 1000; hdmi->dc->out->v_size = specs.max_y * 1000; hdmi->dvi = !(specs.misc & FB_MISC_HDMI); #ifdef CONFIG_ADF_TEGRA tegra_adf_process_hotplug_connected(hdmi->dc->adf, &specs); #endif #ifdef CONFIG_TEGRA_DC_EXTENSIONS tegra_fb_update_monspecs(hdmi->dc->fb, &specs, tegra_dc_hdmi_mode_filter); #endif #ifdef CONFIG_SWITCH state = tegra_edid_audio_supported(hdmi->edid) ? 1 : 0; switch_set_state(&hdmi->audio_switch, state); pr_info("%s: audio_switch %d\n", __func__, state); switch_set_state(&hdmi->hpd_switch, 1); pr_info("Display connected, hpd_switch 1\n"); #endif hdmi->dc->connected = true; #ifdef CONFIG_TEGRA_DC_EXTENSIONS tegra_dc_ext_process_hotplug(hdmi->dc->ndev->id); #endif if (unlikely(tegra_is_clk_enabled(hdmi->clk))) { /* the only time this should happen is on boot, where the * sequence is that hdmi is enabled before EDID is read. * hdmi_enable() doesn't have EDID information yet so can't * setup audio and infoframes, so we have to do so here. */ pr_info("%s: setting audio and infoframes\n", __func__); tegra_dc_io_start(hdmi->dc); tegra_dc_hdmi_setup_audio_and_infoframes(hdmi->dc); tegra_dc_io_end(hdmi->dc); } hdmi_state_machine_set_state_l(HDMI_STATE_DONE_ENABLED, -1); return; end_disabled: hdmi->eld_retrieved = false; hdmi_disable_l(hdmi); hdmi_state_machine_set_state_l(HDMI_STATE_DONE_DISABLED, -1); }
int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, int mclk) { int new_baseclock; bool clk_change; int err; bool reenable_clock; switch (srate) { case 11025: case 22050: case 44100: case 88200: if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20) new_baseclock = 56448000; else if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA30) new_baseclock = 564480000; else new_baseclock = 282240000; break; case 8000: case 16000: case 32000: case 48000: case 64000: case 96000: if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20) new_baseclock = 73728000; else if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA30) new_baseclock = 552960000; else new_baseclock = 368640000; break; default: return -EINVAL; } clk_change = ((new_baseclock != data->set_baseclock) || (mclk != data->set_mclk)); if (!clk_change) return 0; /* Don't change rate if already one dai-link is using it */ if (data->lock_count) return -EINVAL; data->set_baseclock = 0; data->set_mclk = 0; reenable_clock = false; if(tegra_is_clk_enabled(data->clk_pll_a)) { clk_disable_unprepare(data->clk_pll_a); reenable_clock = true; } err = clk_set_rate(data->clk_pll_a, new_baseclock); if (err) { dev_err(data->dev, "Can't set pll_a rate: %d\n", err); return err; } if(reenable_clock) clk_prepare_enable(data->clk_pll_a); reenable_clock = false; if(tegra_is_clk_enabled(data->clk_pll_a_out0)) { clk_disable_unprepare(data->clk_pll_a_out0); reenable_clock = true; } err = clk_set_rate(data->clk_pll_a_out0, mclk); if (err) { dev_err(data->dev, "Can't set clk_pll_a_out0 rate: %d\n", err); return err; } if(reenable_clock) clk_prepare_enable(data->clk_pll_a_out0); data->set_baseclock = new_baseclock; data->set_mclk = mclk; return 0; }