You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'rproc-v4.10' of git://github.com/andersson/remoteproc
Pull remoteproc updates from Bjorn Andersson: - introduce remoteproc "subdevice" support, which allows remoteproc driver to associate devices to the "running" state of the remoteproc, allowing devices to be probed and removed as the remote processor is booted, shut down or recovering from a crash. - handling of virtio device resources was improved, vring memory is now allocated as part of other memory allocation. This ensures that all vrings for all virtio devices are allocated before we boot the remote processor. - the debugfs mechanism for starting and stopping remoteproc instances was replaced with a sysfs interface, also providing a mechanism for specifying firmware to use by the instance. This allows user space to load and boot use case specific firmware on remote processors. - new drivers for the ST Slimcore and Qualcomm Hexagon DSP as well as removal of the unused StE modem loader. - finally support for crash recovery in the Qualcomm Wirelss subsystem (used for WiFi/BT/FM on a number of platforms) and a number of bug fixes and cleanups * tag 'rproc-v4.10' of git://github.com/andersson/remoteproc: (49 commits) remoteproc: qcom_adsp_pil: select qcom_scm remoteproc: Drop wait in __rproc_boot() remoteproc/ste: Delete unused driver remoteproc: Remove "experimental" warning remoteproc: qcom_adsp_pil: select qcom_scm dt-binding: soc: qcom: smd: Add label property remoteproc: qcom: mdt_loader: add include for sizes remoteproc: Update last rproc_put users to rproc_free remoteproc: qcom: adsp: Add missing MODULE_DEVICE_TABLE remoteproc: wcnss-pil: add QCOM_SMD dependency dmaengine: st_fdma: Revert: "Revert: Update st_fdma to 'depends on REMOTEPROC'" remoteproc: Add support for xo clock remoteproc: adsp-pil: fix recursive dependency remoteproc: Introduce Qualcomm ADSP PIL dt-binding: remoteproc: Introduce ADSP loader binding remoteproc: qcom_wcnss: Fix circular module dependency remoteproc: Merge table_ptr and cached_table pointers remoteproc: Remove custom vdev handler list remoteproc: Update max_notifyid as we allocate vrings remoteproc: Decouple vdev resources and devices ...
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
What: /sys/class/remoteproc/.../firmware
|
||||
Date: October 2016
|
||||
Contact: Matt Redfearn <matt.redfearn@imgtec.com>
|
||||
Description: Remote processor firmware
|
||||
|
||||
Reports the name of the firmware currently loaded to the
|
||||
remote processor.
|
||||
|
||||
To change the running firmware, ensure the remote processor is
|
||||
stopped (using /sys/class/remoteproc/.../state) and write a new filename.
|
||||
|
||||
What: /sys/class/remoteproc/.../state
|
||||
Date: October 2016
|
||||
Contact: Matt Redfearn <matt.redfearn@imgtec.com>
|
||||
Description: Remote processor state
|
||||
|
||||
Reports the state of the remote processor, which will be one of:
|
||||
|
||||
"offline"
|
||||
"suspended"
|
||||
"running"
|
||||
"crashed"
|
||||
"invalid"
|
||||
|
||||
"offline" means the remote processor is powered off.
|
||||
|
||||
"suspended" means that the remote processor is suspended and
|
||||
must be woken to receive messages.
|
||||
|
||||
"running" is the normal state of an available remote processor
|
||||
|
||||
"crashed" indicates that a problem/crash has been detected on
|
||||
the remote processor.
|
||||
|
||||
"invalid" is returned if the remote processor is in an
|
||||
unknown state.
|
||||
|
||||
Writing this file controls the state of the remote processor.
|
||||
The following states can be written:
|
||||
|
||||
"start"
|
||||
"stop"
|
||||
|
||||
Writing "start" will attempt to start the processor running the
|
||||
firmware indicated by, or written to,
|
||||
/sys/class/remoteproc/.../firmware. The remote processor should
|
||||
transition to "running" state.
|
||||
|
||||
Writing "stop" will attempt to halt the remote processor and
|
||||
return it to the "offline" state.
|
||||
@@ -0,0 +1,87 @@
|
||||
* STMicroelectronics Flexible Direct Memory Access Device Tree bindings
|
||||
|
||||
The FDMA is a general-purpose direct memory access controller capable of
|
||||
supporting 16 independent DMA channels. It accepts up to 32 DMA requests.
|
||||
The FDMA is based on a Slim processor which requires a firmware.
|
||||
|
||||
* FDMA Controller
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be one of
|
||||
- st,stih407-fdma-mpe31-11, "st,slim-rproc";
|
||||
- st,stih407-fdma-mpe31-12, "st,slim-rproc";
|
||||
- st,stih407-fdma-mpe31-13, "st,slim-rproc";
|
||||
- reg : Should contain an entry for each name in reg-names
|
||||
- reg-names : Must contain "slimcore", "dmem", "peripherals", "imem" entries
|
||||
- interrupts : Should contain one interrupt shared by all channels
|
||||
- dma-channels : Number of channels supported by the controller
|
||||
- #dma-cells : Must be <3>. See DMA client section below
|
||||
- clocks : Must contain an entry for each clock
|
||||
See: Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
fdma0: dma-controller@8e20000 {
|
||||
compatible = "st,stih407-fdma-mpe31-11", "st,slim-rproc";
|
||||
reg = <0x8e20000 0x8000>,
|
||||
<0x8e30000 0x3000>,
|
||||
<0x8e37000 0x1000>,
|
||||
<0x8e38000 0x8000>;
|
||||
reg-names = "slimcore", "dmem", "peripherals", "imem";
|
||||
clocks = <&clk_s_c0_flexgen CLK_FDMA>,
|
||||
<&clk_s_c0_flexgen CLK_EXT2F_A9>,
|
||||
<&clk_s_c0_flexgen CLK_EXT2F_A9>,
|
||||
<&clk_s_c0_flexgen CLK_EXT2F_A9>;
|
||||
interrupts = <GIC_SPI 5 IRQ_TYPE_NONE>;
|
||||
dma-channels = <16>;
|
||||
#dma-cells = <3>;
|
||||
};
|
||||
|
||||
* DMA client
|
||||
|
||||
Required properties:
|
||||
- dmas: Comma separated list of dma channel requests
|
||||
- dma-names: Names of the aforementioned requested channels
|
||||
|
||||
Each dmas request consists of 4 cells:
|
||||
1. A phandle pointing to the FDMA controller
|
||||
2. The request line number
|
||||
3. A 32bit mask specifying (see include/linux/platform_data/dma-st-fdma.h)
|
||||
-bit 2-0: Holdoff value, dreq will be masked for
|
||||
0x0: 0-0.5us
|
||||
0x1: 0.5-1us
|
||||
0x2: 1-1.5us
|
||||
-bit 17: data swap
|
||||
0x0: disabled
|
||||
0x1: enabled
|
||||
-bit 21: Increment Address
|
||||
0x0: no address increment between transfers
|
||||
0x1: increment address between transfers
|
||||
-bit 22: 2 STBus Initiator Coprocessor interface
|
||||
0x0: high priority port
|
||||
0x1: low priority port
|
||||
4. transfers type
|
||||
0 free running
|
||||
1 paced
|
||||
|
||||
Example:
|
||||
|
||||
sti_uni_player2: sti-uni-player@2 {
|
||||
compatible = "st,sti-uni-player";
|
||||
status = "disabled";
|
||||
#sound-dai-cells = <0>;
|
||||
st,syscfg = <&syscfg_core>;
|
||||
clocks = <&clk_s_d0_flexgen CLK_PCM_2>;
|
||||
assigned-clocks = <&clk_s_d0_flexgen CLK_PCM_2>;
|
||||
assigned-clock-parents = <&clk_s_d0_quadfs 2>;
|
||||
assigned-clock-rates = <50000000>;
|
||||
reg = <0x8D82000 0x158>;
|
||||
interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>;
|
||||
dmas = <&fdma0 4 0 1>;
|
||||
dai-name = "Uni Player #1 (DAC)";
|
||||
dma-names = "tx";
|
||||
st,uniperiph-id = <2>;
|
||||
st,version = <5>;
|
||||
st,mode = "PCM";
|
||||
};
|
||||
@@ -0,0 +1,98 @@
|
||||
Qualcomm ADSP Peripheral Image Loader
|
||||
|
||||
This document defines the binding for a component that loads and boots firmware
|
||||
on the Qualcomm ADSP Hexagon core.
|
||||
|
||||
- compatible:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: must be one of:
|
||||
"qcom,msm8974-adsp-pil"
|
||||
"qcom,msm8996-adsp-pil"
|
||||
|
||||
- interrupts-extended:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: must list the watchdog, fatal IRQs ready, handover and
|
||||
stop-ack IRQs
|
||||
|
||||
- interrupt-names:
|
||||
Usage: required
|
||||
Value type: <stringlist>
|
||||
Definition: must be "wdog", "fatal", "ready", "handover", "stop-ack"
|
||||
|
||||
- clocks:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: reference to the xo clock to be held on behalf of the
|
||||
booting Hexagon core
|
||||
|
||||
- clock-names:
|
||||
Usage: required
|
||||
Value type: <stringlist>
|
||||
Definition: must be "xo"
|
||||
|
||||
- cx-supply:
|
||||
Usage: required
|
||||
Value type: <phandle>
|
||||
Definition: reference to the regulator to be held on behalf of the
|
||||
booting Hexagon core
|
||||
|
||||
- memory-region:
|
||||
Usage: required
|
||||
Value type: <phandle>
|
||||
Definition: reference to the reserved-memory for the ADSP
|
||||
|
||||
- qcom,smem-states:
|
||||
Usage: required
|
||||
Value type: <phandle>
|
||||
Definition: reference to the smem state for requesting the ADSP to
|
||||
shut down
|
||||
|
||||
- qcom,smem-state-names:
|
||||
Usage: required
|
||||
Value type: <stringlist>
|
||||
Definition: must be "stop"
|
||||
|
||||
|
||||
= SUBNODES
|
||||
The adsp node may have an subnode named "smd-edge" that describes the SMD edge,
|
||||
channels and devices related to the ADSP. See ../soc/qcom/qcom,smd.txt for
|
||||
details on how to describe the SMD edge.
|
||||
|
||||
|
||||
= EXAMPLE
|
||||
The following example describes the resources needed to boot control the
|
||||
ADSP, as it is found on MSM8974 boards.
|
||||
|
||||
adsp {
|
||||
compatible = "qcom,msm8974-adsp-pil";
|
||||
|
||||
interrupts-extended = <&intc 0 162 IRQ_TYPE_EDGE_RISING>,
|
||||
<&adsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
|
||||
<&adsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
|
||||
<&adsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
|
||||
<&adsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-names = "wdog",
|
||||
"fatal",
|
||||
"ready",
|
||||
"handover",
|
||||
"stop-ack";
|
||||
|
||||
clocks = <&rpmcc RPM_CXO_CLK>;
|
||||
clock-names = "xo";
|
||||
|
||||
cx-supply = <&pm8841_s2>;
|
||||
|
||||
memory-region = <&adsp_region>;
|
||||
|
||||
qcom,smem-states = <&adsp_smp2p_out 0>;
|
||||
qcom,smem-state-names = "stop";
|
||||
|
||||
smd-edge {
|
||||
interrupts = <0 156 IRQ_TYPE_EDGE_RISING>;
|
||||
|
||||
qcom,ipc = <&apcs 8 8>;
|
||||
qcom,smd-edge = <1>;
|
||||
};
|
||||
};
|
||||
@@ -60,8 +60,8 @@ on the Qualcomm WCNSS core.
|
||||
see ../reserved-memory/reserved-memory.txt
|
||||
|
||||
= SUBNODES
|
||||
A single subnode of the WCNSS PIL describes the attached rf module and its
|
||||
resource dependencies.
|
||||
A required subnode of the WCNSS PIL is used to describe the attached rf module
|
||||
and its resource dependencies. It is described by the following properties:
|
||||
|
||||
- compatible:
|
||||
Usage: required
|
||||
@@ -90,6 +90,11 @@ resource dependencies.
|
||||
Definition: reference to the regulators to be held on behalf of the
|
||||
booting of the WCNSS core
|
||||
|
||||
|
||||
The wcnss node can also have an subnode named "smd-edge" that describes the SMD
|
||||
edge, channels and devices related to the WCNSS.
|
||||
See ../soc/qcom/qcom,smd.txt for details on how to describe the SMD edge.
|
||||
|
||||
= EXAMPLE
|
||||
The following example describes the resources needed to boot control the WCNSS,
|
||||
with attached WCN3680, as it is commonly found on MSM8974 boards.
|
||||
@@ -129,4 +134,25 @@ pronto@fb204000 {
|
||||
vddpa-supply = <&pm8941_l19>;
|
||||
vdddig-supply = <&pm8941_s3>;
|
||||
};
|
||||
|
||||
smd-edge {
|
||||
interrupts = <0 142 1>;
|
||||
|
||||
qcom,ipc = <&apcs 8 17>;
|
||||
qcom,smd-edge = <6>;
|
||||
qcom,remote-pid = <4>;
|
||||
|
||||
label = "pronto";
|
||||
|
||||
wcnss {
|
||||
compatible = "qcom,wcnss";
|
||||
qcom,smd-channels = "WCNSS_CTRL";
|
||||
|
||||
qcom,mmio = <&pronto>;
|
||||
|
||||
bt {
|
||||
compatible = "qcom,wcnss-bt";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -43,6 +43,13 @@ The edge is described by the following properties:
|
||||
Definition: the identifier for the remote processor as known by the rest
|
||||
of the system.
|
||||
|
||||
- label:
|
||||
Usage: optional
|
||||
Value type: <string>
|
||||
Definition: name of the edge, used for debugging and identification
|
||||
purposes. The node name will be used if this is not
|
||||
present.
|
||||
|
||||
= SMD DEVICES
|
||||
|
||||
In turn, subnodes of the "edges" represent devices tied to SMD channels on that
|
||||
|
||||
@@ -1792,6 +1792,7 @@ F: drivers/char/hw_random/st-rng.c
|
||||
F: drivers/clocksource/arm_global_timer.c
|
||||
F: drivers/clocksource/clksrc_st_lpc.c
|
||||
F: drivers/cpufreq/sti-cpufreq.c
|
||||
F: drivers/dma/st_fdma*
|
||||
F: drivers/i2c/busses/i2c-st.c
|
||||
F: drivers/media/rc/st_rc.c
|
||||
F: drivers/media/platform/sti/c8sectpfe/
|
||||
@@ -1802,6 +1803,7 @@ F: drivers/phy/phy-stih407-usb.c
|
||||
F: drivers/phy/phy-stih41x-usb.c
|
||||
F: drivers/pinctrl/pinctrl-st.c
|
||||
F: drivers/remoteproc/st_remoteproc.c
|
||||
F: drivers/remoteproc/st_slim_rproc.c
|
||||
F: drivers/reset/sti/
|
||||
F: drivers/rtc/rtc-st-lpc.c
|
||||
F: drivers/tty/serial/st-asc.c
|
||||
@@ -1810,6 +1812,7 @@ F: drivers/usb/host/ehci-st.c
|
||||
F: drivers/usb/host/ohci-st.c
|
||||
F: drivers/watchdog/st_lpc_wdt.c
|
||||
F: drivers/ata/ahci_st.c
|
||||
F: include/linux/remoteproc/st_slim_rproc.h
|
||||
|
||||
ARM/STM32 ARCHITECTURE
|
||||
M: Maxime Coquelin <mcoquelin.stm32@gmail.com>
|
||||
|
||||
@@ -649,6 +649,9 @@ CONFIG_SND_SOC_AK4642=m
|
||||
CONFIG_SND_SOC_SGTL5000=m
|
||||
CONFIG_SND_SOC_SPDIF=m
|
||||
CONFIG_SND_SOC_WM8978=m
|
||||
CONFIG_SND_SOC_STI=m
|
||||
CONFIG_SND_SOC_STI_SAS=m
|
||||
CONFIG_SND_SIMPLE_CARD=m
|
||||
CONFIG_USB=y
|
||||
CONFIG_USB_XHCI_HCD=y
|
||||
CONFIG_USB_XHCI_MVEBU=y
|
||||
@@ -790,6 +793,7 @@ CONFIG_DMA_OMAP=y
|
||||
CONFIG_QCOM_BAM_DMA=y
|
||||
CONFIG_XILINX_DMA=y
|
||||
CONFIG_DMA_SUN6I=y
|
||||
CONFIG_ST_FDMA=m
|
||||
CONFIG_STAGING=y
|
||||
CONFIG_SENSORS_ISL29018=y
|
||||
CONFIG_SENSORS_ISL29028=y
|
||||
@@ -823,6 +827,8 @@ CONFIG_HWSPINLOCK_QCOM=y
|
||||
CONFIG_ROCKCHIP_IOMMU=y
|
||||
CONFIG_TEGRA_IOMMU_GART=y
|
||||
CONFIG_TEGRA_IOMMU_SMMU=y
|
||||
CONFIG_REMOTEPROC=m
|
||||
CONFIG_ST_REMOTEPROC=m
|
||||
CONFIG_PM_DEVFREQ=y
|
||||
CONFIG_ARM_TEGRA_DEVFREQ=m
|
||||
CONFIG_MEMORY=y
|
||||
|
||||
@@ -436,6 +436,20 @@ config STE_DMA40
|
||||
help
|
||||
Support for ST-Ericsson DMA40 controller
|
||||
|
||||
config ST_FDMA
|
||||
tristate "ST FDMA dmaengine support"
|
||||
depends on ARCH_STI
|
||||
depends on REMOTEPROC
|
||||
select ST_SLIM_REMOTEPROC
|
||||
select DMA_ENGINE
|
||||
select DMA_VIRTUAL_CHANNELS
|
||||
help
|
||||
Enable support for ST FDMA controller.
|
||||
It supports 16 independent DMA channels, accepts up to 32 DMA requests
|
||||
|
||||
Say Y here if you have such a chipset.
|
||||
If unsure, say N.
|
||||
|
||||
config STM32_DMA
|
||||
bool "STMicroelectronics STM32 DMA support"
|
||||
depends on ARCH_STM32 || COMPILE_TEST
|
||||
|
||||
@@ -67,6 +67,7 @@ obj-$(CONFIG_TI_DMA_CROSSBAR) += ti-dma-crossbar.o
|
||||
obj-$(CONFIG_TI_EDMA) += edma.o
|
||||
obj-$(CONFIG_XGENE_DMA) += xgene-dma.o
|
||||
obj-$(CONFIG_ZX_DMA) += zx296702_dma.o
|
||||
obj-$(CONFIG_ST_FDMA) += st_fdma.o
|
||||
|
||||
obj-y += qcom/
|
||||
obj-y += xilinx/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* DMA driver header for STMicroelectronics STi FDMA controller
|
||||
*
|
||||
* Copyright (C) 2014 STMicroelectronics
|
||||
*
|
||||
* Author: Ludovic Barre <Ludovic.barre@st.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
#ifndef __DMA_ST_FDMA_H
|
||||
#define __DMA_ST_FDMA_H
|
||||
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/remoteproc/st_slim_rproc.h>
|
||||
#include "virt-dma.h"
|
||||
|
||||
#define ST_FDMA_NR_DREQS 32
|
||||
#define FW_NAME_SIZE 30
|
||||
#define DRIVER_NAME "st-fdma"
|
||||
|
||||
/**
|
||||
* struct st_fdma_generic_node - Free running/paced generic node
|
||||
*
|
||||
* @length: Length in bytes of a line in a 2D mem to mem
|
||||
* @sstride: Stride, in bytes, between source lines in a 2D data move
|
||||
* @dstride: Stride, in bytes, between destination lines in a 2D data move
|
||||
*/
|
||||
struct st_fdma_generic_node {
|
||||
u32 length;
|
||||
u32 sstride;
|
||||
u32 dstride;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct st_fdma_hw_node - Node structure used by fdma hw
|
||||
*
|
||||
* @next: Pointer to next node
|
||||
* @control: Transfer Control Parameters
|
||||
* @nbytes: Number of Bytes to read
|
||||
* @saddr: Source address
|
||||
* @daddr: Destination address
|
||||
*
|
||||
* @generic: generic node for free running/paced transfert type
|
||||
* 2 others transfert type are possible, but not yet implemented
|
||||
*
|
||||
* The NODE structures must be aligned to a 32 byte boundary
|
||||
*/
|
||||
struct st_fdma_hw_node {
|
||||
u32 next;
|
||||
u32 control;
|
||||
u32 nbytes;
|
||||
u32 saddr;
|
||||
u32 daddr;
|
||||
union {
|
||||
struct st_fdma_generic_node generic;
|
||||
};
|
||||
} __aligned(32);
|
||||
|
||||
/*
|
||||
* node control parameters
|
||||
*/
|
||||
#define FDMA_NODE_CTRL_REQ_MAP_MASK GENMASK(4, 0)
|
||||
#define FDMA_NODE_CTRL_REQ_MAP_FREE_RUN 0x0
|
||||
#define FDMA_NODE_CTRL_REQ_MAP_DREQ(n) ((n)&FDMA_NODE_CTRL_REQ_MAP_MASK)
|
||||
#define FDMA_NODE_CTRL_REQ_MAP_EXT FDMA_NODE_CTRL_REQ_MAP_MASK
|
||||
#define FDMA_NODE_CTRL_SRC_MASK GENMASK(6, 5)
|
||||
#define FDMA_NODE_CTRL_SRC_STATIC BIT(5)
|
||||
#define FDMA_NODE_CTRL_SRC_INCR BIT(6)
|
||||
#define FDMA_NODE_CTRL_DST_MASK GENMASK(8, 7)
|
||||
#define FDMA_NODE_CTRL_DST_STATIC BIT(7)
|
||||
#define FDMA_NODE_CTRL_DST_INCR BIT(8)
|
||||
#define FDMA_NODE_CTRL_SECURE BIT(15)
|
||||
#define FDMA_NODE_CTRL_PAUSE_EON BIT(30)
|
||||
#define FDMA_NODE_CTRL_INT_EON BIT(31)
|
||||
|
||||
/**
|
||||
* struct st_fdma_sw_node - descriptor structure for link list
|
||||
*
|
||||
* @pdesc: Physical address of desc
|
||||
* @node: link used for putting this into a channel queue
|
||||
*/
|
||||
struct st_fdma_sw_node {
|
||||
dma_addr_t pdesc;
|
||||
struct st_fdma_hw_node *desc;
|
||||
};
|
||||
|
||||
#define NAME_SZ 10
|
||||
|
||||
struct st_fdma_driverdata {
|
||||
u32 id;
|
||||
char name[NAME_SZ];
|
||||
};
|
||||
|
||||
struct st_fdma_desc {
|
||||
struct virt_dma_desc vdesc;
|
||||
struct st_fdma_chan *fchan;
|
||||
bool iscyclic;
|
||||
unsigned int n_nodes;
|
||||
struct st_fdma_sw_node node[];
|
||||
};
|
||||
|
||||
enum st_fdma_type {
|
||||
ST_FDMA_TYPE_FREE_RUN,
|
||||
ST_FDMA_TYPE_PACED,
|
||||
};
|
||||
|
||||
struct st_fdma_cfg {
|
||||
struct device_node *of_node;
|
||||
enum st_fdma_type type;
|
||||
dma_addr_t dev_addr;
|
||||
enum dma_transfer_direction dir;
|
||||
int req_line; /* request line */
|
||||
long req_ctrl; /* Request control */
|
||||
};
|
||||
|
||||
struct st_fdma_chan {
|
||||
struct st_fdma_dev *fdev;
|
||||
struct dma_pool *node_pool;
|
||||
struct dma_slave_config scfg;
|
||||
struct st_fdma_cfg cfg;
|
||||
|
||||
int dreq_line;
|
||||
|
||||
struct virt_dma_chan vchan;
|
||||
struct st_fdma_desc *fdesc;
|
||||
enum dma_status status;
|
||||
};
|
||||
|
||||
struct st_fdma_dev {
|
||||
struct device *dev;
|
||||
const struct st_fdma_driverdata *drvdata;
|
||||
struct dma_device dma_device;
|
||||
|
||||
struct st_slim_rproc *slim_rproc;
|
||||
|
||||
int irq;
|
||||
|
||||
struct st_fdma_chan *chans;
|
||||
|
||||
spinlock_t dreq_lock;
|
||||
unsigned long dreq_mask;
|
||||
|
||||
u32 nr_channels;
|
||||
char fw_name[FW_NAME_SIZE];
|
||||
};
|
||||
|
||||
/* Peripheral Registers*/
|
||||
|
||||
#define FDMA_CMD_STA_OFST 0xFC0
|
||||
#define FDMA_CMD_SET_OFST 0xFC4
|
||||
#define FDMA_CMD_CLR_OFST 0xFC8
|
||||
#define FDMA_CMD_MASK_OFST 0xFCC
|
||||
#define FDMA_CMD_START(ch) (0x1 << (ch << 1))
|
||||
#define FDMA_CMD_PAUSE(ch) (0x2 << (ch << 1))
|
||||
#define FDMA_CMD_FLUSH(ch) (0x3 << (ch << 1))
|
||||
|
||||
#define FDMA_INT_STA_OFST 0xFD0
|
||||
#define FDMA_INT_STA_CH 0x1
|
||||
#define FDMA_INT_STA_ERR 0x2
|
||||
|
||||
#define FDMA_INT_SET_OFST 0xFD4
|
||||
#define FDMA_INT_CLR_OFST 0xFD8
|
||||
#define FDMA_INT_MASK_OFST 0xFDC
|
||||
|
||||
#define fdma_read(fdev, name) \
|
||||
readl((fdev)->slim_rproc->peri + name)
|
||||
|
||||
#define fdma_write(fdev, val, name) \
|
||||
writel((val), (fdev)->slim_rproc->peri + name)
|
||||
|
||||
/* fchan interface (dmem) */
|
||||
#define FDMA_CH_CMD_OFST 0x200
|
||||
#define FDMA_CH_CMD_STA_MASK GENMASK(1, 0)
|
||||
#define FDMA_CH_CMD_STA_IDLE (0x0)
|
||||
#define FDMA_CH_CMD_STA_START (0x1)
|
||||
#define FDMA_CH_CMD_STA_RUNNING (0x2)
|
||||
#define FDMA_CH_CMD_STA_PAUSED (0x3)
|
||||
#define FDMA_CH_CMD_ERR_MASK GENMASK(4, 2)
|
||||
#define FDMA_CH_CMD_ERR_INT (0x0 << 2)
|
||||
#define FDMA_CH_CMD_ERR_NAND (0x1 << 2)
|
||||
#define FDMA_CH_CMD_ERR_MCHI (0x2 << 2)
|
||||
#define FDMA_CH_CMD_DATA_MASK GENMASK(31, 5)
|
||||
#define fchan_read(fchan, name) \
|
||||
readl((fchan)->fdev->slim_rproc->mem[ST_SLIM_DMEM].cpu_addr \
|
||||
+ (fchan)->vchan.chan.chan_id * 0x4 \
|
||||
+ name)
|
||||
|
||||
#define fchan_write(fchan, val, name) \
|
||||
writel((val), (fchan)->fdev->slim_rproc->mem[ST_SLIM_DMEM].cpu_addr \
|
||||
+ (fchan)->vchan.chan.chan_id * 0x4 \
|
||||
+ name)
|
||||
|
||||
/* req interface */
|
||||
#define FDMA_REQ_CTRL_OFST 0x240
|
||||
#define dreq_write(fchan, val, name) \
|
||||
writel((val), (fchan)->fdev->slim_rproc->mem[ST_SLIM_DMEM].cpu_addr \
|
||||
+ fchan->dreq_line * 0x04 \
|
||||
+ name)
|
||||
/* node interface */
|
||||
#define FDMA_NODE_SZ 128
|
||||
#define FDMA_PTRN_OFST 0x800
|
||||
#define FDMA_CNTN_OFST 0x808
|
||||
#define FDMA_SADDRN_OFST 0x80c
|
||||
#define FDMA_DADDRN_OFST 0x810
|
||||
#define fnode_read(fchan, name) \
|
||||
readl((fchan)->fdev->slim_rproc->mem[ST_SLIM_DMEM].cpu_addr \
|
||||
+ (fchan)->vchan.chan.chan_id * FDMA_NODE_SZ \
|
||||
+ name)
|
||||
|
||||
#define fnode_write(fchan, val, name) \
|
||||
writel((val), (fchan)->fdev->slim_rproc->mem[ST_SLIM_DMEM].cpu_addr \
|
||||
+ (fchan)->vchan.chan.chan_id * FDMA_NODE_SZ \
|
||||
+ name)
|
||||
|
||||
/*
|
||||
* request control bits
|
||||
*/
|
||||
#define FDMA_REQ_CTRL_NUM_OPS_MASK GENMASK(31, 24)
|
||||
#define FDMA_REQ_CTRL_NUM_OPS(n) (FDMA_REQ_CTRL_NUM_OPS_MASK & \
|
||||
((n) << 24))
|
||||
#define FDMA_REQ_CTRL_INITIATOR_MASK BIT(22)
|
||||
#define FDMA_REQ_CTRL_INIT0 (0x0 << 22)
|
||||
#define FDMA_REQ_CTRL_INIT1 (0x1 << 22)
|
||||
#define FDMA_REQ_CTRL_INC_ADDR_ON BIT(21)
|
||||
#define FDMA_REQ_CTRL_DATA_SWAP_ON BIT(17)
|
||||
#define FDMA_REQ_CTRL_WNR BIT(14)
|
||||
#define FDMA_REQ_CTRL_OPCODE_MASK GENMASK(7, 4)
|
||||
#define FDMA_REQ_CTRL_OPCODE_LD_ST1 (0x0 << 4)
|
||||
#define FDMA_REQ_CTRL_OPCODE_LD_ST2 (0x1 << 4)
|
||||
#define FDMA_REQ_CTRL_OPCODE_LD_ST4 (0x2 << 4)
|
||||
#define FDMA_REQ_CTRL_OPCODE_LD_ST8 (0x3 << 4)
|
||||
#define FDMA_REQ_CTRL_OPCODE_LD_ST16 (0x4 << 4)
|
||||
#define FDMA_REQ_CTRL_OPCODE_LD_ST32 (0x5 << 4)
|
||||
#define FDMA_REQ_CTRL_OPCODE_LD_ST64 (0x6 << 4)
|
||||
#define FDMA_REQ_CTRL_HOLDOFF_MASK GENMASK(2, 0)
|
||||
#define FDMA_REQ_CTRL_HOLDOFF(n) ((n) & FDMA_REQ_CTRL_HOLDOFF_MASK)
|
||||
|
||||
/* bits used by client to configure request control */
|
||||
#define FDMA_REQ_CTRL_CFG_MASK (FDMA_REQ_CTRL_HOLDOFF_MASK | \
|
||||
FDMA_REQ_CTRL_DATA_SWAP_ON | \
|
||||
FDMA_REQ_CTRL_INC_ADDR_ON | \
|
||||
FDMA_REQ_CTRL_INITIATOR_MASK)
|
||||
|
||||
#endif /* __DMA_ST_FDMA_H */
|
||||
+29
-23
@@ -1,20 +1,21 @@
|
||||
menu "Remoteproc drivers"
|
||||
|
||||
# REMOTEPROC gets selected by whoever wants it
|
||||
config REMOTEPROC
|
||||
tristate
|
||||
tristate "Support for Remote Processor subsystem"
|
||||
depends on HAS_DMA
|
||||
select CRC32
|
||||
select FW_LOADER
|
||||
select VIRTIO
|
||||
select VIRTUALIZATION
|
||||
|
||||
if REMOTEPROC
|
||||
|
||||
config OMAP_REMOTEPROC
|
||||
tristate "OMAP remoteproc support"
|
||||
depends on HAS_DMA
|
||||
depends on ARCH_OMAP4 || SOC_OMAP5
|
||||
depends on OMAP_IOMMU
|
||||
select REMOTEPROC
|
||||
depends on REMOTEPROC
|
||||
select MAILBOX
|
||||
select OMAP2PLUS_MBOX
|
||||
select RPMSG_VIRTIO
|
||||
@@ -31,20 +32,10 @@ config OMAP_REMOTEPROC
|
||||
It's safe to say n here if you're not interested in multimedia
|
||||
offloading or just want a bare minimum kernel.
|
||||
|
||||
config STE_MODEM_RPROC
|
||||
tristate "STE-Modem remoteproc support"
|
||||
depends on HAS_DMA
|
||||
select REMOTEPROC
|
||||
default n
|
||||
help
|
||||
Say y or m here to support STE-Modem shared memory driver.
|
||||
This can be either built-in or a loadable module.
|
||||
If unsure say N.
|
||||
|
||||
config WKUP_M3_RPROC
|
||||
tristate "AMx3xx Wakeup M3 remoteproc support"
|
||||
depends on SOC_AM33XX || SOC_AM43XX
|
||||
select REMOTEPROC
|
||||
depends on REMOTEPROC
|
||||
help
|
||||
Say y here to support Wakeup M3 remote processor on TI AM33xx
|
||||
and AM43xx family of SoCs.
|
||||
@@ -57,8 +48,8 @@ config WKUP_M3_RPROC
|
||||
config DA8XX_REMOTEPROC
|
||||
tristate "DA8xx/OMAP-L13x remoteproc support"
|
||||
depends on ARCH_DAVINCI_DA8XX
|
||||
depends on REMOTEPROC
|
||||
select CMA if MMU
|
||||
select REMOTEPROC
|
||||
select RPMSG_VIRTIO
|
||||
help
|
||||
Say y here to support DA8xx/OMAP-L13x remote processors via the
|
||||
@@ -77,6 +68,18 @@ config DA8XX_REMOTEPROC
|
||||
It's safe to say n here if you're not interested in multimedia
|
||||
offloading.
|
||||
|
||||
config QCOM_ADSP_PIL
|
||||
tristate "Qualcomm ADSP Peripheral Image Loader"
|
||||
depends on OF && ARCH_QCOM
|
||||
depends on REMOTEPROC
|
||||
depends on QCOM_SMEM
|
||||
select MFD_SYSCON
|
||||
select QCOM_MDT_LOADER
|
||||
select QCOM_SCM
|
||||
help
|
||||
Say y here to support the TrustZone based Peripherial Image Loader
|
||||
for the Qualcomm ADSP remote processors.
|
||||
|
||||
config QCOM_MDT_LOADER
|
||||
tristate
|
||||
|
||||
@@ -84,25 +87,22 @@ config QCOM_Q6V5_PIL
|
||||
tristate "Qualcomm Hexagon V5 Peripherial Image Loader"
|
||||
depends on OF && ARCH_QCOM
|
||||
depends on QCOM_SMEM
|
||||
depends on REMOTEPROC
|
||||
select MFD_SYSCON
|
||||
select QCOM_MDT_LOADER
|
||||
select REMOTEPROC
|
||||
select QCOM_SCM
|
||||
help
|
||||
Say y here to support the Qualcomm Peripherial Image Loader for the
|
||||
Hexagon V5 based remote processors.
|
||||
|
||||
config QCOM_WCNSS_IRIS
|
||||
tristate
|
||||
depends on OF && ARCH_QCOM
|
||||
|
||||
config QCOM_WCNSS_PIL
|
||||
tristate "Qualcomm WCNSS Peripheral Image Loader"
|
||||
depends on OF && ARCH_QCOM
|
||||
depends on QCOM_SMD || (COMPILE_TEST && QCOM_SMD=n)
|
||||
depends on QCOM_SMEM
|
||||
depends on REMOTEPROC
|
||||
select QCOM_MDT_LOADER
|
||||
select QCOM_SCM
|
||||
select QCOM_WCNSS_IRIS
|
||||
select REMOTEPROC
|
||||
help
|
||||
Say y here to support the Peripheral Image Loader for the Qualcomm
|
||||
Wireless Connectivity Subsystem.
|
||||
@@ -110,10 +110,16 @@ config QCOM_WCNSS_PIL
|
||||
config ST_REMOTEPROC
|
||||
tristate "ST remoteproc support"
|
||||
depends on ARCH_STI
|
||||
select REMOTEPROC
|
||||
depends on REMOTEPROC
|
||||
help
|
||||
Say y here to support ST's adjunct processors via the remote
|
||||
processor framework.
|
||||
This can be either built-in or a loadable module.
|
||||
|
||||
config ST_SLIM_REMOTEPROC
|
||||
tristate
|
||||
depends on REMOTEPROC
|
||||
|
||||
endif # REMOTEPROC
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -5,14 +5,17 @@
|
||||
obj-$(CONFIG_REMOTEPROC) += remoteproc.o
|
||||
remoteproc-y := remoteproc_core.o
|
||||
remoteproc-y += remoteproc_debugfs.o
|
||||
remoteproc-y += remoteproc_sysfs.o
|
||||
remoteproc-y += remoteproc_virtio.o
|
||||
remoteproc-y += remoteproc_elf_loader.o
|
||||
obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o
|
||||
obj-$(CONFIG_STE_MODEM_RPROC) += ste_modem_rproc.o
|
||||
obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o
|
||||
obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o
|
||||
obj-$(CONFIG_QCOM_ADSP_PIL) += qcom_adsp_pil.o
|
||||
obj-$(CONFIG_QCOM_MDT_LOADER) += qcom_mdt_loader.o
|
||||
obj-$(CONFIG_QCOM_Q6V5_PIL) += qcom_q6v5_pil.o
|
||||
obj-$(CONFIG_QCOM_WCNSS_IRIS) += qcom_wcnss_iris.o
|
||||
obj-$(CONFIG_QCOM_WCNSS_PIL) += qcom_wcnss.o
|
||||
obj-$(CONFIG_QCOM_WCNSS_PIL) += qcom_wcnss_pil.o
|
||||
qcom_wcnss_pil-y += qcom_wcnss.o
|
||||
qcom_wcnss_pil-y += qcom_wcnss_iris.o
|
||||
obj-$(CONFIG_ST_REMOTEPROC) += st_remoteproc.o
|
||||
obj-$(CONFIG_ST_SLIM_REMOTEPROC) += st_slim_rproc.o
|
||||
|
||||
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
* Qualcomm ADSP 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.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/qcom_scm.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/remoteproc.h>
|
||||
#include <linux/soc/qcom/smem.h>
|
||||
#include <linux/soc/qcom/smem_state.h>
|
||||
|
||||
#include "qcom_mdt_loader.h"
|
||||
#include "remoteproc_internal.h"
|
||||
|
||||
#define ADSP_CRASH_REASON_SMEM 423
|
||||
#define ADSP_FIRMWARE_NAME "adsp.mdt"
|
||||
#define ADSP_PAS_ID 1
|
||||
|
||||
struct qcom_adsp {
|
||||
struct device *dev;
|
||||
struct rproc *rproc;
|
||||
|
||||
int wdog_irq;
|
||||
int fatal_irq;
|
||||
int ready_irq;
|
||||
int handover_irq;
|
||||
int stop_ack_irq;
|
||||
|
||||
struct qcom_smem_state *state;
|
||||
unsigned stop_bit;
|
||||
|
||||
struct clk *xo;
|
||||
|
||||
struct regulator *cx_supply;
|
||||
|
||||
struct completion start_done;
|
||||
struct completion stop_done;
|
||||
|
||||
phys_addr_t mem_phys;
|
||||
phys_addr_t mem_reloc;
|
||||
void *mem_region;
|
||||
size_t mem_size;
|
||||
};
|
||||
|
||||
static int adsp_load(struct rproc *rproc, const struct firmware *fw)
|
||||
{
|
||||
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
|
||||
phys_addr_t fw_addr;
|
||||
size_t fw_size;
|
||||
bool relocate;
|
||||
int ret;
|
||||
|
||||
ret = qcom_scm_pas_init_image(ADSP_PAS_ID, fw->data, fw->size);
|
||||
if (ret) {
|
||||
dev_err(&rproc->dev, "invalid firmware metadata\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = qcom_mdt_parse(fw, &fw_addr, &fw_size, &relocate);
|
||||
if (ret) {
|
||||
dev_err(&rproc->dev, "failed to parse mdt header\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (relocate) {
|
||||
adsp->mem_reloc = fw_addr;
|
||||
|
||||
ret = qcom_scm_pas_mem_setup(ADSP_PAS_ID, adsp->mem_phys, fw_size);
|
||||
if (ret) {
|
||||
dev_err(&rproc->dev, "unable to setup memory for image\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return qcom_mdt_load(rproc, fw, rproc->firmware);
|
||||
}
|
||||
|
||||
static const struct rproc_fw_ops adsp_fw_ops = {
|
||||
.find_rsc_table = qcom_mdt_find_rsc_table,
|
||||
.load = adsp_load,
|
||||
};
|
||||
|
||||
static int adsp_start(struct rproc *rproc)
|
||||
{
|
||||
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(adsp->xo);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regulator_enable(adsp->cx_supply);
|
||||
if (ret)
|
||||
goto disable_clocks;
|
||||
|
||||
ret = qcom_scm_pas_auth_and_reset(ADSP_PAS_ID);
|
||||
if (ret) {
|
||||
dev_err(adsp->dev,
|
||||
"failed to authenticate image and release reset\n");
|
||||
goto disable_regulators;
|
||||
}
|
||||
|
||||
ret = wait_for_completion_timeout(&adsp->start_done,
|
||||
msecs_to_jiffies(5000));
|
||||
if (!ret) {
|
||||
dev_err(adsp->dev, "start timed out\n");
|
||||
qcom_scm_pas_shutdown(ADSP_PAS_ID);
|
||||
ret = -ETIMEDOUT;
|
||||
goto disable_regulators;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
disable_regulators:
|
||||
regulator_disable(adsp->cx_supply);
|
||||
disable_clocks:
|
||||
clk_disable_unprepare(adsp->xo);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adsp_stop(struct rproc *rproc)
|
||||
{
|
||||
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
|
||||
int ret;
|
||||
|
||||
qcom_smem_state_update_bits(adsp->state,
|
||||
BIT(adsp->stop_bit),
|
||||
BIT(adsp->stop_bit));
|
||||
|
||||
ret = wait_for_completion_timeout(&adsp->stop_done,
|
||||
msecs_to_jiffies(5000));
|
||||
if (ret == 0)
|
||||
dev_err(adsp->dev, "timed out on wait\n");
|
||||
|
||||
qcom_smem_state_update_bits(adsp->state,
|
||||
BIT(adsp->stop_bit),
|
||||
0);
|
||||
|
||||
ret = qcom_scm_pas_shutdown(ADSP_PAS_ID);
|
||||
if (ret)
|
||||
dev_err(adsp->dev, "failed to shutdown: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
|
||||
{
|
||||
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
|
||||
int offset;
|
||||
|
||||
offset = da - adsp->mem_reloc;
|
||||
if (offset < 0 || offset + len > adsp->mem_size)
|
||||
return NULL;
|
||||
|
||||
return adsp->mem_region + offset;
|
||||
}
|
||||
|
||||
static const struct rproc_ops adsp_ops = {
|
||||
.start = adsp_start,
|
||||
.stop = adsp_stop,
|
||||
.da_to_va = adsp_da_to_va,
|
||||
};
|
||||
|
||||
static irqreturn_t adsp_wdog_interrupt(int irq, void *dev)
|
||||
{
|
||||
struct qcom_adsp *adsp = dev;
|
||||
|
||||
rproc_report_crash(adsp->rproc, RPROC_WATCHDOG);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t adsp_fatal_interrupt(int irq, void *dev)
|
||||
{
|
||||
struct qcom_adsp *adsp = dev;
|
||||
size_t len;
|
||||
char *msg;
|
||||
|
||||
msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, ADSP_CRASH_REASON_SMEM, &len);
|
||||
if (!IS_ERR(msg) && len > 0 && msg[0])
|
||||
dev_err(adsp->dev, "fatal error received: %s\n", msg);
|
||||
|
||||
rproc_report_crash(adsp->rproc, RPROC_FATAL_ERROR);
|
||||
|
||||
if (!IS_ERR(msg))
|
||||
msg[0] = '\0';
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t adsp_ready_interrupt(int irq, void *dev)
|
||||
{
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t adsp_handover_interrupt(int irq, void *dev)
|
||||
{
|
||||
struct qcom_adsp *adsp = dev;
|
||||
|
||||
complete(&adsp->start_done);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t adsp_stop_ack_interrupt(int irq, void *dev)
|
||||
{
|
||||
struct qcom_adsp *adsp = dev;
|
||||
|
||||
complete(&adsp->stop_done);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int adsp_init_clock(struct qcom_adsp *adsp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
adsp->xo = devm_clk_get(adsp->dev, "xo");
|
||||
if (IS_ERR(adsp->xo)) {
|
||||
ret = PTR_ERR(adsp->xo);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(adsp->dev, "failed to get xo clock");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adsp_init_regulator(struct qcom_adsp *adsp)
|
||||
{
|
||||
adsp->cx_supply = devm_regulator_get(adsp->dev, "cx");
|
||||
if (IS_ERR(adsp->cx_supply))
|
||||
return PTR_ERR(adsp->cx_supply);
|
||||
|
||||
regulator_set_load(adsp->cx_supply, 100000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adsp_request_irq(struct qcom_adsp *adsp,
|
||||
struct platform_device *pdev,
|
||||
const char *name,
|
||||
irq_handler_t thread_fn)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = platform_get_irq_byname(pdev, name);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "no %s IRQ defined\n", name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, ret,
|
||||
NULL, thread_fn,
|
||||
IRQF_ONESHOT,
|
||||
"adsp", adsp);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "request %s IRQ failed\n", name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adsp_alloc_memory_region(struct qcom_adsp *adsp)
|
||||
{
|
||||
struct device_node *node;
|
||||
struct resource r;
|
||||
int ret;
|
||||
|
||||
node = of_parse_phandle(adsp->dev->of_node, "memory-region", 0);
|
||||
if (!node) {
|
||||
dev_err(adsp->dev, "no memory-region specified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = of_address_to_resource(node, 0, &r);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
adsp->mem_phys = adsp->mem_reloc = r.start;
|
||||
adsp->mem_size = resource_size(&r);
|
||||
adsp->mem_region = devm_ioremap_wc(adsp->dev, adsp->mem_phys, adsp->mem_size);
|
||||
if (!adsp->mem_region) {
|
||||
dev_err(adsp->dev, "unable to map memory region: %pa+%zx\n",
|
||||
&r.start, adsp->mem_size);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adsp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct qcom_adsp *adsp;
|
||||
struct rproc *rproc;
|
||||
int ret;
|
||||
|
||||
if (!qcom_scm_is_available())
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
if (!qcom_scm_pas_supported(ADSP_PAS_ID)) {
|
||||
dev_err(&pdev->dev, "PAS is not available for ADSP\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
rproc = rproc_alloc(&pdev->dev, pdev->name, &adsp_ops,
|
||||
ADSP_FIRMWARE_NAME, sizeof(*adsp));
|
||||
if (!rproc) {
|
||||
dev_err(&pdev->dev, "unable to allocate remoteproc\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rproc->fw_ops = &adsp_fw_ops;
|
||||
|
||||
adsp = (struct qcom_adsp *)rproc->priv;
|
||||
adsp->dev = &pdev->dev;
|
||||
adsp->rproc = rproc;
|
||||
platform_set_drvdata(pdev, adsp);
|
||||
|
||||
init_completion(&adsp->start_done);
|
||||
init_completion(&adsp->stop_done);
|
||||
|
||||
ret = adsp_alloc_memory_region(adsp);
|
||||
if (ret)
|
||||
goto free_rproc;
|
||||
|
||||
ret = adsp_init_clock(adsp);
|
||||
if (ret)
|
||||
goto free_rproc;
|
||||
|
||||
ret = adsp_init_regulator(adsp);
|
||||
if (ret)
|
||||
goto free_rproc;
|
||||
|
||||
ret = adsp_request_irq(adsp, pdev, "wdog", adsp_wdog_interrupt);
|
||||
if (ret < 0)
|
||||
goto free_rproc;
|
||||
adsp->wdog_irq = ret;
|
||||
|
||||
ret = adsp_request_irq(adsp, pdev, "fatal", adsp_fatal_interrupt);
|
||||
if (ret < 0)
|
||||
goto free_rproc;
|
||||
adsp->fatal_irq = ret;
|
||||
|
||||
ret = adsp_request_irq(adsp, pdev, "ready", adsp_ready_interrupt);
|
||||
if (ret < 0)
|
||||
goto free_rproc;
|
||||
adsp->ready_irq = ret;
|
||||
|
||||
ret = adsp_request_irq(adsp, pdev, "handover", adsp_handover_interrupt);
|
||||
if (ret < 0)
|
||||
goto free_rproc;
|
||||
adsp->handover_irq = ret;
|
||||
|
||||
ret = adsp_request_irq(adsp, pdev, "stop-ack", adsp_stop_ack_interrupt);
|
||||
if (ret < 0)
|
||||
goto free_rproc;
|
||||
adsp->stop_ack_irq = ret;
|
||||
|
||||
adsp->state = qcom_smem_state_get(&pdev->dev, "stop",
|
||||
&adsp->stop_bit);
|
||||
if (IS_ERR(adsp->state)) {
|
||||
ret = PTR_ERR(adsp->state);
|
||||
goto free_rproc;
|
||||
}
|
||||
|
||||
ret = rproc_add(rproc);
|
||||
if (ret)
|
||||
goto free_rproc;
|
||||
|
||||
return 0;
|
||||
|
||||
free_rproc:
|
||||
rproc_free(rproc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adsp_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct qcom_adsp *adsp = platform_get_drvdata(pdev);
|
||||
|
||||
qcom_smem_state_put(adsp->state);
|
||||
rproc_del(adsp->rproc);
|
||||
rproc_free(adsp->rproc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id adsp_of_match[] = {
|
||||
{ .compatible = "qcom,msm8974-adsp-pil" },
|
||||
{ .compatible = "qcom,msm8996-adsp-pil" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adsp_of_match);
|
||||
|
||||
static struct platform_driver adsp_driver = {
|
||||
.probe = adsp_probe,
|
||||
.remove = adsp_remove,
|
||||
.driver = {
|
||||
.name = "qcom_adsp_pil",
|
||||
.of_match_table = adsp_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(adsp_driver);
|
||||
MODULE_DESCRIPTION("Qualcomm MSM8974/MSM8996 ADSP Peripherial Image Loader");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/remoteproc.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "remoteproc_internal.h"
|
||||
|
||||
@@ -894,6 +894,7 @@ static const struct of_device_id q6v5_of_match[] = {
|
||||
{ .compatible = "qcom,q6v5-pil", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, q6v5_of_match);
|
||||
|
||||
static struct platform_driver q6v5_driver = {
|
||||
.probe = q6v5_probe,
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <linux/remoteproc.h>
|
||||
#include <linux/soc/qcom/smem.h>
|
||||
#include <linux/soc/qcom/smem_state.h>
|
||||
#include <linux/rpmsg/qcom_smd.h>
|
||||
|
||||
#include "qcom_mdt_loader.h"
|
||||
#include "remoteproc_internal.h"
|
||||
@@ -94,6 +95,10 @@ struct qcom_wcnss {
|
||||
phys_addr_t mem_reloc;
|
||||
void *mem_region;
|
||||
size_t mem_size;
|
||||
|
||||
struct device_node *smd_node;
|
||||
struct qcom_smd_edge *smd_edge;
|
||||
struct rproc_subdev smd_subdev;
|
||||
};
|
||||
|
||||
static const struct wcnss_data riva_data = {
|
||||
@@ -143,7 +148,6 @@ void qcom_wcnss_assign_iris(struct qcom_wcnss *wcnss,
|
||||
|
||||
mutex_unlock(&wcnss->iris_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_wcnss_assign_iris);
|
||||
|
||||
static int wcnss_load(struct rproc *rproc, const struct firmware *fw)
|
||||
{
|
||||
@@ -396,6 +400,23 @@ static irqreturn_t wcnss_stop_ack_interrupt(int irq, void *dev)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int wcnss_smd_probe(struct rproc_subdev *subdev)
|
||||
{
|
||||
struct qcom_wcnss *wcnss = container_of(subdev, struct qcom_wcnss, smd_subdev);
|
||||
|
||||
wcnss->smd_edge = qcom_smd_register_edge(wcnss->dev, wcnss->smd_node);
|
||||
|
||||
return IS_ERR(wcnss->smd_edge) ? PTR_ERR(wcnss->smd_edge) : 0;
|
||||
}
|
||||
|
||||
static void wcnss_smd_remove(struct rproc_subdev *subdev)
|
||||
{
|
||||
struct qcom_wcnss *wcnss = container_of(subdev, struct qcom_wcnss, smd_subdev);
|
||||
|
||||
qcom_smd_unregister_edge(wcnss->smd_edge);
|
||||
wcnss->smd_edge = NULL;
|
||||
}
|
||||
|
||||
static int wcnss_init_regulators(struct qcom_wcnss *wcnss,
|
||||
const struct wcnss_vreg_info *info,
|
||||
int num_vregs)
|
||||
@@ -578,6 +599,10 @@ static int wcnss_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
wcnss->smd_node = of_get_child_by_name(pdev->dev.of_node, "smd-edge");
|
||||
if (wcnss->smd_node)
|
||||
rproc_add_subdev(rproc, &wcnss->smd_subdev, wcnss_smd_probe, wcnss_smd_remove);
|
||||
|
||||
ret = rproc_add(rproc);
|
||||
if (ret)
|
||||
goto free_rproc;
|
||||
@@ -596,6 +621,7 @@ static int wcnss_remove(struct platform_device *pdev)
|
||||
|
||||
of_platform_depopulate(&pdev->dev);
|
||||
|
||||
of_node_put(wcnss->smd_node);
|
||||
qcom_smem_state_put(wcnss->state);
|
||||
rproc_del(wcnss->rproc);
|
||||
rproc_free(wcnss->rproc);
|
||||
@@ -609,6 +635,7 @@ static const struct of_device_id wcnss_of_match[] = {
|
||||
{ .compatible = "qcom,pronto-v2-pil", &pronto_v2_data },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, wcnss_of_match);
|
||||
|
||||
static struct platform_driver wcnss_driver = {
|
||||
.probe = wcnss_probe,
|
||||
@@ -619,6 +646,28 @@ static struct platform_driver wcnss_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(wcnss_driver);
|
||||
static int __init wcnss_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&wcnss_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = platform_driver_register(&qcom_iris_driver);
|
||||
if (ret)
|
||||
platform_driver_unregister(&wcnss_driver);
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(wcnss_init);
|
||||
|
||||
static void __exit wcnss_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&qcom_iris_driver);
|
||||
platform_driver_unregister(&wcnss_driver);
|
||||
}
|
||||
module_exit(wcnss_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Qualcomm Peripherial Image Loader for Wireless Subsystem");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
struct qcom_iris;
|
||||
struct qcom_wcnss;
|
||||
|
||||
extern struct platform_driver qcom_iris_driver;
|
||||
|
||||
struct wcnss_vreg_info {
|
||||
const char * const name;
|
||||
int min_voltage;
|
||||
|
||||
@@ -94,14 +94,12 @@ disable_regulators:
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_iris_enable);
|
||||
|
||||
void qcom_iris_disable(struct qcom_iris *iris)
|
||||
{
|
||||
clk_disable_unprepare(iris->xo_clk);
|
||||
regulator_bulk_disable(iris->num_vregs, iris->vregs);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_iris_disable);
|
||||
|
||||
static int qcom_iris_probe(struct platform_device *pdev)
|
||||
{
|
||||
@@ -173,8 +171,9 @@ static const struct of_device_id iris_of_match[] = {
|
||||
{ .compatible = "qcom,wcn3680", .data = &wcn3680_data },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, iris_of_match);
|
||||
|
||||
static struct platform_driver wcnss_driver = {
|
||||
struct platform_driver qcom_iris_driver = {
|
||||
.probe = qcom_iris_probe,
|
||||
.remove = qcom_iris_remove,
|
||||
.driver = {
|
||||
@@ -182,7 +181,3 @@ static struct platform_driver wcnss_driver = {
|
||||
.of_match_table = iris_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(wcnss_driver);
|
||||
MODULE_DESCRIPTION("Qualcomm Wireless Subsystem Iris driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
@@ -236,6 +236,10 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
|
||||
}
|
||||
notifyid = ret;
|
||||
|
||||
/* Potentially bump max_notifyid */
|
||||
if (notifyid > rproc->max_notifyid)
|
||||
rproc->max_notifyid = notifyid;
|
||||
|
||||
dev_dbg(dev, "vring%d: va %p dma %pad size 0x%x idr %d\n",
|
||||
i, va, &dma, size, notifyid);
|
||||
|
||||
@@ -296,6 +300,20 @@ void rproc_free_vring(struct rproc_vring *rvring)
|
||||
rsc->vring[idx].notifyid = -1;
|
||||
}
|
||||
|
||||
static int rproc_vdev_do_probe(struct rproc_subdev *subdev)
|
||||
{
|
||||
struct rproc_vdev *rvdev = container_of(subdev, struct rproc_vdev, subdev);
|
||||
|
||||
return rproc_add_virtio_dev(rvdev, rvdev->id);
|
||||
}
|
||||
|
||||
static void rproc_vdev_do_remove(struct rproc_subdev *subdev)
|
||||
{
|
||||
struct rproc_vdev *rvdev = container_of(subdev, struct rproc_vdev, subdev);
|
||||
|
||||
rproc_remove_virtio_dev(rvdev);
|
||||
}
|
||||
|
||||
/**
|
||||
* rproc_handle_vdev() - handle a vdev fw resource
|
||||
* @rproc: the remote processor
|
||||
@@ -356,6 +374,9 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
|
||||
if (!rvdev)
|
||||
return -ENOMEM;
|
||||
|
||||
kref_init(&rvdev->refcount);
|
||||
|
||||
rvdev->id = rsc->id;
|
||||
rvdev->rproc = rproc;
|
||||
|
||||
/* parse the vrings */
|
||||
@@ -368,22 +389,51 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
|
||||
/* remember the resource offset*/
|
||||
rvdev->rsc_offset = offset;
|
||||
|
||||
/* allocate the vring resources */
|
||||
for (i = 0; i < rsc->num_of_vrings; i++) {
|
||||
ret = rproc_alloc_vring(rvdev, i);
|
||||
if (ret)
|
||||
goto unwind_vring_allocations;
|
||||
}
|
||||
|
||||
/* track the rvdevs list reference */
|
||||
kref_get(&rvdev->refcount);
|
||||
|
||||
list_add_tail(&rvdev->node, &rproc->rvdevs);
|
||||
|
||||
/* it is now safe to add the virtio device */
|
||||
ret = rproc_add_virtio_dev(rvdev, rsc->id);
|
||||
if (ret)
|
||||
goto remove_rvdev;
|
||||
rproc_add_subdev(rproc, &rvdev->subdev,
|
||||
rproc_vdev_do_probe, rproc_vdev_do_remove);
|
||||
|
||||
return 0;
|
||||
|
||||
remove_rvdev:
|
||||
list_del(&rvdev->node);
|
||||
unwind_vring_allocations:
|
||||
for (i--; i >= 0; i--)
|
||||
rproc_free_vring(&rvdev->vring[i]);
|
||||
free_rvdev:
|
||||
kfree(rvdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rproc_vdev_release(struct kref *ref)
|
||||
{
|
||||
struct rproc_vdev *rvdev = container_of(ref, struct rproc_vdev, refcount);
|
||||
struct rproc_vring *rvring;
|
||||
struct rproc *rproc = rvdev->rproc;
|
||||
int id;
|
||||
|
||||
for (id = 0; id < ARRAY_SIZE(rvdev->vring); id++) {
|
||||
rvring = &rvdev->vring[id];
|
||||
if (!rvring->va)
|
||||
continue;
|
||||
|
||||
rproc_free_vring(rvring);
|
||||
}
|
||||
|
||||
rproc_remove_subdev(rproc, &rvdev->subdev);
|
||||
list_del(&rvdev->node);
|
||||
kfree(rvdev);
|
||||
}
|
||||
|
||||
/**
|
||||
* rproc_handle_trace() - handle a shared trace buffer resource
|
||||
* @rproc: the remote processor
|
||||
@@ -673,15 +723,6 @@ free_carv:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rproc_count_vrings(struct rproc *rproc, struct fw_rsc_vdev *rsc,
|
||||
int offset, int avail)
|
||||
{
|
||||
/* Summarize the number of notification IDs */
|
||||
rproc->max_notifyid += rsc->num_of_vrings;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* A lookup table for resource handlers. The indices are defined in
|
||||
* enum fw_resource_type.
|
||||
@@ -690,10 +731,6 @@ static rproc_handle_resource_t rproc_loading_handlers[RSC_LAST] = {
|
||||
[RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout,
|
||||
[RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem,
|
||||
[RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace,
|
||||
[RSC_VDEV] = (rproc_handle_resource_t)rproc_count_vrings,
|
||||
};
|
||||
|
||||
static rproc_handle_resource_t rproc_vdev_handler[RSC_LAST] = {
|
||||
[RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev,
|
||||
};
|
||||
|
||||
@@ -736,6 +773,34 @@ static int rproc_handle_resources(struct rproc *rproc, int len,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rproc_probe_subdevices(struct rproc *rproc)
|
||||
{
|
||||
struct rproc_subdev *subdev;
|
||||
int ret;
|
||||
|
||||
list_for_each_entry(subdev, &rproc->subdevs, node) {
|
||||
ret = subdev->probe(subdev);
|
||||
if (ret)
|
||||
goto unroll_registration;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
unroll_registration:
|
||||
list_for_each_entry_continue_reverse(subdev, &rproc->subdevs, node)
|
||||
subdev->remove(subdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rproc_remove_subdevices(struct rproc *rproc)
|
||||
{
|
||||
struct rproc_subdev *subdev;
|
||||
|
||||
list_for_each_entry(subdev, &rproc->subdevs, node)
|
||||
subdev->remove(subdev);
|
||||
}
|
||||
|
||||
/**
|
||||
* rproc_resource_cleanup() - clean up and free all acquired resources
|
||||
* @rproc: rproc handle
|
||||
@@ -782,7 +847,7 @@ static void rproc_resource_cleanup(struct rproc *rproc)
|
||||
|
||||
/* clean up remote vdev entries */
|
||||
list_for_each_entry_safe(rvdev, rvtmp, &rproc->rvdevs, node)
|
||||
rproc_remove_virtio_dev(rvdev);
|
||||
kref_put(&rvdev->refcount, rproc_vdev_release);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -824,25 +889,16 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
|
||||
/*
|
||||
* Create a copy of the resource table. When a virtio device starts
|
||||
* and calls vring_new_virtqueue() the address of the allocated vring
|
||||
* will be stored in the cached_table. Before the device is started,
|
||||
* cached_table will be copied into device memory.
|
||||
* will be stored in the table_ptr. Before the device is started,
|
||||
* table_ptr will be copied into device memory.
|
||||
*/
|
||||
rproc->cached_table = kmemdup(table, tablesz, GFP_KERNEL);
|
||||
if (!rproc->cached_table)
|
||||
rproc->table_ptr = kmemdup(table, tablesz, GFP_KERNEL);
|
||||
if (!rproc->table_ptr)
|
||||
goto clean_up;
|
||||
|
||||
rproc->table_ptr = rproc->cached_table;
|
||||
|
||||
/* reset max_notifyid */
|
||||
rproc->max_notifyid = -1;
|
||||
|
||||
/* look for virtio devices and register them */
|
||||
ret = rproc_handle_resources(rproc, tablesz, rproc_vdev_handler);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to handle vdev resources: %d\n", ret);
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
/* handle fw resources which are required to boot rproc */
|
||||
ret = rproc_handle_resources(rproc, tablesz, rproc_loading_handlers);
|
||||
if (ret) {
|
||||
@@ -858,18 +914,16 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
|
||||
}
|
||||
|
||||
/*
|
||||
* The starting device has been given the rproc->cached_table as the
|
||||
* The starting device has been given the rproc->table_ptr as the
|
||||
* resource table. The address of the vring along with the other
|
||||
* allocated resources (carveouts etc) is stored in cached_table.
|
||||
* allocated resources (carveouts etc) is stored in table_ptr.
|
||||
* In order to pass this information to the remote device we must copy
|
||||
* this information to device memory. We also update the table_ptr so
|
||||
* that any subsequent changes will be applied to the loaded version.
|
||||
*/
|
||||
loaded_table = rproc_find_loaded_rsc_table(rproc, fw);
|
||||
if (loaded_table) {
|
||||
memcpy(loaded_table, rproc->cached_table, tablesz);
|
||||
rproc->table_ptr = loaded_table;
|
||||
}
|
||||
if (loaded_table)
|
||||
memcpy(loaded_table, rproc->table_ptr, tablesz);
|
||||
|
||||
/* power up the remote processor */
|
||||
ret = rproc->ops->start(rproc);
|
||||
@@ -878,17 +932,26 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
|
||||
goto clean_up_resources;
|
||||
}
|
||||
|
||||
/* probe any subdevices for the remote processor */
|
||||
ret = rproc_probe_subdevices(rproc);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to probe subdevices for %s: %d\n",
|
||||
rproc->name, ret);
|
||||
goto stop_rproc;
|
||||
}
|
||||
|
||||
rproc->state = RPROC_RUNNING;
|
||||
|
||||
dev_info(dev, "remote processor %s is now up\n", rproc->name);
|
||||
|
||||
return 0;
|
||||
|
||||
stop_rproc:
|
||||
rproc->ops->stop(rproc);
|
||||
clean_up_resources:
|
||||
rproc_resource_cleanup(rproc);
|
||||
clean_up:
|
||||
kfree(rproc->cached_table);
|
||||
rproc->cached_table = NULL;
|
||||
kfree(rproc->table_ptr);
|
||||
rproc->table_ptr = NULL;
|
||||
|
||||
rproc_disable_iommu(rproc);
|
||||
@@ -909,7 +972,7 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context)
|
||||
|
||||
/* if rproc is marked always-on, request it to boot */
|
||||
if (rproc->auto_boot)
|
||||
rproc_boot_nowait(rproc);
|
||||
rproc_boot(rproc);
|
||||
|
||||
release_firmware(fw);
|
||||
/* allow rproc_del() contexts, if any, to proceed */
|
||||
@@ -1007,7 +1070,6 @@ static void rproc_crash_handler_work(struct work_struct *work)
|
||||
/**
|
||||
* __rproc_boot() - boot a remote processor
|
||||
* @rproc: handle of a remote processor
|
||||
* @wait: wait for rproc registration completion
|
||||
*
|
||||
* Boot a remote processor (i.e. load its firmware, power it on, ...).
|
||||
*
|
||||
@@ -1016,7 +1078,7 @@ static void rproc_crash_handler_work(struct work_struct *work)
|
||||
*
|
||||
* Returns 0 on success, and an appropriate error value otherwise.
|
||||
*/
|
||||
static int __rproc_boot(struct rproc *rproc, bool wait)
|
||||
static int __rproc_boot(struct rproc *rproc)
|
||||
{
|
||||
const struct firmware *firmware_p;
|
||||
struct device *dev;
|
||||
@@ -1050,10 +1112,6 @@ static int __rproc_boot(struct rproc *rproc, bool wait)
|
||||
goto downref_rproc;
|
||||
}
|
||||
|
||||
/* if rproc virtio is not yet configured, wait */
|
||||
if (wait)
|
||||
wait_for_completion(&rproc->firmware_loading_complete);
|
||||
|
||||
ret = rproc_fw_boot(rproc, firmware_p);
|
||||
|
||||
release_firmware(firmware_p);
|
||||
@@ -1072,21 +1130,10 @@ unlock_mutex:
|
||||
*/
|
||||
int rproc_boot(struct rproc *rproc)
|
||||
{
|
||||
return __rproc_boot(rproc, true);
|
||||
return __rproc_boot(rproc);
|
||||
}
|
||||
EXPORT_SYMBOL(rproc_boot);
|
||||
|
||||
/**
|
||||
* rproc_boot_nowait() - boot a remote processor
|
||||
* @rproc: handle of a remote processor
|
||||
*
|
||||
* Same as rproc_boot() but don't wait for rproc registration completion
|
||||
*/
|
||||
int rproc_boot_nowait(struct rproc *rproc)
|
||||
{
|
||||
return __rproc_boot(rproc, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* rproc_shutdown() - power off the remote processor
|
||||
* @rproc: the remote processor
|
||||
@@ -1121,6 +1168,9 @@ void rproc_shutdown(struct rproc *rproc)
|
||||
if (!atomic_dec_and_test(&rproc->power))
|
||||
goto out;
|
||||
|
||||
/* remove any subdevices for the remote processor */
|
||||
rproc_remove_subdevices(rproc);
|
||||
|
||||
/* power off the remote processor */
|
||||
ret = rproc->ops->stop(rproc);
|
||||
if (ret) {
|
||||
@@ -1135,8 +1185,7 @@ void rproc_shutdown(struct rproc *rproc)
|
||||
rproc_disable_iommu(rproc);
|
||||
|
||||
/* Free the copy of the resource table */
|
||||
kfree(rproc->cached_table);
|
||||
rproc->cached_table = NULL;
|
||||
kfree(rproc->table_ptr);
|
||||
rproc->table_ptr = NULL;
|
||||
|
||||
/* if in crash state, unlock crash handler */
|
||||
@@ -1233,9 +1282,6 @@ int rproc_add(struct rproc *rproc)
|
||||
|
||||
dev_info(dev, "%s is available\n", rproc->name);
|
||||
|
||||
dev_info(dev, "Note: remoteproc is still under development and considered experimental.\n");
|
||||
dev_info(dev, "THE BINARY FORMAT IS NOT YET FINALIZED, and backward compatibility isn't yet guaranteed.\n");
|
||||
|
||||
/* create debugfs entries */
|
||||
rproc_create_debug_dir(rproc);
|
||||
ret = rproc_add_virtio_devices(rproc);
|
||||
@@ -1273,6 +1319,7 @@ static void rproc_type_release(struct device *dev)
|
||||
if (rproc->index >= 0)
|
||||
ida_simple_remove(&rproc_dev_index, rproc->index);
|
||||
|
||||
kfree(rproc->firmware);
|
||||
kfree(rproc);
|
||||
}
|
||||
|
||||
@@ -1310,31 +1357,31 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
|
||||
{
|
||||
struct rproc *rproc;
|
||||
char *p, *template = "rproc-%s-fw";
|
||||
int name_len = 0;
|
||||
int name_len;
|
||||
|
||||
if (!dev || !name || !ops)
|
||||
return NULL;
|
||||
|
||||
if (!firmware)
|
||||
if (!firmware) {
|
||||
/*
|
||||
* Make room for default firmware name (minus %s plus '\0').
|
||||
* If the caller didn't pass in a firmware name then
|
||||
* construct a default name. We're already glomming 'len'
|
||||
* bytes onto the end of the struct rproc allocation, so do
|
||||
* a few more for the default firmware name (but only if
|
||||
* the caller doesn't pass one).
|
||||
* construct a default name.
|
||||
*/
|
||||
name_len = strlen(name) + strlen(template) - 2 + 1;
|
||||
|
||||
rproc = kzalloc(sizeof(*rproc) + len + name_len, GFP_KERNEL);
|
||||
if (!rproc)
|
||||
return NULL;
|
||||
|
||||
if (!firmware) {
|
||||
p = (char *)rproc + sizeof(struct rproc) + len;
|
||||
p = kmalloc(name_len, GFP_KERNEL);
|
||||
if (!p)
|
||||
return NULL;
|
||||
snprintf(p, name_len, template, name);
|
||||
} else {
|
||||
p = (char *)firmware;
|
||||
p = kstrdup(firmware, GFP_KERNEL);
|
||||
if (!p)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rproc = kzalloc(sizeof(struct rproc) + len, GFP_KERNEL);
|
||||
if (!rproc) {
|
||||
kfree(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rproc->firmware = p;
|
||||
@@ -1346,6 +1393,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
|
||||
device_initialize(&rproc->dev);
|
||||
rproc->dev.parent = dev;
|
||||
rproc->dev.type = &rproc_type;
|
||||
rproc->dev.class = &rproc_class;
|
||||
|
||||
/* Assign a unique device index and name */
|
||||
rproc->index = ida_simple_get(&rproc_dev_index, 0, 0, GFP_KERNEL);
|
||||
@@ -1370,6 +1418,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
|
||||
INIT_LIST_HEAD(&rproc->mappings);
|
||||
INIT_LIST_HEAD(&rproc->traces);
|
||||
INIT_LIST_HEAD(&rproc->rvdevs);
|
||||
INIT_LIST_HEAD(&rproc->subdevs);
|
||||
|
||||
INIT_WORK(&rproc->crash_handler, rproc_crash_handler_work);
|
||||
init_completion(&rproc->crash_comp);
|
||||
@@ -1428,8 +1477,6 @@ EXPORT_SYMBOL(rproc_put);
|
||||
*/
|
||||
int rproc_del(struct rproc *rproc)
|
||||
{
|
||||
struct rproc_vdev *rvdev, *tmp;
|
||||
|
||||
if (!rproc)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -1441,10 +1488,6 @@ int rproc_del(struct rproc *rproc)
|
||||
if (rproc->auto_boot)
|
||||
rproc_shutdown(rproc);
|
||||
|
||||
/* clean up remote vdev entries */
|
||||
list_for_each_entry_safe(rvdev, tmp, &rproc->rvdevs, node)
|
||||
rproc_remove_virtio_dev(rvdev);
|
||||
|
||||
/* the rproc is downref'ed as soon as it's removed from the klist */
|
||||
mutex_lock(&rproc_list_mutex);
|
||||
list_del(&rproc->node);
|
||||
@@ -1456,6 +1499,36 @@ int rproc_del(struct rproc *rproc)
|
||||
}
|
||||
EXPORT_SYMBOL(rproc_del);
|
||||
|
||||
/**
|
||||
* rproc_add_subdev() - add a subdevice to a remoteproc
|
||||
* @rproc: rproc handle to add the subdevice to
|
||||
* @subdev: subdev handle to register
|
||||
* @probe: function to call when the rproc boots
|
||||
* @remove: function to call when the rproc shuts down
|
||||
*/
|
||||
void rproc_add_subdev(struct rproc *rproc,
|
||||
struct rproc_subdev *subdev,
|
||||
int (*probe)(struct rproc_subdev *subdev),
|
||||
void (*remove)(struct rproc_subdev *subdev))
|
||||
{
|
||||
subdev->probe = probe;
|
||||
subdev->remove = remove;
|
||||
|
||||
list_add_tail(&subdev->node, &rproc->subdevs);
|
||||
}
|
||||
EXPORT_SYMBOL(rproc_add_subdev);
|
||||
|
||||
/**
|
||||
* rproc_remove_subdev() - remove a subdevice from a remoteproc
|
||||
* @rproc: rproc handle to remove the subdevice from
|
||||
* @subdev: subdev handle, previously registered with rproc_add_subdev()
|
||||
*/
|
||||
void rproc_remove_subdev(struct rproc *rproc, struct rproc_subdev *subdev)
|
||||
{
|
||||
list_del(&subdev->node);
|
||||
}
|
||||
EXPORT_SYMBOL(rproc_remove_subdev);
|
||||
|
||||
/**
|
||||
* rproc_report_crash() - rproc crash reporter function
|
||||
* @rproc: remote processor
|
||||
@@ -1484,6 +1557,7 @@ EXPORT_SYMBOL(rproc_report_crash);
|
||||
|
||||
static int __init remoteproc_init(void)
|
||||
{
|
||||
rproc_init_sysfs();
|
||||
rproc_init_debugfs();
|
||||
|
||||
return 0;
|
||||
@@ -1495,6 +1569,7 @@ static void __exit remoteproc_exit(void)
|
||||
ida_destroy(&rproc_dev_index);
|
||||
|
||||
rproc_exit_debugfs();
|
||||
rproc_exit_sysfs();
|
||||
}
|
||||
module_exit(remoteproc_exit);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user