diff options
author | Konsta Holtta <kholtta@nvidia.com> | 2014-10-14 04:48:40 -0400 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2015-03-18 15:11:49 -0400 |
commit | 3f3844a11ccac7957fdb7139a1c9c2a767d315a5 (patch) | |
tree | 728a145ec168983d833dcb1de04d5dab84bb43e7 /drivers/gpu/nvgpu/gk20a/gr_gk20a.c | |
parent | a870ff1d294126a3b46db4e0fdc14276035a2840 (diff) |
gpu: nvgpu: select ucode boot init by signature
Compute a signature checksum for ctxsw ucode boot section and determine
the format of boot initialization data by it. This unifies gk20a and
gk20b ucode segment loading a lot by separating the bootloader loading
logic to separate functions.
Note: Whenever the boot segment binary changes, its updated signature
must be added here. Management of different bootloaders must be
supported for repo-crossing staging issues.
Bug 1519397
Change-Id: I96f9b905d3631dfdebf71ea3a652a0968615fd0a
Signed-off-by: Konsta Holtta <kholtta@nvidia.com>
Reviewed-on: http://git-master/r/556679
GVS: Gerrit_Virtual_Submit
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/gr_gk20a.c')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gr_gk20a.c | 105 |
1 files changed, 86 insertions, 19 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/gr_gk20a.c b/drivers/gpu/nvgpu/gk20a/gr_gk20a.c index 84b79b42..30ea49a7 100644 --- a/drivers/gpu/nvgpu/gk20a/gr_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/gr_gk20a.c | |||
@@ -1776,9 +1776,17 @@ static int gr_gk20a_copy_ctxsw_ucode_segments( | |||
1776 | u32 *bootimage, | 1776 | u32 *bootimage, |
1777 | u32 *code, u32 *data) | 1777 | u32 *code, u32 *data) |
1778 | { | 1778 | { |
1779 | int i; | ||
1780 | |||
1779 | memcpy(buf + segments->boot.offset, bootimage, segments->boot.size); | 1781 | memcpy(buf + segments->boot.offset, bootimage, segments->boot.size); |
1780 | memcpy(buf + segments->code.offset, code, segments->code.size); | 1782 | memcpy(buf + segments->code.offset, code, segments->code.size); |
1781 | memcpy(buf + segments->data.offset, data, segments->data.size); | 1783 | memcpy(buf + segments->data.offset, data, segments->data.size); |
1784 | |||
1785 | /* compute a "checksum" for the boot binary to detect its version */ | ||
1786 | segments->boot_signature = 0; | ||
1787 | for (i = 0; i < segments->boot.size / sizeof(u32); i++) | ||
1788 | segments->boot_signature += bootimage[i]; | ||
1789 | |||
1782 | return 0; | 1790 | return 0; |
1783 | } | 1791 | } |
1784 | 1792 | ||
@@ -1968,22 +1976,14 @@ void gr_gk20a_load_falcon_bind_instblk(struct gk20a *g) | |||
1968 | gk20a_err(dev_from_gk20a(g), "arbiter complete timeout"); | 1976 | gk20a_err(dev_from_gk20a(g), "arbiter complete timeout"); |
1969 | } | 1977 | } |
1970 | 1978 | ||
1971 | static int gr_gk20a_load_ctxsw_ucode_segments(struct gk20a *g, u64 addr_base, | 1979 | void gr_gk20a_load_ctxsw_ucode_header(struct gk20a *g, u64 addr_base, |
1972 | struct gk20a_ctxsw_ucode_segments *segments, u32 reg_offset) | 1980 | struct gk20a_ctxsw_ucode_segments *segments, u32 reg_offset) |
1973 | { | 1981 | { |
1974 | u32 addr_code32; | 1982 | u32 addr_code32; |
1975 | u32 addr_data32; | 1983 | u32 addr_data32; |
1976 | u32 addr_load32; | ||
1977 | u32 dst = 0; | ||
1978 | u32 blocks; | ||
1979 | u32 b; | ||
1980 | 1984 | ||
1981 | addr_code32 = u64_lo32((addr_base + segments->code.offset) >> 8); | 1985 | addr_code32 = u64_lo32((addr_base + segments->code.offset) >> 8); |
1982 | addr_data32 = u64_lo32((addr_base + segments->data.offset) >> 8); | 1986 | addr_data32 = u64_lo32((addr_base + segments->data.offset) >> 8); |
1983 | addr_load32 = u64_lo32((addr_base + segments->boot.offset) >> 8); | ||
1984 | |||
1985 | gk20a_writel(g, reg_offset + gr_fecs_dmactl_r(), | ||
1986 | gr_fecs_dmactl_require_ctx_f(0)); | ||
1987 | 1987 | ||
1988 | /* | 1988 | /* |
1989 | * Copy falcon bootloader header into dmem at offset 0. | 1989 | * Copy falcon bootloader header into dmem at offset 0. |
@@ -1996,17 +1996,73 @@ static int gr_gk20a_load_ctxsw_ucode_segments(struct gk20a *g, u64 addr_base, | |||
1996 | gr_fecs_dmemc_aincw_f(1)); | 1996 | gr_fecs_dmemc_aincw_f(1)); |
1997 | 1997 | ||
1998 | /* Write out the actual data */ | 1998 | /* Write out the actual data */ |
1999 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); | 1999 | switch (segments->boot_signature) { |
2000 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), addr_code32); | 2000 | case FALCON_UCODE_SIG_T12X_FECS_WITH_RESERVED: |
2001 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); | 2001 | case FALCON_UCODE_SIG_T12X_GPCCS_WITH_RESERVED: |
2002 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), segments->code.size); | 2002 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); |
2003 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); | 2003 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); |
2004 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), addr_data32); | 2004 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); |
2005 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), segments->data.size); | 2005 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); |
2006 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), addr_code32); | 2006 | /* fallthrough */ |
2007 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); | 2007 | case FALCON_UCODE_SIG_T12X_FECS_WITHOUT_RESERVED: |
2008 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); | 2008 | case FALCON_UCODE_SIG_T12X_GPCCS_WITHOUT_RESERVED: |
2009 | case FALCON_UCODE_SIG_T21X_FECS_WITHOUT_RESERVED: | ||
2010 | case FALCON_UCODE_SIG_T21X_FECS_WITHOUT_RESERVED2: | ||
2011 | case FALCON_UCODE_SIG_T21X_GPCCS_WITHOUT_RESERVED: | ||
2012 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); | ||
2013 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); | ||
2014 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); | ||
2015 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); | ||
2016 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 4); | ||
2017 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), | ||
2018 | addr_code32); | ||
2019 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); | ||
2020 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), | ||
2021 | segments->code.size); | ||
2022 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); | ||
2023 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); | ||
2024 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); | ||
2025 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), | ||
2026 | addr_data32); | ||
2027 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), | ||
2028 | segments->data.size); | ||
2029 | break; | ||
2030 | case FALCON_UCODE_SIG_T12X_FECS_OLDER: | ||
2031 | case FALCON_UCODE_SIG_T12X_GPCCS_OLDER: | ||
2032 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); | ||
2033 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), | ||
2034 | addr_code32); | ||
2035 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); | ||
2036 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), | ||
2037 | segments->code.size); | ||
2038 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); | ||
2039 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), | ||
2040 | addr_data32); | ||
2041 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), | ||
2042 | segments->data.size); | ||
2043 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), | ||
2044 | addr_code32); | ||
2045 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); | ||
2046 | gk20a_writel(g, reg_offset + gr_fecs_dmemd_r(0), 0); | ||
2047 | break; | ||
2048 | default: | ||
2049 | gk20a_err(dev_from_gk20a(g), | ||
2050 | "unknown falcon ucode boot signature 0x%08x" | ||
2051 | " with reg_offset 0x%08x", | ||
2052 | segments->boot_signature, reg_offset); | ||
2053 | BUG(); | ||
2054 | } | ||
2055 | } | ||
2056 | |||
2057 | void gr_gk20a_load_ctxsw_ucode_boot(struct gk20a *g, u64 addr_base, | ||
2058 | struct gk20a_ctxsw_ucode_segments *segments, u32 reg_offset) | ||
2059 | { | ||
2060 | u32 addr_load32; | ||
2061 | u32 blocks; | ||
2062 | u32 b; | ||
2063 | u32 dst; | ||
2009 | 2064 | ||
2065 | addr_load32 = u64_lo32((addr_base + segments->boot.offset) >> 8); | ||
2010 | blocks = ((segments->boot.size + 0xFF) & ~0xFF) >> 8; | 2066 | blocks = ((segments->boot.size + 0xFF) & ~0xFF) >> 8; |
2011 | 2067 | ||
2012 | /* | 2068 | /* |
@@ -2038,6 +2094,17 @@ static int gr_gk20a_load_ctxsw_ucode_segments(struct gk20a *g, u64 addr_base, | |||
2038 | /* Specify the falcon boot vector */ | 2094 | /* Specify the falcon boot vector */ |
2039 | gk20a_writel(g, reg_offset + gr_fecs_bootvec_r(), | 2095 | gk20a_writel(g, reg_offset + gr_fecs_bootvec_r(), |
2040 | gr_fecs_bootvec_vec_f(segments->boot_entry)); | 2096 | gr_fecs_bootvec_vec_f(segments->boot_entry)); |
2097 | } | ||
2098 | |||
2099 | int gr_gk20a_load_ctxsw_ucode_segments(struct gk20a *g, u64 addr_base, | ||
2100 | struct gk20a_ctxsw_ucode_segments *segments, u32 reg_offset) | ||
2101 | { | ||
2102 | gk20a_writel(g, reg_offset + gr_fecs_dmactl_r(), | ||
2103 | gr_fecs_dmactl_require_ctx_f(0)); | ||
2104 | |||
2105 | /* Copy falcon bootloader into dmem */ | ||
2106 | gr_gk20a_load_ctxsw_ucode_header(g, addr_base, segments, reg_offset); | ||
2107 | gr_gk20a_load_ctxsw_ucode_boot(g, addr_base, segments, reg_offset); | ||
2041 | 2108 | ||
2042 | /* Write to CPUCTL to start the falcon */ | 2109 | /* Write to CPUCTL to start the falcon */ |
2043 | gk20a_writel(g, reg_offset + gr_fecs_cpuctl_r(), | 2110 | gk20a_writel(g, reg_offset + gr_fecs_cpuctl_r(), |