This commit enables basic support for Hopper GPUs, and is intended
primarily as a base supporting Blackwell GPUs, which reuse most of
the code added here.

Advanced features such as Confidential Compute are not supported.

Beyond a few miscellaneous register moves and HW class ID plumbing,
the bulk of the changes implemented here are to support the GSP-RM
boot sequence used on Hopper/Blackwell GPUs, as well as a new page
table layout.

There should be no changes here that impact prior GPUs.

Signed-off-by: Ben Skeggs <bske...@nvidia.com>
Co-developed-by: Timur Tabi <tt...@nvidia.com>
Signed-off-by: Timur Tabi <tt...@nvidia.com>
Reviewed-by: Dave Airlie <airl...@redhat.com>
Reviewed-by: Timur Tabi <tt...@nvidia.com>
Tested-by: Timur Tabi <tt...@nvidia.com>
---
 .../include/nvhw/ref/gh100/dev_falcon_v4.h    |  20 +
 .../nouveau/include/nvhw/ref/gh100/dev_fb.h   |  15 +
 .../include/nvhw/ref/gh100/dev_fsp_pri.h      |  28 ++
 .../nouveau/include/nvhw/ref/gh100/dev_mmu.h  | 173 +++++++++
 .../include/nvhw/ref/gh100/dev_riscv_pri.h    |  14 +
 .../include/nvhw/ref/gh100/dev_therm.h        |  17 +
 .../include/nvhw/ref/gh100/dev_xtl_ep_pri.h   |  10 +
 .../include/nvhw/ref/gh100/pri_nv_xal_ep.h    |  13 +
 drivers/gpu/drm/nouveau/include/nvif/cl0080.h |   1 +
 drivers/gpu/drm/nouveau/include/nvif/class.h  |   9 +
 .../drm/nouveau/include/nvkm/core/device.h    |   4 +
 .../drm/nouveau/include/nvkm/core/layout.h    |   1 +
 .../gpu/drm/nouveau/include/nvkm/subdev/fb.h  |   1 +
 .../gpu/drm/nouveau/include/nvkm/subdev/fsp.h |  22 ++
 .../gpu/drm/nouveau/include/nvkm/subdev/gsp.h |  13 +
 .../drm/nouveau/include/nvkm/subdev/instmem.h |   1 +
 .../gpu/drm/nouveau/include/nvkm/subdev/mmu.h |   1 +
 .../gpu/drm/nouveau/include/nvkm/subdev/pci.h |   1 +
 drivers/gpu/drm/nouveau/nouveau_bo.c          |   1 +
 drivers/gpu/drm/nouveau/nouveau_chan.c        |   1 +
 drivers/gpu/drm/nouveau/nouveau_drm.c         |   1 +
 drivers/gpu/drm/nouveau/nvif/user.c           |   1 +
 .../gpu/drm/nouveau/nvkm/engine/device/base.c |  18 +
 .../gpu/drm/nouveau/nvkm/engine/device/priv.h |   1 +
 .../gpu/drm/nouveau/nvkm/engine/device/user.c |   1 +
 drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild    |   1 +
 drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild |   1 +
 .../gpu/drm/nouveau/nvkm/subdev/fb/ga102.c    |   2 +-
 .../gpu/drm/nouveau/nvkm/subdev/fb/gh100.c    |  30 ++
 drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h |   2 +
 .../gpu/drm/nouveau/nvkm/subdev/fsp/Kbuild    |   6 +
 .../gpu/drm/nouveau/nvkm/subdev/fsp/base.c    |  66 ++++
 .../gpu/drm/nouveau/nvkm/subdev/fsp/gh100.c   | 275 ++++++++++++++
 .../gpu/drm/nouveau/nvkm/subdev/fsp/priv.h    |  28 ++
 .../gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild    |   1 +
 .../gpu/drm/nouveau/nvkm/subdev/gsp/base.c    |   2 +
 .../gpu/drm/nouveau/nvkm/subdev/gsp/gh100.c   | 353 ++++++++++++++++++
 .../gpu/drm/nouveau/nvkm/subdev/gsp/priv.h    |   8 +
 .../gpu/drm/nouveau/nvkm/subdev/gsp/rm/Kbuild |   1 +
 .../drm/nouveau/nvkm/subdev/gsp/rm/gh100.c    |  27 ++
 .../gpu/drm/nouveau/nvkm/subdev/gsp/rm/gpu.h  |   1 +
 .../drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c |   6 +
 .../drm/nouveau/nvkm/subdev/gsp/rm/r570/gsp.c |  11 +-
 .../nvkm/subdev/gsp/rm/r570/nvrm/gsp.h        |  58 +++
 .../drm/nouveau/nvkm/subdev/gsp/rm/r570/rm.c  |  15 +
 .../gpu/drm/nouveau/nvkm/subdev/gsp/rm/rm.h   |   3 +
 .../gpu/drm/nouveau/nvkm/subdev/gsp/tu102.c   |   4 +-
 .../drm/nouveau/nvkm/subdev/instmem/Kbuild    |   1 +
 .../drm/nouveau/nvkm/subdev/instmem/gh100.c   |  28 ++
 .../drm/nouveau/nvkm/subdev/instmem/nv50.c    |   6 +-
 .../drm/nouveau/nvkm/subdev/instmem/priv.h    |   5 +
 .../gpu/drm/nouveau/nvkm/subdev/mmu/Kbuild    |   2 +
 .../gpu/drm/nouveau/nvkm/subdev/mmu/gh100.c   |  25 ++
 .../gpu/drm/nouveau/nvkm/subdev/mmu/priv.h    |   2 +
 .../gpu/drm/nouveau/nvkm/subdev/mmu/tu102.c   |   2 +-
 drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h |   7 +
 .../drm/nouveau/nvkm/subdev/mmu/vmmgh100.c    | 306 +++++++++++++++
 .../drm/nouveau/nvkm/subdev/mmu/vmmgp100.c    |   3 +
 .../drm/nouveau/nvkm/subdev/mmu/vmmtu102.c    |   2 +-
 .../gpu/drm/nouveau/nvkm/subdev/pci/Kbuild    |   1 +
 .../gpu/drm/nouveau/nvkm/subdev/pci/gh100.c   |  30 ++
 61 files changed, 1680 insertions(+), 9 deletions(-)
 create mode 100644 
drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_falcon_v4.h
 create mode 100644 drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_fb.h
 create mode 100644 drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_fsp_pri.h
 create mode 100644 drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_mmu.h
 create mode 100644 
drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_riscv_pri.h
 create mode 100644 drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_therm.h
 create mode 100644 
drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_xtl_ep_pri.h
 create mode 100644 
drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/pri_nv_xal_ep.h
 create mode 100644 drivers/gpu/drm/nouveau/include/nvkm/subdev/fsp.h
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/fb/gh100.c
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/fsp/Kbuild
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/fsp/base.c
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/fsp/gh100.c
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/fsp/priv.h
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/gsp/gh100.c
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/gh100.c
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gh100.c
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gh100.c
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgh100.c
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/pci/gh100.c

diff --git a/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_falcon_v4.h 
b/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_falcon_v4.h
new file mode 100644
index 000000000000..52171b412aa1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_falcon_v4.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
+ */
+#ifndef __gh100_dev_falcon_v4_h__
+#define __gh100_dev_falcon_v4_h__
+
+#define NV_PFALCON_FALCON_MAILBOX0                                             
                        0x00000040     /* RW-4R */
+#define NV_PFALCON_FALCON_MAILBOX0_DATA                                        
                        31:0           /* RWIVF */
+#define NV_PFALCON_FALCON_MAILBOX0_DATA_INIT                                   
                        0x00000000     /* RWI-V */
+#define NV_PFALCON_FALCON_MAILBOX1                                             
                        0x00000044     /* RW-4R */
+#define NV_PFALCON_FALCON_MAILBOX1_DATA                                        
                        31:0           /* RWIVF */
+#define NV_PFALCON_FALCON_MAILBOX1_DATA_INIT                                   
                        0x00000000     /* RWI-V */
+
+#define NV_PFALCON_FALCON_HWCFG2                                               
                        0x000000f4     /* R--4R */
+#define NV_PFALCON_FALCON_HWCFG2_RISCV_BR_PRIV_LOCKDOWN                        
                        13:13          /* R--VF */
+#define NV_PFALCON_FALCON_HWCFG2_RISCV_BR_PRIV_LOCKDOWN_LOCK                   
                        0x00000001     /* R---V */
+#define NV_PFALCON_FALCON_HWCFG2_RISCV_BR_PRIV_LOCKDOWN_UNLOCK                 
                        0x00000000     /* R---V */
+
+#endif // __gh100_dev_falcon_v4_h__
diff --git a/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_fb.h 
b/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_fb.h
new file mode 100644
index 000000000000..819f09465952
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_fb.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
+ */
+#ifndef __gh100_dev_fb_h_
+#define __gh100_dev_fb_h_
+
+#define NV_PFB_NISO_FLUSH_SYSMEM_ADDR_SHIFT                       8 /*       */
+#define NV_PFB_FBHUB_PCIE_FLUSH_SYSMEM_ADDR_LO           0x00100A34 /* RW-4R */
+#define NV_PFB_FBHUB_PCIE_FLUSH_SYSMEM_ADDR_LO_ADR             31:0 /* RWIVF */
+#define NV_PFB_FBHUB_PCIE_FLUSH_SYSMEM_ADDR_HI           0x00100A38 /* RW-4R */
+#define NV_PFB_FBHUB_PCIE_FLUSH_SYSMEM_ADDR_HI_ADR             31:0 /* RWIVF */
+#define NV_PFB_FBHUB_PCIE_FLUSH_SYSMEM_ADDR_HI_ADR_MASK  0x000FFFFF /* ----V */
+
+#endif // __gh100_dev_fb_h_
diff --git a/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_fsp_pri.h 
b/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_fsp_pri.h
new file mode 100644
index 000000000000..e9507242cae5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_fsp_pri.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
+ */
+#ifndef __gh100_dev_fsp_pri_h__
+#define __gh100_dev_fsp_pri_h__
+
+#define NV_PFSP             0x8F3FFF:0x8F0000 /* RW--D */
+
+#define NV_PFSP_MSGQ_HEAD(i)                                                   
                          (0x008F2c80+(i)*8) /* RW-4A */
+#define NV_PFSP_MSGQ_HEAD__SIZE_1                                              
                          8              /*       */
+#define NV_PFSP_MSGQ_HEAD_VAL                                                  
                          31:0           /* RWIUF */
+#define NV_PFSP_MSGQ_HEAD_VAL_INIT                                             
                          0x00000000     /* RWI-V */
+#define NV_PFSP_MSGQ_TAIL(i)                                                   
                          (0x008F2c84+(i)*8) /* RW-4A */
+#define NV_PFSP_MSGQ_TAIL__SIZE_1                                              
                          8              /*       */
+#define NV_PFSP_MSGQ_TAIL_VAL                                                  
                          31:0           /* RWIUF */
+#define NV_PFSP_MSGQ_TAIL_VAL_INIT                                             
                          0x00000000     /* RWI-V */
+
+#define NV_PFSP_QUEUE_HEAD(i)                                                  
                          (0x008F2c00+(i)*8) /* RW-4A */
+#define NV_PFSP_QUEUE_HEAD__SIZE_1                                             
                          8              /*       */
+#define NV_PFSP_QUEUE_HEAD_ADDRESS                                             
                          31:0           /* RWIVF */
+#define NV_PFSP_QUEUE_HEAD_ADDRESS_INIT                                        
                          0x00000000     /* RWI-V */
+#define NV_PFSP_QUEUE_TAIL(i)                                                  
                          (0x008F2c04+(i)*8) /* RW-4A */
+#define NV_PFSP_QUEUE_TAIL__SIZE_1                                             
                          8              /*       */
+#define NV_PFSP_QUEUE_TAIL_ADDRESS                                             
                          31:0           /* RWIVF */
+#define NV_PFSP_QUEUE_TAIL_ADDRESS_INIT                                        
                          0x00000000     /* RWI-V */
+
+#endif // __gh100_dev_fsp_pri_h__
diff --git a/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_mmu.h 
b/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_mmu.h
new file mode 100644
index 000000000000..6707e0e3b96b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_mmu.h
@@ -0,0 +1,173 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
+ */
+#ifndef __gh100_dev_mmu_h__
+#define __gh100_dev_mmu_h__
+
+#define NV_MMU_PTE                                                      /* 
----G */
+#define NV_MMU_PTE_APERTURE                           (1*32+2):(1*32+1) /* 
RWXVF */
+#define NV_MMU_PTE_APERTURE_VIDEO_MEMORY                     0x00000000 /* 
RW--V */
+#define NV_MMU_PTE_APERTURE_PEER_MEMORY                      0x00000001 /* 
RW--V */
+#define NV_MMU_PTE_APERTURE_SYSTEM_COHERENT_MEMORY           0x00000002 /* 
RW--V */
+#define NV_MMU_PTE_APERTURE_SYSTEM_NON_COHERENT_MEMORY       0x00000003 /* 
RW--V */
+#define NV_MMU_PTE_KIND                              (1*32+7):(1*32+4) /* 
RWXVF */
+#define NV_MMU_PTE_KIND_INVALID                       0x07 /* R---V */
+#define NV_MMU_PTE_KIND_PITCH                         0x00 /* R---V */
+#define NV_MMU_PTE_KIND_GENERIC_MEMORY                                         
         0x6 /* R---V */
+#define NV_MMU_PTE_KIND_Z16                                                    
         0x1 /* R---V */
+#define NV_MMU_PTE_KIND_S8                                                     
         0x2 /* R---V */
+#define NV_MMU_PTE_KIND_S8Z24                                                  
         0x3 /* R---V */
+#define NV_MMU_PTE_KIND_ZF32_X24S8                                             
         0x4 /* R---V */
+#define NV_MMU_PTE_KIND_Z24S8                                                  
         0x5 /* R---V */
+#define NV_MMU_PTE_KIND_GENERIC_MEMORY_COMPRESSIBLE                            
         0x8 /* R---V */
+#define NV_MMU_PTE_KIND_GENERIC_MEMORY_COMPRESSIBLE_DISABLE_PLC                
         0x9 /* R---V */
+#define NV_MMU_PTE_KIND_S8_COMPRESSIBLE_DISABLE_PLC                            
         0xA /* R---V */
+#define NV_MMU_PTE_KIND_Z16_COMPRESSIBLE_DISABLE_PLC                           
         0xB /* R---V */
+#define NV_MMU_PTE_KIND_S8Z24_COMPRESSIBLE_DISABLE_PLC                         
         0xC /* R---V */
+#define NV_MMU_PTE_KIND_ZF32_X24S8_COMPRESSIBLE_DISABLE_PLC                    
         0xD /* R---V */
+#define NV_MMU_PTE_KIND_Z24S8_COMPRESSIBLE_DISABLE_PLC                         
         0xE /* R---V */
