// SPDX-License-Identifier: GPL-2.0-only
/*
* Qualcomm ADSP/SLPI Peripheral Image Loader for MSM8974 and MSM8996
*
* Copyright (C) 2016 Linaro Ltd
* Copyright (C) 2014 Sony Mobile Communications AB
* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/regulator/consumer.h>
#include <linux/remoteproc.h>
#include <linux/soc/qcom/mdt_loader.h>
#include <linux/soc/qcom/smem.h>
#include <linux/soc/qcom/smem_state.h>
#include "qcom_common.h"
#include "qcom_pil_info.h"
#include "qcom_q6v5.h"
#include "remoteproc_internal.h"
#define ADSP_DECRYPT_SHUTDOWN_DELAY_MS 100
struct adsp_data {
int crash_reason_smem;
const char *firmware_name;
const char *dtb_firmware_name;
int pas_id;
int dtb_pas_id;
unsigned int minidump_id;
bool auto_boot;
bool decrypt_shutdown;
char **proxy_pd_names;
const char *load_state;
const char *ssr_name;
const char *sysmon_name;
int ssctl_id;
int region_assign_idx;
};
struct qcom_adsp {
struct device *dev;
struct rproc *rproc;
struct qcom_q6v5 q6v5;
struct clk *xo;
struct clk *aggre2_clk;
struct regulator *cx_supply;
struct regulator *px_supply;
struct device *proxy_pds[3];
int proxy_pd_count;
const char *dtb_firmware_name;
int pas_id;
int dtb_pas_id;
unsigned int minidump_id;
int crash_reason_smem;
bool decrypt_shutdown;
const char *info_name;
const struct firmware *firmware;
const struct firmware *dtb_firmware;
struct completion start_done;
struct completion stop_done;
phys_addr_t mem_phys;
phys_addr_t dtb_mem_phys;
phys_addr_t mem_reloc;
phys_addr_t dtb_mem_reloc;
phys_addr_t region_assign_phys;
void *mem_region;
void *dtb_mem_region;
size_t mem_size;
size_t dtb_mem_size;
size_t region_assign_size;
int region_assign_idx;
u64 region_assign_perms;
struct qcom_rproc_glink glink_subdev;
struct qcom_rproc_subdev smd_subdev;
struct qcom_rproc_ssr ssr_subdev;
struct qcom_sysmon *sysmon;
struct qcom_scm_pas_metadata pas_metadata;
struct qcom_scm_pas_metadata dtb_pas_metadata;
};
static void adsp_segment_dump(struct rproc *rproc, struct rproc_dump_segment *segment,
void *dest, size_t offset, size_t size)
{
struct qcom_adsp *adsp = rproc->priv;
int total_offset;
total_offset = segment->da + segment->offset + offset - adsp->mem_phys;
if (total_offset < 0 || total_offset + size > adsp->mem_size) {
dev_err(adsp->dev,
"invalid copy request for segment %pad with offset %zu and size %zu)\n",
&segment->da, offset, size);
memset(dest, 0xff, size);
return;
}
memcpy_fromio(dest, adsp->mem_region + total_offset, size);
}
static void adsp_minidump(struct rproc *rproc)
{
struct qcom_adsp *adsp = rproc->priv;
if (rproc->dump_conf == RPROC_COREDUMP_DISABLED)