static int clk_disable_gpcpll(struct gk20a *g, int allow_slide) { u32 cfg, coeff, m, nlo; struct clk_gk20a *clk = &g->clk; /* slide to VCO min */ cfg = gk20a_readl(g, trim_sys_gpcpll_cfg_r()); if (allow_slide && trim_sys_gpcpll_cfg_enable_v(cfg)) { coeff = gk20a_readl(g, trim_sys_gpcpll_coeff_r()); m = trim_sys_gpcpll_coeff_mdiv_v(coeff); nlo = DIV_ROUND_UP(m * gpc_pll_params.min_vco, clk->gpc_pll.clk_in); clk_slide_gpc_pll(g, nlo); } /* put PLL in bypass before disabling it */ cfg = gk20a_readl(g, trim_sys_sel_vco_r()); cfg = set_field(cfg, trim_sys_sel_vco_gpc2clk_out_m(), trim_sys_sel_vco_gpc2clk_out_bypass_f()); gk20a_writel(g, trim_sys_sel_vco_r(), cfg); /* disable PLL */ cfg = gk20a_readl(g, trim_sys_gpcpll_cfg_r()); cfg = set_field(cfg, trim_sys_gpcpll_cfg_enable_m(), trim_sys_gpcpll_cfg_enable_no_f()); gk20a_writel(g, trim_sys_gpcpll_cfg_r(), cfg); gk20a_readl(g, trim_sys_gpcpll_cfg_r()); clk->gpc_pll.enabled = false; return 0; }
void gm20b_ltc_init_fs_state(struct gk20a *g) { u32 reg; gk20a_dbg_info("initialize gm20b l2"); g->max_ltc_count = gk20a_readl(g, top_num_ltcs_r()); g->ltc_count = gk20a_readl(g, pri_ringmaster_enum_ltc_r()); gk20a_dbg_info("%d ltcs out of %d", g->ltc_count, g->max_ltc_count); gk20a_writel(g, ltc_ltcs_ltss_cbc_num_active_ltcs_r(), g->ltc_count); gk20a_writel(g, ltc_ltcs_misc_ltc_num_active_ltcs_r(), g->ltc_count); gk20a_writel(g, ltc_ltcs_ltss_dstg_cfg0_r(), gk20a_readl(g, ltc_ltc0_lts0_dstg_cfg0_r()) | ltc_ltcs_ltss_dstg_cfg0_vdc_4to2_disable_m()); /* Disable LTC interrupts */ reg = gk20a_readl(g, ltc_ltcs_ltss_intr_r()); reg &= ~ltc_ltcs_ltss_intr_en_evicted_cb_m(); reg &= ~ltc_ltcs_ltss_intr_en_illegal_compstat_access_m(); reg &= ~ltc_ltcs_ltss_intr_en_illegal_compstat_m(); gk20a_writel(g, ltc_ltcs_ltss_intr_r(), reg); }
static void gr_gm20b_set_hww_esr_report_mask(struct gk20a *g) { /* setup sm warp esr report masks */ gk20a_writel(g, gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_r(), gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_stack_error_report_f() | gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_api_stack_error_report_f() | gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_ret_empty_stack_error_report_f() | gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_pc_wrap_report_f() | gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_misaligned_pc_report_f() | gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_pc_overflow_report_f() | gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_misaligned_immc_addr_report_f() | gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_misaligned_reg_report_f() | gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_illegal_instr_encoding_report_f() | gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_illegal_sph_instr_combo_report_f() | gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_illegal_instr_param_report_f() | gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_invalid_const_addr_report_f() | gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_oor_reg_report_f() | gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_oor_addr_report_f() | gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_misaligned_addr_report_f() | gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_invalid_addr_space_report_f() | gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_illegal_instr_param2_report_f() | gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_invalid_const_addr_ldc_report_f() | gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_mmu_fault_report_f() | gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_stack_overflow_report_f() | gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_geometry_sm_error_report_f() | gr_gpcs_tpcs_sm_hww_warp_esr_report_mask_divergent_report_f()); /* setup sm global esr report mask */ gk20a_writel(g, gr_gpcs_tpcs_sm_hww_global_esr_report_mask_r(), gr_gpcs_tpcs_sm_hww_global_esr_report_mask_sm_to_sm_fault_report_f() | gr_gpcs_tpcs_sm_hww_global_esr_report_mask_multiple_warp_errors_report_f()); }
static void gm20b_fb_dump_vpr_wpr_info(struct gk20a *g) { u32 val; /* print vpr and wpr info */ val = gk20a_readl(g, fb_mmu_vpr_info_r()); val &= ~0x3; val |= fb_mmu_vpr_info_index_addr_lo_v(); gk20a_writel(g, fb_mmu_vpr_info_r(), val); gk20a_err(dev_from_gk20a(g), "VPR: %08x %08x %08x %08x", gk20a_readl(g, fb_mmu_vpr_info_r()), gk20a_readl(g, fb_mmu_vpr_info_r()), gk20a_readl(g, fb_mmu_vpr_info_r()), gk20a_readl(g, fb_mmu_vpr_info_r())); val = gk20a_readl(g, fb_mmu_wpr_info_r()); val &= ~0xf; val |= (fb_mmu_wpr_info_index_allow_read_v()); gk20a_writel(g, fb_mmu_wpr_info_r(), val); gk20a_err(dev_from_gk20a(g), "WPR: %08x %08x %08x %08x %08x %08x", gk20a_readl(g, fb_mmu_wpr_info_r()), gk20a_readl(g, fb_mmu_wpr_info_r()), gk20a_readl(g, fb_mmu_wpr_info_r()), gk20a_readl(g, fb_mmu_wpr_info_r()), gk20a_readl(g, fb_mmu_wpr_info_r()), gk20a_readl(g, fb_mmu_wpr_info_r())); }
static int monitor_get(void *data, u64 *val) { struct gk20a *g = (struct gk20a *)data; struct clk_gk20a *clk = &g->clk; u32 ncycle = 100; /* count GPCCLK for ncycle of clkin */ u32 clkin = clk->gpc_pll.clk_in; u32 count1, count2; gk20a_busy(g->dev); gk20a_writel(g, trim_gpc_clk_cntr_ncgpcclk_cfg_r(0), trim_gpc_clk_cntr_ncgpcclk_cfg_reset_asserted_f()); gk20a_writel(g, trim_gpc_clk_cntr_ncgpcclk_cfg_r(0), trim_gpc_clk_cntr_ncgpcclk_cfg_enable_asserted_f() | trim_gpc_clk_cntr_ncgpcclk_cfg_write_en_asserted_f() | trim_gpc_clk_cntr_ncgpcclk_cfg_noofipclks_f(ncycle)); /* start */ /* It should take about 8us to finish 100 cycle of 12MHz. But longer than 100us delay is required here. */ gk20a_readl(g, trim_gpc_clk_cntr_ncgpcclk_cfg_r(0)); udelay(2000); count1 = gk20a_readl(g, trim_gpc_clk_cntr_ncgpcclk_cnt_r(0)); udelay(100); count2 = gk20a_readl(g, trim_gpc_clk_cntr_ncgpcclk_cnt_r(0)); *val = (u64)(trim_gpc_clk_cntr_ncgpcclk_cnt_value_v(count2) * clkin / ncycle); gk20a_idle(g->dev); if (count1 != count2) return -EBUSY; return 0; }
/* * Sets the ZBC depth for the passed index. */ static void gk20a_ltc_set_zbc_depth_entry(struct gk20a *g, struct zbc_entry *depth_val, u32 index) { u32 real_index = index + GK20A_STARTOF_ZBC_TABLE; gk20a_writel(g, ltc_ltcs_ltss_dstg_zbc_index_r(), ltc_ltcs_ltss_dstg_zbc_index_address_f(real_index)); gk20a_writel(g, ltc_ltcs_ltss_dstg_zbc_depth_clear_value_r(), depth_val->depth); }
static void gr_gm20b_set_circular_buffer_size(struct gk20a *g, u32 data) { struct gr_gk20a *gr = &g->gr; u32 gpc_index, ppc_index, stride, val; u32 cb_size = data * 4; gk20a_dbg_fn(""); if (cb_size > gr->attrib_cb_size) cb_size = gr->attrib_cb_size; gk20a_writel(g, gr_ds_tga_constraintlogic_r(), (gk20a_readl(g, gr_ds_tga_constraintlogic_r()) & ~gr_ds_tga_constraintlogic_beta_cbsize_f(~0)) | gr_ds_tga_constraintlogic_beta_cbsize_f(cb_size)); for (gpc_index = 0; gpc_index < gr->gpc_count; gpc_index++) { stride = proj_gpc_stride_v() * gpc_index; for (ppc_index = 0; ppc_index < gr->gpc_ppc_count[gpc_index]; ppc_index++) { val = gk20a_readl(g, gr_gpc0_ppc0_cbm_beta_cb_size_r() + stride + proj_ppc_in_gpc_stride_v() * ppc_index); val = set_field(val, gr_gpc0_ppc0_cbm_beta_cb_size_v_m(), gr_gpc0_ppc0_cbm_beta_cb_size_v_f(cb_size * gr->pes_tpc_count[ppc_index][gpc_index])); gk20a_writel(g, gr_gpc0_ppc0_cbm_beta_cb_size_r() + stride + proj_ppc_in_gpc_stride_v() * ppc_index, val); val = gk20a_readl(g, gr_gpcs_swdx_tc_beta_cb_size_r( ppc_index + gpc_index)); val = set_field(val, gr_gpcs_swdx_tc_beta_cb_size_v_m(), gr_gpcs_swdx_tc_beta_cb_size_v_f(cb_size * gr->gpc_ppc_count[gpc_index])); val = set_field(val, gr_gpcs_swdx_tc_beta_cb_size_div3_m(), gr_gpcs_swdx_tc_beta_cb_size_div3_f((cb_size * gr->gpc_ppc_count[gpc_index])/3)); gk20a_writel(g, gr_gpcs_swdx_tc_beta_cb_size_r( ppc_index + gpc_index), val); } } }
static void gr_gm20b_init_gpc_mmu(struct gk20a *g) { u32 temp; gk20a_dbg_info("initialize gpc mmu"); if (!g->ops.privsecurity) { /* Bypass MMU check for non-secure boot. For * secure-boot,this register write has no-effect */ gk20a_writel(g, fb_priv_mmu_phy_secure_r(), 0xffffffff); } temp = gk20a_readl(g, fb_mmu_ctrl_r()); temp &= gr_gpcs_pri_mmu_ctrl_vm_pg_size_m() | gr_gpcs_pri_mmu_ctrl_use_pdb_big_page_size_m() | gr_gpcs_pri_mmu_ctrl_vol_fault_m() | gr_gpcs_pri_mmu_ctrl_comp_fault_m() | gr_gpcs_pri_mmu_ctrl_miss_gran_m() | gr_gpcs_pri_mmu_ctrl_cache_mode_m() | gr_gpcs_pri_mmu_ctrl_mmu_aperture_m() | gr_gpcs_pri_mmu_ctrl_mmu_vol_m() | gr_gpcs_pri_mmu_ctrl_mmu_disable_m(); gk20a_writel(g, gr_gpcs_pri_mmu_ctrl_r(), temp); gk20a_writel(g, gr_gpcs_pri_mmu_pm_unit_mask_r(), 0); gk20a_writel(g, gr_gpcs_pri_mmu_pm_req_mask_r(), 0); gk20a_writel(g, gr_gpcs_pri_mmu_debug_ctrl_r(), gk20a_readl(g, fb_mmu_debug_ctrl_r())); gk20a_writel(g, gr_gpcs_pri_mmu_debug_wr_r(), gk20a_readl(g, fb_mmu_debug_wr_r())); gk20a_writel(g, gr_gpcs_pri_mmu_debug_rd_r(), gk20a_readl(g, fb_mmu_debug_rd_r())); gk20a_writel(g, gr_gpcs_mmu_num_active_ltcs_r(), gk20a_readl(g, fb_fbhub_num_active_ltcs_r())); }
/* * Sets the ZBC color for the passed index. */ static void gk20a_ltc_set_zbc_color_entry(struct gk20a *g, struct zbc_entry *color_val, u32 index) { u32 i; u32 real_index = index + GK20A_STARTOF_ZBC_TABLE; gk20a_writel(g, ltc_ltcs_ltss_dstg_zbc_index_r(), ltc_ltcs_ltss_dstg_zbc_index_address_f(real_index)); for (i = 0; i < ltc_ltcs_ltss_dstg_zbc_color_clear_value__size_1_v(); i++) gk20a_writel(g, ltc_ltcs_ltss_dstg_zbc_color_clear_value_r(i), color_val->color_l2[i]); }
/* Flushes the compression bit cache as well as "data". * Note: the name here is a bit of a misnomer. ELPG uses this * internally... but ELPG doesn't have to be on to do it manually. */ static void gk20a_mm_g_elpg_flush_locked(struct gk20a *g) { u32 data; s32 retry = 100; gk20a_dbg_fn(""); /* Make sure all previous writes are committed to the L2. There's no guarantee that writes are to DRAM. This will be a sysmembar internal to the L2. */ gk20a_writel(g, ltc_ltcs_ltss_g_elpg_r(), ltc_ltcs_ltss_g_elpg_flush_pending_f()); do { data = gk20a_readl(g, ltc_ltc0_ltss_g_elpg_r()); if (ltc_ltc0_ltss_g_elpg_flush_v(data) == ltc_ltc0_ltss_g_elpg_flush_pending_v()) { gk20a_dbg_info("g_elpg_flush 0x%x", data); retry--; usleep_range(20, 40); } else break; } while (retry >= 0 || !tegra_platform_is_silicon()); if (retry < 0) gk20a_warn(dev_from_gk20a(g), "g_elpg_flush too many retries"); }
static void fb_gm20b_init_fs_state(struct gk20a *g) { gk20a_dbg_info("initialize gm20b fb"); gk20a_writel(g, fb_fbhub_num_active_ltcs_r(), g->ltc_count); }
static void gm20b_fb_set_mmu_page_size(struct gk20a *g) { /* set large page size in fb */ u32 fb_mmu_ctrl = gk20a_readl(g, fb_mmu_ctrl_r()); fb_mmu_ctrl |= fb_mmu_ctrl_use_pdb_big_page_size_true_f(); gk20a_writel(g, fb_mmu_ctrl_r(), fb_mmu_ctrl); }
static void gr_gm20b_set_alpha_circular_buffer_size(struct gk20a *g, u32 data) { struct gr_gk20a *gr = &g->gr; u32 gpc_index, ppc_index, stride, val; u32 pd_ab_max_output; u32 alpha_cb_size = data * 4; gk20a_dbg_fn(""); /* if (NO_ALPHA_BETA_TIMESLICE_SUPPORT_DEF) return; */ if (alpha_cb_size > gr->alpha_cb_size) alpha_cb_size = gr->alpha_cb_size; gk20a_writel(g, gr_ds_tga_constraintlogic_r(), (gk20a_readl(g, gr_ds_tga_constraintlogic_r()) & ~gr_ds_tga_constraintlogic_alpha_cbsize_f(~0)) | gr_ds_tga_constraintlogic_alpha_cbsize_f(alpha_cb_size)); pd_ab_max_output = alpha_cb_size * gr_gpc0_ppc0_cbm_alpha_cb_size_v_granularity_v() / gr_pd_ab_dist_cfg1_max_output_granularity_v(); gk20a_writel(g, gr_pd_ab_dist_cfg1_r(), gr_pd_ab_dist_cfg1_max_output_f(pd_ab_max_output) | gr_pd_ab_dist_cfg1_max_batches_init_f()); for (gpc_index = 0; gpc_index < gr->gpc_count; gpc_index++) { stride = proj_gpc_stride_v() * gpc_index; for (ppc_index = 0; ppc_index < gr->gpc_ppc_count[gpc_index]; ppc_index++) { val = gk20a_readl(g, gr_gpc0_ppc0_cbm_alpha_cb_size_r() + stride + proj_ppc_in_gpc_stride_v() * ppc_index); val = set_field(val, gr_gpc0_ppc0_cbm_alpha_cb_size_v_m(), gr_gpc0_ppc0_cbm_alpha_cb_size_v_f(alpha_cb_size * gr->pes_tpc_count[ppc_index][gpc_index])); gk20a_writel(g, gr_gpc0_ppc0_cbm_alpha_cb_size_r() + stride + proj_ppc_in_gpc_stride_v() * ppc_index, val); } } }
static int gr_gm20b_load_ctxsw_ucode_segments(struct gk20a *g, u64 addr_base, struct gk20a_ctxsw_ucode_segments *segments, u32 reg_offset) { gk20a_writel(g, reg_offset + gr_fecs_dmactl_r(), gr_fecs_dmactl_require_ctx_f(0)); /* Copy falcon bootloader into dmem */ gr_gk20a_load_ctxsw_ucode_header(g, addr_base, segments, reg_offset); gr_gk20a_load_ctxsw_ucode_boot(g, addr_base, segments, reg_offset); /* start the falcon immediately if PRIV security is disabled*/ if (!g->ops.privsecurity) { gk20a_writel(g, reg_offset + gr_fecs_cpuctl_r(), gr_fecs_cpuctl_startcpu_f(0x01)); } return 0; }
static bool gm20b_fb_set_use_full_comp_tag_line(struct gk20a *g) { /* set large page size in fb */ u32 fb_mmu_ctrl = gk20a_readl(g, fb_mmu_ctrl_r()); fb_mmu_ctrl |= fb_mmu_ctrl_use_full_comp_tag_line_true_f(); gk20a_writel(g, fb_mmu_ctrl_r(), fb_mmu_ctrl); return true; }
static int gk20a_init_therm_setup_hw(struct gk20a *g) { u32 v; /* program NV_THERM registers */ gk20a_writel(g, therm_use_a_r(), NV_THERM_USE_A_INIT); gk20a_writel(g, therm_evt_ext_therm_0_r(), NV_THERM_EVT_EXT_THERM_0_INIT); gk20a_writel(g, therm_evt_ext_therm_1_r(), NV_THERM_EVT_EXT_THERM_1_INIT); gk20a_writel(g, therm_evt_ext_therm_2_r(), NV_THERM_EVT_EXT_THERM_2_INIT); gk20a_writel(g, therm_grad_stepping_table_r(0), therm_grad_stepping_table_slowdown_factor0_f(therm_grad_stepping_table_slowdown_factor0_fpdiv_by1p5_f()) | therm_grad_stepping_table_slowdown_factor1_f(therm_grad_stepping_table_slowdown_factor0_fpdiv_by2_f()) | therm_grad_stepping_table_slowdown_factor2_f(therm_grad_stepping_table_slowdown_factor0_fpdiv_by4_f()) | therm_grad_stepping_table_slowdown_factor3_f(therm_grad_stepping_table_slowdown_factor0_fpdiv_by8_f()) | therm_grad_stepping_table_slowdown_factor4_f(therm_grad_stepping_table_slowdown_factor0_fpdiv_by8_f())); gk20a_writel(g, therm_grad_stepping_table_r(1), therm_grad_stepping_table_slowdown_factor0_f(therm_grad_stepping_table_slowdown_factor0_fpdiv_by8_f()) | therm_grad_stepping_table_slowdown_factor1_f(therm_grad_stepping_table_slowdown_factor0_fpdiv_by8_f()) | therm_grad_stepping_table_slowdown_factor2_f(therm_grad_stepping_table_slowdown_factor0_fpdiv_by8_f()) | therm_grad_stepping_table_slowdown_factor3_f(therm_grad_stepping_table_slowdown_factor0_fpdiv_by8_f()) | therm_grad_stepping_table_slowdown_factor4_f(therm_grad_stepping_table_slowdown_factor0_fpdiv_by8_f())); v = gk20a_readl(g, therm_clk_timing_r(0)); v |= therm_clk_timing_grad_slowdown_enabled_f(); gk20a_writel(g, therm_clk_timing_r(0), v); v = gk20a_readl(g, therm_config2_r()); v |= therm_config2_grad_enable_f(1); v |= therm_config2_slowdown_factor_extended_f(1); gk20a_writel(g, therm_config2_r(), v); gk20a_writel(g, therm_grad_stepping1_r(), therm_grad_stepping1_pdiv_duration_f(32)); v = gk20a_readl(g, therm_grad_stepping0_r()); v |= therm_grad_stepping0_feature_enable_f(); gk20a_writel(g, therm_grad_stepping0_r(), v); return 0; }
void gk20a_reset_priv_ring(struct gk20a *g) { if (tegra_platform_is_linsim()) return; gk20a_reset(g, mc_enable_priv_ring_enabled_f()); if (g->ops.clock_gating.slcg_priring_load_gating_prod) g->ops.clock_gating.slcg_priring_load_gating_prod(g, g->slcg_enabled); gk20a_writel(g,pri_ringmaster_command_r(), 0x4); gk20a_writel(g, pri_ringstation_sys_decode_config_r(), 0x2); gk20a_readl(g, pri_ringstation_sys_decode_config_r()); }
/* * Set the maximum number of ways that can have the "EVIST_LAST" class. */ static void gk20a_ltc_set_max_ways_evict_last(struct gk20a *g, u32 max_ways) { u32 mgmt_reg; mgmt_reg = gk20a_readl(g, ltc_ltcs_ltss_tstg_set_mgmt_r()) & ~ltc_ltcs_ltss_tstg_set_mgmt_max_ways_evict_last_f(~0); mgmt_reg |= ltc_ltcs_ltss_tstg_set_mgmt_max_ways_evict_last_f(max_ways); gk20a_writel(g, ltc_ltcs_ltss_tstg_set_mgmt_r(), mgmt_reg); }
void gk20a_priv_ring_isr(struct gk20a *g) { u32 status0, status1; u32 cmd; s32 retry = 100; if (tegra_platform_is_linsim()) return; status0 = gk20a_readl(g, pri_ringmaster_intr_status0_r()); status1 = gk20a_readl(g, pri_ringmaster_intr_status1_r()); gk20a_dbg(gpu_dbg_intr, "ringmaster intr status0: 0x%08x," "status1: 0x%08x", status0, status1); if (status0 & (0x1 | 0x2 | 0x4)) { gk20a_reset_priv_ring(g); } if (status0 & 0x100) { gk20a_dbg(gpu_dbg_intr, "SYS write error. ADR %08x WRDAT %08x INFO %08x, CODE %08x", gk20a_readl(g, 0x122120), gk20a_readl(g, 0x122124), gk20a_readl(g, 0x122128), gk20a_readl(g, 0x12212c)); } if (status1 & 0x1) { gk20a_dbg(gpu_dbg_intr, "GPC write error. ADR %08x WRDAT %08x INFO %08x, CODE %08x", gk20a_readl(g, 0x128120), gk20a_readl(g, 0x128124), gk20a_readl(g, 0x128128), gk20a_readl(g, 0x12812c)); } cmd = gk20a_readl(g, pri_ringmaster_command_r()); cmd = set_field(cmd, pri_ringmaster_command_cmd_m(), pri_ringmaster_command_cmd_ack_interrupt_f()); gk20a_writel(g, pri_ringmaster_command_r(), cmd); do { cmd = pri_ringmaster_command_cmd_v( gk20a_readl(g, pri_ringmaster_command_r())); usleep_range(20, 40); } while (cmd != pri_ringmaster_command_cmd_no_cmd_v() && --retry); if (retry <= 0) gk20a_warn(dev_from_gk20a(g), "priv ringmaster cmd ack too many retries"); status0 = gk20a_readl(g, pri_ringmaster_intr_status0_r()); status1 = gk20a_readl(g, pri_ringmaster_intr_status1_r()); gk20a_dbg_info("ringmaster intr status0: 0x%08x," " status1: 0x%08x", status0, status1); }
void gk20a_reset_priv_ring(struct gk20a *g) { u32 data; data = gk20a_readl(g, trim_sys_gpc2clk_out_r()); data = set_field(data, trim_sys_gpc2clk_out_bypdiv_m(), trim_sys_gpc2clk_out_bypdiv_f(0)); gk20a_writel(g, trim_sys_gpc2clk_out_r(), data); gk20a_reset(g, mc_enable_priv_ring_enabled_f()); if (g->ops.clock_gating.slcg_priring_load_gating_prod) g->ops.clock_gating.slcg_priring_load_gating_prod(g, g->slcg_enabled); gk20a_writel(g,pri_ringmaster_command_r(), 0x4); gk20a_writel(g, pri_ringstation_sys_decode_config_r(), 0x2); gk20a_readl(g, pri_ringstation_sys_decode_config_r()); }
int gk20a_init_clk_support(struct gk20a *g) { struct clk_gk20a *clk = &g->clk; u32 err; nvhost_dbg_fn(""); clk->g = g; err = gk20a_init_clk_reset_enable_hw(g); if (err) return err; err = gk20a_init_clk_setup_sw(g); if (err) return err; mutex_lock(&clk->clk_mutex); clk->clk_hw_on = true; err = gk20a_init_clk_setup_hw(g); mutex_unlock(&clk->clk_mutex); if (err) return err; err = gk20a_clk_register_export_ops(g); if (err) return err; /* FIXME: this effectively prevents host level clock gating */ err = clk_enable(g->clk.tegra_clk); if (err) return err; /* The prev call may not enable PLL if gbus is unbalanced - force it */ mutex_lock(&clk->clk_mutex); err = set_pll_freq(g, clk->gpc_pll.freq, clk->gpc_pll.freq); mutex_unlock(&clk->clk_mutex); if (err) return err; gk20a_writel(g, timer_pri_timeout_r(), timer_pri_timeout_period_f(0x200) | timer_pri_timeout_en_m()); return err; }
static void gk20a_ltc_init_cbc(struct gk20a *g, struct gr_gk20a *gr) { u32 max_size = gr->max_comptag_mem; u32 max_comptag_lines = max_size << 3; u32 compbit_base_post_divide; u64 compbit_base_post_multiply64; u64 compbit_store_iova; u64 compbit_base_post_divide64; if (tegra_platform_is_linsim()) compbit_store_iova = gk20a_mem_phys(&gr->compbit_store.mem); else compbit_store_iova = g->ops.mm.get_iova_addr(g, gr->compbit_store.mem.sgt->sgl, 0); compbit_base_post_divide64 = compbit_store_iova >> ltc_ltcs_ltss_cbc_base_alignment_shift_v(); do_div(compbit_base_post_divide64, g->ltc_count); compbit_base_post_divide = u64_lo32(compbit_base_post_divide64); compbit_base_post_multiply64 = ((u64)compbit_base_post_divide * g->ltc_count) << ltc_ltcs_ltss_cbc_base_alignment_shift_v(); if (compbit_base_post_multiply64 < compbit_store_iova) compbit_base_post_divide++; /* Bug 1477079 indicates sw adjustment on the posted divided base. */ if (g->ops.ltc.cbc_fix_config) compbit_base_post_divide = g->ops.ltc.cbc_fix_config(g, compbit_base_post_divide); gk20a_writel(g, ltc_ltcs_ltss_cbc_base_r(), compbit_base_post_divide); gk20a_dbg(gpu_dbg_info | gpu_dbg_map | gpu_dbg_pte, "compbit base.pa: 0x%x,%08x cbc_base:0x%08x\n", (u32)(compbit_store_iova >> 32), (u32)(compbit_store_iova & 0xffffffff), compbit_base_post_divide); gr->compbit_store.base_hw = compbit_base_post_divide; g->ops.ltc.cbc_ctrl(g, gk20a_cbc_op_invalidate, 0, max_comptag_lines - 1); }
void gm20b_ltc_g_elpg_flush_locked(struct gk20a *g) { u32 data; bool done[g->ltc_count]; s32 retry = 100; int i; int num_done = 0; u32 ltc_d = ltc_ltc1_ltss_g_elpg_r() - ltc_ltc0_ltss_g_elpg_r(); gk20a_dbg_fn(""); trace_gk20a_mm_g_elpg_flush_locked(g->dev->name); for (i = 0; i < g->ltc_count; i++) done[i] = 0; gk20a_writel(g, ltc_ltcs_ltss_g_elpg_r(), ltc_ltcs_ltss_g_elpg_flush_pending_f()); do { for (i = 0; i < g->ltc_count; i++) { if (done[i]) continue; data = gk20a_readl(g, ltc_ltc0_ltss_g_elpg_r() + ltc_d * i); if (ltc_ltc0_ltss_g_elpg_flush_v(data)) { gk20a_dbg_info("g_elpg_flush 0x%x", data); } else { done[i] = 1; num_done++; } } if (num_done < g->ltc_count) { retry--; udelay(5); } else break; } while (retry >= 0 || !tegra_platform_is_silicon()); if (retry < 0 && tegra_platform_is_silicon()) gk20a_warn(dev_from_gk20a(g), "g_elpg_flush too many retries"); trace_gk20a_mm_g_elpg_flush_locked_done(g->dev->name); }
static int gk20a_init_clk_setup_hw(struct gk20a *g) { u32 data; gk20a_dbg_fn(""); data = gk20a_readl(g, trim_sys_gpc2clk_out_r()); data = set_field(data, trim_sys_gpc2clk_out_sdiv14_m() | trim_sys_gpc2clk_out_vcodiv_m() | trim_sys_gpc2clk_out_bypdiv_m(), trim_sys_gpc2clk_out_sdiv14_indiv4_mode_f() | trim_sys_gpc2clk_out_vcodiv_by1_f() | trim_sys_gpc2clk_out_bypdiv_f(0)); gk20a_writel(g, trim_sys_gpc2clk_out_r(), data); return 0; }
static void gk20a_ltc_sync_debugfs(struct gk20a *g) { u32 reg_f = ltc_ltcs_ltss_tstg_set_mgmt_2_l2_bypass_mode_enabled_f(); spin_lock(&g->debugfs_lock); if (g->mm.ltc_enabled != g->mm.ltc_enabled_debug) { u32 reg = gk20a_readl(g, ltc_ltcs_ltss_tstg_set_mgmt_2_r()); if (g->mm.ltc_enabled_debug) /* bypass disabled (normal caching ops)*/ reg &= ~reg_f; else /* bypass enabled (no caching) */ reg |= reg_f; gk20a_writel(g, ltc_ltcs_ltss_tstg_set_mgmt_2_r(), reg); g->mm.ltc_enabled = g->mm.ltc_enabled_debug; } spin_unlock(&g->debugfs_lock); }
static void gk20a_ltc_init_cbc(struct gk20a *g, struct gr_gk20a *gr) { u32 max_size = gr->max_comptag_mem; u32 max_comptag_lines = max_size << 3; u32 compbit_base_post_divide; u64 compbit_base_post_multiply64; u64 compbit_store_base_iova; u64 compbit_base_post_divide64; if (IS_ENABLED(CONFIG_GK20A_PHYS_PAGE_TABLES)) compbit_store_base_iova = gr->compbit_store.base_iova; else compbit_store_base_iova = NV_MC_SMMU_VADDR_TRANSLATE( gr->compbit_store.base_iova); compbit_base_post_divide64 = compbit_store_base_iova >> ltc_ltcs_ltss_cbc_base_alignment_shift_v(); do_div(compbit_base_post_divide64, gr->num_fbps); compbit_base_post_divide = u64_lo32(compbit_base_post_divide64); compbit_base_post_multiply64 = ((u64)compbit_base_post_divide * gr->num_fbps) << ltc_ltcs_ltss_cbc_base_alignment_shift_v(); if (compbit_base_post_multiply64 < compbit_store_base_iova) compbit_base_post_divide++; gk20a_writel(g, ltc_ltcs_ltss_cbc_base_r(), compbit_base_post_divide); gk20a_dbg(gpu_dbg_info | gpu_dbg_map | gpu_dbg_pte, "compbit base.pa: 0x%x,%08x cbc_base:0x%08x\n", (u32)(compbit_store_base_iova >> 32), (u32)(compbit_store_base_iova & 0xffffffff), compbit_base_post_divide); g->ops.ltc.cbc_ctrl(g, gk20a_cbc_op_invalidate, 0, max_comptag_lines - 1); }
void gk20a_priv_ring_isr(struct gk20a *g) { u32 status0, status1; u32 cmd; s32 retry = 100; status0 = gk20a_readl(g, pri_ringmaster_intr_status0_r()); status1 = gk20a_readl(g, pri_ringmaster_intr_status1_r()); gk20a_dbg_info("ringmaster intr status0: 0x%08x," "status1: 0x%08x", status0, status1); if (status0 & (0x1 | 0x2 | 0x4)) { gk20a_reset_priv_ring(g); } cmd = gk20a_readl(g, pri_ringmaster_command_r()); cmd = set_field(cmd, pri_ringmaster_command_cmd_m(), pri_ringmaster_command_cmd_ack_interrupt_f()); gk20a_writel(g, pri_ringmaster_command_r(), cmd); do { cmd = pri_ringmaster_command_cmd_v( gk20a_readl(g, pri_ringmaster_command_r())); usleep_range(20, 40); } while (cmd != pri_ringmaster_command_cmd_no_cmd_v() && --retry); if (retry <= 0) gk20a_warn(dev_from_gk20a(g), "priv ringmaster cmd ack too many retries"); status0 = gk20a_readl(g, pri_ringmaster_intr_status0_r()); status1 = gk20a_readl(g, pri_ringmaster_intr_status1_r()); gk20a_dbg_info("ringmaster intr status0: 0x%08x," " status1: 0x%08x", status0, status1); }
void gm20b_ltc_isr(struct gk20a *g) { u32 mc_intr, ltc_intr; int ltc, slice; mc_intr = gk20a_readl(g, mc_intr_ltc_r()); gk20a_err(dev_from_gk20a(g), "mc_ltc_intr: %08x", mc_intr); for (ltc = 0; ltc < g->ltc_count; ltc++) { if ((mc_intr & 1 << ltc) == 0) continue; for (slice = 0; slice < g->gr.slices_per_ltc; slice++) { ltc_intr = gk20a_readl(g, ltc_ltc0_lts0_intr_r() + proj_ltc_stride_v() * ltc + proj_lts_stride_v() * slice); gk20a_err(dev_from_gk20a(g), "ltc%d, slice %d: %08x", ltc, slice, ltc_intr); gk20a_writel(g, ltc_ltc0_lts0_intr_r() + proj_ltc_stride_v() * ltc + proj_lts_stride_v() * slice, ltc_intr); } } }
int gm20b_ltc_cbc_ctrl(struct gk20a *g, enum gk20a_cbc_op op, u32 min, u32 max) { int err = 0; struct gr_gk20a *gr = &g->gr; u32 ltc, slice, ctrl1, val, hw_op = 0; s32 retry = 200; u32 slices_per_ltc = ltc_ltcs_ltss_cbc_param_slices_per_ltc_v( gk20a_readl(g, ltc_ltcs_ltss_cbc_param_r())); gk20a_dbg_fn(""); trace_gk20a_ltc_cbc_ctrl_start(g->dev->name, op, min, max); if (gr->compbit_store.mem.size == 0) return 0; mutex_lock(&g->mm.l2_op_lock); if (op == gk20a_cbc_op_clear) { gk20a_writel(g, ltc_ltcs_ltss_cbc_ctrl2_r(), ltc_ltcs_ltss_cbc_ctrl2_clear_lower_bound_f(min)); gk20a_writel(g, ltc_ltcs_ltss_cbc_ctrl3_r(), ltc_ltcs_ltss_cbc_ctrl3_clear_upper_bound_f(max)); hw_op = ltc_ltcs_ltss_cbc_ctrl1_clear_active_f(); } else if (op == gk20a_cbc_op_clean) { hw_op = ltc_ltcs_ltss_cbc_ctrl1_clean_active_f(); } else if (op == gk20a_cbc_op_invalidate) { hw_op = ltc_ltcs_ltss_cbc_ctrl1_invalidate_active_f(); } else { BUG_ON(1); } gk20a_writel(g, ltc_ltcs_ltss_cbc_ctrl1_r(), gk20a_readl(g, ltc_ltcs_ltss_cbc_ctrl1_r()) | hw_op); for (ltc = 0; ltc < g->ltc_count; ltc++) { for (slice = 0; slice < slices_per_ltc; slice++) { ctrl1 = ltc_ltc0_lts0_cbc_ctrl1_r() + ltc * proj_ltc_stride_v() + slice * proj_lts_stride_v(); retry = 200; do { val = gk20a_readl(g, ctrl1); if (!(val & hw_op)) break; retry--; udelay(5); } while (retry >= 0 || !tegra_platform_is_silicon()); if (retry < 0 && tegra_platform_is_silicon()) { gk20a_err(dev_from_gk20a(g), "comp tag clear timeout\n"); err = -EBUSY; goto out; } } } out: trace_gk20a_ltc_cbc_ctrl_done(g->dev->name); mutex_unlock(&g->mm.l2_op_lock); return err; }
/* * Performs a full flush of the L2 cache. */ void gm20b_flush_ltc(struct gk20a *g) { unsigned long timeout; int ltc; #define __timeout_init() \ do { \ timeout = jiffies + HZ; \ } while (0) #define __timeout_check() \ do { \ if (tegra_platform_is_silicon() && \ time_after(jiffies, timeout)) { \ gk20a_err(dev_from_gk20a(g), "L2 flush timeout!"); \ break; \ } \ } while (0) /* Clean... */ gk20a_writel(g, ltc_ltcs_ltss_tstg_cmgmt1_r(), ltc_ltcs_ltss_tstg_cmgmt1_clean_pending_f() | ltc_ltcs_ltss_tstg_cmgmt1_max_cycles_between_cleans_3_f() | ltc_ltcs_ltss_tstg_cmgmt1_clean_wait_for_fb_to_pull_true_f() | ltc_ltcs_ltss_tstg_cmgmt1_clean_evict_last_class_true_f() | ltc_ltcs_ltss_tstg_cmgmt1_clean_evict_normal_class_true_f() | ltc_ltcs_ltss_tstg_cmgmt1_clean_evict_first_class_true_f()); /* Wait on each LTC individually. */ for (ltc = 0; ltc < g->ltc_count; ltc++) { u32 op_pending; __timeout_init(); do { int cmgmt1 = ltc_ltc0_ltss_tstg_cmgmt1_r() + ltc * proj_ltc_stride_v(); op_pending = gk20a_readl(g, cmgmt1); __timeout_check(); } while (op_pending & ltc_ltc0_ltss_tstg_cmgmt1_clean_pending_f()); } /* And invalidate. */ gk20a_writel(g, ltc_ltcs_ltss_tstg_cmgmt0_r(), ltc_ltcs_ltss_tstg_cmgmt0_invalidate_pending_f() | ltc_ltcs_ltss_tstg_cmgmt0_max_cycles_between_invalidates_3_f() | ltc_ltcs_ltss_tstg_cmgmt0_invalidate_evict_last_class_true_f() | ltc_ltcs_ltss_tstg_cmgmt0_invalidate_evict_normal_class_true_f() | ltc_ltcs_ltss_tstg_cmgmt0_invalidate_evict_first_class_true_f()); /* Wait on each LTC individually. */ for (ltc = 0; ltc < g->ltc_count; ltc++) { u32 op_pending; __timeout_init(); do { int cmgmt0 = ltc_ltc0_ltss_tstg_cmgmt0_r() + ltc * proj_ltc_stride_v(); op_pending = gk20a_readl(g, cmgmt0); __timeout_check(); } while (op_pending & ltc_ltc0_ltss_tstg_cmgmt0_invalidate_pending_f()); } }