cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

acp-loader.c (5757B)


      1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
      2//
      3// This file is provided under a dual BSD/GPLv2 license. When using or
      4// redistributing this file, you may do so under either license.
      5//
      6// Copyright(c) 2021 Advanced Micro Devices, Inc.
      7//
      8// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
      9
     10/*
     11 * Hardware interface for ACP DSP Firmware binaries loader
     12 */
     13
     14#include <linux/firmware.h>
     15#include <linux/module.h>
     16#include <linux/pci.h>
     17
     18#include "../ops.h"
     19#include "acp-dsp-offset.h"
     20#include "acp.h"
     21
     22#define FW_BIN		0
     23#define FW_DATA_BIN	1
     24
     25#define FW_BIN_PTE_OFFSET	0x00
     26#define FW_DATA_BIN_PTE_OFFSET	0x08
     27
     28#define ACP_DSP_RUN	0x00
     29
     30int acp_dsp_block_read(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type,
     31		       u32 offset, void *dest, size_t size)
     32{
     33	switch (blk_type) {
     34	case SOF_FW_BLK_TYPE_SRAM:
     35		offset = offset - ACP_SCRATCH_MEMORY_ADDRESS;
     36		memcpy_from_scratch(sdev, offset, dest, size);
     37		break;
     38	default:
     39		dev_err(sdev->dev, "bad blk type 0x%x\n", blk_type);
     40		return -EINVAL;
     41	}
     42
     43	return 0;
     44}
     45EXPORT_SYMBOL_NS(acp_dsp_block_read, SND_SOC_SOF_AMD_COMMON);
     46
     47int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type,
     48			u32 offset, void *src, size_t size)
     49{
     50	struct snd_sof_pdata *plat_data = sdev->pdata;
     51	struct pci_dev *pci = to_pci_dev(sdev->dev);
     52	struct acp_dev_data *adata;
     53	void *dest;
     54	u32 dma_size, page_count;
     55	unsigned int size_fw;
     56
     57	adata = sdev->pdata->hw_pdata;
     58
     59	switch (blk_type) {
     60	case SOF_FW_BLK_TYPE_IRAM:
     61		if (!adata->bin_buf) {
     62			size_fw = plat_data->fw->size;
     63			page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT;
     64			dma_size = page_count * ACP_PAGE_SIZE;
     65			adata->bin_buf = dma_alloc_coherent(&pci->dev, dma_size,
     66							    &adata->sha_dma_addr,
     67							    GFP_ATOMIC);
     68			if (!adata->bin_buf)
     69				return -ENOMEM;
     70		}
     71		adata->fw_bin_size = size + offset;
     72		dest = adata->bin_buf + offset;
     73		break;
     74	case SOF_FW_BLK_TYPE_DRAM:
     75		if (!adata->data_buf) {
     76			adata->data_buf = dma_alloc_coherent(&pci->dev,
     77							     ACP_DEFAULT_DRAM_LENGTH,
     78							     &adata->dma_addr,
     79							     GFP_ATOMIC);
     80			if (!adata->data_buf)
     81				return -ENOMEM;
     82		}
     83		dest = adata->data_buf + offset;
     84		adata->fw_data_bin_size = size + offset;
     85		break;
     86	case SOF_FW_BLK_TYPE_SRAM:
     87		offset = offset - ACP_SCRATCH_MEMORY_ADDRESS;
     88		memcpy_to_scratch(sdev, offset, src, size);
     89		return 0;
     90	default:
     91		dev_err(sdev->dev, "bad blk type 0x%x\n", blk_type);
     92		return -EINVAL;
     93	}
     94
     95	memcpy(dest, src, size);
     96	return 0;
     97}
     98EXPORT_SYMBOL_NS(acp_dsp_block_write, SND_SOC_SOF_AMD_COMMON);
     99
    100int acp_get_bar_index(struct snd_sof_dev *sdev, u32 type)
    101{
    102	return type;
    103}
    104EXPORT_SYMBOL_NS(acp_get_bar_index, SND_SOC_SOF_AMD_COMMON);
    105
    106static void configure_pte_for_fw_loading(int type, int num_pages, struct acp_dev_data *adata)
    107{
    108	struct snd_sof_dev *sdev;
    109	unsigned int low, high;
    110	dma_addr_t addr;
    111	u16 page_idx;
    112	u32 offset;
    113
    114	sdev = adata->dev;
    115
    116	switch (type) {
    117	case FW_BIN:
    118		offset = FW_BIN_PTE_OFFSET;
    119		addr = adata->sha_dma_addr;
    120		break;
    121	case FW_DATA_BIN:
    122		offset = adata->fw_bin_page_count * 8;
    123		addr = adata->dma_addr;
    124		break;
    125	default:
    126		dev_err(sdev->dev, "Invalid data type %x\n", type);
    127		return;
    128	}
    129
    130	/* Group Enable */
    131	snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACPAXI2AXI_ATU_BASE_ADDR_GRP_1,
    132			  ACP_SRAM_PTE_OFFSET | BIT(31));
    133	snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1,
    134			  PAGE_SIZE_4K_ENABLE);
    135
    136	for (page_idx = 0; page_idx < num_pages; page_idx++) {
    137		low = lower_32_bits(addr);
    138		high = upper_32_bits(addr);
    139		snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + offset, low);
    140		high |= BIT(31);
    141		snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + offset + 4, high);
    142		offset += 8;
    143		addr += PAGE_SIZE;
    144	}
    145
    146	/* Flush ATU Cache after PTE Update */
    147	snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACPAXI2AXI_ATU_CTRL, ACP_ATU_CACHE_INVALID);
    148}
    149
    150/* pre fw run operations */
    151int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev)
    152{
    153	struct pci_dev *pci = to_pci_dev(sdev->dev);
    154	struct snd_sof_pdata *plat_data = sdev->pdata;
    155	struct acp_dev_data *adata;
    156	unsigned int src_addr, size_fw;
    157	u32 page_count, dma_size;
    158	int ret;
    159
    160	adata = sdev->pdata->hw_pdata;
    161	size_fw = adata->fw_bin_size;
    162
    163	page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT;
    164	adata->fw_bin_page_count = page_count;
    165
    166	configure_pte_for_fw_loading(FW_BIN, page_count, adata);
    167	ret = configure_and_run_sha_dma(adata, adata->bin_buf, ACP_SYSTEM_MEMORY_WINDOW,
    168					ACP_IRAM_BASE_ADDRESS, size_fw);
    169	if (ret < 0) {
    170		dev_err(sdev->dev, "SHA DMA transfer failed status: %d\n", ret);
    171		return ret;
    172	}
    173	configure_pte_for_fw_loading(FW_DATA_BIN, ACP_DRAM_PAGE_COUNT, adata);
    174
    175	src_addr = ACP_SYSTEM_MEMORY_WINDOW + page_count * ACP_PAGE_SIZE;
    176	ret = configure_and_run_dma(adata, src_addr, ACP_DATA_RAM_BASE_ADDRESS,
    177				    adata->fw_data_bin_size);
    178	if (ret < 0) {
    179		dev_err(sdev->dev, "acp dma configuration failed: %d\n", ret);
    180		return ret;
    181	}
    182
    183	ret = acp_dma_status(adata, 0);
    184	if (ret < 0)
    185		dev_err(sdev->dev, "acp dma transfer status: %d\n", ret);
    186
    187	/* Free memory once DMA is complete */
    188	dma_size =  (PAGE_ALIGN(plat_data->fw->size) >> PAGE_SHIFT) * ACP_PAGE_SIZE;
    189	dma_free_coherent(&pci->dev, dma_size, adata->bin_buf, adata->sha_dma_addr);
    190	dma_free_coherent(&pci->dev, ACP_DEFAULT_DRAM_LENGTH, adata->data_buf, adata->dma_addr);
    191	adata->bin_buf = NULL;
    192	adata->data_buf = NULL;
    193
    194	return ret;
    195}
    196EXPORT_SYMBOL_NS(acp_dsp_pre_fw_run, SND_SOC_SOF_AMD_COMMON);
    197
    198int acp_sof_dsp_run(struct snd_sof_dev *sdev)
    199{
    200	int val;
    201
    202	snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DSP0_RUNSTALL, ACP_DSP_RUN);
    203	val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DSP0_RUNSTALL);
    204	dev_dbg(sdev->dev, "ACP_DSP0_RUNSTALL : 0x%0x\n", val);
    205
    206	return 0;
    207}
    208EXPORT_SYMBOL_NS(acp_sof_dsp_run, SND_SOC_SOF_AMD_COMMON);