+#define NV_MMU_PTE_KIND_SMSKED_MESSAGE                                         
         0xF /* R---V */
+
+#define NV_MMU_VER3_PDE                                                      
/* ----G */
+#define NV_MMU_VER3_PDE_IS_PTE                                           0:0 
/* RWXVF */
+#define NV_MMU_VER3_PDE_IS_PTE_TRUE                                      0x1 
/* RW--V */
+#define NV_MMU_VER3_PDE_IS_PTE_FALSE                                     0x0 
/* RW--V */
+#define NV_MMU_VER3_PDE_VALID                                            0:0 
/* RWXVF */
+#define NV_MMU_VER3_PDE_VALID_TRUE                                       0x1 
/* RW--V */
+#define NV_MMU_VER3_PDE_VALID_FALSE                                      0x0 
/* RW--V */
+#define NV_MMU_VER3_PDE_APERTURE                                         2:1 
/* RWXVF */
+#define NV_MMU_VER3_PDE_APERTURE_INVALID                          0x00000000 
/* RW--V */
+#define NV_MMU_VER3_PDE_APERTURE_VIDEO_MEMORY                     0x00000001 
/* RW--V */
+#define NV_MMU_VER3_PDE_APERTURE_SYSTEM_COHERENT_MEMORY           0x00000002 
/* RW--V */
+#define NV_MMU_VER3_PDE_APERTURE_SYSTEM_NON_COHERENT_MEMORY       0x00000003 
/* RW--V */
+#define NV_MMU_VER3_PDE_PCF                                                    
                    5:3 /* RWXVF */
+#define NV_MMU_VER3_PDE_PCF_VALID_CACHED_ATS_ALLOWED__OR__INVALID_ATS_ALLOWED  
             0x00000000 /* RW--V */
+#define NV_MMU_VER3_PDE_PCF_VALID_CACHED_ATS_ALLOWED                           
             0x00000000 /* RW--V */
+#define NV_MMU_VER3_PDE_PCF_INVALID_ATS_ALLOWED                                
             0x00000000 /* RW--V */
+#define NV_MMU_VER3_PDE_PCF_VALID_UNCACHED_ATS_ALLOWED__OR__SPARSE_ATS_ALLOWED 
             0x00000001 /* RW--V */
+#define NV_MMU_VER3_PDE_PCF_VALID_UNCACHED_ATS_ALLOWED                         
             0x00000001 /* RW--V */
+#define NV_MMU_VER3_PDE_PCF_SPARSE_ATS_ALLOWED                                 
             0x00000001 /* RW--V */
+#define 
NV_MMU_VER3_PDE_PCF_VALID_CACHED_ATS_NOT_ALLOWED__OR__INVALID_ATS_NOT_ALLOWED   
    0x00000002 /* RW--V */
+#define NV_MMU_VER3_PDE_PCF_VALID_CACHED_ATS_NOT_ALLOWED                       
             0x00000002 /* RW--V */
+#define NV_MMU_VER3_PDE_PCF_INVALID_ATS_NOT_ALLOWED                            
             0x00000002 /* RW--V */
+#define 
NV_MMU_VER3_PDE_PCF_VALID_UNCACHED_ATS_NOT_ALLOWED__OR__SPARSE_ATS_NOT_ALLOWED  
    0x00000003 /* RW--V */
+#define NV_MMU_VER3_PDE_PCF_VALID_UNCACHED_ATS_NOT_ALLOWED                     
             0x00000003 /* RW--V */
+#define NV_MMU_VER3_PDE_PCF_SPARSE_ATS_NOT_ALLOWED                             
             0x00000003 /* RW--V */
+#define NV_MMU_VER3_PDE_ADDRESS                                             
51:12 /* RWXVF */
+#define NV_MMU_VER3_PDE_ADDRESS_SHIFT                                  
0x0000000c /*       */
+#define NV_MMU_VER3_PDE__SIZE                                              8
+
+#define NV_MMU_VER3_DUAL_PDE                                                   
   /* ----G */
+#define NV_MMU_VER3_DUAL_PDE_IS_PTE                                           
0:0 /* RWXVF */
+#define NV_MMU_VER3_DUAL_PDE_IS_PTE_TRUE                                      
0x1 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_IS_PTE_FALSE                                     
0x0 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_VALID                                            
0:0 /* RWXVF */
+#define NV_MMU_VER3_DUAL_PDE_VALID_TRUE                                       
0x1 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_VALID_FALSE                                      
0x0 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_APERTURE_BIG                                     
2:1 /* RWXVF */
+#define NV_MMU_VER3_DUAL_PDE_APERTURE_BIG_INVALID                      
0x00000000 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_APERTURE_BIG_VIDEO_MEMORY                 
0x00000001 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_APERTURE_BIG_SYSTEM_COHERENT_MEMORY       
0x00000002 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_APERTURE_BIG_SYSTEM_NON_COHERENT_MEMORY   
0x00000003 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_PCF_BIG                                           
                             5:3 /* RWXVF */
+#define 
NV_MMU_VER3_DUAL_PDE_PCF_BIG_VALID_CACHED_ATS_ALLOWED__OR__INVALID_ATS_ALLOWED  
             0x00000000 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_PCF_BIG_VALID_CACHED_ATS_ALLOWED                  
                      0x00000000 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_PCF_BIG_INVALID_ATS_ALLOWED                       
                      0x00000000 /* RW--V */
+#define 
NV_MMU_VER3_DUAL_PDE_PCF_BIG_VALID_UNCACHED_ATS_ALLOWED__OR__SPARSE_ATS_ALLOWED 
             0x00000001 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_PCF_BIG_VALID_UNCACHED_ATS_ALLOWED                
                      0x00000001 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_PCF_BIG_SPARSE_ATS_ALLOWED                        
                      0x00000001 /* RW--V */
+#define 
NV_MMU_VER3_DUAL_PDE_PCF_BIG_VALID_CACHED_ATS_NOT_ALLOWED__OR__INVALID_ATS_NOT_ALLOWED
       0x00000002 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_PCF_BIG_VALID_CACHED_ATS_NOT_ALLOWED              
                      0x00000002 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_PCF_BIG_INVALID_ATS_NOT_ALLOWED                   
                      0x00000002 /* RW--V */
+#define 
NV_MMU_VER3_DUAL_PDE_PCF_BIG_VALID_UNCACHED_ATS_NOT_ALLOWED__OR__SPARSE_ATS_NOT_ALLOWED
      0x00000003 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_PCF_BIG_VALID_UNCACHED_ATS_NOT_ALLOWED            
                      0x00000003 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_PCF_BIG_SPARSE_ATS_NOT_ALLOWED                    
                      0x00000003 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_ADDRESS_BIG                                     
51:8 /* RWXVF */
+#define NV_MMU_VER3_DUAL_PDE_APERTURE_SMALL                                 
66:65 /* RWXVF */
+#define NV_MMU_VER3_DUAL_PDE_APERTURE_SMALL_INVALID                    
0x00000000 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_APERTURE_SMALL_VIDEO_MEMORY               
0x00000001 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_APERTURE_SMALL_SYSTEM_COHERENT_MEMORY     
0x00000002 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_APERTURE_SMALL_SYSTEM_NON_COHERENT_MEMORY 
0x00000003 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_PCF_SMALL                                         
                             69:67 /* RWXVF */
+#define 
NV_MMU_VER3_DUAL_PDE_PCF_SMALL_VALID_CACHED_ATS_ALLOWED__OR__INVALID_ATS_ALLOWED
               0x00000000 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_PCF_SMALL_VALID_CACHED_ATS_ALLOWED                
                        0x00000000 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_PCF_SMALL_INVALID_ATS_ALLOWED                     
                        0x00000000 /* RW--V */
+#define 
NV_MMU_VER3_DUAL_PDE_PCF_SMALL_VALID_UNCACHED_ATS_ALLOWED__OR__SPARSE_ATS_ALLOWED
              0x00000001 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_PCF_SMALL_VALID_UNCACHED_ATS_ALLOWED              
                        0x00000001 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_PCF_SMALL_SPARSE_ATS_ALLOWED                      
                        0x00000001 /* RW--V */
+#define 
NV_MMU_VER3_DUAL_PDE_PCF_SMALL_VALID_CACHED_ATS_NOT_ALLOWED__OR__INVALID_ATS_NOT_ALLOWED
       0x00000002 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_PCF_SMALL_VALID_CACHED_ATS_NOT_ALLOWED            
                        0x00000002 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_PCF_SMALL_INVALID_ATS_NOT_ALLOWED                 
                        0x00000002 /* RW--V */
+#define 
NV_MMU_VER3_DUAL_PDE_PCF_SMALL_VALID_UNCACHED_ATS_NOT_ALLOWED__OR__SPARSE_ATS_NOT_ALLOWED
      0x00000003 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_PCF_SMALL_VALID_UNCACHED_ATS_NOT_ALLOWED          
                        0x00000003 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_PCF_SMALL_SPARSE_ATS_NOT_ALLOWED                  
                        0x00000003 /* RW--V */
+#define NV_MMU_VER3_DUAL_PDE_ADDRESS_SMALL                                 
115:76 /* RWXVF */
+#define NV_MMU_VER3_DUAL_PDE_ADDRESS_SHIFT                             
0x0000000c /*       */
+#define NV_MMU_VER3_DUAL_PDE_ADDRESS_BIG_SHIFT 8 /*       */
+#define NV_MMU_VER3_DUAL_PDE__SIZE                                             
16
+
+#define NV_MMU_VER3_PTE                                                      
/* ----G */
+#define NV_MMU_VER3_PTE_VALID                                            0:0 
/* RWXVF */
+#define NV_MMU_VER3_PTE_VALID_TRUE                                       0x1 
/* RW--V */
+#define NV_MMU_VER3_PTE_VALID_FALSE                                      0x0 
/* RW--V */
+#define NV_MMU_VER3_PTE_APERTURE                                         2:1 
/* RWXVF */
+#define NV_MMU_VER3_PTE_APERTURE_VIDEO_MEMORY                     0x00000000 
/* RW--V */
+#define NV_MMU_VER3_PTE_APERTURE_PEER_MEMORY                      0x00000001 
/* RW--V */
+#define NV_MMU_VER3_PTE_APERTURE_SYSTEM_COHERENT_MEMORY           0x00000002 
/* RW--V */
+#define NV_MMU_VER3_PTE_APERTURE_SYSTEM_NON_COHERENT_MEMORY       0x00000003 
/* RW--V */
+#define NV_MMU_VER3_PTE_PCF                                                    
                    7:3 /* RWXVF */
+#define NV_MMU_VER3_PTE_PCF_INVALID                                            
             0x00000000 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_SPARSE                                             
             0x00000001 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_MAPPING_NOWHERE                                    
             0x00000002 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_NO_VALID_4KB_PAGE                                  
             0x00000003 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_REGULAR_RW_ATOMIC_CACHED_ACE                       
             0x00000000 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_REGULAR_RW_ATOMIC_UNCACHED_ACE                     
             0x00000001 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_PRIVILEGE_RW_ATOMIC_CACHED_ACE                     
             0x00000002 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_PRIVILEGE_RW_ATOMIC_UNCACHED_ACE                   
             0x00000003 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_REGULAR_RO_ATOMIC_CACHED_ACE                       
             0x00000004 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_REGULAR_RO_ATOMIC_UNCACHED_ACE                     
              0x00000005 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_PRIVILEGE_RO_ATOMIC_CACHED_ACE                     
             0x00000006 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_PRIVILEGE_RO_ATOMIC_UNCACHED_ACE                   
             0x00000007 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_REGULAR_RW_NO_ATOMIC_CACHED_ACE                    
             0x00000008 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_REGULAR_RW_NO_ATOMIC_UNCACHED_ACE                  
             0x00000009 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_PRIVILEGE_RW_NO_ATOMIC_CACHED_ACE                  
             0x0000000A /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_PRIVILEGE_RW_NO_ATOMIC_UNCACHED_ACE                
             0x0000000B /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_REGULAR_RO_NO_ATOMIC_CACHED_ACE                    
             0x0000000C /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_REGULAR_RO_NO_ATOMIC_UNCACHED_ACE                  
             0x0000000D /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_PRIVILEGE_RO_NO_ATOMIC_CACHED_ACE                  
             0x0000000E /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_PRIVILEGE_RO_NO_ATOMIC_UNCACHED_ACE                
             0x0000000F /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_REGULAR_RW_ATOMIC_CACHED_ACD                       
             0x00000010 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_REGULAR_RW_ATOMIC_UNCACHED_ACD                     
             0x00000011 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_PRIVILEGE_RW_ATOMIC_CACHED_ACD                     
             0x00000012 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_PRIVILEGE_RW_ATOMIC_UNCACHED_ACD                   
             0x00000013 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_REGULAR_RO_ATOMIC_CACHED_ACD                       
             0x00000014 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_REGULAR_RO_ATOMIC_UNCACHED_ACD                     
             0x00000015 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_PRIVILEGE_RO_ATOMIC_CACHED_ACD                     
             0x00000016 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_PRIVILEGE_RO_ATOMIC_UNCACHED_ACD                   
             0x00000017 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_REGULAR_RW_NO_ATOMIC_CACHED_ACD                    
             0x00000018 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_REGULAR_RW_NO_ATOMIC_UNCACHED_ACD                  
             0x00000019 /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_PRIVILEGE_RW_NO_ATOMIC_CACHED_ACD                  
             0x0000001A /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_PRIVILEGE_RW_NO_ATOMIC_UNCACHED_ACD                
             0x0000001B /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_REGULAR_RO_NO_ATOMIC_CACHED_ACD                    
             0x0000001C /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_REGULAR_RO_NO_ATOMIC_UNCACHED_ACD                  
             0x0000001D /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_PRIVILEGE_RO_NO_ATOMIC_CACHED_ACD                  
             0x0000001E /* RW--V */
+#define NV_MMU_VER3_PTE_PCF_PRIVILEGE_RO_NO_ATOMIC_UNCACHED_ACD                
             0x0000001F /* RW--V */
