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