/* * Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. */ #include "gk20a/gk20a.h" #include "gm206/bios_gm206.h" #include "bios_gp106.h" #include static void gp106_init_xmemsel_zm_nv_reg_array(struct gk20a *g, bool *condition, u32 reg, u32 stride, u32 count, u32 data_table_offset) { u8 i; u32 data, strap, index; if (*condition) { strap = gk20a_readl(g, gc6_sci_strap_r()) & 0xf; index = g->bios.mem_strap_xlat_tbl_ptr ? gm206_bios_read_u8(g, g->bios.mem_strap_xlat_tbl_ptr + strap) : strap; for (i = 0; i < count; i++) { data = gm206_bios_read_u32(g, data_table_offset + ((i * g->bios.mem_strap_data_count + index) * sizeof(u32))); gk20a_writel(g, reg, data); reg += stride; } } } static void gp106_init_condition(struct gk20a *g, bool *condition, u32 condition_id) { struct condition_entry entry; entry.cond_addr = gm206_bios_read_u32(g, g->bios.condition_table_ptr + sizeof(entry)*condition_id); entry.cond_mask = gm206_bios_read_u32(g, g->bios.condition_table_ptr + sizeof(entry)*condition_id + 4); entry.cond_compare = gm206_bios_read_u32(g, g->bios.condition_table_ptr + sizeof(entry)*condition_id + 8); if ((gk20a_readl(g, entry.cond_addr) & entry.cond_mask) != entry.cond_compare) { *condition = false; } } static int gp106_execute_script(struct gk20a *g, u32 offset) { u8 opcode; u32 ip; u32 operand[8]; bool condition, end; int status = 0; ip = offset; condition = true; end = false; while (!end) { opcode = gm206_bios_read_u8(g, ip++); switch (opcode) { case INIT_XMEMSEL_ZM_NV_REG_ARRAY: operand[0] = gm206_bios_read_u32(g, ip); operand[1] = gm206_bios_read_u8(g, ip+4); operand[2] = gm206_bios_read_u8(g, ip+5); ip += 6; gp106_init_xmemsel_zm_nv_reg_array(g, &condition, operand[0], operand[1], operand[2], ip); ip += operand[2] * sizeof(u32) * g->bios.mem_strap_data_count; break; case INIT_CONDITION: operand[0] = gm206_bios_read_u8(g, ip); ip++; gp106_init_condition(g, &condition, operand[0]); break; case INIT_RESUME: condition = true; break; case INIT_DONE: end = true; break; default: gk20a_err(dev_from_gk20a(g), "opcode: 0x%02x", opcode); end = true; status = -EINVAL; break; } } return status; } void gp106_init_bios(struct gpu_ops *gops) { gm206_init_bios(gops); gops->bios.execute_script = gp106_execute_script; }