mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-24 10:11:26 +03:00
drm/tegra: nvhost support for t264
- VIC RISC-V EB boot support - Programming sequence modification needed for Thor - Reloc block linear addressing not needed for t264 Bug 4132685 Signed-off-by: Santosh BS <santoshb@nvidia.com> Change-Id: I8ad47cce31cfd06020e33d3457a0d674a11e4d49
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include <linux/of.h>
|
||||
|
||||
#include "riscv.h"
|
||||
#include "falcon.h"
|
||||
|
||||
#define RISCV_CPUCTL 0x4388
|
||||
#define RISCV_CPUCTL_STARTCPU_TRUE (1 << 0)
|
||||
@@ -31,6 +32,13 @@
|
||||
#define RISCV_BCR_DMAADDR_FMCDATA_HI 0x4684
|
||||
#define RISCV_BCR_DMACFG_SEC 0x4694
|
||||
#define RISCV_BCR_DMACFG_SEC_GSCID(v) ((v) << 16)
|
||||
#define RISCV_BOOT_VECTOR_LO 0x1780
|
||||
#define RISCV_BOOT_VECTOR_HI 0x1784
|
||||
|
||||
enum riscv_memory {
|
||||
RISCV_MEMORY_IMEM,
|
||||
RISCV_MEMORY_DATA,
|
||||
};
|
||||
|
||||
static void riscv_writel(struct tegra_drm_riscv *riscv, u32 value, u32 offset)
|
||||
{
|
||||
@@ -100,3 +108,141 @@ int tegra_drm_riscv_boot_bootrom(struct tegra_drm_riscv *riscv, phys_addr_t imag
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tegra_drm_riscv_read_firmware(struct tegra_drm_riscv *riscv, const char *name)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* request_firmware prints error if it fails */
|
||||
err = request_firmware(&riscv->firmware.firmware, name, riscv->dev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
riscv->firmware.size = riscv->firmware.firmware->size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tegra_drm_riscv_load_firmware(struct tegra_drm_riscv *riscv)
|
||||
{
|
||||
const struct firmware *firmware = riscv->firmware.firmware;
|
||||
u32 *virt = riscv->firmware.virt;
|
||||
size_t i;
|
||||
|
||||
/* Copy firmware image into local area taking into account endianness */
|
||||
for (i = 0; i < firmware->size / sizeof(u32); i++)
|
||||
virt[i] = le32_to_cpu(((__le32 *)firmware->data)[i]);
|
||||
|
||||
release_firmware(firmware);
|
||||
riscv->firmware.firmware = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tegra_drm_riscv_init(struct tegra_drm_riscv *riscv)
|
||||
{
|
||||
riscv->firmware.virt = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tegra_drm_riscv_exit(struct tegra_drm_riscv *riscv)
|
||||
{
|
||||
if (riscv->firmware.firmware)
|
||||
release_firmware(riscv->firmware.firmware);
|
||||
}
|
||||
|
||||
static int tegra_drm_riscv_dma_wait_idle(struct tegra_drm_riscv *riscv)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
return readl_poll_timeout(riscv->regs + FALCON_DMATRFCMD, value,
|
||||
(value & FALCON_DMATRFCMD_IDLE), 10, 100000);
|
||||
}
|
||||
|
||||
static int tegra_drm_riscv_copy_chunk(struct tegra_drm_riscv *riscv,
|
||||
phys_addr_t base,
|
||||
unsigned long offset,
|
||||
enum riscv_memory target)
|
||||
{
|
||||
u32 cmd = FALCON_DMATRFCMD_SIZE_256B;
|
||||
|
||||
if (target == RISCV_MEMORY_IMEM)
|
||||
cmd |= FALCON_DMATRFCMD_IMEM;
|
||||
|
||||
/*
|
||||
* Use second DMA context (i.e. the one for firmware). Strictly
|
||||
* speaking, at this point both DMA contexts point to the firmware
|
||||
* stream ID, but this register's value will be reused by the firmware
|
||||
* for later DMA transactions, so we need to use the correct value.
|
||||
*/
|
||||
cmd |= FALCON_DMATRFCMD_DMACTX(1);
|
||||
|
||||
riscv_writel(riscv, offset, FALCON_DMATRFMOFFS);
|
||||
riscv_writel(riscv, base, FALCON_DMATRFFBOFFS);
|
||||
riscv_writel(riscv, cmd, FALCON_DMATRFCMD);
|
||||
|
||||
return tegra_drm_riscv_dma_wait_idle(riscv);
|
||||
}
|
||||
|
||||
int tegra_drm_riscv_boot_external(struct tegra_drm_riscv *riscv)
|
||||
{
|
||||
unsigned long offset;
|
||||
u32 value;
|
||||
int err;
|
||||
|
||||
if (!riscv->firmware.virt)
|
||||
return -EINVAL;
|
||||
|
||||
err = readl_poll_timeout(riscv->regs + FALCON_DMACTL, value,
|
||||
(value & (FALCON_DMACTL_IMEM_SCRUBBING |
|
||||
FALCON_DMACTL_DMEM_SCRUBBING)) == 0,
|
||||
10, 10000);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
riscv_writel(riscv, 0, FALCON_DMACTL);
|
||||
|
||||
/* setup the address of the binary data so Falcon can access it later */
|
||||
riscv_writel(riscv, riscv->firmware.iova >> 8, FALCON_DMATRFBASE);
|
||||
|
||||
/* copy the data segment into riscv internal memory */
|
||||
for (offset = 0; offset < riscv->os_desc.data_size; offset += 256) {
|
||||
err = tegra_drm_riscv_copy_chunk(riscv,
|
||||
riscv->os_desc.data_offset + offset,
|
||||
offset, RISCV_MEMORY_DATA);
|
||||
}
|
||||
|
||||
/* copy the code segment into riscv internal memory */
|
||||
for (offset = 0; offset < riscv->os_desc.code_size; offset += 256) {
|
||||
err = tegra_drm_riscv_copy_chunk(riscv,
|
||||
riscv->os_desc.code_offset + offset,
|
||||
offset, RISCV_MEMORY_IMEM);
|
||||
}
|
||||
|
||||
/* setup riscv interrupts */
|
||||
riscv_writel(riscv, FALCON_IRQMSET_EXT(0xff) |
|
||||
FALCON_IRQMSET_SWGEN1 |
|
||||
FALCON_IRQMSET_SWGEN0 |
|
||||
FALCON_IRQMSET_EXTERR |
|
||||
FALCON_IRQMSET_HALT |
|
||||
FALCON_IRQMSET_WDTMR,
|
||||
FALCON_IRQMSET);
|
||||
riscv_writel(riscv, FALCON_IRQDEST_EXT(0xff) |
|
||||
FALCON_IRQDEST_SWGEN1 |
|
||||
FALCON_IRQDEST_SWGEN0 |
|
||||
FALCON_IRQDEST_EXTERR |
|
||||
FALCON_IRQDEST_HALT,
|
||||
FALCON_IRQDEST);
|
||||
|
||||
/* enable interface */
|
||||
riscv_writel(riscv, FALCON_ITFEN_MTHDEN |
|
||||
FALCON_ITFEN_CTXEN,
|
||||
FALCON_ITFEN);
|
||||
|
||||
/* boot riscv */
|
||||
riscv_writel(riscv, 0x00000000, RISCV_BOOT_VECTOR_HI);
|
||||
riscv_writel(riscv, 0x00100000, RISCV_BOOT_VECTOR_LO);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user