diff options
author | David Nieto <dmartineznie@nvidia.com> | 2016-08-19 20:09:35 -0400 |
---|---|---|
committer | Deepak Nibade <dnibade@nvidia.com> | 2016-12-27 04:56:50 -0500 |
commit | 905f1c0392bf244b321f56f82661eeb2fe00ee05 (patch) | |
tree | d525a6d5554b537e0a34ca7917c90364176dbb2e /drivers/gpu/nvgpu/clk | |
parent | 4a94ce451b0352ce67e11a2971bbbd75c2e58df1 (diff) |
gpu: nvgpu: parse and execute mclk shadow script
* Parsing of shadow registers from VBIOS
* Partial devinit engine interpreter implementation
JIRA DNVGPU-117
Change-Id: I42179748889f17d674ad0a986e81c418b3b8df11
Signed-off-by: David Nieto <dmartineznie@nvidia.com>
Reviewed-on: http://git-master/r/1214956
Reviewed-on: http://git-master/r/1237293
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/clk')
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk_mclk.c | 278 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk_mclk.h | 3 |
2 files changed, 195 insertions, 86 deletions
diff --git a/drivers/gpu/nvgpu/clk/clk_mclk.c b/drivers/gpu/nvgpu/clk/clk_mclk.c index df010221..b63fab1e 100644 --- a/drivers/gpu/nvgpu/clk/clk_mclk.c +++ b/drivers/gpu/nvgpu/clk/clk_mclk.c | |||
@@ -17,6 +17,9 @@ | |||
17 | #include "gm206/bios_gm206.h" | 17 | #include "gm206/bios_gm206.h" |
18 | #include "gk20a/pmu_gk20a.h" | 18 | #include "gk20a/pmu_gk20a.h" |
19 | #include "gk20a/hw_pwr_gk20a.h" | 19 | #include "gk20a/hw_pwr_gk20a.h" |
20 | #include "gp106/hw_fb_gp106.h" | ||
21 | |||
22 | #include "include/bios.h" | ||
20 | 23 | ||
21 | #define VREG_COUNT 24 | 24 | #define VREG_COUNT 24 |
22 | 25 | ||
@@ -29,63 +32,6 @@ struct memory_link_training_pattern { | |||
29 | u32 writeval; | 32 | u32 writeval; |
30 | }; | 33 | }; |
31 | 34 | ||
32 | static struct memory_link_training_pattern memory_shadow_p0_reglist[] = { | ||
33 | {0x9a065c, 0x20}, | ||
34 | {0x98467c, 0xffff0000}, | ||
35 | {0x984708, 0x30550}, | ||
36 | {0x98470c, 0x4C4C}, | ||
37 | {0x9006a0, 0x03030303}, | ||
38 | {0x9006a4, 0x03030303}, | ||
39 | {0x9046a0, 0x03030303}, | ||
40 | {0x9046a4, 0x03030303}, | ||
41 | {0x9086a0, 0x03030303}, | ||
42 | {0x9086a4, 0x03030303}, | ||
43 | {0x9846a8, 0x03030303}, | ||
44 | {0x9846ac, 0x03030303}, | ||
45 | {0x9a065c, 0x00}, | ||
46 | }; | ||
47 | |||
48 | static struct memory_link_training_pattern memory_shadow_p5_reglist[] = { | ||
49 | {0x9a065c, 0x10}, | ||
50 | {0x98467c, 0xfff10000}, | ||
51 | {0x984708, 0x30002}, | ||
52 | {0x98470c, 0x1414}, | ||
53 | {0x9006a0, 0x12121212}, | ||
54 | {0x9006a4, 0x12121212}, | ||
55 | {0x9046a0, 0x12121212}, | ||
56 | {0x9046a4, 0x12121212}, | ||
57 | {0x9086a0, 0x12121212}, | ||
58 | {0x9086a4, 0x12121212}, | ||
59 | {0x90c6a0, 0x12121212}, | ||
60 | {0x90c6a4, 0x12121212}, | ||
61 | {0x9106a0, 0x12121212}, | ||
62 | {0x9106a4, 0x12121212}, | ||
63 | {0x9146a0, 0x12121212}, | ||
64 | {0x9146a4, 0x12121212}, | ||
65 | {0x9a065c, 0x0}, | ||
66 | {0x9a08e0, 0x10}, | ||
67 | {0x9846a8, 0x0f0f0f0f}, | ||
68 | {0x9846ac, 0x0f0f0f0f}, | ||
69 | {0x984d98, 0x22222222}, | ||
70 | {0x984d9c, 0x22222222}, | ||
71 | {0x984da0, 0x22222222}, | ||
72 | {0x984da4, 0x22222222}, | ||
73 | {0x984da8, 0x22222222}, | ||
74 | {0x984dac, 0x22222222}, | ||
75 | {0x984dac, 0x22222222}, | ||
76 | {0x984d70, 0x0}, | ||
77 | {0x984d74, 0x0}, | ||
78 | {0x984d78, 0x0}, | ||
79 | {0x984d7c, 0x0}, | ||
80 | {0x984d80, 0x0}, | ||
81 | {0x984d84, 0x0}, | ||
82 | {0x984d88, 0x0}, | ||
83 | {0x984d8c, 0x0}, | ||
84 | {0x984d90, 0x0}, | ||
85 | {0x984d94, 0x0}, | ||
86 | {0x9a08e0, 0x0}, | ||
87 | }; | ||
88 | |||
89 | static struct memory_link_training_pattern memory_pattern_reglist[] = { | 35 | static struct memory_link_training_pattern memory_pattern_reglist[] = { |
90 | {0x9a0968, 0x0}, | 36 | {0x9a0968, 0x0}, |
91 | {0x9a0920, 0x0}, | 37 | {0x9a0920, 0x0}, |
@@ -2026,31 +1972,6 @@ static void mclk_memory_load_training_pattern(struct gk20a *g) | |||
2026 | gk20a_dbg_fn("done"); | 1972 | gk20a_dbg_fn("done"); |
2027 | } | 1973 | } |
2028 | 1974 | ||
2029 | static void mclk_memory_load_shadow_regs(struct gk20a *g) | ||
2030 | { | ||
2031 | u32 reg_writes; | ||
2032 | u32 index; | ||
2033 | |||
2034 | gk20a_dbg_info(""); | ||
2035 | |||
2036 | reg_writes = ((sizeof(memory_shadow_p0_reglist) / | ||
2037 | sizeof((memory_shadow_p0_reglist)[0]))); | ||
2038 | for (index = 0; index < reg_writes; index++) { | ||
2039 | gk20a_writel(g, memory_shadow_p0_reglist[index].regaddr, | ||
2040 | memory_shadow_p0_reglist[index].writeval); | ||
2041 | } | ||
2042 | |||
2043 | reg_writes = ((sizeof(memory_shadow_p5_reglist) / | ||
2044 | sizeof((memory_shadow_p5_reglist)[0]))); | ||
2045 | for (index = 0; index < reg_writes; index++) { | ||
2046 | gk20a_writel(g, memory_shadow_p5_reglist[index].regaddr, | ||
2047 | memory_shadow_p5_reglist[index].writeval); | ||
2048 | } | ||
2049 | |||
2050 | gk20a_dbg_fn("done"); | ||
2051 | |||
2052 | } | ||
2053 | |||
2054 | static void mclk_seq_pmucmdhandler(struct gk20a *g, struct pmu_msg *_msg, | 1975 | static void mclk_seq_pmucmdhandler(struct gk20a *g, struct pmu_msg *_msg, |
2055 | void *param, u32 handle, u32 status) | 1976 | void *param, u32 handle, u32 status) |
2056 | { | 1977 | { |
@@ -2082,9 +2003,189 @@ status_update: | |||
2082 | *((u32 *)param) = msg_status; | 2003 | *((u32 *)param) = msg_status; |
2083 | } | 2004 | } |
2084 | 2005 | ||
2006 | static int mclk_get_memclk_table(struct gk20a *g) | ||
2007 | { | ||
2008 | int status = 0; | ||
2009 | u8 *mem_table_ptr = NULL; | ||
2010 | u32 idx_to_ptr_tbl[8]; | ||
2011 | u32 idx_to_cmd_ptr_tbl[8]; | ||
2012 | |||
2013 | u32 old_fbio_delay; | ||
2014 | u32 old_fbio_cmd_delay; | ||
2015 | |||
2016 | u32 cmd_idx; | ||
2017 | u32 shadow_idx; | ||
2018 | |||
2019 | struct vbios_memory_clock_header_1x memclock_table_header = { 0 }; | ||
2020 | struct vbios_memory_clock_base_entry_11 memclock_base_entry = { 0 }; | ||
2021 | |||
2022 | u8 *mem_entry_ptr = NULL; | ||
2023 | int index; | ||
2024 | |||
2025 | gk20a_dbg_info(""); | ||
2026 | |||
2027 | if (!(g->ops.bios.get_perf_table_ptrs && | ||
2028 | g->ops.bios.execute_script)) { | ||
2029 | goto done; | ||
2030 | } | ||
2031 | |||
2032 | mem_table_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g, | ||
2033 | g->bios.perf_token, | ||
2034 | MEMORY_CLOCK_TABLE); | ||
2035 | if (mem_table_ptr == NULL) { | ||
2036 | status = -EPERM; | ||
2037 | goto done; | ||
2038 | } | ||
2039 | |||
2040 | memcpy(&memclock_table_header, mem_table_ptr, | ||
2041 | sizeof(memclock_table_header)); | ||
2042 | |||
2043 | if ((memclock_table_header.version < | ||
2044 | VBIOS_MEMORY_CLOCK_HEADER_11_VERSION) || | ||
2045 | (memclock_table_header.base_entry_size < | ||
2046 | VBIOS_MEMORY_CLOCK_BASE_ENTRY_11_2_SIZE)) { | ||
2047 | status = -EINVAL; | ||
2048 | goto done; | ||
2049 | } | ||
2050 | |||
2051 | /* reset and save shadow table map and registers */ | ||
2052 | old_fbio_delay = gk20a_readl(g, fb_fbpa_fbio_delay_r()); | ||
2053 | old_fbio_cmd_delay = gk20a_readl(g, fb_fbpa_fbio_cmd_delay_r()); | ||
2054 | |||
2055 | memset(idx_to_ptr_tbl, 0, sizeof(idx_to_ptr_tbl)); | ||
2056 | memset(idx_to_cmd_ptr_tbl, 0, sizeof(idx_to_cmd_ptr_tbl)); | ||
2057 | |||
2058 | /* Read table entries */ | ||
2059 | mem_entry_ptr = mem_table_ptr + memclock_table_header.header_size; | ||
2060 | for (index = 0; index < memclock_table_header.entry_count; index++) { | ||
2061 | u8 script_index, cmd_script_index; | ||
2062 | u32 script_ptr = 0, cmd_script_ptr = 0; | ||
2063 | |||
2064 | memcpy(&memclock_base_entry, mem_entry_ptr, | ||
2065 | memclock_table_header.base_entry_size); | ||
2066 | if (memclock_base_entry.maximum == 0) | ||
2067 | continue; | ||
2068 | |||
2069 | script_index = BIOS_GET_FIELD(memclock_base_entry.flags1, | ||
2070 | VBIOS_MEMORY_CLOCK_BASE_ENTRY_11_FLAGS1_SCRIPT_INDEX); | ||
2071 | |||
2072 | script_ptr = gm206_bios_read_u32(g, | ||
2073 | memclock_table_header.script_list_ptr + | ||
2074 | script_index * sizeof(u32)); | ||
2075 | |||
2076 | if (!script_ptr) | ||
2077 | continue; | ||
2078 | |||
2079 | /* Link and execute shadow scripts */ | ||
2080 | |||
2081 | for (shadow_idx = 0; shadow_idx <= fb_fbpa_fbio_delay_priv_max_v(); | ||
2082 | ++shadow_idx) { | ||
2083 | if (script_ptr == idx_to_ptr_tbl[shadow_idx]) { | ||
2084 | break; | ||
2085 | } | ||
2086 | } | ||
2087 | |||
2088 | /* script has not been executed before */ | ||
2089 | if (shadow_idx > fb_fbpa_fbio_delay_priv_max_v()) { | ||
2090 | /* find unused index */ | ||
2091 | for (shadow_idx = 0; shadow_idx < | ||
2092 | fb_fbpa_fbio_delay_priv_max_v(); | ||
2093 | ++shadow_idx) { | ||
2094 | if (idx_to_ptr_tbl[shadow_idx] == 0) | ||
2095 | break; | ||
2096 | } | ||
2097 | |||
2098 | if (shadow_idx > fb_fbpa_fbio_delay_priv_max_v()) { | ||
2099 | gk20a_err(dev_from_gk20a(g), | ||
2100 | "invalid shadow reg script index"); | ||
2101 | status = -EINVAL; | ||
2102 | goto done; | ||
2103 | } | ||
2104 | |||
2105 | idx_to_ptr_tbl[shadow_idx] = script_ptr; | ||
2106 | |||
2107 | gk20a_writel(g, fb_fbpa_fbio_delay_r(), | ||
2108 | set_field(old_fbio_delay, | ||
2109 | fb_fbpa_fbio_delay_priv_m(), | ||
2110 | fb_fbpa_fbio_delay_priv_f(shadow_idx))); | ||
2111 | |||
2112 | status = g->ops.bios.execute_script(g, script_ptr); | ||
2113 | if (status < 0) { | ||
2114 | gk20a_writel(g, fb_fbpa_fbio_delay_r(), | ||
2115 | old_fbio_delay); | ||
2116 | goto done; | ||
2117 | } | ||
2118 | |||
2119 | gk20a_writel(g, fb_fbpa_fbio_delay_r(), old_fbio_delay); | ||
2120 | |||
2121 | } | ||
2122 | |||
2123 | cmd_script_index = BIOS_GET_FIELD(memclock_base_entry.flags2, | ||
2124 | VBIOS_MEMORY_CLOCK_BASE_ENTRY_12_FLAGS2_CMD_SCRIPT_INDEX); | ||
2125 | |||
2126 | cmd_script_ptr = gm206_bios_read_u32(g, | ||
2127 | memclock_table_header.cmd_script_list_ptr + | ||
2128 | cmd_script_index * sizeof(u32)); | ||
2129 | |||
2130 | if (!cmd_script_ptr) | ||
2131 | continue; | ||
2132 | |||
2133 | /* Link and execute cmd shadow scripts */ | ||
2134 | for (cmd_idx = 0; cmd_idx <= fb_fbpa_fbio_cmd_delay_cmd_priv_max_v(); | ||
2135 | ++cmd_idx) { | ||
2136 | if (cmd_script_ptr == idx_to_cmd_ptr_tbl[cmd_idx]) | ||
2137 | break; | ||
2138 | } | ||
2139 | |||
2140 | /* script has not been executed before */ | ||
2141 | if (cmd_idx > fb_fbpa_fbio_cmd_delay_cmd_priv_max_v()) { | ||
2142 | /* find unused index */ | ||
2143 | for (cmd_idx = 0; cmd_idx < | ||
2144 | fb_fbpa_fbio_cmd_delay_cmd_priv_max_v(); | ||
2145 | ++cmd_idx) { | ||
2146 | if (idx_to_cmd_ptr_tbl[cmd_idx] == 0) | ||
2147 | break; | ||
2148 | } | ||
2149 | |||
2150 | if (cmd_idx > fb_fbpa_fbio_cmd_delay_cmd_priv_max_v()) { | ||
2151 | gk20a_err(dev_from_gk20a(g), | ||
2152 | "invalid shadow reg cmd script index"); | ||
2153 | status = -EINVAL; | ||
2154 | goto done; | ||
2155 | } | ||
2156 | |||
2157 | idx_to_cmd_ptr_tbl[cmd_idx] = cmd_script_ptr; | ||
2158 | gk20a_writel(g, fb_fbpa_fbio_cmd_delay_r(), | ||
2159 | set_field(old_fbio_cmd_delay, | ||
2160 | fb_fbpa_fbio_cmd_delay_cmd_priv_m(), | ||
2161 | fb_fbpa_fbio_cmd_delay_cmd_priv_f( | ||
2162 | cmd_idx))); | ||
2163 | |||
2164 | status = g->ops.bios.execute_script(g, cmd_script_ptr); | ||
2165 | if (status < 0) { | ||
2166 | gk20a_writel(g, fb_fbpa_fbio_cmd_delay_r(), | ||
2167 | old_fbio_cmd_delay); | ||
2168 | goto done; | ||
2169 | } | ||
2170 | |||
2171 | gk20a_writel(g, fb_fbpa_fbio_cmd_delay_r(), | ||
2172 | old_fbio_cmd_delay); | ||
2173 | |||
2174 | } | ||
2175 | |||
2176 | mem_entry_ptr += memclock_table_header.base_entry_size + | ||
2177 | memclock_table_header.strap_entry_count * | ||
2178 | memclock_table_header.strap_entry_size; | ||
2179 | } | ||
2180 | |||
2181 | done: | ||
2182 | return status; | ||
2183 | } | ||
2184 | |||
2085 | int clk_mclkseq_init_mclk_gddr5(struct gk20a *g) | 2185 | int clk_mclkseq_init_mclk_gddr5(struct gk20a *g) |
2086 | { | 2186 | { |
2087 | struct clk_mclk_state *mclk; | 2187 | struct clk_mclk_state *mclk; |
2188 | int status; | ||
2088 | 2189 | ||
2089 | gk20a_dbg_fn(""); | 2190 | gk20a_dbg_fn(""); |
2090 | 2191 | ||
@@ -2094,8 +2195,10 @@ int clk_mclkseq_init_mclk_gddr5(struct gk20a *g) | |||
2094 | 2195 | ||
2095 | mclk->speed = gk20a_mclk_low_speed; /* Value from Devinit */ | 2196 | mclk->speed = gk20a_mclk_low_speed; /* Value from Devinit */ |
2096 | 2197 | ||
2097 | /* Load Shadow registers */ | 2198 | /* Parse VBIOS */ |
2098 | mclk_memory_load_shadow_regs(g); | 2199 | status = mclk_get_memclk_table(g); |
2200 | if (status < 0) | ||
2201 | return status; | ||
2099 | 2202 | ||
2100 | /* Load RAM pattern */ | 2203 | /* Load RAM pattern */ |
2101 | mclk_memory_load_training_pattern(g); | 2204 | mclk_memory_load_training_pattern(g); |
@@ -2115,6 +2218,8 @@ int clk_mclkseq_init_mclk_gddr5(struct gk20a *g) | |||
2115 | #endif | 2218 | #endif |
2116 | mclk->change = clk_mclkseq_change_mclk_gddr5; | 2219 | mclk->change = clk_mclkseq_change_mclk_gddr5; |
2117 | 2220 | ||
2221 | mclk->init = true; | ||
2222 | |||
2118 | return mclk->change(g, DEFAULT_BOOT_MCLK_SPEED); | 2223 | return mclk->change(g, DEFAULT_BOOT_MCLK_SPEED); |
2119 | } | 2224 | } |
2120 | 2225 | ||
@@ -2125,7 +2230,7 @@ int clk_mclkseq_change_mclk_gddr5(struct gk20a *g, enum gk20a_mclk_speed speed) | |||
2125 | struct nv_pmu_seq_cmd cmd; | 2230 | struct nv_pmu_seq_cmd cmd; |
2126 | struct nv_pmu_seq_cmd_run_script *pseq_cmd; | 2231 | struct nv_pmu_seq_cmd_run_script *pseq_cmd; |
2127 | u32 seqdesc; | 2232 | u32 seqdesc; |
2128 | u32 status = 0; | 2233 | int status = 0; |
2129 | u32 seq_completion_status = ~0x0; | 2234 | u32 seq_completion_status = ~0x0; |
2130 | u8 *seq_script_ptr = NULL; | 2235 | u8 *seq_script_ptr = NULL; |
2131 | size_t seq_script_size = 0; | 2236 | size_t seq_script_size = 0; |
@@ -2139,6 +2244,9 @@ int clk_mclkseq_change_mclk_gddr5(struct gk20a *g, enum gk20a_mclk_speed speed) | |||
2139 | 2244 | ||
2140 | mutex_lock(&mclk->mclk_mutex); | 2245 | mutex_lock(&mclk->mclk_mutex); |
2141 | 2246 | ||
2247 | if (!mclk->init) | ||
2248 | goto exit_status; | ||
2249 | |||
2142 | if (speed == mclk->speed) | 2250 | if (speed == mclk->speed) |
2143 | goto exit_status; | 2251 | goto exit_status; |
2144 | 2252 | ||
diff --git a/drivers/gpu/nvgpu/clk/clk_mclk.h b/drivers/gpu/nvgpu/clk/clk_mclk.h index c3261eac..edb7eb78 100644 --- a/drivers/gpu/nvgpu/clk/clk_mclk.h +++ b/drivers/gpu/nvgpu/clk/clk_mclk.h | |||
@@ -19,13 +19,14 @@ | |||
19 | enum gk20a_mclk_speed { | 19 | enum gk20a_mclk_speed { |
20 | gk20a_mclk_low_speed, | 20 | gk20a_mclk_low_speed, |
21 | gk20a_mclk_mid_speed, | 21 | gk20a_mclk_mid_speed, |
22 | gk20a_mclk_high_speed | 22 | gk20a_mclk_high_speed, |
23 | }; | 23 | }; |
24 | 24 | ||
25 | struct clk_mclk_state { | 25 | struct clk_mclk_state { |
26 | enum gk20a_mclk_speed speed; | 26 | enum gk20a_mclk_speed speed; |
27 | struct mutex mclk_mutex; | 27 | struct mutex mclk_mutex; |
28 | void *vreg_buf; | 28 | void *vreg_buf; |
29 | bool init; | ||
29 | 30 | ||
30 | /* function pointers */ | 31 | /* function pointers */ |
31 | int (*change)(struct gk20a *g, enum gk20a_mclk_speed speed); | 32 | int (*change)(struct gk20a *g, enum gk20a_mclk_speed speed); |