| /* SPDX-License-Identifier: GPL-2.0-only OR MIT */ | |
| /* Copyright (c) 2023 Imagination Technologies Ltd. */ | |
| #ifndef PVR_FW_H | |
| #define PVR_FW_H | |
| #include "pvr_fw_info.h" | |
| #include "pvr_fw_trace.h" | |
| #include "pvr_gem.h" | |
| #include <drm/drm_mm.h> | |
| #include <linux/types.h> | |
| /* Forward declarations from "pvr_device.h". */ | |
| struct pvr_device; | |
| struct pvr_file; | |
| /* Forward declaration from "pvr_vm.h". */ | |
| struct pvr_vm_context; | |
| #define ROGUE_FWIF_FWCCB_NUMCMDS_LOG2 5 | |
| #define ROGUE_FWIF_KCCB_NUMCMDS_LOG2_DEFAULT 7 | |
| /** | |
| * struct pvr_fw_object - container for firmware memory allocations | |
| */ | |
| struct pvr_fw_object { | |
| /** @ref_count: FW object reference counter. */ | |
| struct kref ref_count; | |
| /** @gem: GEM object backing the FW object. */ | |
| struct pvr_gem_object *gem; | |
| /** | |
| * @fw_mm_node: Node representing mapping in FW address space. @pvr_obj->lock must | |
| * be held when writing. | |
| */ | |
| struct drm_mm_node fw_mm_node; | |
| /** | |
| * @fw_addr_offset: Virtual address offset of firmware mapping. Only | |
| * valid if @flags has %PVR_GEM_OBJECT_FLAGS_FW_MAPPED | |
| * set. | |
| */ | |
| u32 fw_addr_offset; | |
| /** | |
| * @init: Initialisation callback. Will be called on object creation and FW hard reset. | |
| * Object will have been zeroed before this is called. | |
| */ | |
| void (*init)(void *cpu_ptr, void *priv); | |
| /** @init_priv: Private data for initialisation callback. */ | |
| void *init_priv; | |
| /** @node: Node for firmware object list. */ | |
| struct list_head node; | |
| }; | |
| /** | |
| * struct pvr_fw_defs - FW processor function table and static definitions | |
| */ | |
| struct pvr_fw_defs { | |
| /** | |
| * @init: | |
| * | |
| * FW processor specific initialisation. | |
| * @pvr_dev: Target PowerVR device. | |
| * | |
| * This function must call pvr_fw_heap_calculate() to initialise the firmware heap for this | |
| * FW processor. | |
| * | |
| * This function is mandatory. | |
| * | |
| * Returns: | |
| * * 0 on success, or | |
| * * Any appropriate error on failure. | |
| */ | |
| int (*init)(struct pvr_device *pvr_dev); | |
| /** | |
| * @fini: | |
| * | |
| * FW processor specific finalisation. | |
| * @pvr_dev: Target PowerVR device. | |
| * | |
| * This function is optional. | |
| */ | |
| void (*fini)(struct pvr_device *pvr_dev); | |
| /** | |
| * @fw_process: | |
| * | |
| * Load and process firmware image. | |
| * @pvr_dev: Target PowerVR device. | |
| * @fw: Pointer to firmware image. | |
| * @fw_code_ptr: Pointer to firmware code section. | |
| * @fw_data_ptr: Pointer to firmware data section. | |
| * @fw_core_code_ptr: Pointer to firmware core code section. May be %NULL. | |
| * @fw_core_data_ptr: Pointer to firmware core data section. May be %NULL. | |
| * @core_code_alloc_size: Total allocation size of core code section. | |
| * | |
| * This function is mandatory. | |
| * | |
| * Returns: | |
| * * 0 on success, or | |
| * * Any appropriate error on failure. | |
| */ | |
| int (*fw_process)(struct pvr_device *pvr_dev, const u8 *fw, | |
| u8 *fw_code_ptr, u8 *fw_data_ptr, u8 *fw_core_code_ptr, | |
| u8 *fw_core_data_ptr, u32 core_code_alloc_size); | |
| /** | |
| * @vm_map: | |
| * | |
| * Map FW object into FW processor address space. | |
| * @pvr_dev: Target PowerVR device. | |
| * @fw_obj: FW object to map. | |
| * | |
| * This function is mandatory. | |
| * | |
| * Returns: | |
| * * 0 on success, or | |
| * * Any appropriate error on failure. | |
| */ | |
| int (*vm_map)(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj); | |
| /** | |
| * @vm_unmap: | |
| * | |
| * Unmap FW object from FW processor address space. | |
| * @pvr_dev: Target PowerVR device. | |
| * @fw_obj: FW object to map. | |
| * | |
| * This function is mandatory. | |
| */ | |
| void (*vm_unmap)(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj); | |
| /** | |
| * @get_fw_addr_with_offset: | |
| * | |
| * Called to get address of object in firmware address space, with offset. | |
| * @fw_obj: Pointer to object. | |
| * @offset: Desired offset from start of object. | |
| * | |
| * This function is mandatory. | |
| * | |
| * Returns: | |
| * * Address in firmware address space. | |
| */ | |
| u32 (*get_fw_addr_with_offset)(struct pvr_fw_object *fw_obj, u32 offset); | |
| /** | |
| * @wrapper_init: | |
| * | |
| * Called to initialise FW wrapper. | |
| * @pvr_dev: Target PowerVR device. | |
| * | |
| * This function is mandatory. | |
| * | |
| * Returns: | |
| * * 0 on success. | |
| * * Any appropriate error on failure. | |
| */ | |
| int (*wrapper_init)(struct pvr_device *pvr_dev); | |
| /** | |
| * @irq_pending: Check interrupt status register for pending interrupts. | |
| * | |
| * @pvr_dev: Target PowerVR device. | |
| * | |
| * This function is mandatory. | |
| */ | |
| bool (*irq_pending)(struct pvr_device *pvr_dev); | |
| /** | |
| * @irq_clear: Clear pending interrupts. | |
| * | |
| * @pvr_dev: Target PowerVR device. | |
| * | |
| * This function is mandatory. | |
| */ | |
| void (*irq_clear)(struct pvr_device *pvr_dev); | |
| /** | |
| * @has_fixed_data_addr: Specify whether the firmware fixed data must be loaded at the | |
| * address given by the firmware layout table. | |
| * | |
| * This value is mandatory. | |
| */ | |
| bool has_fixed_data_addr; | |
| }; | |
| /** | |
| * struct pvr_fw_mem - FW memory allocations | |
| */ | |
| struct pvr_fw_mem { | |
| /** @code_obj: Object representing firmware code. */ | |
| struct pvr_fw_object *code_obj; | |
| /** @data_obj: Object representing firmware data. */ | |
| struct pvr_fw_object *data_obj; | |
| /** | |
| * @core_code_obj: Object representing firmware core code. May be | |
| * %NULL if firmware does not contain this section. | |
| */ | |
| struct pvr_fw_object *core_code_obj; | |
| /** | |
| * @core_data_obj: Object representing firmware core data. May be | |
| * %NULL if firmware does not contain this section. | |
| */ | |
| struct pvr_fw_object *core_data_obj; | |
| /** @code: Driver-side copy of firmware code. */ | |
| u8 *code; | |
| /** @data: Driver-side copy of firmware data. */ | |
| u8 *data; | |
| /** | |
| * @core_code: Driver-side copy of firmware core code. May be %NULL if firmware does not | |
| * contain this section. | |
| */ | |
| u8 *core_code; | |
| /** | |
| * @core_data: Driver-side copy of firmware core data. May be %NULL if firmware does not | |
| * contain this section. | |
| */ | |
| u8 *core_data; | |
| /** @code_alloc_size: Allocation size of firmware code section. */ | |
| u32 code_alloc_size; | |
| /** @data_alloc_size: Allocation size of firmware data section. */ | |
| u32 data_alloc_size; | |
| /** @core_code_alloc_size: Allocation size of firmware core code section. */ | |
| u32 core_code_alloc_size; | |
| /** @core_data_alloc_size: Allocation size of firmware core data section. */ | |
| u32 core_data_alloc_size; | |
| /** | |
| * @fwif_connection_ctl_obj: Object representing FWIF connection control | |
| * structure. | |
| */ | |
| struct pvr_fw_object *fwif_connection_ctl_obj; | |
| /** @osinit_obj: Object representing FW OSINIT structure. */ | |
| struct pvr_fw_object *osinit_obj; | |
| /** @sysinit_obj: Object representing FW SYSINIT structure. */ | |
| struct pvr_fw_object *sysinit_obj; | |
| /** @osdata_obj: Object representing FW OSDATA structure. */ | |
| struct pvr_fw_object *osdata_obj; | |
| /** @hwrinfobuf_obj: Object representing FW hwrinfobuf structure. */ | |
| struct pvr_fw_object *hwrinfobuf_obj; | |
| /** @sysdata_obj: Object representing FW SYSDATA structure. */ | |
| struct pvr_fw_object *sysdata_obj; | |
| /** @power_sync_obj: Object representing power sync state. */ | |
| struct pvr_fw_object *power_sync_obj; | |
| /** @fault_page_obj: Object representing FW fault page. */ | |
| struct pvr_fw_object *fault_page_obj; | |
| /** @gpu_util_fwcb_obj: Object representing FW GPU utilisation control structure. */ | |
| struct pvr_fw_object *gpu_util_fwcb_obj; | |
| /** @runtime_cfg_obj: Object representing FW runtime config structure. */ | |
| struct pvr_fw_object *runtime_cfg_obj; | |
| /** @mmucache_sync_obj: Object used as the sync parameter in an MMU cache operation. */ | |
| struct pvr_fw_object *mmucache_sync_obj; | |
| }; | |
| struct pvr_fw_device { | |
| /** @firmware: Handle to the firmware loaded into the device. */ | |
| const struct firmware *firmware; | |
| /** @header: Pointer to firmware header. */ | |
| const struct pvr_fw_info_header *header; | |
| /** @layout_entries: Pointer to firmware layout. */ | |
| const struct pvr_fw_layout_entry *layout_entries; | |
| /** @mem: Structure containing objects representing firmware memory allocations. */ | |
| struct pvr_fw_mem mem; | |
| /** | |
| * @initialised: %true if the firmware has been successfully initialised, | |
| * %false otherwise. | |
| */ | |
| bool initialised; | |
| /** | |
| * @processor_type: FW processor type for this device. Must be one of | |
| * %PVR_FW_PROCESSOR_TYPE_*. | |
| */ | |
| u16 processor_type; | |
| /** @funcs: Function table for the FW processor used by this device. */ | |
| const struct pvr_fw_defs *defs; | |
| /** @processor_data: Pointer to data specific to FW processor. */ | |
| union { | |
| /** @mips_data: Pointer to MIPS-specific data. */ | |
| struct pvr_fw_mips_data *mips_data; | |
| } processor_data; | |
| /** @fw_heap_info: Firmware heap information. */ | |
| struct { | |
| /** @gpu_addr: Base address of firmware heap in GPU address space. */ | |
| u64 gpu_addr; | |
| /** @size: Size of main area of heap. */ | |
| u32 size; | |
| /** @offset_mask: Mask for offsets within FW heap. */ | |
| u32 offset_mask; | |
| /** @raw_size: Raw size of heap, including reserved areas. */ | |
| u32 raw_size; | |
| /** @log2_size: Log2 of raw size of heap. */ | |
| u32 log2_size; | |
| /** @config_offset: Offset of config area within heap. */ | |
| u32 config_offset; | |
| /** @reserved_size: Size of reserved area in heap. */ | |
| u32 reserved_size; | |
| } fw_heap_info; | |
| /** @fw_mm: Firmware address space allocator. */ | |
| struct drm_mm fw_mm; | |
| /** @fw_mm_lock: Lock protecting access to &fw_mm. */ | |
| spinlock_t fw_mm_lock; | |
| /** @fw_mm_base: Base address of address space managed by @fw_mm. */ | |
| u64 fw_mm_base; | |
| /** | |
| * @fwif_connection_ctl: Pointer to CPU mapping of FWIF connection | |
| * control structure. | |
| */ | |
| struct rogue_fwif_connection_ctl *fwif_connection_ctl; | |
| /** @fwif_sysinit: Pointer to CPU mapping of FW SYSINIT structure. */ | |
| struct rogue_fwif_sysinit *fwif_sysinit; | |
| /** @fwif_sysdata: Pointer to CPU mapping of FW SYSDATA structure. */ | |
| struct rogue_fwif_sysdata *fwif_sysdata; | |
| /** @fwif_osinit: Pointer to CPU mapping of FW OSINIT structure. */ | |
| struct rogue_fwif_osinit *fwif_osinit; | |
| /** @fwif_osdata: Pointer to CPU mapping of FW OSDATA structure. */ | |
| struct rogue_fwif_osdata *fwif_osdata; | |
| /** @power_sync: Pointer to CPU mapping of power sync state. */ | |
| u32 *power_sync; | |
| /** @hwrinfobuf: Pointer to CPU mapping of FW HWR info buffer. */ | |
| struct rogue_fwif_hwrinfobuf *hwrinfobuf; | |
| /** @fw_trace: Device firmware trace buffer state. */ | |
| struct pvr_fw_trace fw_trace; | |
| /** @fw_objs: Structure tracking FW objects. */ | |
| struct { | |
| /** @list: Head of FW object list. */ | |
| struct list_head list; | |
| /** @lock: Lock protecting access to FW object list. */ | |
| struct mutex lock; | |
| } fw_objs; | |
| }; | |
| enum pvr_fw_processor_type { | |
| PVR_FW_PROCESSOR_TYPE_META = 0, | |
| PVR_FW_PROCESSOR_TYPE_MIPS, | |
| PVR_FW_PROCESSOR_TYPE_RISCV, | |
| PVR_FW_PROCESSOR_TYPE_COUNT, | |
| }; | |
| extern const struct pvr_fw_defs pvr_fw_defs_meta; | |
| extern const struct pvr_fw_defs pvr_fw_defs_mips; | |
| extern const struct pvr_fw_defs pvr_fw_defs_riscv; | |
| int pvr_fw_validate_init_device_info(struct pvr_device *pvr_dev); | |
| int pvr_fw_init(struct pvr_device *pvr_dev); | |
| void pvr_fw_fini(struct pvr_device *pvr_dev); | |
| int pvr_wait_for_fw_boot(struct pvr_device *pvr_dev); | |
| int | |
| pvr_fw_hard_reset(struct pvr_device *pvr_dev); | |
| void pvr_fw_mts_schedule(struct pvr_device *pvr_dev, u32 val); | |
| void | |
| pvr_fw_heap_info_init(struct pvr_device *pvr_dev, u32 log2_size, u32 reserved_size); | |
| const struct pvr_fw_layout_entry * | |
| pvr_fw_find_layout_entry(struct pvr_device *pvr_dev, enum pvr_fw_section_id id); | |
| int | |
| pvr_fw_find_mmu_segment(struct pvr_device *pvr_dev, u32 addr, u32 size, void *fw_code_ptr, | |
| void *fw_data_ptr, void *fw_core_code_ptr, void *fw_core_data_ptr, | |
| void **host_addr_out); | |
| int | |
| pvr_fw_structure_cleanup(struct pvr_device *pvr_dev, u32 type, struct pvr_fw_object *fw_obj, | |
| u32 offset); | |
| int pvr_fw_object_create(struct pvr_device *pvr_dev, size_t size, u64 flags, | |
| void (*init)(void *cpu_ptr, void *priv), void *init_priv, | |
| struct pvr_fw_object **pvr_obj_out); | |
| void *pvr_fw_object_create_and_map(struct pvr_device *pvr_dev, size_t size, u64 flags, | |
| void (*init)(void *cpu_ptr, void *priv), | |
| void *init_priv, struct pvr_fw_object **pvr_obj_out); | |
| void * | |
| pvr_fw_object_create_and_map_offset(struct pvr_device *pvr_dev, u32 dev_offset, size_t size, | |
| u64 flags, void (*init)(void *cpu_ptr, void *priv), | |
| void *init_priv, struct pvr_fw_object **pvr_obj_out); | |
| static __always_inline void * | |
| pvr_fw_object_vmap(struct pvr_fw_object *fw_obj) | |
| { | |
| return pvr_gem_object_vmap(fw_obj->gem); | |
| } | |
| static __always_inline void | |
| pvr_fw_object_vunmap(struct pvr_fw_object *fw_obj) | |
| { | |
| pvr_gem_object_vunmap(fw_obj->gem); | |
| } | |
| void pvr_fw_object_destroy(struct pvr_fw_object *fw_obj); | |
| static __always_inline void | |
| pvr_fw_object_unmap_and_destroy(struct pvr_fw_object *fw_obj) | |
| { | |
| pvr_fw_object_vunmap(fw_obj); | |
| pvr_fw_object_destroy(fw_obj); | |
| } | |
| /** | |
| * pvr_fw_object_get_dma_addr() - Get DMA address for given offset in firmware | |
| * object. | |
| * @fw_obj: Pointer to object to lookup address in. | |
| * @offset: Offset within object to lookup address at. | |
| * @dma_addr_out: Pointer to location to store DMA address. | |
| * | |
| * Returns: | |
| * * 0 on success, or | |
| * * -%EINVAL if object is not currently backed, or if @offset is out of valid | |
| * range for this object. | |
| */ | |
| static __always_inline int | |
| pvr_fw_object_get_dma_addr(struct pvr_fw_object *fw_obj, u32 offset, dma_addr_t *dma_addr_out) | |
| { | |
| return pvr_gem_get_dma_addr(fw_obj->gem, offset, dma_addr_out); | |
| } | |
| void pvr_fw_object_get_fw_addr_offset(struct pvr_fw_object *fw_obj, u32 offset, u32 *fw_addr_out); | |
| static __always_inline void | |
| pvr_fw_object_get_fw_addr(struct pvr_fw_object *fw_obj, u32 *fw_addr_out) | |
| { | |
| pvr_fw_object_get_fw_addr_offset(fw_obj, 0, fw_addr_out); | |
| } | |
| u64 | |
| pvr_fw_obj_get_gpu_addr(struct pvr_fw_object *fw_obj); | |
| static __always_inline size_t | |
| pvr_fw_obj_get_object_size(struct pvr_fw_object *fw_obj) | |
| { | |
| return pvr_gem_object_size(fw_obj->gem); | |
| } | |
| /* Util functions defined in pvr_fw_util.c. These are intended for use in pvr_fw_<arch>.c files. */ | |
| int | |
| pvr_fw_process_elf_command_stream(struct pvr_device *pvr_dev, const u8 *fw, u8 *fw_code_ptr, | |
| u8 *fw_data_ptr, u8 *fw_core_code_ptr, u8 *fw_core_data_ptr); | |
| #endif /* PVR_FW_H */ |