| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- // SPDX-License-Identifier: GPL-2.0-only OR MIT
- /* Copyright (c) 2023 Imagination Technologies Ltd. */
- #include "pvr_device.h"
- #include "pvr_fw.h"
- #include "pvr_fw_meta.h"
- #include "pvr_fw_startstop.h"
- #include "pvr_rogue_cr_defs.h"
- #include "pvr_rogue_meta.h"
- #include "pvr_vm.h"
- #include <linux/compiler.h>
- #include <linux/delay.h>
- #include <linux/ktime.h>
- #include <linux/types.h>
- #define POLL_TIMEOUT_USEC 1000000
- static void
- rogue_axi_ace_list_init(struct pvr_device *pvr_dev)
- {
- /* Setup AXI-ACE config. Set everything to outer cache. */
- u64 reg_val =
- (3U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWDOMAIN_NON_SNOOPING_SHIFT) |
- (3U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_NON_SNOOPING_SHIFT) |
- (2U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_CACHE_MAINTENANCE_SHIFT) |
- (2U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWDOMAIN_COHERENT_SHIFT) |
- (2U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_COHERENT_SHIFT) |
- (2U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWCACHE_COHERENT_SHIFT) |
- (2U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARCACHE_COHERENT_SHIFT) |
- (2U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARCACHE_CACHE_MAINTENANCE_SHIFT);
- pvr_cr_write64(pvr_dev, ROGUE_CR_AXI_ACE_LITE_CONFIGURATION, reg_val);
- }
- static void
- rogue_bif_init(struct pvr_device *pvr_dev)
- {
- dma_addr_t pc_dma_addr;
- u64 pc_addr;
- /* Acquire the address of the Kernel Page Catalogue. */
- pc_dma_addr = pvr_vm_get_page_table_root_addr(pvr_dev->kernel_vm_ctx);
- /* Write the kernel catalogue base. */
- pc_addr = ((((u64)pc_dma_addr >> ROGUE_CR_BIF_CAT_BASE0_ADDR_ALIGNSHIFT)
- << ROGUE_CR_BIF_CAT_BASE0_ADDR_SHIFT) &
- ~ROGUE_CR_BIF_CAT_BASE0_ADDR_CLRMSK);
- pvr_cr_write64(pvr_dev, BIF_CAT_BASEX(MMU_CONTEXT_MAPPING_FWPRIV),
- pc_addr);
- }
- static int
- rogue_slc_init(struct pvr_device *pvr_dev)
- {
- u16 slc_cache_line_size_bits;
- u32 reg_val;
- int err;
- /*
- * SLC Misc control.
- *
- * Note: This is a 64bit register and we set only the lower 32bits
- * leaving the top 32bits (ROGUE_CR_SLC_CTRL_MISC_SCRAMBLE_BITS)
- * unchanged from the HW default.
- */
- reg_val = (pvr_cr_read32(pvr_dev, ROGUE_CR_SLC_CTRL_MISC) &
- ROGUE_CR_SLC_CTRL_MISC_ENABLE_PSG_HAZARD_CHECK_EN) |
- ROGUE_CR_SLC_CTRL_MISC_ADDR_DECODE_MODE_PVR_HASH1;
- err = PVR_FEATURE_VALUE(pvr_dev, slc_cache_line_size_bits, &slc_cache_line_size_bits);
- if (err)
- return err;
- /* Bypass burst combiner if SLC line size is smaller than 1024 bits. */
- if (slc_cache_line_size_bits < 1024)
- reg_val |= ROGUE_CR_SLC_CTRL_MISC_BYPASS_BURST_COMBINER_EN;
- if (PVR_HAS_QUIRK(pvr_dev, 71242) && !PVR_HAS_FEATURE(pvr_dev, gpu_multicore_support))
- reg_val |= ROGUE_CR_SLC_CTRL_MISC_LAZYWB_OVERRIDE_EN;
- pvr_cr_write32(pvr_dev, ROGUE_CR_SLC_CTRL_MISC, reg_val);
- return 0;
- }
- /**
- * pvr_fw_start() - Start FW processor and boot firmware
- * @pvr_dev: Target PowerVR device.
- *
- * Returns:
- * * 0 on success, or
- * * Any error returned by rogue_slc_init().
- */
- int
- pvr_fw_start(struct pvr_device *pvr_dev)
- {
- bool has_reset2 = PVR_HAS_FEATURE(pvr_dev, xe_tpu2);
- u64 soft_reset_mask;
- int err;
- if (PVR_HAS_FEATURE(pvr_dev, pbe2_in_xe))
- soft_reset_mask = ROGUE_CR_SOFT_RESET__PBE2_XE__MASKFULL;
- else
- soft_reset_mask = ROGUE_CR_SOFT_RESET_MASKFULL;
- if (PVR_HAS_FEATURE(pvr_dev, sys_bus_secure_reset)) {
- /*
- * Disable the default sys_bus_secure protection to perform
- * minimal setup.
- */
- pvr_cr_write32(pvr_dev, ROGUE_CR_SYS_BUS_SECURE, 0);
- (void)pvr_cr_read32(pvr_dev, ROGUE_CR_SYS_BUS_SECURE); /* Fence write */
- }
- /* Set Rogue in soft-reset. */
- pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, soft_reset_mask);
- if (has_reset2)
- pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET2, ROGUE_CR_SOFT_RESET2_MASKFULL);
- /* Read soft-reset to fence previous write in order to clear the SOCIF pipeline. */
- (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET);
- if (has_reset2)
- (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET2);
- /* Take Rascal and Dust out of reset. */
- pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET,
- soft_reset_mask ^ ROGUE_CR_SOFT_RESET_RASCALDUSTS_EN);
- if (has_reset2)
- pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET2, 0);
- (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET);
- if (has_reset2)
- (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET2);
- /* Take everything out of reset but the FW processor. */
- pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, ROGUE_CR_SOFT_RESET_GARTEN_EN);
- if (has_reset2)
- pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET2, 0);
- (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET);
- if (has_reset2)
- (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET2);
- err = rogue_slc_init(pvr_dev);
- if (err)
- goto err_reset;
- /* Initialise Firmware wrapper. */
- pvr_dev->fw_dev.defs->wrapper_init(pvr_dev);
- /* We must init the AXI-ACE interface before first BIF transaction. */
- rogue_axi_ace_list_init(pvr_dev);
- if (pvr_dev->fw_dev.processor_type != PVR_FW_PROCESSOR_TYPE_MIPS) {
- /* Initialise BIF. */
- rogue_bif_init(pvr_dev);
- }
- /* Need to wait for at least 16 cycles before taking the FW processor out of reset ... */
- udelay(3);
- pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, 0x0);
- (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET);
- /* ... and afterwards. */
- udelay(3);
- return 0;
- err_reset:
- /* Put everything back into soft-reset. */
- pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, soft_reset_mask);
- return err;
- }
- /**
- * pvr_fw_stop() - Stop FW processor
- * @pvr_dev: Target PowerVR device.
- *
- * Returns:
- * * 0 on success, or
- * * Any error returned by pvr_cr_poll_reg32().
- */
- int
- pvr_fw_stop(struct pvr_device *pvr_dev)
- {
- const u32 sidekick_idle_mask = ROGUE_CR_SIDEKICK_IDLE_MASKFULL &
- ~(ROGUE_CR_SIDEKICK_IDLE_GARTEN_EN |
- ROGUE_CR_SIDEKICK_IDLE_SOCIF_EN |
- ROGUE_CR_SIDEKICK_IDLE_HOSTIF_EN);
- bool skip_garten_idle = false;
- u32 reg_value;
- int err;
- /*
- * Wait for Sidekick/Jones to signal IDLE except for the Garten Wrapper.
- * For cores with the LAYOUT_MARS feature, SIDEKICK would have been
- * powered down by the FW.
- */
- err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_SIDEKICK_IDLE, sidekick_idle_mask,
- sidekick_idle_mask, POLL_TIMEOUT_USEC);
- if (err)
- return err;
- /* Unset MTS DM association with threads. */
- pvr_cr_write32(pvr_dev, ROGUE_CR_MTS_INTCTX_THREAD0_DM_ASSOC,
- ROGUE_CR_MTS_INTCTX_THREAD0_DM_ASSOC_MASKFULL &
- ROGUE_CR_MTS_INTCTX_THREAD0_DM_ASSOC_DM_ASSOC_CLRMSK);
- pvr_cr_write32(pvr_dev, ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC,
- ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC_MASKFULL &
- ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC_DM_ASSOC_CLRMSK);
- pvr_cr_write32(pvr_dev, ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC,
- ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC_MASKFULL &
- ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC_DM_ASSOC_CLRMSK);
- pvr_cr_write32(pvr_dev, ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC,
- ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC_MASKFULL &
- ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC_DM_ASSOC_CLRMSK);
- /* Extra Idle checks. */
- err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_BIF_STATUS_MMU, 0,
- ROGUE_CR_BIF_STATUS_MMU_MASKFULL,
- POLL_TIMEOUT_USEC);
- if (err)
- return err;
- err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_BIFPM_STATUS_MMU, 0,
- ROGUE_CR_BIFPM_STATUS_MMU_MASKFULL,
- POLL_TIMEOUT_USEC);
- if (err)
- return err;
- if (!PVR_HAS_FEATURE(pvr_dev, xt_top_infrastructure)) {
- err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_BIF_READS_EXT_STATUS, 0,
- ROGUE_CR_BIF_READS_EXT_STATUS_MASKFULL,
- POLL_TIMEOUT_USEC);
- if (err)
- return err;
- }
- err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_BIFPM_READS_EXT_STATUS, 0,
- ROGUE_CR_BIFPM_READS_EXT_STATUS_MASKFULL,
- POLL_TIMEOUT_USEC);
- if (err)
- return err;
- err = pvr_cr_poll_reg64(pvr_dev, ROGUE_CR_SLC_STATUS1, 0,
- ROGUE_CR_SLC_STATUS1_MASKFULL,
- POLL_TIMEOUT_USEC);
- if (err)
- return err;
- /*
- * Wait for SLC to signal IDLE.
- * For cores with the LAYOUT_MARS feature, SLC would have been powered
- * down by the FW.
- */
- err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_SLC_IDLE,
- ROGUE_CR_SLC_IDLE_MASKFULL,
- ROGUE_CR_SLC_IDLE_MASKFULL, POLL_TIMEOUT_USEC);
- if (err)
- return err;
- /*
- * Wait for Sidekick/Jones to signal IDLE except for the Garten Wrapper.
- * For cores with the LAYOUT_MARS feature, SIDEKICK would have been powered
- * down by the FW.
- */
- err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_SIDEKICK_IDLE, sidekick_idle_mask,
- sidekick_idle_mask, POLL_TIMEOUT_USEC);
- if (err)
- return err;
- if (pvr_dev->fw_dev.processor_type == PVR_FW_PROCESSOR_TYPE_META) {
- err = pvr_meta_cr_read32(pvr_dev, META_CR_TxVECINT_BHALT, ®_value);
- if (err)
- return err;
- /*
- * Wait for Sidekick/Jones to signal IDLE including the Garten
- * Wrapper if there is no debugger attached (TxVECINT_BHALT =
- * 0x0).
- */
- if (reg_value)
- skip_garten_idle = true;
- }
- if (!skip_garten_idle) {
- err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_SIDEKICK_IDLE,
- ROGUE_CR_SIDEKICK_IDLE_GARTEN_EN,
- ROGUE_CR_SIDEKICK_IDLE_GARTEN_EN,
- POLL_TIMEOUT_USEC);
- if (err)
- return err;
- }
- if (PVR_HAS_FEATURE(pvr_dev, pbe2_in_xe))
- pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET,
- ROGUE_CR_SOFT_RESET__PBE2_XE__MASKFULL);
- else
- pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, ROGUE_CR_SOFT_RESET_MASKFULL);
- return 0;
- }
|