+#define NV_MMU_VER3_PTE_KIND                                           11:8 /* 
RWXVF */
+#define NV_MMU_VER3_PTE_ADDRESS                                         51:12 
/* RWXVF */
+#define NV_MMU_VER3_PTE_ADDRESS_SYS                                     51:12 
/* RWXVF */
+#define NV_MMU_VER3_PTE_ADDRESS_PEER                                    51:12 
/* RWXVF */
+#define NV_MMU_VER3_PTE_ADDRESS_VID                                     39:12 
/* RWXVF */
+#define NV_MMU_VER3_PTE_PEER_ID                63:(64-3) /* RWXVF */
+#define NV_MMU_VER3_PTE_PEER_ID_0                                 0x00000000 
/* RW--V */
+#define NV_MMU_VER3_PTE_PEER_ID_1                                 0x00000001 
/* RW--V */
+#define NV_MMU_VER3_PTE_PEER_ID_2                                 0x00000002 
/* RW--V */
+#define NV_MMU_VER3_PTE_PEER_ID_3                                 0x00000003 
/* RW--V */
+#define NV_MMU_VER3_PTE_PEER_ID_4                                 0x00000004 
/* RW--V */
+#define NV_MMU_VER3_PTE_PEER_ID_5                                 0x00000005 
/* RW--V */
+#define NV_MMU_VER3_PTE_PEER_ID_6                                 0x00000006 
/* RW--V */
+#define NV_MMU_VER3_PTE_PEER_ID_7                                 0x00000007 
/* RW--V */
+#define NV_MMU_VER3_PTE_ADDRESS_SHIFT                             0x0000000c 
/*       */
+#define NV_MMU_VER3_PTE__SIZE                                              8
+
+#endif // __gh100_dev_mmu_h__
diff --git a/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_riscv_pri.h 
b/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_riscv_pri.h
new file mode 100644
index 000000000000..8ff4663168d2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_riscv_pri.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
+ */
+#ifndef __gh100_dev_riscv_pri_h__
+#define __gh100_dev_riscv_pri_h__
+
+#define NV_PRISCV_RISCV_CPUCTL                                                 
                        0x00000388     /* RW-4R */
+#define NV_PRISCV_RISCV_CPUCTL_HALTED                                          
                        4:4            /* R-IVF */
+#define NV_PRISCV_RISCV_CPUCTL_HALTED_INIT                                     
                        0x00000001     /* R-I-V */
+#define NV_PRISCV_RISCV_CPUCTL_HALTED_TRUE                                     
                        0x00000001     /* R---V */
+#define NV_PRISCV_RISCV_CPUCTL_HALTED_FALSE                                    
                        0x00000000     /* R---V */
+
+#endif // __gh100_dev_riscv_pri_h__
diff --git a/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_therm.h 
b/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_therm.h
new file mode 100644
index 000000000000..49b4816cb00b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_therm.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
+ */
+#ifndef __gh100_dev_therm_h__
+#define __gh100_dev_therm_h__
+
+#define NV_THERM_I2CS_SCRATCH                                                  
0x000200bc /* RW-4R */
+#define NV_THERM_I2CS_SCRATCH_DATA                                             
      31:0 /* RWIVF */
+#define NV_THERM_I2CS_SCRATCH_DATA_INIT                                        
0x00000000 /* RWI-V */
+
+#define NV_THERM_I2CS_SCRATCH_FSP_BOOT_COMPLETE                                
   NV_THERM_I2CS_SCRATCH
+#define NV_THERM_I2CS_SCRATCH_FSP_BOOT_COMPLETE_STATUS                         
                    31:0
+#define NV_THERM_I2CS_SCRATCH_FSP_BOOT_COMPLETE_STATUS_SUCCESS                 
              0x000000FF
+#define NV_THERM_I2CS_SCRATCH_FSP_BOOT_COMPLETE_STATUS_FAILED                  
              0x00000000
+
+#endif // __gh100_dev_therm_h__
diff --git a/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_xtl_ep_pri.h 
b/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_xtl_ep_pri.h
new file mode 100644
index 000000000000..12b49e9894a2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/dev_xtl_ep_pri.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
+ */
+#ifndef __gh100_dev_xtl_ep_pri_h__
+#define __gh100_dev_xtl_ep_pri_h__
+
+#define NV_EP_PCFGM                                                            
  0x92FFF:0x92000        /* RW--D */
+
+#endif // __gh100_dev_xtl_ep_pri_h__
diff --git a/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/pri_nv_xal_ep.h 
b/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/pri_nv_xal_ep.h
new file mode 100644
index 000000000000..1a891bd33fa3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvhw/ref/gh100/pri_nv_xal_ep.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
+ */
+#ifndef __gh100_pri_nv_xal_ep_h__
+#define __gh100_pri_nv_xal_ep_h__
+
+#define NV_XAL_EP_BAR0_WINDOW_BASE_SHIFT                                       
  0x000010
+#define NV_XAL_EP_BAR0_WINDOW_BASE                                             
      21:0
+#define NV_XAL_EP_BAR0_WINDOW                                                  
0x0010fd40
+
+#endif // __gh100_pri_nv_xal_ep_h__
+
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl0080.h 
b/drivers/gpu/drm/nouveau/include/nvif/cl0080.h
index ea937fa7bc55..60a52ef52071 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/cl0080.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/cl0080.h
@@ -29,6 +29,7 @@ struct nv_device_info_v0 {
 #define NV_DEVICE_INFO_V0_TURING                                           0x0c
 #define NV_DEVICE_INFO_V0_AMPERE                                           0x0d
 #define NV_DEVICE_INFO_V0_ADA                                              0x0e
+#define NV_DEVICE_INFO_V0_HOPPER                                           0x0f
        __u8  family;
        __u8  pad06[2];
        __u64 ram_size;
diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h 
b/drivers/gpu/drm/nouveau/include/nvif/class.h
index 71a2a53bff7f..83acf367a65c 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/class.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/class.h
@@ -63,6 +63,7 @@
 #define VOLTA_USERMODE_A                                             0x0000c361
 #define TURING_USERMODE_A                                            0x0000c461
 #define AMPERE_USERMODE_A                                            0x0000c561
+#define HOPPER_USERMODE_A                                            0x0000c661
 
 #define MAXWELL_FAULT_BUFFER_A                        /* clb069.h */ 0x0000b069
 #define VOLTA_FAULT_BUFFER_A                          /* clb069.h */ 0x0000c369
@@ -85,6 +86,7 @@
 #define TURING_CHANNEL_GPFIFO_A                       /* if0020.h */ 0x0000c46f
 #define AMPERE_CHANNEL_GPFIFO_A                       /* if0020.h */ 0x0000c56f
 #define AMPERE_CHANNEL_GPFIFO_B                       /* if0020.h */ 0x0000c76f
+#define HOPPER_CHANNEL_GPFIFO_A                                      0x0000c86f
 
 #define NV50_DISP                                     /* if0010.h */ 0x00005070
 #define G82_DISP                                      /* if0010.h */ 0x00008270
@@ -194,8 +196,11 @@
 
 #define ADA_A                                         /* cl9097.h */ 0x0000c997
 
+#define HOPPER_A                                                     0x0000cb97
+
 #define NV74_BSP                                                     0x000074b0
 
+#define NVB8B0_VIDEO_DECODER                                         0x0000b8b0
 #define NVC4B0_VIDEO_DECODER                                         0x0000c4b0
 #define NVC6B0_VIDEO_DECODER                                         0x0000c6b0
 #define NVC7B0_VIDEO_DECODER                                         0x0000c7b0
@@ -228,6 +233,7 @@
 #define TURING_DMA_COPY_A                                            0x0000c5b5
 #define AMPERE_DMA_COPY_A                                            0x0000c6b5
 #define AMPERE_DMA_COPY_B                                            0x0000c7b5
+#define HOPPER_DMA_COPY_A                                            0x0000c8b5
 
 #define NVC4B7_VIDEO_ENCODER                                         0x0000c4b7
 #define NVC7B7_VIDEO_ENCODER                                         0x0000c7b7
@@ -250,12 +256,15 @@
 #define AMPERE_COMPUTE_A                                             0x0000c6c0
 #define AMPERE_COMPUTE_B                                             0x0000c7c0
 #define ADA_COMPUTE_A                                                0x0000c9c0
+#define HOPPER_COMPUTE_A                                             0x0000cbc0
 
 #define NV74_CIPHER                                                  0x000074c1
 
+#define NVB8D1_VIDEO_NVJPG                                           0x0000b8d1
 #define NVC4D1_VIDEO_NVJPG                                           0x0000c4d1
 #define NVC9D1_VIDEO_NVJPG                                           0x0000c9d1
 
+#define NVB8FA_VIDEO_OFA                                             0x0000b8fa
 #define NVC6FA_VIDEO_OFA                                             0x0000c6fa
 #define NVC7FA_VIDEO_OFA                                             0x0000c7fa
 #define NVC9FA_VIDEO_OFA                                             0x0000c9fa
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h 
b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h
index f50f52d4dc3f..926542350abc 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h
@@ -46,6 +46,7 @@ struct nvkm_device {
                GV100    = 0x140,
                TU100    = 0x160,
                GA100    = 0x170,
+               GH100    = 0x180,
                AD100    = 0x190,
        } card_type;
        u32 chipset;
@@ -131,6 +132,9 @@ struct nvkm_device *nvkm_device_find(u64 name);
        _temp;                                                                 \
 })
 
+#define NVKM_RD32_(p,o,dr) nvkm_rd32((p), (o) + (dr))
+#define NVKM_RD32(p,A...) DRF_RV(NVKM_RD32_, (p), 0, ##A)
+
 void nvkm_device_del(struct nvkm_device **);
 
 struct nvkm_device_oclass {
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/layout.h 
b/drivers/gpu/drm/nouveau/include/nvkm/core/layout.h
index 2debef27bd95..d92ffd17b729 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/layout.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/layout.h
@@ -1,4 +1,5 @@
 /* SPDX-License-Identifier: MIT */
+NVKM_LAYOUT_ONCE(NVKM_SUBDEV_FSP     , struct nvkm_fsp     ,      fsp)
 NVKM_LAYOUT_ONCE(NVKM_SUBDEV_GSP     , struct nvkm_gsp     ,      gsp)
 NVKM_LAYOUT_ONCE(NVKM_SUBDEV_TOP     , struct nvkm_top     ,      top)
 NVKM_LAYOUT_ONCE(NVKM_SUBDEV_VFN     , struct nvkm_vfn     ,      vfn)
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h 
b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h
index 5b798a1a313d..c114903ce388 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h
@@ -102,6 +102,7 @@ int gv100_fb_new(struct nvkm_device *, enum 
nvkm_subdev_type, int inst, struct n
 int tu102_fb_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct 
nvkm_fb **);
 int ga100_fb_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct 
nvkm_fb **);
 int ga102_fb_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct 
nvkm_fb **);
+int gh100_fb_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct 
nvkm_fb **);
 
 #include <subdev/bios.h>
 #include <subdev/bios/ramcfg.h>
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fsp.h 
b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fsp.h
new file mode 100644
index 000000000000..2a8c1d5a65f9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fsp.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
+ */
+#ifndef __NVKM_FSP_H__
+#define __NVKM_FSP_H__
+#include <core/subdev.h>
+#include <core/falcon.h>
+
+struct nvkm_fsp {
+       const struct nvkm_fsp_func *func;
+       struct nvkm_subdev subdev;
+
+       struct nvkm_falcon falcon;
+};
+
+bool nvkm_fsp_verify_gsp_fmc(struct nvkm_fsp *, u32 hash_size, u32 pkey_size, 
u32 sig_size);
+int nvkm_fsp_boot_gsp_fmc(struct nvkm_fsp *, u64 args_addr, u32 rsvd_size, 
bool resume,
+                         u64 img_addr, const u8 *hash, const u8 *pkey, const 
u8 *sig);
+
+int gh100_fsp_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, 
struct nvkm_fsp **);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h 
b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h
index 4ad07f3ced69..8f611b2503b7 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h
@@ -68,6 +68,9 @@ struct nvkm_gsp {
                        const struct firmware *load;
                        const struct firmware *unload;
                } booter;
+
+               const struct firmware *fmc;
+
                const struct firmware *bl;
                const struct firmware *rm;
        } fws;
@@ -113,6 +116,15 @@ struct nvkm_gsp {
                struct nvkm_falcon_fw unload;
        } booter;
 
+       struct {
+               struct nvkm_gsp_mem fw;
+               u8 *hash;
+               u8 *pkey;
+               u8 *sig;
+
+               struct nvkm_gsp_mem args;
+       } fmc;
+
        struct {
                struct nvkm_gsp_mem fw;
                u32 code_offset;
@@ -478,5 +490,6 @@ int tu102_gsp_new(struct nvkm_device *, enum 
nvkm_subdev_type, int, struct nvkm_
 int tu116_gsp_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct 
nvkm_gsp **);
 int ga100_gsp_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct 
nvkm_gsp **);
 int ga102_gsp_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct 
nvkm_gsp **);
+int gh100_gsp_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct 
nvkm_gsp **);
 int ad102_gsp_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct 
nvkm_gsp **);
 #endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h 
b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h
index 7d93c742ee59..db835cf7b8ac 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h
@@ -36,4 +36,5 @@ int nv04_instmem_new(struct nvkm_device *, enum 
nvkm_subdev_type, int, struct nv
 int nv40_instmem_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct 
nvkm_instmem **);
 int nv50_instmem_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct 
nvkm_instmem **);
 int gk20a_instmem_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct 
nvkm_instmem **);
+int gh100_instmem_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct 
nvkm_instmem **);
 #endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h 
b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h
index 4cab139f3236..abcb0dbcde70 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h
@@ -166,4 +166,5 @@ int gp100_mmu_new(struct nvkm_device *, enum 
nvkm_subdev_type, int inst, struct
 int gp10b_mmu_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, 
struct nvkm_mmu **);
 int gv100_mmu_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, 
struct nvkm_mmu **);
 int tu102_mmu_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, 
struct nvkm_mmu **);
+int gh100_mmu_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, 
struct nvkm_mmu **);
 #endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h 
b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h
index 3c103101d5fc..112b674ed9c8 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h
@@ -50,6 +50,7 @@ int gf100_pci_new(struct nvkm_device *, enum 
nvkm_subdev_type, int inst, struct
 int gf106_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, 
struct nvkm_pci **);
 int gk104_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, 
struct nvkm_pci **);
 int gp100_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, 
