Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.19-rc3 165 lines 5.0 kB view raw
1// SPDX-License-Identifier: GPL-2.0 OR MIT 2/* Copyright (c) 2024 Imagination Technologies Ltd. */ 3 4#include "pvr_device.h" 5#include "pvr_fw.h" 6#include "pvr_fw_info.h" 7#include "pvr_fw_mips.h" 8#include "pvr_gem.h" 9#include "pvr_rogue_cr_defs.h" 10#include "pvr_rogue_riscv.h" 11#include "pvr_vm.h" 12 13#include <linux/compiler.h> 14#include <linux/delay.h> 15#include <linux/firmware.h> 16#include <linux/ktime.h> 17#include <linux/types.h> 18 19#define ROGUE_FW_HEAP_RISCV_SHIFT 25 /* 32 MB */ 20#define ROGUE_FW_HEAP_RISCV_SIZE (1u << ROGUE_FW_HEAP_RISCV_SHIFT) 21 22static int 23pvr_riscv_wrapper_init(struct pvr_device *pvr_dev) 24{ 25 const u64 common_opts = 26 ((u64)(ROGUE_FW_HEAP_RISCV_SIZE >> FWCORE_ADDR_REMAP_CONFIG0_SIZE_ALIGNSHIFT) 27 << ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_SIZE_SHIFT) | 28 ((u64)MMU_CONTEXT_MAPPING_FWPRIV 29 << FWCORE_ADDR_REMAP_CONFIG0_MMU_CONTEXT_SHIFT); 30 31 u64 code_addr = pvr_fw_obj_get_gpu_addr(pvr_dev->fw_dev.mem.code_obj); 32 u64 data_addr = pvr_fw_obj_get_gpu_addr(pvr_dev->fw_dev.mem.data_obj); 33 34 /* This condition allows us to OR the addresses into the register directly. */ 35 static_assert(ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_DEVVADDR_SHIFT == 36 ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_DEVVADDR_ALIGNSHIFT); 37 38 WARN_ON(code_addr & ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_DEVVADDR_CLRMSK); 39 WARN_ON(data_addr & ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_DEVVADDR_CLRMSK); 40 41 pvr_cr_write64(pvr_dev, ROGUE_RISCVFW_REGION_REMAP_CR(BOOTLDR_CODE), 42 code_addr | common_opts | ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_FETCH_EN_EN); 43 44 pvr_cr_write64(pvr_dev, ROGUE_RISCVFW_REGION_REMAP_CR(BOOTLDR_DATA), 45 data_addr | common_opts | 46 ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_LOAD_STORE_EN_EN); 47 48 /* Garten IDLE bit controlled by RISC-V. */ 49 pvr_cr_write64(pvr_dev, ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG, 50 ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_IDLE_CTRL_META); 51 52 return 0; 53} 54 55struct rogue_riscv_fw_boot_data { 56 u64 coremem_code_dev_vaddr; 57 u64 coremem_data_dev_vaddr; 58 u32 coremem_code_fw_addr; 59 u32 coremem_data_fw_addr; 60 u32 coremem_code_size; 61 u32 coremem_data_size; 62 u32 flags; 63 u32 reserved; 64}; 65 66static int 67pvr_riscv_fw_process(struct pvr_device *pvr_dev, const u8 *fw, 68 u8 *fw_code_ptr, u8 *fw_data_ptr, u8 *fw_core_code_ptr, u8 *fw_core_data_ptr, 69 u32 core_code_alloc_size) 70{ 71 struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; 72 struct pvr_fw_mem *fw_mem = &fw_dev->mem; 73 struct rogue_riscv_fw_boot_data *boot_data; 74 int err; 75 76 err = pvr_fw_process_elf_command_stream(pvr_dev, fw, fw_code_ptr, fw_data_ptr, 77 fw_core_code_ptr, fw_core_data_ptr); 78 if (err) 79 goto err_out; 80 81 boot_data = (struct rogue_riscv_fw_boot_data *)fw_data_ptr; 82 83 if (fw_mem->core_code_obj) { 84 boot_data->coremem_code_dev_vaddr = pvr_fw_obj_get_gpu_addr(fw_mem->core_code_obj); 85 pvr_fw_object_get_fw_addr(fw_mem->core_code_obj, &boot_data->coremem_code_fw_addr); 86 boot_data->coremem_code_size = pvr_fw_obj_get_object_size(fw_mem->core_code_obj); 87 } 88 89 if (fw_mem->core_data_obj) { 90 boot_data->coremem_data_dev_vaddr = pvr_fw_obj_get_gpu_addr(fw_mem->core_data_obj); 91 pvr_fw_object_get_fw_addr(fw_mem->core_data_obj, &boot_data->coremem_data_fw_addr); 92 boot_data->coremem_data_size = pvr_fw_obj_get_object_size(fw_mem->core_data_obj); 93 } 94 95 return 0; 96 97err_out: 98 return err; 99} 100 101static int 102pvr_riscv_init(struct pvr_device *pvr_dev) 103{ 104 pvr_fw_heap_info_init(pvr_dev, ROGUE_FW_HEAP_RISCV_SHIFT, 0); 105 106 return 0; 107} 108 109static u32 110pvr_riscv_get_fw_addr_with_offset(struct pvr_fw_object *fw_obj, u32 offset) 111{ 112 u32 fw_addr = fw_obj->fw_addr_offset + offset; 113 114 /* RISC-V cacheability is determined by address. */ 115 if (fw_obj->gem->flags & PVR_BO_FW_FLAGS_DEVICE_UNCACHED) 116 fw_addr |= ROGUE_RISCVFW_REGION_BASE(SHARED_UNCACHED_DATA); 117 else 118 fw_addr |= ROGUE_RISCVFW_REGION_BASE(SHARED_CACHED_DATA); 119 120 return fw_addr; 121} 122 123static int 124pvr_riscv_vm_map(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj) 125{ 126 struct pvr_gem_object *pvr_obj = fw_obj->gem; 127 128 return pvr_vm_map(pvr_dev->kernel_vm_ctx, pvr_obj, 0, fw_obj->fw_mm_node.start, 129 pvr_gem_object_size(pvr_obj)); 130} 131 132static void 133pvr_riscv_vm_unmap(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj) 134{ 135 struct pvr_gem_object *pvr_obj = fw_obj->gem; 136 137 pvr_vm_unmap_obj(pvr_dev->kernel_vm_ctx, pvr_obj, 138 fw_obj->fw_mm_node.start, fw_obj->fw_mm_node.size); 139} 140 141static bool 142pvr_riscv_irq_pending(struct pvr_device *pvr_dev) 143{ 144 return pvr_cr_read32(pvr_dev, ROGUE_CR_IRQ_OS0_EVENT_STATUS) & 145 ROGUE_CR_IRQ_OS0_EVENT_STATUS_SOURCE_EN; 146} 147 148static void 149pvr_riscv_irq_clear(struct pvr_device *pvr_dev) 150{ 151 pvr_cr_write32(pvr_dev, ROGUE_CR_IRQ_OS0_EVENT_CLEAR, 152 ROGUE_CR_IRQ_OS0_EVENT_CLEAR_SOURCE_EN); 153} 154 155const struct pvr_fw_defs pvr_fw_defs_riscv = { 156 .init = pvr_riscv_init, 157 .fw_process = pvr_riscv_fw_process, 158 .vm_map = pvr_riscv_vm_map, 159 .vm_unmap = pvr_riscv_vm_unmap, 160 .get_fw_addr_with_offset = pvr_riscv_get_fw_addr_with_offset, 161 .wrapper_init = pvr_riscv_wrapper_init, 162 .irq_pending = pvr_riscv_irq_pending, 163 .irq_clear = pvr_riscv_irq_clear, 164 .has_fixed_data_addr = false, 165};