1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
/*
* 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 "hw_gc6_gp106.h"
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;
}
|