struct nvkm_pci **);
+int gh100_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, 
struct nvkm_pci **);
 
 /* pcie functions */
 int nvkm_pcie_set_link(struct nvkm_pci *, enum nvkm_pcie_speed, u8 width);
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c 
b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 9ab8380feb39..fbe0144927e8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -923,6 +923,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm)
                            struct ttm_resource *, struct ttm_resource *);
                int (*init)(struct nouveau_channel *, u32 handle);
        } _methods[] = {
+               {  "COPY", 4, 0xc8b5, nve0_bo_move_copy, nve0_bo_move_init },
                {  "COPY", 4, 0xc7b5, nve0_bo_move_copy, nve0_bo_move_init },
                {  "GRCE", 0, 0xc7b5, nve0_bo_move_copy, nvc0_bo_move_init },
                {  "COPY", 4, 0xc6b5, nve0_bo_move_copy, nve0_bo_move_init },
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c 
b/drivers/gpu/drm/nouveau/nouveau_chan.c
index 5bcd29809c1e..a14aa6715bb9 100644
--- a/drivers/gpu/drm/nouveau/nouveau_chan.c
+++ b/drivers/gpu/drm/nouveau/nouveau_chan.c
@@ -255,6 +255,7 @@ nouveau_channel_ctor(struct nouveau_cli *cli, bool priv, 
u64 runm,
                     struct nouveau_channel **pchan)
 {
        const struct nvif_mclass hosts[] = {
+               {  HOPPER_CHANNEL_GPFIFO_A, 0 },
                {  AMPERE_CHANNEL_GPFIFO_B, 0 },
                {  AMPERE_CHANNEL_GPFIFO_A, 0 },
                {  TURING_CHANNEL_GPFIFO_A, 0 },
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c 
b/drivers/gpu/drm/nouveau/nouveau_drm.c
index e7544942791d..5b6bb4c2f78b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -509,6 +509,7 @@ nouveau_accel_init(struct nouveau_drm *drm)
                case TURING_CHANNEL_GPFIFO_A:
                case AMPERE_CHANNEL_GPFIFO_A:
                case AMPERE_CHANNEL_GPFIFO_B:
+               case HOPPER_CHANNEL_GPFIFO_A:
                        ret = gv100_fence_create(drm);
                        break;
                default:
diff --git a/drivers/gpu/drm/nouveau/nvif/user.c 
b/drivers/gpu/drm/nouveau/nvif/user.c
index b648a5e036af..ae470a1fdfb8 100644
--- a/drivers/gpu/drm/nouveau/nvif/user.c
+++ b/drivers/gpu/drm/nouveau/nvif/user.c
@@ -41,6 +41,7 @@ nvif_user_ctor(struct nvif_device *device, const char *name)
                int version;
                const struct nvif_user_func *func;
        } users[] = {
+               { HOPPER_USERMODE_A, -1, &nvif_userc361 },
                { AMPERE_USERMODE_A, -1, &nvif_userc361 },
                { TURING_USERMODE_A, -1, &nvif_userc361 },
                {  VOLTA_USERMODE_A, -1, &nvif_userc361 },
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c 
b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
index ebcaf2ecff48..5082fe5f1966 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
@@ -2681,6 +2681,22 @@ nv177_chipset = {
        .sec2     = { 0x00000001, ga102_sec2_new },
 };
 
+static const struct nvkm_device_chip
+nv180_chipset = {
+       .name = "GH100",
+       .bar      = { 0x00000001, tu102_bar_new },
+       .fault    = { 0x00000001, tu102_fault_new },
+       .fb       = { 0x00000001, gh100_fb_new },
+       .fsp      = { 0x00000001, gh100_fsp_new },
+       .gsp      = { 0x00000001, gh100_gsp_new },
+       .imem     = { 0x00000001, gh100_instmem_new },
+       .mmu      = { 0x00000001, gh100_mmu_new },
+       .pci      = { 0x00000001, gh100_pci_new },
+       .timer    = { 0x00000001, gk20a_timer_new },
+       .vfn      = { 0x00000001, ga100_vfn_new },
+       .fifo     = { 0x00000001, ga102_fifo_new },
+};
+
 static const struct nvkm_device_chip
 nv192_chipset = {
        .name = "AD102",
@@ -3101,6 +3117,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
                case 0x140: device->card_type = GV100; break;
                case 0x160: device->card_type = TU100; break;
                case 0x170: device->card_type = GA100; break;
+               case 0x180: device->card_type = GH100; break;
                case 0x190: device->card_type = AD100; break;
                default:
                        break;
@@ -3204,6 +3221,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
        case 0x174: device->chip = &nv174_chipset; break;
        case 0x176: device->chip = &nv176_chipset; break;
        case 0x177: device->chip = &nv177_chipset; break;
+       case 0x180: device->chip = &nv180_chipset; break;
        case 0x192: device->chip = &nv192_chipset; break;
        case 0x193: device->chip = &nv193_chipset; break;
        case 0x194: device->chip = &nv194_chipset; break;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h 
b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h
index 8da5e896dd74..75ee7506d443 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h
@@ -11,6 +11,7 @@
 #include <subdev/devinit.h>
 #include <subdev/fault.h>
 #include <subdev/fb.h>
+#include <subdev/fsp.h>
 #include <subdev/fuse.h>
 #include <subdev/gpio.h>
 #include <subdev/gsp.h>
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c 
b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
index 1f331ec8d747..57c2678022b5 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
@@ -148,6 +148,7 @@ nvkm_udevice_info(struct nvkm_udevice *udev, void *data, 
u32 size)
        case TU100: args->v0.family = NV_DEVICE_INFO_V0_TURING; break;
        case GA100: args->v0.family = NV_DEVICE_INFO_V0_AMPERE; break;
        case AD100: args->v0.family = NV_DEVICE_INFO_V0_ADA; break;
+       case GH100: args->v0.family = NV_DEVICE_INFO_V0_HOPPER; break;
        default:
                args->v0.family = 0;
                break;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild 
b/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild
index 4c2f6fc4ef58..c19ea4ea9bd3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild
@@ -9,6 +9,7 @@ include $(src)/nvkm/subdev/fault/Kbuild
 include $(src)/nvkm/subdev/fb/Kbuild
 include $(src)/nvkm/subdev/fuse/Kbuild
 include $(src)/nvkm/subdev/gpio/Kbuild
+include $(src)/nvkm/subdev/fsp/Kbuild
 include $(src)/nvkm/subdev/gsp/Kbuild
 include $(src)/nvkm/subdev/i2c/Kbuild
 include $(src)/nvkm/subdev/iccsense/Kbuild
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild 
b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild
index d1611ad3bf81..f13312934131 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild
@@ -35,6 +35,7 @@ nvkm-y += nvkm/subdev/fb/gv100.o
 nvkm-y += nvkm/subdev/fb/tu102.o
 nvkm-y += nvkm/subdev/fb/ga100.o
 nvkm-y += nvkm/subdev/fb/ga102.o
+nvkm-y += nvkm/subdev/fb/gh100.o
 
 nvkm-y += nvkm/subdev/fb/r535.o
 
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c 
b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c
index 25f82b372bca..2819780050d8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c
@@ -25,7 +25,7 @@
 #include <subdev/gsp.h>
 #include <engine/nvdec.h>
 
-static u64
+u64
 ga102_fb_vidmem_size(struct nvkm_fb *fb)
 {
        return (u64)nvkm_rd32(fb->subdev.device, 0x1183a4) << 20;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gh100.c 
b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gh100.c
new file mode 100644
index 000000000000..2d8c51f882d5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gh100.c
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
+ */
+#include "priv.h"
+
+#include <nvhw/drf.h>
+#include <nvhw/ref/gh100/dev_fb.h>
+
+static void
+gh100_fb_sysmem_flush_page_init(struct nvkm_fb *fb)
+{
+       const u64 addr = fb->sysmem.flush_page_addr >> 
NV_PFB_NISO_FLUSH_SYSMEM_ADDR_SHIFT;
+       struct nvkm_device *device = fb->subdev.device;
+
+       nvkm_wr32(device, NV_PFB_FBHUB_PCIE_FLUSH_SYSMEM_ADDR_HI, 
upper_32_bits(addr));
+       nvkm_wr32(device, NV_PFB_FBHUB_PCIE_FLUSH_SYSMEM_ADDR_LO, 
lower_32_bits(addr));
+}
+
+static const struct nvkm_fb_func
+gh100_fb = {
+       .sysmem.flush_page_init = gh100_fb_sysmem_flush_page_init,
+       .vidmem.size = ga102_fb_vidmem_size,
+};
+
+int
+gh100_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, 
struct nvkm_fb **pfb)
+{
+       return r535_fb_new(&gh100_fb, device, type, inst, pfb);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h 
b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h
index 35c55dfba23d..ebe996503ab2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h
@@ -98,4 +98,6 @@ int gp102_fb_vpr_scrub(struct nvkm_fb *);
 int gv100_fb_init_page(struct nvkm_fb *);
 
 bool tu102_fb_vpr_scrub_required(struct nvkm_fb *);
+
+u64 ga102_fb_vidmem_size(struct nvkm_fb *);
 #endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fsp/Kbuild 
b/drivers/gpu/drm/nouveau/nvkm/subdev/fsp/Kbuild
new file mode 100644
index 000000000000..ff04992b181d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fsp/Kbuild
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: MIT
+#
+# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
+
+nvkm-y += nvkm/subdev/fsp/base.o
+nvkm-y += nvkm/subdev/fsp/gh100.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fsp/base.c 
b/drivers/gpu/drm/nouveau/nvkm/subdev/fsp/base.c
new file mode 100644
index 000000000000..e366a980baa9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fsp/base.c
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
+ */
+#include "priv.h"
+
+int
+nvkm_fsp_boot_gsp_fmc(struct nvkm_fsp *fsp, u64 args_addr, u32 rsvd_size, bool 
resume,
+                     u64 img_addr, const u8 *hash, const u8 *pkey, const u8 
*sig)
+{
+       return fsp->func->cot.boot_gsp_fmc(fsp, args_addr, rsvd_size, resume,
+                                          img_addr, hash, pkey, sig);
+}
+
+bool
+nvkm_fsp_verify_gsp_fmc(struct nvkm_fsp *fsp, u32 hash_size, u32 pkey_size, 
u32 sig_size)
+{
+       return hash_size == fsp->func->cot.size_hash &&
+              pkey_size == fsp->func->cot.size_pkey &&
+               sig_size == fsp->func->cot.size_sig;
+}
+
+static int
+nvkm_fsp_preinit(struct nvkm_subdev *subdev)
+{
+       struct nvkm_fsp *fsp = nvkm_fsp(subdev);
+
+       return fsp->func->wait_secure_boot(fsp);
+}
+
+static void *
+nvkm_fsp_dtor(struct nvkm_subdev *subdev)
+{
+       struct nvkm_fsp *fsp = nvkm_fsp(subdev);
+
+       nvkm_falcon_dtor(&fsp->falcon);
+       return fsp;
+}
+
+static const struct nvkm_falcon_func
+nvkm_fsp_flcn = {
+       .emem_pio = &gp102_flcn_emem_pio,
+};
+
+static const struct nvkm_subdev_func
+nvkm_fsp = {
+       .dtor = nvkm_fsp_dtor,
+       .preinit = nvkm_fsp_preinit,
+};
+
+int
+nvkm_fsp_new_(const struct nvkm_fsp_func *func,
+             struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+             struct nvkm_fsp **pfsp)
+{
+       struct nvkm_fsp *fsp;
+
+       fsp = *pfsp = kzalloc(sizeof(*fsp), GFP_KERNEL);
+       if (!fsp)
+               return -ENOMEM;
+
+       fsp->func = func;
+       nvkm_subdev_ctor(&nvkm_fsp, device, type, inst, &fsp->subdev);
+
+       return nvkm_falcon_ctor(&nvkm_fsp_flcn, &fsp->subdev, "fsp", 0x8f2000, 
&fsp->falcon);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fsp/gh100.c 
b/drivers/gpu/drm/nouveau/nvkm/subdev/fsp/gh100.c
new file mode 100644
index 000000000000..9f4285af3fed
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fsp/gh100.c
@@ -0,0 +1,275 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
+ */
+#include "priv.h"
+
+#include <nvhw/drf.h>
+#include <nvhw/ref/gh100/dev_fsp_pri.h>
+#include <nvhw/ref/gh100/dev_therm.h>
+
+#include <nvrm/nvtypes.h>
+
+#define MCTP_HEADER_VERSION          3:0
+#define MCTP_HEADER_RSVD             7:4
+
+#define MCTP_HEADER_DEID            15:8
+#define MCTP_HEADER_SEID            23:16
+
+#define MCTP_HEADER_TAG             26:24
+#define MCTP_HEADER_TO              27:27
+#define MCTP_HEADER_SEQ             29:28
+#define MCTP_HEADER_EOM             30:30
+#define MCTP_HEADER_SOM             31:31
+
+#define MCTP_MSG_HEADER_TYPE         6:0
+#define MCTP_MSG_HEADER_IC           7:7
+
+#define MCTP_MSG_HEADER_VENDOR_ID   23:8
+#define MCTP_MSG_HEADER_NVDM_TYPE   31:24
+
+#define MCTP_MSG_HEADER_TYPE_VENDOR_PCI 0x7e
+#define MCTP_MSG_HEADER_VENDOR_ID_NV    0x10de
+
+#define NVDM_TYPE_COT                   0x14
+#define NVDM_TYPE_FSP_RESPONSE          0x15
+
+#pragma pack(1)
+typedef struct nvdm_payload_cot
+{
+    NvU16 version;
+    NvU16 size;
+    NvU64 gspFmcSysmemOffset;
+    NvU64 frtsSysmemOffset;
+    NvU32 frtsSysmemSize;
+
+    // Note this is an offset from the end of FB
+    NvU64 frtsVidmemOffset;
+    NvU32 frtsVidmemSize;
+
+    // Authentication related fields
+    NvU32 hash384[12];
+    NvU32 publicKey[96];
+    NvU32 signature[96];
+
+    NvU64 gspBootArgsSysmemOffset;
+} NVDM_PAYLOAD_COT;
+#pragma pack()
+
+#pragma pack(1)
+typedef struct
+{
+    NvU32 taskId;
+    NvU32 commandNvdmType;
+    NvU32 errorCode;
+} NVDM_PAYLOAD_COMMAND_RESPONSE;
+#pragma pack()
+
+static u32
+gh100_fsp_poll(struct nvkm_fsp *fsp)
+{
+       struct nvkm_device *device = fsp->subdev.device;
+       u32 head, tail;
+
+       head = nvkm_rd32(device, NV_PFSP_MSGQ_HEAD(0));
+       tail = nvkm_rd32(device, NV_PFSP_MSGQ_TAIL(0));
+
+       if (head == tail)
+               return 0;
+
+       return (tail - head) + sizeof(u32); /* TAIL points at last DWORD 
written. */
+}
+
+static int
+gh100_fsp_recv(struct nvkm_fsp *fsp, u8 *packet, u32 max_packet_size)
+{
+       struct nvkm_device *device = fsp->subdev.device;
+       u32 packet_size;
+       int ret;
+
+       packet_size = gh100_fsp_poll(fsp);
+       if (!packet_size || WARN_ON(packet_size % 4 || packet_size > 
max_packet_size))
+               return -EINVAL;
+
+       ret = nvkm_falcon_pio_rd(&fsp->falcon, 0, EMEM, 0, packet, 0, 
packet_size);
+       if (ret)
+               return ret;
+
+       nvkm_wr32(device, NV_PFSP_MSGQ_TAIL(0), 0);
+       nvkm_wr32(device, NV_PFSP_MSGQ_HEAD(0), 0);
+
+       return packet_size;
+}
+
+static int
+gh100_fsp_wait(struct nvkm_fsp *fsp)
+{
+       int time = 1000;
+
+       do {
+               if (gh100_fsp_poll(fsp))
+                       return 0;
+
+               usleep_range(1000, 2000);
+       } while(time--);
+
+       return -ETIMEDOUT;
+}
+
+static int
+gh100_fsp_send(struct nvkm_fsp *fsp, const u8 *packet, u32 packet_size)
+{
+       struct nvkm_device *device = fsp->subdev.device;
+       int time = 1000, ret;
+
+       if (WARN_ON(packet_size % sizeof(u32)))
+               return -EINVAL;
+
+       /* Ensure any previously sent message has been consumed. */
+       do {
+               u32 head = nvkm_rd32(device, NV_PFSP_QUEUE_HEAD(0));
+               u32 tail = nvkm_rd32(device, NV_PFSP_QUEUE_TAIL(0));
+
+               if (tail == head)
+                       break;
+
+               usleep_range(1000, 2000);
+       } while(time--);
+
+       if (time < 0)
+               return -ETIMEDOUT;
+
+       /* Write message to EMEM. */
+       ret = nvkm_falcon_pio_wr(&fsp->falcon, packet, 0, 0, EMEM, 0, 
packet_size, 0, false);
+       if (ret)
+               return ret;
+
+       /* Update queue pointers - TAIL points at last DWORD written. */
+       nvkm_wr32(device, NV_PFSP_QUEUE_TAIL(0), packet_size - sizeof(u32));
+       nvkm_wr32(device, NV_PFSP_QUEUE_HEAD(0), 0);
+       return 0;
+}
+
+static int
+gh100_fsp_send_sync(struct nvkm_fsp *fsp, u8 nvdm_type, const u8 *packet, u32 
packet_size)
+{
+       struct nvkm_subdev *subdev = &fsp->subdev;
+       struct {
+               u32 mctp_header;
+               u32 nvdm_header;
+               NVDM_PAYLOAD_COMMAND_RESPONSE response;
+       } reply;
+       int ret;
+
+       ret = gh100_fsp_send(fsp, packet, packet_size);
+       if (ret)
+               return ret;
+
+       ret = gh100_fsp_wait(fsp);
+       if (ret)
+               return ret;
+
+       ret = gh100_fsp_recv(fsp, (u8 *)&reply, sizeof(reply));
+       if (ret < 0)
+               return ret;
+
+       if (NVVAL_TEST(reply.mctp_header, MCTP, HEADER, SOM, !=, 1) ||
+           NVVAL_TEST(reply.mctp_header, MCTP, HEADER, EOM, !=, 1)) {
+               nvkm_error(subdev, "unexpected MCTP header in reply: 0x%08x\n", 
reply.mctp_header);
+               return -EIO;
+       }
+
+       if (NVDEF_TEST(reply.nvdm_header, MCTP, MSG_HEADER, TYPE, !=, 
VENDOR_PCI) ||
+           NVDEF_TEST(reply.nvdm_header, MCTP, MSG_HEADER, VENDOR_ID, !=, NV) 
||
+           NVVAL_TEST(reply.nvdm_header, MCTP, MSG_HEADER, NVDM_TYPE, !=, 
NVDM_TYPE_FSP_RESPONSE)) {
+               nvkm_error(subdev, "unexpected NVDM header in reply: 0x%08x\n", 
reply.nvdm_header);
+               return -EIO;
+       }
+
+       if (reply.response.commandNvdmType != nvdm_type) {
+               nvkm_error(subdev, "expected NVDM type 0x%02x in reply, got 
0x%02x\n",
+                          nvdm_type, reply.response.commandNvdmType);
+               return -EIO;
+       }
+
+       if (reply.response.errorCode) {
+               nvkm_error(subdev, "NVDM command 0x%02x failed with error 
0x%08x\n",
+                          nvdm_type, reply.response.errorCode);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+int
+gh100_fsp_boot_gsp_fmc(struct nvkm_fsp *fsp, u64 args_addr, u32 rsvd_size, 
bool resume,
+                      u64 img_addr, const u8 *hash, const u8 *pkey, const u8 
*sig)
+{
+       struct {
+               u32 mctp_header;
+               u32 nvdm_header;
+               NVDM_PAYLOAD_COT cot;
+       } msg = {};
+
+       msg.mctp_header = NVVAL(MCTP, HEADER, SOM, 1) |
+                         NVVAL(MCTP, HEADER, EOM, 1) |
+                         NVVAL(MCTP, HEADER, SEID, 0) |
+                         NVVAL(MCTP, HEADER, SEQ, 0);
+
+       msg.nvdm_header = NVDEF(MCTP, MSG_HEADER, TYPE, VENDOR_PCI) |
+                         NVDEF(MCTP, MSG_HEADER, VENDOR_ID, NV) |
+                         NVVAL(MCTP, MSG_HEADER, NVDM_TYPE, NVDM_TYPE_COT);
+
+       msg.cot.version = fsp->func->cot.version;
+       msg.cot.size = sizeof(msg.cot);
+       msg.cot.gspFmcSysmemOffset = img_addr;
+       if (!resume) {
+               msg.cot.frtsVidmemOffset = ALIGN(rsvd_size, 0x200000);
+               msg.cot.frtsVidmemSize = 0x100000;
+       }
+
+       memcpy(msg.cot.hash384, hash, fsp->func->cot.size_hash);
+       memcpy(msg.cot.publicKey, pkey, fsp->func->cot.size_pkey);
+       memcpy(msg.cot.signature, sig, fsp->func->cot.size_sig);
+
+       msg.cot.gspBootArgsSysmemOffset = args_addr;
+
+       return gh100_fsp_send_sync(fsp, NVDM_TYPE_COT, (const u8 *)&msg, 
sizeof(msg));
+}
+
+static int
+gh100_fsp_wait_secure_boot(struct nvkm_fsp *fsp)
+{
+       struct nvkm_device *device = fsp->subdev.device;
+       unsigned timeout_ms = 4000;
+
+       do {
+               u32 status = NVKM_RD32(device, NV_THERM, I2CS_SCRATCH, 
FSP_BOOT_COMPLETE_STATUS);
+
+               if (status == 
NV_THERM_I2CS_SCRATCH_FSP_BOOT_COMPLETE_STATUS_SUCCESS)
+                       return 0;
+
+               usleep_range(1000, 2000);
+       } while (timeout_ms--);
+
+       return -ETIMEDOUT;
+}
+
+static const struct nvkm_fsp_func
+gh100_fsp = {
+       .wait_secure_boot = gh100_fsp_wait_secure_boot,
+       .cot = {
+               .version = 1,
+               .size_hash = 48,
+               .size_pkey = 384,
+               .size_sig = 384,
+               .boot_gsp_fmc = gh100_fsp_boot_gsp_fmc,
+       },
+};
+
+int
+gh100_fsp_new(struct nvkm_device *device,
+             enum nvkm_subdev_type type, int inst, struct nvkm_fsp **pfsp)
+{
+       return nvkm_fsp_new_(&gh100_fsp, device, type, inst, pfsp);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fsp/priv.h 
b/drivers/gpu/drm/nouveau/nvkm/subdev/fsp/priv.h
new file mode 100644
index 000000000000..91517f3dedfb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fsp/priv.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
+ */
+#ifndef __NVKM_FSP_PRIV_H__
+#define __NVKM_FSP_PRIV_H__
+#define nvkm_fsp(p) container_of((p), struct nvkm_fsp, subdev)
+#include <subdev/fsp.h>
+
+struct nvkm_fsp_func {
+       int (*wait_secure_boot)(struct nvkm_fsp *);
+
+       struct {
+               u32 version;
+               u32 size_hash;
+               u32 size_pkey;
+               u32 size_sig;
+               int (*boot_gsp_fmc)(struct nvkm_fsp *, u64 args_addr, u32 
rsvd_size, bool resume,
+                                   u64 img_addr, const u8 *hash, const u8 
*pkey, const u8 *sig);
+       } cot;
+};
+
+int nvkm_fsp_new_(const struct nvkm_fsp_func *,
+                 struct nvkm_device *, enum nvkm_subdev_type, int inst, struct 
nvkm_fsp **);
+
+int gh100_fsp_boot_gsp_fmc(struct nvkm_fsp *, u64 args_addr, u32 rsvd_size, 
bool resume,
+                          u64 img_addr, const u8 *hash, const u8 *pkey, const 
u8 *sig);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild 
b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild
index ba892c111c26..3c6c1309c4b4 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild
@@ -7,6 +7,7 @@ nvkm-y += nvkm/subdev/gsp/tu102.o
 nvkm-y += nvkm/subdev/gsp/tu116.o
 nvkm-y += nvkm/subdev/gsp/ga100.o
 nvkm-y += nvkm/subdev/gsp/ga102.o
+nvkm-y += nvkm/subdev/gsp/gh100.o
 nvkm-y += nvkm/subdev/gsp/ad102.o
 
 include $(src)/nvkm/subdev/gsp/rm/Kbuild
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c 
b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c
index 3a452349afde..d23243a83a4c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c
@@ -83,6 +83,8 @@ nvkm_gsp_oneinit(struct nvkm_subdev *subdev)
 void
 nvkm_gsp_dtor_fws(struct nvkm_gsp *gsp)
 {
+       nvkm_firmware_put(gsp->fws.fmc);
+       gsp->fws.fmc = NULL;
        nvkm_firmware_put(gsp->fws.bl);
        gsp->fws.bl = NULL;
        nvkm_firmware_put(gsp->fws.booter.unload);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/gh100.c 
b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/gh100.c
new file mode 100644
index 000000000000..3ad71696c111
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/gh100.c
@@ -0,0 +1,353 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
+ */
+#include "priv.h"
+
+#include <linux/elf.h>
+#include <linux/crc32.h>
+
+#include <subdev/fb.h>
+#include <subdev/fsp.h>
+
+#include <rm/r570/nvrm/gsp.h>
+
+#include <nvhw/drf.h>
+#include <nvhw/ref/gh100/dev_falcon_v4.h>
+#include <nvhw/ref/gh100/dev_riscv_pri.h>
+
+static int
+gh100_gsp_fini(struct nvkm_gsp *gsp, bool suspend)
+{
+       struct nvkm_falcon *falcon = &gsp->falcon;
+       int ret, time = 4000;
+
+       /* Shutdown RM. */
+       ret = r535_gsp_fini(gsp, suspend);
+       if (ret && suspend)
+               return ret;
+
+       /* Wait for RISC-V to halt. */
+       do {
+               u32 data = nvkm_falcon_rd32(falcon, falcon->addr2 + 
NV_PRISCV_RISCV_CPUCTL);
+
+               if (NVVAL_GET(data, NV_PRISCV, RISCV_CPUCTL, HALTED))
+                       return 0;
+
+               usleep_range(1000, 2000);
+       } while(time--);
+
+       return -ETIMEDOUT;
+}
+
+static bool
+gh100_gsp_lockdown_released(struct nvkm_gsp *gsp, u32 *mbox0)
+{
+       u32 data;
+
+       /* Wait for GSP access via BAR0 to be allowed. */
+       *mbox0 = nvkm_falcon_rd32(&gsp->falcon, NV_PFALCON_FALCON_MAILBOX0);
+
+       if (*mbox0 && (*mbox0 & 0xffffff00) == 0xbadf4100)
+               return false;
+
+       /* Check if an error code has been reported. */
+       if (*mbox0) {
+               u32 mbox1 = nvkm_falcon_rd32(&gsp->falcon, 
NV_PFALCON_FALCON_MAILBOX1);
+
+               /* Any value that's not GSP_FMC_BOOT_PARAMS addr is an error. */
+               if ((((u64)mbox1 << 32) | *mbox0) != gsp->fmc.args.addr)
+                       return true;
+       }
+
+       /* Check if lockdown has been released. */
+       data = nvkm_falcon_rd32(&gsp->falcon, NV_PFALCON_FALCON_HWCFG2);
+       return !NVVAL_GET(data, NV_PFALCON, FALCON_HWCFG2, 
RISCV_BR_PRIV_LOCKDOWN);
+}
+
+static int
+gh100_gsp_init(struct nvkm_gsp *gsp)
+{
+       struct nvkm_subdev *subdev = &gsp->subdev;
+       struct nvkm_device *device = subdev->device;
+       const bool resume = gsp->sr.meta.data != NULL;
+       struct nvkm_gsp_mem *meta;
+       GSP_FMC_BOOT_PARAMS *args;
+       int ret, time = 4000;
+       u32 mbox0;
+
+       if (!resume) {
+               ret = nvkm_gsp_mem_ctor(gsp, sizeof(*args), &gsp->fmc.args);
+               if (ret)
+                       return ret;
+
+               meta = &gsp->wpr_meta;
+       } else {
+               gsp->rm->api->gsp->set_rmargs(gsp, true);
+               meta = &gsp->sr.meta;
+       }
+
+       args = gsp->fmc.args.data;
+
+       args->bootGspRmParams.gspRmDescOffset = meta->addr;
+       args->bootGspRmParams.gspRmDescSize = meta->size;
+       args->bootGspRmParams.target = GSP_DMA_TARGET_COHERENT_SYSTEM;
+       args->bootGspRmParams.bIsGspRmBoot = 1;
+
+       args->gspRmParams.target = GSP_DMA_TARGET_NONCOHERENT_SYSTEM;
+       args->gspRmParams.bootArgsOffset = gsp->libos.addr;
+
+       ret = nvkm_fsp_boot_gsp_fmc(device->fsp, gsp->fmc.args.addr, 
gsp->fb.heap.size, resume,
+                                   gsp->fmc.fw.addr, gsp->fmc.hash, 
gsp->fmc.pkey, gsp->fmc.sig);
+       if (ret)
+               return ret;
+
+       do {
+               if (gh100_gsp_lockdown_released(gsp, &mbox0))
+                       break;
+
+               usleep_range(1000, 2000);
+       } while(time--);
+
+       if (time < 0) {
+               nvkm_error(subdev, "GSP-FMC boot timed out\n");
+               return -ETIMEDOUT;
+       }
+
+       if (mbox0) {
+               nvkm_error(subdev, "GSP-FMC boot failed (mbox: 0x%08x)\n", 
mbox0);
+               return -EIO;
+       }
+
+       return r535_gsp_init(gsp);
+}
+
+static int
+gh100_gsp_wpr_meta_init(struct nvkm_gsp *gsp)
+{
+       GspFwWprMeta *meta;
+       int ret;
+
+       ret = nvkm_gsp_mem_ctor(gsp, sizeof(*meta), &gsp->wpr_meta);
+       if (ret)
+               return ret;
+
+       gsp->fb.size = nvkm_fb_vidmem_size(gsp->subdev.device);
+       gsp->fb.bios.vga_workspace.size = 128 * 1024;
+       gsp->fb.heap.size = gsp->rm->wpr->heap_size_non_wpr;
+
+       meta = gsp->wpr_meta.data;
+
+       meta->magic = GSP_FW_WPR_META_MAGIC;
+       meta->revision = GSP_FW_WPR_META_REVISION;
+
+       meta->sizeOfRadix3Elf = gsp->fw.len;
+       meta->sysmemAddrOfRadix3Elf = gsp->radix3.lvl0.addr;
+
+       meta->sizeOfBootloader = gsp->boot.fw.size;
+       meta->sysmemAddrOfBootloader = gsp->boot.fw.addr;
+       meta->bootloaderCodeOffset = gsp->boot.code_offset;
+       meta->bootloaderDataOffset = gsp->boot.data_offset;
+       meta->bootloaderManifestOffset = gsp->boot.manifest_offset;
+
+       meta->sysmemAddrOfSignature = gsp->sig.addr;
+       meta->sizeOfSignature = gsp->sig.size;
+
+       meta->nonWprHeapSize = gsp->fb.heap.size;
+       meta->gspFwHeapSize = tu102_gsp_wpr_heap_size(gsp);
+       meta->frtsSize = 0x100000;
+       meta->vgaWorkspaceSize = gsp->fb.bios.vga_workspace.size;
+       meta->pmuReservedSize = 0;
+       return 0;
+}
+
+/* The sh_flags value for the binary blobs in the ELF image */
+#define FMC_SHF_FLAGS (SHF_MASKPROC | SHF_MASKOS | SHF_OS_NONCONFORMING | 
SHF_ALLOC)
+
+#define ELF_HDR_SIZE ((u8)sizeof(struct elf32_hdr))
+#define ELF_SHDR_SIZE ((u8)sizeof(struct elf32_shdr))
+
+/* The FMC ELF header must be exactly this */
+static const u8 elf_header[] = {
+       0x7f, 'E', 'L', 'F', 1, 1, 1, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+
+       0, 0, 0, 0, 1, 0, 0, 0, /* e_type, e_machine, e_version */
+       0, 0, 0, 0, 0, 0, 0, 0, /* e_entry, e_phoff */
+
+       ELF_HDR_SIZE, 0, 0, 0, 0, 0, 0, 0, /* e_shoff, e_flags */
+       ELF_HDR_SIZE, 0, 0, 0, /* e_ehsize, e_phentsize */
+       0, 0, ELF_SHDR_SIZE, 0, /* e_phnum, e_shentsize */
+
+       6, 0, 1, 0, /* e_shnum, e_shstrndx */
+};
+
+/**
+ * elf_validate_sections - validate each section in the FMC ELF image
+ * @elf: ELF image
+ * @length: size of the entire ELF image
+ */
+static bool
+elf_validate_sections(const void *elf, size_t length)
+{
+       const struct elf32_hdr *ehdr = elf;
+       const struct elf32_shdr *shdr = elf + ehdr->e_shoff;
+
+       /* The offset of the first section */
+       Elf32_Off section_begin = ehdr->e_shoff + ehdr->e_shnum * 
ehdr->e_shentsize;
+
+       if (section_begin > length)
+               return false;
+
+       /* The first section header is the null section, so skip it */
+       for (unsigned int i = 1; i < ehdr->e_shnum; i++) {
+               if (i == ehdr->e_shstrndx) {
+                       if (shdr[i].sh_type != SHT_STRTAB)
+                               return false;
+                       if (shdr[i].sh_flags != SHF_STRINGS)
+                               return false;
+               } else {
+                       if (shdr[i].sh_type != SHT_PROGBITS)
+                               return false;
+                       if (shdr[i].sh_flags != FMC_SHF_FLAGS)
+                               return false;
+               }
+
+               /* Ensure that each section is inside the image */
+               if (shdr[i].sh_offset < section_begin ||
+                   (u64)shdr[i].sh_offset + shdr[i].sh_size > length)
+                       return false;
+
+               /* Non-zero sh_info is a CRC */
+               if (shdr[i].sh_info) {
+                       /* The kernel's CRC32 needs a pre- and post-xor to 
match standard CRCs */
+                       u32 crc32 = crc32_le(~0, elf + shdr[i].sh_offset, 
shdr[i].sh_size) ^ ~0;
+
+                       if (shdr[i].sh_info != crc32)
+                               return false;
+               }
+       }
+
+       return true;
+}
+
+/**
+ * elf_section - return a pointer to the data for a given section
+ * @elf: ELF image
+ * @name: section name to search for
+ * @len: pointer to returned length of found section
+ */
+static const void *
+elf_section(const void *elf, const char *name, unsigned int *len)
+{
+       const struct elf32_hdr *ehdr = elf;
+       const struct elf32_shdr *shdr = elf + ehdr->e_shoff;
+       const char *names = elf + shdr[ehdr->e_shstrndx].sh_offset;
+
+       for (unsigned int i = 1; i < ehdr->e_shnum; i++) {
+               if (!strcmp(&names[shdr[i].sh_name], name)) {
+                       *len = shdr[i].sh_size;
+                       return elf + shdr[i].sh_offset;
+               }
+       }
+
+       return NULL;
+}
+
+static int
+gh100_gsp_oneinit(struct nvkm_gsp *gsp)
+{
+       struct nvkm_subdev *subdev = &gsp->subdev;
+       struct nvkm_device *device = subdev->device;
+       struct nvkm_fsp *fsp = device->fsp;
+       const void *fw = gsp->fws.fmc->data;
+       const void *hash, *sig, *pkey, *img;
+       unsigned int img_len = 0, hash_len = 0, pkey_len = 0, sig_len = 0;
+       int ret;
+
+       if (gsp->fws.fmc->size < ELF_HDR_SIZE ||
+           memcmp(fw, elf_header, sizeof(elf_header)) ||
+           !elf_validate_sections(fw, gsp->fws.fmc->size)) {
+               nvkm_error(subdev, "fmc firmware image is invalid\n");
+               return -ENODATA;
+       }
+
+       hash = elf_section(fw, "hash", &hash_len);
+       sig = elf_section(fw, "signature", &sig_len);
+       pkey = elf_section(fw, "publickey", &pkey_len);
+       img = elf_section(fw, "image", &img_len);
+
+       if (!hash || !sig || !pkey || !img) {
+               nvkm_error(subdev, "fmc firmware image is invalid\n");
+               return -ENODATA;
+       }
+
+       if (!nvkm_fsp_verify_gsp_fmc(fsp, hash_len, pkey_len, sig_len))
+               return -EINVAL;
+
+       /* Load GSP-FMC FW into memory. */
+       ret = nvkm_gsp_mem_ctor(gsp, img_len, &gsp->fmc.fw);
+       if (ret)
+               return ret;
+
+       memcpy(gsp->fmc.fw.data, img, img_len);
+
+       gsp->fmc.hash = kmemdup(hash, hash_len, GFP_KERNEL);
+       gsp->fmc.pkey = kmemdup(pkey, pkey_len, GFP_KERNEL);
+       gsp->fmc.sig = kmemdup(sig, sig_len, GFP_KERNEL);
+       if (!gsp->fmc.hash || !gsp->fmc.pkey || !gsp->fmc.sig)
+               return -ENOMEM;
+
+       ret = r535_gsp_oneinit(gsp);
+       if (ret)
+               return ret;
+
+       return gh100_gsp_wpr_meta_init(gsp);
+}
+
+static const struct nvkm_gsp_func
+gh100_gsp = {
+       .flcn = &ga102_gsp_flcn,
+
+       .sig_section = ".fwsignature_gh100",
+
+       .dtor = r535_gsp_dtor,
+       .oneinit = gh100_gsp_oneinit,
+       .init = gh100_gsp_init,
+       .fini = gh100_gsp_fini,
+
+       .rm.gpu = &gh100_gpu,
+};
+
+static int
+gh100_gsp_load(struct nvkm_gsp *gsp, int ver, const struct nvkm_gsp_fwif *fwif)
+{
+       int ret;
+
+       ret = tu102_gsp_load_rm(gsp, fwif);
+       if (ret)
+               goto done;
+
+       ret = nvkm_gsp_load_fw(gsp, "fmc", fwif->ver, &gsp->fws.fmc);
+
+done:
+       if (ret)
+               nvkm_gsp_dtor_fws(gsp);
+
+       return ret;
+}
+
+static struct nvkm_gsp_fwif
+gh100_gsps[] = {
+       { 0, gh100_gsp_load, &gh100_gsp, &r570_rm_gh100, "570.144", true },
+       {}
+};
+
+int
+gh100_gsp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+             struct nvkm_gsp **pgsp)
+{
+       return nvkm_gsp_new_(gh100_gsps, device, type, inst, pgsp);
+}
+
+NVKM_GSP_FIRMWARE_FMC(gh100, 570.144);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h 
b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h
index c8429863b642..86ec580ba936 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h
@@ -22,7 +22,9 @@ int nvkm_gsp_load_fw(struct nvkm_gsp *, const char *name, 
const char *ver,
 void nvkm_gsp_dtor_fws(struct nvkm_gsp *);
 
 int gv100_gsp_nofw(struct nvkm_gsp *, int, const struct nvkm_gsp_fwif *);
+
 int tu102_gsp_load(struct nvkm_gsp *, int, const struct nvkm_gsp_fwif *);
+int tu102_gsp_load_rm(struct nvkm_gsp *, const struct nvkm_gsp_fwif *);
 
 #define NVKM_GSP_FIRMWARE_BOOTER(chip,vers)                      \
 MODULE_FIRMWARE("nvidia/"#chip"/gsp/booter_load-"#vers".bin");   \
@@ -30,6 +32,11 @@ 
MODULE_FIRMWARE("nvidia/"#chip"/gsp/booter_unload-"#vers".bin"); \
 MODULE_FIRMWARE("nvidia/"#chip"/gsp/bootloader-"#vers".bin");    \
 MODULE_FIRMWARE("nvidia/"#chip"/gsp/gsp-"#vers".bin")
 
+#define NVKM_GSP_FIRMWARE_FMC(chip,vers)                      \
+MODULE_FIRMWARE("nvidia/"#chip"/gsp/fmc-"#vers".bin");        \
+MODULE_FIRMWARE("nvidia/"#chip"/gsp/bootloader-"#vers".bin"); \
+MODULE_FIRMWARE("nvidia/"#chip"/gsp/gsp-"#vers".bin")
+
 struct nvkm_gsp_func {
        const struct nvkm_falcon_func *flcn;
        const struct nvkm_falcon_fw_func *fwsec;
@@ -60,6 +67,7 @@ int tu102_gsp_oneinit(struct nvkm_gsp *);
 int tu102_gsp_init(struct nvkm_gsp *);
 int tu102_gsp_fini(struct nvkm_gsp *, bool suspend);
 int tu102_gsp_reset(struct nvkm_gsp *);
+u64 tu102_gsp_wpr_heap_size(struct nvkm_gsp *);
 
 extern const struct nvkm_falcon_func ga102_gsp_flcn;
 extern const struct nvkm_falcon_fw_func ga102_gsp_fwsec;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/Kbuild 
b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/Kbuild
index d3f4e60bb131..2a71868d6710 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/Kbuild
@@ -11,6 +11,7 @@ nvkm-y += nvkm/subdev/gsp/rm/tu1xx.o
 nvkm-y += nvkm/subdev/gsp/rm/ga100.o
 nvkm-y += nvkm/subdev/gsp/rm/ga1xx.o
 nvkm-y += nvkm/subdev/gsp/rm/ad10x.o
+nvkm-y += nvkm/subdev/gsp/rm/gh100.o
 
 include $(src)/nvkm/subdev/gsp/rm/r535/Kbuild
 include $(src)/nvkm/subdev/gsp/rm/r570/Kbuild
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/gh100.c 
b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/gh100.c
new file mode 100644
index 000000000000..088250559e12
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/gh100.c
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
+ */
+#include "gpu.h"
+
+#include <nvif/class.h>
+
+const struct nvkm_rm_gpu
+gh100_gpu = {
+       .usermode.class = HOPPER_USERMODE_A,
+
+       .fifo.chan = {
+               .class = HOPPER_CHANNEL_GPFIFO_A,
+       },
+
+       .ce.class = HOPPER_DMA_COPY_A,
+       .gr.class = {
+               .i2m = KEPLER_INLINE_TO_MEMORY_B,
+               .twod = FERMI_TWOD_A,
+               .threed = HOPPER_A,
+               .compute = HOPPER_COMPUTE_A,
+       },
+       .nvdec.class = NVB8B0_VIDEO_DECODER,
+       .nvjpg.class = NVB8D1_VIDEO_NVJPG,
+       .ofa.class = NVB8FA_VIDEO_OFA,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/gpu.h 
b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/gpu.h
index a256be42ab6e..443753f3369a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/gpu.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/gpu.h
@@ -62,4 +62,5 @@ extern const struct nvkm_rm_gpu tu1xx_gpu;
 extern const struct nvkm_rm_gpu ga100_gpu;
 extern const struct nvkm_rm_gpu ga1xx_gpu;
 extern const struct nvkm_rm_gpu ad10x_gpu;
+extern const struct nvkm_rm_gpu gh100_gpu;
 #endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c 
b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c
index fe00425c5479..baf42339f93e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c
@@ -2073,6 +2073,12 @@ r535_gsp_dtor(struct nvkm_gsp *gsp)
        nvkm_falcon_fw_dtor(&gsp->booter.unload);
        nvkm_falcon_fw_dtor(&gsp->booter.load);
 
+       nvkm_gsp_mem_dtor(&gsp->fmc.args);
+       kfree(gsp->fmc.sig);
+       kfree(gsp->fmc.pkey);
+       kfree(gsp->fmc.hash);
+       nvkm_gsp_mem_dtor(&gsp->fmc.fw);
+
        mutex_destroy(&gsp->msgq.mutex);
        mutex_destroy(&gsp->cmdq.mutex);
 
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/gsp.c 
b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/gsp.c
index 730dcb645cca..9d2fa4e66d59 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/gsp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/gsp.c
@@ -26,8 +26,10 @@ r570_gsp_sr_data_size(struct nvkm_gsp *gsp)
 static void
 r570_gsp_drop_post_nocat_record(struct nvkm_gsp *gsp)
 {
-       if (gsp->subdev.debug < NV_DBG_DEBUG)
+       if (gsp->subdev.debug < NV_DBG_DEBUG) {
                r535_gsp_msg_ntfy_add(gsp, 
NV_VGPU_MSG_EVENT_GSP_POST_NOCAT_RECORD, NULL, NULL);
+               r535_gsp_msg_ntfy_add(gsp, 
NV_VGPU_MSG_EVENT_GSP_LOCKDOWN_NOTICE, NULL, NULL);
+       }
 }
 
 static bool
@@ -102,6 +104,13 @@ r570_gsp_get_static_info(struct nvkm_gsp *gsp)
 
        r535_gsp_get_static_info_fb(gsp, &rpc->fbRegionInfoParams);
 
+       if (gsp->rm->wpr->offset_set_by_acr) {
+               GspFwWprMeta *meta = gsp->wpr_meta.data;
+
+               meta->nonWprHeapOffset = 
rpc->fwWprLayoutOffset.nonWprHeapOffset;
+               meta->frtsOffset = rpc->fwWprLayoutOffset.frtsOffset;
+       }
+
        nvkm_gsp_rpc_done(gsp, rpc);
 
        ret = r570_gr_gpc_mask(gsp, &gpc_mask);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/nvrm/gsp.h 
b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/nvrm/gsp.h
index 4685a898fac6..b6075021e74f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/nvrm/gsp.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/nvrm/gsp.h
@@ -573,4 +573,62 @@ typedef struct
                                     (88u + 
(BULLSEYE_ROOT_HEAP_ALLOC_RM_DATA_SECTION_SIZE_DELTA) + \
                                     
(BULLSEYE_ROOT_HEAP_ALLOC_BAREMETAL_LIBOS_HEAP_SIZE_DELTA))
 
+typedef struct GSP_FMC_INIT_PARAMS
+{
+    // CC initialization "registry keys"
+    NvU32 regkeys;
+} GSP_FMC_INIT_PARAMS;
+
+typedef enum {
+    GSP_DMA_TARGET_LOCAL_FB,
+    GSP_DMA_TARGET_COHERENT_SYSTEM,
+    GSP_DMA_TARGET_NONCOHERENT_SYSTEM,
+    GSP_DMA_TARGET_COUNT
+} GSP_DMA_TARGET;
+
+typedef struct GSP_ACR_BOOT_GSP_RM_PARAMS
+{
+    // Physical memory aperture through which gspRmDescPa is accessed
+    GSP_DMA_TARGET target;
+    // Size in bytes of the GSP-RM descriptor structure
+    NvU32          gspRmDescSize;
+    // Physical offset in the target aperture of the GSP-RM descriptor 
structure
+    NvU64          gspRmDescOffset;
+    // Physical offset in FB to set the start of the WPR containing GSP-RM
+    NvU64          wprCarveoutOffset;
+    // Size in bytes of the WPR containing GSP-RM
+    NvU32          wprCarveoutSize;
+    // Whether to boot GSP-RM or GSP-Proxy through ACR
+    NvBool         bIsGspRmBoot;
+} GSP_ACR_BOOT_GSP_RM_PARAMS;
+
+typedef struct GSP_RM_PARAMS
+{
+    // Physical memory aperture through which bootArgsOffset is accessed
+    GSP_DMA_TARGET target;
+    // Physical offset in the memory aperture that will be passed to GSP-RM
+    NvU64          bootArgsOffset;
+} GSP_RM_PARAMS;
+
+typedef struct GSP_SPDM_PARAMS
+{
+    // Physical Memory Aperture through which all addresses are accessed
+    GSP_DMA_TARGET target;
+
+    // Physical offset in the memory aperture where SPDM payload is stored
+    NvU64 payloadBufferOffset;
+
+    // Size of the above payload buffer
+    NvU32 payloadBufferSize;
+} GSP_SPDM_PARAMS;
+
+typedef struct GSP_FMC_BOOT_PARAMS
+{
+    GSP_FMC_INIT_PARAMS         initParams;
+    GSP_ACR_BOOT_GSP_RM_PARAMS  bootGspRmParams;
+    GSP_RM_PARAMS               gspRmParams;
+    GSP_SPDM_PARAMS             gspSpdmParams;
+} GSP_FMC_BOOT_PARAMS;
+
+#define GSP_FW_HEAP_PARAM_BASE_RM_SIZE_GH100              (14 << 20)   // 
Hopper+
 #endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/rm.c 
b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/rm.c
index ad80d8a3d6d3..8a641e5a5b92 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/rm.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/rm.c
@@ -20,6 +20,15 @@ r570_wpr_libos3 = {
        .heap_size_min = GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MIN_MB,
 };
 
+static const struct nvkm_rm_wpr
+r570_wpr_libos3_gh100 = {
+       .os_carveout_size = GSP_FW_HEAP_PARAM_OS_SIZE_LIBOS3_BAREMETAL,
+       .base_size = GSP_FW_HEAP_PARAM_BASE_RM_SIZE_GH100,
+       .heap_size_min = GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MIN_MB,
+       .heap_size_non_wpr = 0x200000,
+       .offset_set_by_acr = true,
+};
+
 static const struct nvkm_rm_api
 r570_api = {
        .gsp = &r570_gsp,
@@ -50,3 +59,9 @@ r570_rm_ga102 = {
        .wpr = &r570_wpr_libos3,
        .api = &r570_api,
 };
+
+const struct nvkm_rm_impl
+r570_rm_gh100 = {
+       .wpr = &r570_wpr_libos3_gh100,
+       .api = &r570_api,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rm.h 
b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rm.h
index ead48c106bb6..626ebce39be5 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rm.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rm.h
@@ -25,6 +25,8 @@ struct nvkm_rm_wpr {
        u32 os_carveout_size;
        u32 base_size;
        u64 heap_size_min;
+       u32 heap_size_non_wpr;
+       bool offset_set_by_acr;
 };
 
 struct nvkm_rm_api {
@@ -173,6 +175,7 @@ extern const struct nvkm_rm_api_engine r535_ofa;
 
 extern const struct nvkm_rm_impl r570_rm_tu102;
 extern const struct nvkm_rm_impl r570_rm_ga102;
+extern const struct nvkm_rm_impl r570_rm_gh100;
 extern const struct nvkm_rm_api_gsp r570_gsp;
 extern const struct nvkm_rm_api_client r570_client;
 extern const struct nvkm_rm_api_fbsr r570_fbsr;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu102.c 
b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu102.c
index 97c02aa93d55..58e233bc53b1 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu102.c
@@ -246,7 +246,7 @@ tu102_gsp_wpr_meta_init(struct nvkm_gsp *gsp)
        return 0;
 }
 
-static u64
+u64
 tu102_gsp_wpr_heap_size(struct nvkm_gsp *gsp)
 {
        u32 fb_size_gb = DIV_ROUND_UP_ULL(gsp->fb.size, 1 << 30);
@@ -379,7 +379,7 @@ tu102_gsp = {
        .rm.gpu = &tu1xx_gpu,
 };
 
-static int
+int
 tu102_gsp_load_rm(struct nvkm_gsp *gsp, const struct nvkm_gsp_fwif *fwif)
 {
        struct nvkm_subdev *subdev = &gsp->subdev;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/Kbuild 
b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/Kbuild
index 06cbe19ce376..fa7a2862dd1f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/Kbuild
@@ -4,3 +4,4 @@ nvkm-y += nvkm/subdev/instmem/nv04.o
 nvkm-y += nvkm/subdev/instmem/nv40.o
 nvkm-y += nvkm/subdev/instmem/nv50.o
 nvkm-y += nvkm/subdev/instmem/gk20a.o
+nvkm-y += nvkm/subdev/instmem/gh100.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gh100.c 
b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gh100.c
new file mode 100644
index 000000000000..8d8dd5f8a6c7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gh100.c
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
+ */
+#include "priv.h"
+
+#include <nvhw/ref/gh100/pri_nv_xal_ep.h>
+
+static void
+gh100_instmem_set_bar0_window_addr(struct nvkm_device *device, u64 addr)
+{
+       nvkm_wr32(device, NV_XAL_EP_BAR0_WINDOW, addr >> 
NV_XAL_EP_BAR0_WINDOW_BASE_SHIFT);
+}
+
+static const struct nvkm_instmem_func
+gh100_instmem = {
+       .fini = nv50_instmem_fini,
+       .memory_new = nv50_instobj_new,
+       .memory_wrap = nv50_instobj_wrap,
+       .set_bar0_window_addr = gh100_instmem_set_bar0_window_addr,
+};
+
+int
+gh100_instmem_new(struct nvkm_device *device, enum nvkm_subdev_type type, int 
inst,
+                 struct nvkm_instmem **pimem)
+{
+       return r535_instmem_new(&gh100_instmem, device, type, inst, pimem);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c 
b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c
index 9d29e5234734..4ca6fb30743d 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c
@@ -353,7 +353,7 @@ nv50_instobj_func = {
        .map = nv50_instobj_map,
 };
 
-static int
+int
 nv50_instobj_wrap(struct nvkm_instmem *base,
                  struct nvkm_memory *memory, struct nvkm_memory **pmemory)
 {
@@ -373,7 +373,7 @@ nv50_instobj_wrap(struct nvkm_instmem *base,
        return 0;
 }
 
-static int
+int
 nv50_instobj_new(struct nvkm_instmem *imem, u32 size, u32 align, bool zero,
                 struct nvkm_memory **pmemory)
 {
@@ -400,7 +400,7 @@ nv50_instmem_set_bar0_window_addr(struct nvkm_device 
*device, u64 addr)
        nvkm_wr32(device, 0x001700, addr >> 16);
 }
 
-static void
+void
 nv50_instmem_fini(struct nvkm_instmem *base)
 {
        nv50_instmem(base)->addr = ~0ULL;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h 
b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h
index d5b5fcd9262b..87bbdd786eaa 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h
@@ -21,6 +21,11 @@ struct nvkm_instmem_func {
 
 int nv50_instmem_new_(const struct nvkm_instmem_func *, struct nvkm_device *,
                      enum nvkm_subdev_type, int, struct nvkm_instmem **);
+void nv50_instmem_fini(struct nvkm_instmem *);
+int nv50_instobj_new(struct nvkm_instmem *, u32 size, u32 align, bool zero,
+                    struct nvkm_memory **);
+int nv50_instobj_wrap(struct nvkm_instmem *, struct nvkm_memory *vram,
+                     struct nvkm_memory **bar2);
 
 void nvkm_instmem_ctor(const struct nvkm_instmem_func *, struct nvkm_device *,
                       enum nvkm_subdev_type, int, struct nvkm_instmem *);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/Kbuild 
b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/Kbuild
index a602b0cb5b31..ea4848931540 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/Kbuild
@@ -15,6 +15,7 @@ nvkm-y += nvkm/subdev/mmu/gp100.o
 nvkm-y += nvkm/subdev/mmu/gp10b.o
 nvkm-y += nvkm/subdev/mmu/gv100.o
 nvkm-y += nvkm/subdev/mmu/tu102.o
+nvkm-y += nvkm/subdev/mmu/gh100.o
 
 nvkm-y += nvkm/subdev/mmu/mem.o
 nvkm-y += nvkm/subdev/mmu/memnv04.o
@@ -36,6 +37,7 @@ nvkm-y += nvkm/subdev/mmu/vmmgp100.o
 nvkm-y += nvkm/subdev/mmu/vmmgp10b.o
 nvkm-y += nvkm/subdev/mmu/vmmgv100.o
 nvkm-y += nvkm/subdev/mmu/vmmtu102.o
+nvkm-y += nvkm/subdev/mmu/vmmgh100.o
 
 nvkm-y += nvkm/subdev/mmu/umem.o
 nvkm-y += nvkm/subdev/mmu/ummu.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gh100.c 
b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gh100.c
new file mode 100644
index 000000000000..2918fb32cc91
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gh100.c
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
+ */
+#include "mem.h"
+#include "vmm.h"
+
+#include <nvif/class.h>
+
+static const struct nvkm_mmu_func
+gh100_mmu = {
+       .dma_bits = 52,
+       .mmu = {{ -1, -1, NVIF_CLASS_MMU_GF100}},
+       .mem = {{ -1,  0, NVIF_CLASS_MEM_GF100}, gf100_mem_new, gf100_mem_map },
+       .vmm = {{ -1,  0, NVIF_CLASS_VMM_GP100}, gh100_vmm_new },
+       .kind = tu102_mmu_kind,
+       .kind_sys = true,
+};
+
+int
+gh100_mmu_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+             struct nvkm_mmu **pmmu)
+{
+       return r535_mmu_new(&gh100_mmu, device, type, inst, pmmu);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h 
b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h
index e9ca6537778c..90efef8f0b54 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h
@@ -53,6 +53,8 @@ const u8 *gf100_mmu_kind(struct nvkm_mmu *, int *count, u8 
*invalid);
 
 const u8 *gm200_mmu_kind(struct nvkm_mmu *, int *, u8 *);
 
+const u8 *tu102_mmu_kind(struct nvkm_mmu *, int *, u8 *);
+
 struct nvkm_mmu_pt {
        union {
                struct nvkm_mmu_ptc *ptc;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu102.c 
b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu102.c
index df662ce4a4b0..7acff3642e20 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu102.c
@@ -28,7 +28,7 @@
 
 #include <nvif/class.h>
 
-static const u8 *
+const u8 *
 tu102_mmu_kind(struct nvkm_mmu *mmu, int *count, u8 *invalid)
 {
        static const u8
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h 
b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h
index f9bc30cdb2b3..4586a425dbe4 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h
@@ -143,6 +143,8 @@ struct nvkm_vmm_func {
        int (*aper)(enum nvkm_memory_target);
        int (*valid)(struct nvkm_vmm *, void *argv, u32 argc,
                     struct nvkm_vmm_map *);
+       int (*valid2)(struct nvkm_vmm *, bool ro, bool priv, u8 kind, u8 comp,
+                     struct nvkm_vmm_map *);
        void (*flush)(struct nvkm_vmm *, int depth);
 
        int (*mthd)(struct nvkm_vmm *, struct nvkm_client *,
@@ -254,6 +256,8 @@ void gp100_vmm_invalidate_pdb(struct nvkm_vmm *, u64 addr);
 
 int gv100_vmm_join(struct nvkm_vmm *, struct nvkm_memory *);
 
+void tu102_vmm_flush(struct nvkm_vmm *, int depth);
+
 int nv04_vmm_new(struct nvkm_mmu *, bool, u64, u64, void *, u32,
                 struct lock_class_key *, const char *, struct nvkm_vmm **);
 int nv41_vmm_new(struct nvkm_mmu *, bool, u64, u64, void *, u32,
@@ -296,6 +300,9 @@ int gv100_vmm_new(struct nvkm_mmu *, bool, u64, u64, void 
*, u32,
 int tu102_vmm_new(struct nvkm_mmu *, bool, u64, u64, void *, u32,
                  struct lock_class_key *, const char *,
                  struct nvkm_vmm **);
+int gh100_vmm_new(struct nvkm_mmu *, bool, u64, u64, void *, u32,
+                 struct lock_class_key *, const char *,
+                 struct nvkm_vmm **);
 
 #define VMM_PRINT(l,v,p,f,a...) do {                                           
\
        struct nvkm_vmm *_vmm = (v);                                           \
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgh100.c 
b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgh100.c
new file mode 100644
index 000000000000..5614df3432da
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgh100.c
@@ -0,0 +1,306 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
+ */
+#include "vmm.h"
+
+#include <subdev/fb.h>
+
+#include <nvhw/drf.h>
+#include <nvhw/ref/gh100/dev_mmu.h>
+
+static inline void
+gh100_vmm_pgt_pte(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt, u32 ptei, u32 
ptes,
+                 struct nvkm_vmm_map *map, u64 addr)
+{
+       u64 data = addr | map->type;
+
+       while (ptes--) {
+               VMM_WO064(pt, vmm, ptei++ * NV_MMU_VER3_PTE__SIZE, data);
+               data += map->next;
+       }
+}
+
+static void
+gh100_vmm_pgt_sgl(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt, u32 ptei, u32 
ptes,
+                 struct nvkm_vmm_map *map)
+{
+       VMM_MAP_ITER_SGL(vmm, pt, ptei, ptes, map, gh100_vmm_pgt_pte);
+}
+
+static void
+gh100_vmm_pgt_dma(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt, u32 ptei, u32 
ptes,
+                 struct nvkm_vmm_map *map)
+{
+       if (map->page->shift == PAGE_SHIFT) {
+               VMM_SPAM(vmm, "DMAA %08x %08x PTE(s)", ptei, ptes);
+
+               nvkm_kmap(pt->memory);
+               while (ptes--) {
+                       const u64 data = *map->dma++ | map->type;
+
+                       VMM_WO064(pt, vmm, ptei++ * NV_MMU_VER3_PTE__SIZE, 
data);
+               }
+               nvkm_done(pt->memory);
+               return;
+       }
+
+       VMM_MAP_ITER_DMA(vmm, pt, ptei, ptes, map, gh100_vmm_pgt_pte);
+}
+
+static void
+gh100_vmm_pgt_mem(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt, u32 ptei, u32 
ptes,
+                 struct nvkm_vmm_map *map)
+{
+       VMM_MAP_ITER_MEM(vmm, pt, ptei, ptes, map, gh100_vmm_pgt_pte);
+}
+
+static void
+gh100_vmm_pgt_sparse(struct nvkm_vmm *vmm,
+                    struct nvkm_mmu_pt *pt, u32 ptei, u32 ptes)
+{
+       const u64 data = NVDEF(NV_MMU, VER3_PTE, PCF, SPARSE);
+
+       VMM_FO064(pt, vmm, ptei * NV_MMU_VER3_PTE__SIZE, data, ptes);
+}
+
+static const struct nvkm_vmm_desc_func
+gh100_vmm_desc_spt = {
+       .unmap = gf100_vmm_pgt_unmap,
+       .sparse = gh100_vmm_pgt_sparse,
+       .mem = gh100_vmm_pgt_mem,
+       .dma = gh100_vmm_pgt_dma,
+       .sgl = gh100_vmm_pgt_sgl,
+};
+
+static void
+gh100_vmm_lpt_invalid(struct nvkm_vmm *vmm,
+                     struct nvkm_mmu_pt *pt, u32 ptei, u32 ptes)
+{
+       const u64 data = NVDEF(NV_MMU, VER3_PTE, PCF, NO_VALID_4KB_PAGE);
+
+       VMM_FO064(pt, vmm, ptei * NV_MMU_VER3_PTE__SIZE, data, ptes);
+}
+
+static const struct nvkm_vmm_desc_func
+gh100_vmm_desc_lpt = {
+       .invalid = gh100_vmm_lpt_invalid,
+       .unmap = gf100_vmm_pgt_unmap,
+       .sparse = gh100_vmm_pgt_sparse,
+       .mem = gh100_vmm_pgt_mem,
+};
+
+static inline void
+gh100_vmm_pd0_pte(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt,
+                 u32 ptei, u32 ptes, struct nvkm_vmm_map *map, u64 addr)
+{
+       u64 data = addr | map->type;
+
+       while (ptes--) {
+               VMM_WO128(pt, vmm, ptei++ * NV_MMU_VER3_DUAL_PDE__SIZE, data, 
0ULL);
+               data += map->next;
+       }
+}
+
+static void
+gh100_vmm_pd0_mem(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt,
+                 u32 ptei, u32 ptes, struct nvkm_vmm_map *map)
+{
+       VMM_MAP_ITER_MEM(vmm, pt, ptei, ptes, map, gh100_vmm_pd0_pte);
+}
+
+static inline bool
+gh100_vmm_pde(struct nvkm_mmu_pt *pt, u64 *data)
+{
+       switch (nvkm_memory_target(pt->memory)) {
+       case NVKM_MEM_TARGET_VRAM:
+               *data |= NVDEF(NV_MMU, VER3_PDE, APERTURE, VIDEO_MEMORY);
+               *data |= NVDEF(NV_MMU, VER3_PDE, PCF, 
VALID_CACHED_ATS_NOT_ALLOWED);
+               break;
+       case NVKM_MEM_TARGET_HOST:
+               *data |= NVDEF(NV_MMU, VER3_PDE, APERTURE, 
SYSTEM_COHERENT_MEMORY);
+               *data |= NVDEF(NV_MMU, VER3_PDE, PCF, 
VALID_UNCACHED_ATS_ALLOWED);
+               break;
+       case NVKM_MEM_TARGET_NCOH:
+               *data |= NVDEF(NV_MMU, VER3_PDE, APERTURE, 
SYSTEM_NON_COHERENT_MEMORY);
+               *data |= NVDEF(NV_MMU, VER3_PDE, PCF, VALID_CACHED_ATS_ALLOWED);
+               break;
+       default:
+               WARN_ON(1);
+               return false;
+       }
+
+       *data |= pt->addr;
+       return true;
+}
+
+static void
+gh100_vmm_pd0_pde(struct nvkm_vmm *vmm, struct nvkm_vmm_pt *pgd, u32 pdei)
+{
+       struct nvkm_vmm_pt *pgt = pgd->pde[pdei];
+       struct nvkm_mmu_pt *pd = pgd->pt[0];
+       u64 data[2] = {};
+
+       if (pgt->pt[0] && !gh100_vmm_pde(pgt->pt[0], &data[0]))
+               return;
+       if (pgt->pt[1] && !gh100_vmm_pde(pgt->pt[1], &data[1]))
+               return;
+
+       nvkm_kmap(pd->memory);
+       VMM_WO128(pd, vmm, pdei * NV_MMU_VER3_DUAL_PDE__SIZE, data[0], data[1]);
+       nvkm_done(pd->memory);
+}
+
+static void
+gh100_vmm_pd0_sparse(struct nvkm_vmm *vmm,
+                    struct nvkm_mmu_pt *pt, u32 pdei, u32 pdes)
+{
+       const u64 data = NVDEF(NV_MMU, VER3_DUAL_PDE, PCF_BIG, 
SPARSE_ATS_ALLOWED);
+
+       VMM_FO128(pt, vmm, pdei * NV_MMU_VER3_DUAL_PDE__SIZE, data, 0ULL, pdes);
+}
+
+static void
+gh100_vmm_pd0_unmap(struct nvkm_vmm *vmm,
+                   struct nvkm_mmu_pt *pt, u32 pdei, u32 pdes)
+{
+       VMM_FO128(pt, vmm, pdei * NV_MMU_VER3_DUAL_PDE__SIZE, 0ULL, 0ULL, pdes);
+}
+
+static const struct nvkm_vmm_desc_func
+gh100_vmm_desc_pd0 = {
+       .unmap = gh100_vmm_pd0_unmap,
+       .sparse = gh100_vmm_pd0_sparse,
+       .pde = gh100_vmm_pd0_pde,
+       .mem = gh100_vmm_pd0_mem,
+};
+
+static void
+gh100_vmm_pd1_pde(struct nvkm_vmm *vmm, struct nvkm_vmm_pt *pgd, u32 pdei)
+{
+       struct nvkm_vmm_pt *pgt = pgd->pde[pdei];
+       struct nvkm_mmu_pt *pd = pgd->pt[0];
+       u64 data = 0;
+
+       if (!gh100_vmm_pde(pgt->pt[0], &data))
+               return;
+
+       nvkm_kmap(pd->memory);
+       VMM_WO064(pd, vmm, pdei * NV_MMU_VER3_PDE__SIZE, data);
+       nvkm_done(pd->memory);
+}
+
+static const struct nvkm_vmm_desc_func
+gh100_vmm_desc_pd1 = {
+       .unmap = gf100_vmm_pgt_unmap,
+       .sparse = gh100_vmm_pgt_sparse,
+       .pde = gh100_vmm_pd1_pde,
+};
+
+static const struct nvkm_vmm_desc
+gh100_vmm_desc_16[] = {
+       { LPT, 5,  8, 0x0100, &gh100_vmm_desc_lpt },
+       { PGD, 8, 16, 0x1000, &gh100_vmm_desc_pd0 },
+       { PGD, 9,  8, 0x1000, &gh100_vmm_desc_pd1 },
+       { PGD, 9,  8, 0x1000, &gh100_vmm_desc_pd1 },
+       { PGD, 9,  8, 0x1000, &gh100_vmm_desc_pd1 },
+       { PGD, 1,  8, 0x1000, &gh100_vmm_desc_pd1 },
+       {}
+};
+
+static const struct nvkm_vmm_desc
+gh100_vmm_desc_12[] = {
+       { SPT, 9,  8, 0x1000, &gh100_vmm_desc_spt },
+       { PGD, 8, 16, 0x1000, &gh100_vmm_desc_pd0 },
+       { PGD, 9,  8, 0x1000, &gh100_vmm_desc_pd1 },
+       { PGD, 9,  8, 0x1000, &gh100_vmm_desc_pd1 },
+       { PGD, 9,  8, 0x1000, &gh100_vmm_desc_pd1 },
+       { PGD, 1,  8, 0x1000, &gh100_vmm_desc_pd1 },
+       {}
+};
+
+static int
+gh100_vmm_valid(struct nvkm_vmm *vmm, bool ro, bool priv, u8 kind, u8 comp,
+               struct nvkm_vmm_map *map)
+{
+       const enum nvkm_memory_target target = nvkm_memory_target(map->memory);
+       const bool vol = target == NVKM_MEM_TARGET_HOST;
+       const struct nvkm_vmm_page *page = map->page;
+       u8 kind_inv, pcf;
+       int kindn, aper;
+       const u8 *kindm;
+
+       map->next = 1ULL << page->shift;
+       map->type = 0;
+
+       aper = vmm->func->aper(target);
+       if (WARN_ON(aper < 0))
+               return aper;
+
+       kindm = vmm->mmu->func->kind(vmm->mmu, &kindn, &kind_inv);
+       if (kind >= kindn || kindm[kind] == kind_inv) {
+               VMM_DEBUG(vmm, "kind %02x", kind);
+               return -EINVAL;
+       }
+
+       if (priv) {
+               if (ro) {
+                       if (vol)
+                               pcf = 
NV_MMU_VER3_PTE_PCF_PRIVILEGE_RO_ATOMIC_UNCACHED_ACD;
+                       else
+                               pcf = 
NV_MMU_VER3_PTE_PCF_PRIVILEGE_RO_ATOMIC_CACHED_ACD;
+               } else {
+                       if (vol)
+                               pcf = 
NV_MMU_VER3_PTE_PCF_PRIVILEGE_RW_ATOMIC_UNCACHED_ACD;
+                       else
+                               pcf = 
NV_MMU_VER3_PTE_PCF_PRIVILEGE_RW_ATOMIC_CACHED_ACD;
+               }
+       } else {
+               if (ro) {
+                       if (vol)
+                               pcf = 
NV_MMU_VER3_PTE_PCF_REGULAR_RO_ATOMIC_UNCACHED_ACD;
+                       else
+                               pcf = 
NV_MMU_VER3_PTE_PCF_REGULAR_RO_ATOMIC_CACHED_ACD;
+               } else {
+                       if (vol)
+                               pcf = 
NV_MMU_VER3_PTE_PCF_REGULAR_RW_ATOMIC_UNCACHED_ACD;
+                       else
+                               pcf = 
NV_MMU_VER3_PTE_PCF_REGULAR_RW_ATOMIC_CACHED_ACD;
+               }
+       }
+
+       map->type |= NVDEF(NV_MMU, VER3_PTE, VALID, TRUE);
+       map->type |= NVVAL(NV_MMU, VER3_PTE, APERTURE, aper);
+       map->type |= NVVAL(NV_MMU, VER3_PTE, PCF, pcf);
+       map->type |= NVVAL(NV_MMU, VER3_PTE, KIND, kind);
+       return 0;
+}
+
+static const struct nvkm_vmm_func
+gh100_vmm = {
+       .join = gv100_vmm_join,
+       .part = gf100_vmm_part,
+       .aper = gf100_vmm_aper,
+       .valid = gp100_vmm_valid,
+       .valid2 = gh100_vmm_valid,
+       .flush = tu102_vmm_flush,
+       .page = {
+               { 56, &gh100_vmm_desc_16[5], NVKM_VMM_PAGE_Sxxx },
+               { 47, &gh100_vmm_desc_16[4], NVKM_VMM_PAGE_Sxxx },
+               { 38, &gh100_vmm_desc_16[3], NVKM_VMM_PAGE_Sxxx },
+               { 29, &gh100_vmm_desc_16[2], NVKM_VMM_PAGE_SVxC },
+               { 21, &gh100_vmm_desc_16[1], NVKM_VMM_PAGE_SVxC },
+               { 16, &gh100_vmm_desc_16[0], NVKM_VMM_PAGE_SVxC },
+               { 12, &gh100_vmm_desc_12[0], NVKM_VMM_PAGE_SVHx },
+               {}
+       }
+};
+
+int
+gh100_vmm_new(struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
+             void *argv, u32 argc, struct lock_class_key *key,
+             const char *name, struct nvkm_vmm **pvmm)
+{
+       return gp100_vmm_new_(&gh100_vmm, mmu, managed, addr, size,
+                             argv, argc, key, name, pvmm);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c 
b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c
index bddac77f48f0..851fd847a2a9 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c
@@ -436,6 +436,9 @@ gp100_vmm_valid(struct nvkm_vmm *vmm, void *argv, u32 argc,
                return ret;
        }
 
+       if (vmm->func->valid2)
+               return vmm->func->valid2(vmm, ro, priv, kind, 0, map);
+
        aper = vmm->func->aper(target);
        if (WARN_ON(aper < 0))
                return aper;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c 
b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c
index 8379e72d77ab..4b30eab40bba 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c
@@ -23,7 +23,7 @@
 
 #include <subdev/timer.h>
 
-static void
+void
 tu102_vmm_flush(struct nvkm_vmm *vmm, int depth)
 {
        struct nvkm_device *device = vmm->mmu->subdev.device;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild 
b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild
index 174bdf995271..a14ea0f7b1c8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild
@@ -13,3 +13,4 @@ nvkm-y += nvkm/subdev/pci/gf100.o
 nvkm-y += nvkm/subdev/pci/gf106.o
 nvkm-y += nvkm/subdev/pci/gk104.o
 nvkm-y += nvkm/subdev/pci/gp100.o
+nvkm-y += nvkm/subdev/pci/gh100.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gh100.c 
b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gh100.c
new file mode 100644
index 000000000000..42da92d7a5fe
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gh100.c
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
+ */
+#include "priv.h"
+
+#include <nvhw/drf.h>
+#include <nvhw/ref/gh100/dev_xtl_ep_pri.h>
+
+static void
+gh100_pci_msi_rearm(struct nvkm_pci *pci)
+{
+       /* Handled by top-level intr ACK. */
+}
+
+static const struct nvkm_pci_func
+gh100_pci = {
+       .cfg = {
+               .addr = DRF_LO(NV_EP_PCFGM),
+               .size = DRF_HI(NV_EP_PCFGM) - DRF_LO(NV_EP_PCFGM) + 1,
+       },
+       .msi_rearm = gh100_pci_msi_rearm,
+};
+
+int
+gh100_pci_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+             struct nvkm_pci **ppci)
+{
+       return nvkm_pci_new_(&gh100_pci, device, type, inst, ppci);
+}
-- 
2.49.0

Reply via email to