Commit 8362fd64 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc

Pull ARM SoC-related driver updates from Olof Johansson:
 "Various driver updates for platforms and a couple of the small driver
  subsystems we merge through our tree:

   - A driver for SCU (system control) on NXP i.MX8QXP

   - Qualcomm Always-on Subsystem messaging driver (AOSS QMP)

   - Qualcomm PM support for MSM8998

   - Support for a newer version of DRAM PHY driver for Broadcom (DPFE)

   - Reset controller support for Bitmain BM1880

   - TI SCI (System Control Interface) support for CPU control on AM654
     processors

   - More TI sysc refactoring and rework"

* tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (84 commits)
  reset: remove redundant null check on pointer dev
  soc: rockchip: work around clang warning
  dt-bindings: reset: imx7: Fix the spelling of 'indices'
  soc: imx: Add i.MX8MN SoC driver support
  soc: aspeed: lpc-ctrl: Fix probe error handling
  soc: qcom: geni: Add support for ACPI
  firmware: ti_sci: Fix gcc unused-but-set-variable warning
  firmware: ti_sci: Use the correct style for SPDX License Identifier
  soc: imx8: Use existing of_root directly
  soc: imx8: Fix potential kernel dump in error path
  firmware/psci: psci_checker: Park kthreads before stopping them
  memory: move jedec_ddr.h from include/memory to drivers/memory/
  memory: move jedec_ddr_data.c from lib/ to drivers/memory/
  MAINTAINERS: Remove myself as qcom maintainer
  soc: aspeed: lpc-ctrl: make parameter optional
  soc: qcom: apr: Don't use reg for domain id
  soc: qcom: fix QCOM_AOSS_QMP dependency and build errors
  memory: tegra: Fix -Wunused-const-variable
  firmware: tegra: Early resume BPMP
  soc/tegra: Select pinctrl for Tegra194
  ...
parents 24e44913 8c099362
......@@ -6,7 +6,7 @@ that are provided by the hardware platform it is running on, including power
and performance functions.
This binding is intended to define the interface the firmware implementing
the SCMI as described in ARM document number ARM DUI 0922B ("ARM System Control
the SCMI as described in ARM document number ARM DEN 0056A ("ARM System Control
and Management Interface Platform Design Document")[0] provide for OSPM in
the device tree.
......
DPAA2 console support
Required properties:
- compatible
Value type: <string>
Definition: Must be "fsl,dpaa2-console".
- reg
Value type: <prop-encoded-array>
Definition: A standard property. Specifies the region where the MCFBA
(MC firmware base address) register can be found.
......@@ -6,6 +6,8 @@ which then translates it into a corresponding voltage on a rail
Required Properties:
- compatible: Should be one of the following
* qcom,msm8996-rpmpd: RPM Power domain for the msm8996 family of SoC
* qcom,msm8998-rpmpd: RPM Power domain for the msm8998 family of SoC
* qcom,qcs404-rpmpd: RPM Power domain for the qcs404 family of SoC
* qcom,sdm845-rpmhpd: RPMh Power domain for the sdm845 family of SoC
- #power-domain-cells: number of cells in Power domain specifier
must be 1.
......
Bitmain BM1880 SoC Reset Controller
===================================
Please also refer to reset.txt in this directory for common reset
controller binding usage.
Required properties:
- compatible: Should be "bitmain,bm1880-reset"
- reg: Offset and length of reset controller space in SCTRL.
- #reset-cells: Must be 1.
Example:
rst: reset-controller@c00 {
compatible = "bitmain,bm1880-reset";
reg = <0xc00 0x8>;
#reset-cells = <1>;
};
......@@ -45,6 +45,6 @@ Example:
};
For list of all valid reset indicies see
For list of all valid reset indices see
<dt-bindings/reset/imx7-reset.h> for i.MX7 and
<dt-bindings/reset/imx8mq-reset.h> for i.MX8MQ
......@@ -2,8 +2,8 @@ Amlogic Canvas
================================
A canvas is a collection of metadata that describes a pixel buffer.
Those metadata include: width, height, phyaddr, wrapping, block mode
and endianness.
Those metadata include: width, height, phyaddr, wrapping and block mode.
Starting with GXBB the endianness can also be described.
Many IPs within Amlogic SoCs rely on canvas indexes to read/write pixel data
rather than use the phy addresses directly. For instance, this is the case for
......@@ -18,7 +18,11 @@ Video Lookup Table
--------------------------
Required properties:
- compatible: "amlogic,canvas"
- compatible: has to be one of:
- "amlogic,meson8-canvas", "amlogic,canvas" on Meson8
- "amlogic,meson8b-canvas", "amlogic,canvas" on Meson8b
- "amlogic,meson8m2-canvas", "amlogic,canvas" on Meson8m2
- "amlogic,canvas" on GXBB and newer
- reg: Base physical address and size of the canvas registers.
Example:
......
Qualcomm Always-On Subsystem side channel binding
This binding describes the hardware component responsible for side channel
requests to the always-on subsystem (AOSS), used for certain power management
requests that is not handled by the standard RPMh interface. Each client in the
SoC has it's own block of message RAM and IRQ for communication with the AOSS.
The protocol used to communicate in the message RAM is known as Qualcomm
Messaging Protocol (QMP)
The AOSS side channel exposes control over a set of resources, used to control
a set of debug related clocks and to affect the low power state of resources
related to the secondary subsystems. These resources are exposed as a set of
power-domains.
- compatible:
Usage: required
Value type: <string>
Definition: must be "qcom,sdm845-aoss-qmp"
- reg:
Usage: required
Value type: <prop-encoded-array>
Definition: the base address and size of the message RAM for this
client's communication with the AOSS
- interrupts:
Usage: required
Value type: <prop-encoded-array>
Definition: should specify the AOSS message IRQ for this client
- mboxes:
Usage: required
Value type: <prop-encoded-array>
Definition: reference to the mailbox representing the outgoing doorbell
in APCS for this client, as described in mailbox/mailbox.txt
- #clock-cells:
Usage: optional
Value type: <u32>
Definition: must be 0
The single clock represents the QDSS clock.
- #power-domain-cells:
Usage: optional
Value type: <u32>
Definition: must be 1
The provided power-domains are:
CDSP state (0), LPASS state (1), modem state (2), SLPI
state (3), SPSS state (4) and Venus state (5).
= SUBNODES
The AOSS side channel also provides the controls for three cooling devices,
these are expressed as subnodes of the QMP node. The name of the node is used
to identify the resource and must therefor be "cx", "mx" or "ebi".
- #cooling-cells:
Usage: optional
Value type: <u32>
Definition: must be 2
= EXAMPLE
The following example represents the AOSS side-channel message RAM and the
mechanism exposing the power-domains, as found in SDM845.
aoss_qmp: qmp@c300000 {
compatible = "qcom,sdm845-aoss-qmp";
reg = <0x0c300000 0x100000>;
interrupts = <GIC_SPI 389 IRQ_TYPE_EDGE_RISING>;
mboxes = <&apss_shared 0>;
#power-domain-cells = <1>;
cx_cdev: cx {
#cooling-cells = <2>;
};
mx_cdev: mx {
#cooling-cells = <2>;
};
};
......@@ -9,7 +9,7 @@ used for audio/voice services on the QDSP.
Value type: <stringlist>
Definition: must be "qcom,apr-v<VERSION-NUMBER>", example "qcom,apr-v2"
- reg
- qcom,apr-domain
Usage: required
Value type: <u32>
Definition: Destination processor ID.
......@@ -49,9 +49,9 @@ by the individual bindings for the specific service
The following example represents a QDSP based sound card on a MSM8996 device
which uses apr as communication between Apps and QDSP.
apr@4 {
apr {
compatible = "qcom,apr-v2";
reg = <APR_DOMAIN_ADSP>;
qcom,apr-domain = <APR_DOMAIN_ADSP>;
q6core@3 {
compatible = "qcom,q6core";
......
......@@ -2091,7 +2091,6 @@ S: Maintained
ARM/QUALCOMM SUPPORT
M: Andy Gross <agross@kernel.org>
M: David Brown <david.brown@linaro.org>
L: linux-arm-msm@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/soc/qcom/
......@@ -2113,7 +2112,7 @@ F: drivers/i2c/busses/i2c-qup.c
F: drivers/i2c/busses/i2c-qcom-geni.c
F: drivers/mfd/ssbi.c
F: drivers/mmc/host/mmci_qcom*
F: drivers/mmc/host/sdhci_msm.c
F: drivers/mmc/host/sdhci-msm.c
F: drivers/pci/controller/dwc/pcie-qcom.c
F: drivers/phy/qualcomm/
F: drivers/power/*/msm*
......@@ -6527,6 +6526,7 @@ M: Li Yang <leoyang.li@nxp.com>
L: linuxppc-dev@lists.ozlabs.org
L: linux-arm-kernel@lists.infradead.org
S: Maintained
F: Documentation/devicetree/bindings/misc/fsl,dpaa2-console.txt
F: Documentation/devicetree/bindings/soc/fsl/
F: drivers/soc/fsl/
F: include/linux/fsl/
......@@ -11907,11 +11907,13 @@ F: include/linux/mtd/onenand*.h
OP-TEE DRIVER
M: Jens Wiklander <jens.wiklander@linaro.org>
L: tee-dev@lists.linaro.org
S: Maintained
F: drivers/tee/optee/
OP-TEE RANDOM NUMBER GENERATOR (RNG) DRIVER
M: Sumit Garg <sumit.garg@linaro.org>
L: tee-dev@lists.linaro.org
S: Maintained
F: drivers/char/hw_random/optee-rng.c
......@@ -13295,7 +13297,7 @@ M: Niklas Cassel <niklas.cassel@linaro.org>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
F: Documentation/devicetree/bindings/net/qcom,dwmac.txt
F: Documentation/devicetree/bindings/net/qcom,ethqos.txt
QUALCOMM GENERIC INTERFACE I2C DRIVER
M: Alok Chauhan <alokc@codeaurora.org>
......@@ -15745,6 +15747,7 @@ F: include/media/i2c/tw9910.h
TEE SUBSYSTEM
M: Jens Wiklander <jens.wiklander@linaro.org>
L: tee-dev@lists.linaro.org
S: Maintained
F: include/linux/tee_drv.h
F: include/uapi/linux/tee.h
......
......@@ -3442,6 +3442,7 @@ static int omap_hwmod_check_module(struct device *dev,
* @dev: struct device
* @oh: module
* @sysc_fields: sysc register bits
* @clockdomain: clockdomain
* @rev_offs: revision register offset
* @sysc_offs: sysconfig register offset
* @syss_offs: sysstatus register offset
......@@ -3453,6 +3454,7 @@ static int omap_hwmod_check_module(struct device *dev,
static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
const struct ti_sysc_module_data *data,
struct sysc_regbits *sysc_fields,
struct clockdomain *clkdm,
s32 rev_offs, s32 sysc_offs,
s32 syss_offs, u32 sysc_flags,
u32 idlemodes)
......@@ -3460,8 +3462,6 @@ static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
struct omap_hwmod_class_sysconfig *sysc;
struct omap_hwmod_class *class = NULL;
struct omap_hwmod_ocp_if *oi = NULL;
struct clockdomain *clkdm = NULL;
struct clk *clk = NULL;
void __iomem *regs = NULL;
unsigned long flags;
......@@ -3508,36 +3508,6 @@ static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
oi->user = OCP_USER_MPU | OCP_USER_SDMA;
}
if (!oh->_clk) {
struct clk_hw_omap *hwclk;
clk = of_clk_get_by_name(dev->of_node, "fck");
if (!IS_ERR(clk))
clk_prepare(clk);
else
clk = NULL;
/*
* Populate clockdomain based on dts clock. It is needed for
* clkdm_deny_idle() and clkdm_allow_idle() until we have have
* interconnect driver and reset driver capable of blocking
* clockdomain idle during reset, enable and idle.
*/
if (clk) {
hwclk = to_clk_hw_omap(__clk_get_hw(clk));
if (hwclk && hwclk->clkdm_name)
clkdm = clkdm_lookup(hwclk->clkdm_name);
}
/*
* Note that we assume interconnect driver manages the clocks
* and do not need to populate oh->_clk for dynamically
* allocated modules.
*/
clk_unprepare(clk);
clk_put(clk);
}
spin_lock_irqsave(&oh->_lock, flags);
if (regs)
oh->_mpu_rt_va = regs;
......@@ -3623,7 +3593,7 @@ int omap_hwmod_init_module(struct device *dev,
u32 sysc_flags, idlemodes;
int error;
if (!dev || !data)
if (!dev || !data || !data->name || !cookie)
return -EINVAL;
oh = _lookup(data->name);
......@@ -3694,7 +3664,8 @@ int omap_hwmod_init_module(struct device *dev,
return error;
return omap_hwmod_allocate_module(dev, oh, data, sysc_fields,
rev_offs, sysc_offs, syss_offs,
cookie->clkdm, rev_offs,
sysc_offs, syss_offs,
sysc_flags, idlemodes);
}
......
......@@ -26,6 +26,7 @@
#include <linux/platform_data/wkup_m3.h>
#include <linux/platform_data/asoc-ti-mcbsp.h>
#include "clockdomain.h"
#include "common.h"
#include "common-board-devices.h"
#include "control.h"
......@@ -460,6 +461,62 @@ static void __init dra7x_evm_mmc_quirk(void)
}
#endif
static struct clockdomain *ti_sysc_find_one_clockdomain(struct clk *clk)
{
struct clockdomain *clkdm = NULL;
struct clk_hw_omap *hwclk;
hwclk = to_clk_hw_omap(__clk_get_hw(clk));
if (hwclk && hwclk->clkdm_name)
clkdm = clkdm_lookup(hwclk->clkdm_name);
return clkdm;
}
/**
* ti_sysc_clkdm_init - find clockdomain based on clock
* @fck: device functional clock
* @ick: device interface clock
* @dev: struct device
*
* Populate clockdomain based on clock. It is needed for
* clkdm_deny_idle() and clkdm_allow_idle() for blocking clockdomain
* clockdomain idle during reset, enable and idle.
*
* Note that we assume interconnect driver manages the clocks
* and do not need to populate oh->_clk for dynamically
* allocated modules.
*/
static int ti_sysc_clkdm_init(struct device *dev,
struct clk *fck, struct clk *ick,
struct ti_sysc_cookie *cookie)
{
if (fck)
cookie->clkdm = ti_sysc_find_one_clockdomain(fck);
if (cookie->clkdm)
return 0;
if (ick)
cookie->clkdm = ti_sysc_find_one_clockdomain(ick);
if (cookie->clkdm)
return 0;
return -ENODEV;
}
static void ti_sysc_clkdm_deny_idle(struct device *dev,
const struct ti_sysc_cookie *cookie)
{
if (cookie->clkdm)
clkdm_deny_idle(cookie->clkdm);
}
static void ti_sysc_clkdm_allow_idle(struct device *dev,
const struct ti_sysc_cookie *cookie)
{
if (cookie->clkdm)
clkdm_allow_idle(cookie->clkdm);
}
static int ti_sysc_enable_module(struct device *dev,
const struct ti_sysc_cookie *cookie)
{
......@@ -491,6 +548,9 @@ static struct of_dev_auxdata omap_auxdata_lookup[];
static struct ti_sysc_platform_data ti_sysc_pdata = {
.auxdata = omap_auxdata_lookup,
.init_clockdomain = ti_sysc_clkdm_init,
.clkdm_deny_idle = ti_sysc_clkdm_deny_idle,
.clkdm_allow_idle = ti_sysc_clkdm_allow_idle,
.init_module = omap_hwmod_init_module,
.enable_module = ti_sysc_enable_module,
.idle_module = ti_sysc_idle_module,
......
......@@ -399,8 +399,8 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
&gisb_panic_notifier);
}
dev_info(&pdev->dev, "registered mem: %p, irqs: %d, %d\n",
gdev->base, timeout_irq, tea_irq);
dev_info(&pdev->dev, "registered irqs: %d, %d\n",
timeout_irq, tea_irq);
return 0;
}
......
......@@ -443,11 +443,31 @@ int dprc_get_obj_region(struct fsl_mc_io *mc_io,
struct fsl_mc_command cmd = { 0 };
struct dprc_cmd_get_obj_region *cmd_params;
struct dprc_rsp_get_obj_region *rsp_params;
u16 major_ver, minor_ver;
int err;
/* prepare command */
cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG,
err = dprc_get_api_version(mc_io, 0,
&major_ver,
&minor_ver);
if (err)
return err;
/**
* MC API version 6.3 introduced a new field to the region
* descriptor: base_address. If the older API is in use then the base
* address is set to zero to indicate it needs to be obtained elsewhere
* (typically the device tree).
*/
if (major_ver > 6 || (major_ver == 6 && minor_ver >= 3))
cmd.header =
mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG_V2,
cmd_flags, token);
else
cmd.header =
mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG,
cmd_flags, token);
cmd_params = (struct dprc_cmd_get_obj_region *)cmd.params;
cmd_params->obj_id = cpu_to_le32(obj_id);
cmd_params->region_index = region_index;
......@@ -461,8 +481,12 @@ int dprc_get_obj_region(struct fsl_mc_io *mc_io,
/* retrieve response parameters */
rsp_params = (struct dprc_rsp_get_obj_region *)cmd.params;
region_desc->base_offset = le64_to_cpu(rsp_params->base_addr);
region_desc->base_offset = le64_to_cpu(rsp_params->base_offset);
region_desc->size = le32_to_cpu(rsp_params->size);
if (major_ver > 6 || (major_ver == 6 && minor_ver >= 3))
region_desc->base_address = le64_to_cpu(rsp_params->base_addr);
else
region_desc->base_address = 0;
return 0;
}
......
......@@ -487,10 +487,19 @@ static int fsl_mc_device_get_mmio_regions(struct fsl_mc_device *mc_dev,
"dprc_get_obj_region() failed: %d\n", error);
goto error_cleanup_regions;
}
/*
* Older MC only returned region offset and no base address
* If base address is in the region_desc use it otherwise
* revert to old mechanism
*/
if (region_desc.base_address)
regions[i].start = region_desc.base_address +
region_desc.base_offset;
else
error = translate_mc_addr(mc_dev, mc_region_type,
region_desc.base_offset,
&regions[i].start);
if (error < 0) {
dev_err(parent_dev,
"Invalid MC offset: %#x (for %s.%d\'s region %d)\n",
......@@ -504,6 +513,8 @@ static int fsl_mc_device_get_mmio_regions(struct fsl_mc_device *mc_dev,
regions[i].flags = IORESOURCE_IO;
if (region_desc.flags & DPRC_REGION_CACHEABLE)
regions[i].flags |= IORESOURCE_CACHEABLE;
if (region_desc.flags & DPRC_REGION_SHAREABLE)
regions[i].flags |= IORESOURCE_MEM;
}
mc_dev->regions = regions;
......
......@@ -79,9 +79,11 @@ int dpmcp_reset(struct fsl_mc_io *mc_io,
/* DPRC command versioning */
#define DPRC_CMD_BASE_VERSION 1
#define DPRC_CMD_2ND_VERSION 2
#define DPRC_CMD_ID_OFFSET 4
#define DPRC_CMD(id) (((id) << DPRC_CMD_ID_OFFSET) | DPRC_CMD_BASE_VERSION)
#define DPRC_CMD_V2(id) (((id) << DPRC_CMD_ID_OFFSET) | DPRC_CMD_2ND_VERSION)
/* DPRC command IDs */
#define DPRC_CMDID_CLOSE DPRC_CMD(0x800)
......@@ -100,6 +102,7 @@ int dpmcp_reset(struct fsl_mc_io *mc_io,
#define DPRC_CMDID_GET_OBJ_COUNT DPRC_CMD(0x159)
#define DPRC_CMDID_GET_OBJ DPRC_CMD(0x15A)
#define DPRC_CMDID_GET_OBJ_REG DPRC_CMD(0x15E)
#define DPRC_CMDID_GET_OBJ_REG_V2 DPRC_CMD_V2(0x15E)
#define DPRC_CMDID_SET_OBJ_IRQ DPRC_CMD(0x15F)
struct dprc_cmd_open {
......@@ -199,9 +202,16 @@ struct dprc_rsp_get_obj_region {
/* response word 0 */
__le64 pad;
/* response word 1 */
__le64 base_addr;
__le64 base_offset;
/* response word 2 */
__le32 size;
__le32 pad2;
/* response word 3 */
__le32 flags;
__le32 pad3;
/* response word 4 */
/* base_addr may be zero if older MC firmware is used */
__le64 base_addr;
};
struct dprc_cmd_set_obj_irq {
......@@ -334,6 +344,7 @@ int dprc_set_obj_irq(struct fsl_mc_io *mc_io,
/* Region flags */
/* Cacheable - Indicates that region should be mapped as cacheable */
#define DPRC_REGION_CACHEABLE 0x00000001
#define DPRC_REGION_SHAREABLE 0x00000002
/**
* enum dprc_region_type - Region type
......@@ -342,7 +353,8 @@ int dprc_set_obj_irq(struct fsl_mc_io *mc_io,
*/
enum dprc_region_type {
DPRC_REGION_TYPE_MC_PORTAL,
DPRC_REGION_TYPE_QBMAN_PORTAL
DPRC_REGION_TYPE_QBMAN_PORTAL,
DPRC_REGION_TYPE_QBMAN_MEM_BACKED_PORTAL
};
/**
......@@ -360,6 +372,7 @@ struct dprc_region_desc {
u32 size;
u32 flags;
enum dprc_region_type type;
u64 base_address;
};
int dprc_get_obj_region(struct fsl_mc_io *mc_io,
......
This diff is collapsed.
......@@ -185,6 +185,8 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id,
if (rate_discrete)
clk->list.num_rates = tot_rate_cnt;
clk->rate_discrete = rate_discrete;
err:
scmi_xfer_put(handle, t);
return ret;
......
......@@ -30,10 +30,12 @@ struct scmi_msg_resp_sensor_description {
__le32 id;
__le32 attributes_low;
#define SUPPORTS_ASYNC_READ(x) ((x) & BIT(31))
#define NUM_TRIP_POINTS(x) (((x) >> 4) & 0xff)
#define NUM_TRIP_POINTS(x) ((x) & 0xff)
__le32 attributes_high;
#define SENSOR_TYPE(x) ((x) & 0xff)
#define SENSOR_SCALE(x) (((x) >> 11) & 0x3f)
#define SENSOR_SCALE(x) (((x) >> 11) & 0x1f)
#define SENSOR_SCALE_SIGN BIT(4)
#define SENSOR_SCALE_EXTEND GENMASK(7, 5)
#define SENSOR_UPDATE_SCALE(x) (((x) >> 22) & 0x1f)
#define SENSOR_UPDATE_BASE(x) (((x) >> 27) & 0x1f)
u8 name[SCMI_MAX_STR_SIZE];
......@@ -140,6 +142,10 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle,
s = &si->sensors[desc_index + cnt];
s->id = le32_to_cpu(buf->desc[cnt].id);
s->type = SENSOR_TYPE(attrh);
s->scale = SENSOR_SCALE(attrh);
/* Sign extend to a full s8 */
if (s->scale & SENSOR_SCALE_SIGN)
s->scale |= SENSOR_SCALE_EXTEND;
strlcpy(s->name, buf->desc[cnt].name, SCMI_MAX_STR_SIZE);
}
......
......@@ -359,16 +359,16 @@ static int suspend_test_thread(void *arg)
for (;;) {
/* Needs to be set first to avoid missing a wakeup. */
set_current_state(TASK_INTERRUPTIBLE);
if (kthread_should_stop()) {
__set_current_state(TASK_RUNNING);
if (kthread_should_park())
break;
}
schedule();
}
pr_info("CPU %d suspend test results: success %d, shallow states %d, errors %d\n",
cpu, nb_suspend, nb_shallow_sleep, nb_err);
kthread_parkme();
return nb_err;
}
......@@ -433,8 +433,10 @@ static int suspend_tests(void)
/* Stop and destroy all threads, get return status. */
for (i = 0; i < nb_threads; ++i)
for (i = 0; i < nb_threads; ++i) {
err += kthread_park(threads[i]);
err += kthread_stop(threads[i]);
}
out:
cpuidle_resume_and_unlock();
kfree(threads);
......
......@@ -803,7 +803,9 @@ static int __maybe_unused tegra_bpmp_resume(struct device *dev)
return 0;
}
static SIMPLE_DEV_PM_OPS(tegra_bpmp_pm_ops, NULL, tegra_bpmp_resume);
static const struct dev_pm_ops tegra_bpmp_pm_ops = {
.resume_early = tegra_bpmp_resume,
};
#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \
IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
......
This diff is collapsed.
This diff is collapsed.
......@@ -18,6 +18,50 @@ struct scmi_sensors {
const struct scmi_sensor_info **info[hwmon_max];
};
static inline u64 __pow10(u8 x)
{
u64 r = 1;
while (x--)
r *= 10;
return r;
}
static int scmi_hwmon_scale(const struct scmi_sensor_info *sensor, u64 *value)
{
s8 scale = sensor->scale;
u64 f;
switch (sensor->type) {
case TEMPERATURE_C:
case VOLTAGE:
case CURRENT:
scale += 3;
break;
case POWER:
case ENERGY:
scale += 6;
break;
default:
break;
}
if (scale == 0)
return 0;
if (abs(scale) > 19)
return -E2BIG;
f = __pow10(abs(scale));
if (scale > 0)
*value *= f;
else
*value = div64_u64(*value, f);
return 0;
}
static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
......@@ -29,6 +73,10 @@ static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
sensor = *(scmi_sensors->info[type] + channel);
ret = h->sensor_ops->reading_get(h, sensor->id, false, &value);
if (ret)
return ret;
ret = scmi_hwmon_scale(sensor, &value);
if (!ret)
*val = value;
......
......@@ -8,6 +8,14 @@ menuconfig MEMORY
if MEMORY
config DDR
bool
help
Data from JEDEC specs for DDR SDRAM memories,
particularly the AC timing parameters and addressing
information. This data is useful for drivers handling
DDR SDRAM controllers.
config ARM_PL172_MPMC
tristate "ARM PL172 MPMC driver"
depends on ARM_AMBA && OF
......
......@@ -3,6 +3,7 @@
# Makefile for memory devices
#
obj-$(CONFIG_DDR) += jedec_ddr_data.o
ifeq ($(CONFIG_DDR),y)
obj-$(CONFIG_OF) += of_memory.o
endif
......
This diff is collapsed.
......@@ -23,8 +23,9 @@
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
#include <memory/jedec_ddr.h>
#include "emif.h"
#include "jedec_ddr.h"
#include "of_memory.h"
/**
......
......@@ -6,8 +6,8 @@
*
* Aneesh V <aneesh@ti.com>
*/
#ifndef __LINUX_JEDEC_DDR_H
#define __LINUX_JEDEC_DDR_H
#ifndef __JEDEC_DDR_H
#define __JEDEC_DDR_H
#include <linux/types.h>
......@@ -169,4 +169,4 @@ extern const struct lpddr2_timings
lpddr2_jedec_timings[NUM_DDR_TIMING_TABLE_ENTRIES];
extern const struct lpddr2_min_tck lpddr2_jedec_min_tck;
#endif /* __LINUX_JEDEC_DDR_H */
#endif /* __JEDEC_DDR_H */
......@@ -7,8 +7,9 @@
* Aneesh V <aneesh@ti.com>
*/
#include <memory/jedec_ddr.h>
#include <linux/module.h>
#include <linux/export.h>
#include "jedec_ddr.h"
/* LPDDR2 addressing details from JESD209-2 section 2.4 */
const struct lpddr2_addressing
......
......@@ -10,8 +10,9 @@
#include <linux/list.h>
#include <linux/of.h>
#include <linux/gfp.h>
#include <memory/jedec_ddr.h>
#include <linux/export.h>
#include "jedec_ddr.h"
#include "of_memory.h"
/**
......
......@@ -30,28 +30,6 @@
#define MC_EMEM_ARB_MISC1 0xdc
#define MC_EMEM_ARB_RING1_THROTTLE 0xe0
static const unsigned long tegra124_mc_emem_regs[] = {
MC_EMEM_ARB_CFG,
MC_EMEM_ARB_OUTSTANDING_REQ,
MC_EMEM_ARB_TIMING_RCD,
MC_EMEM_ARB_TIMING_RP,
MC_EMEM_ARB_TIMING_RC,
MC_EMEM_ARB_TIMING_RAS,
MC_EMEM_ARB_TIMING_FAW,
MC_EMEM_ARB_TIMING_RRD,
MC_EMEM_ARB_TIMING_RAP2PRE,
MC_EMEM_ARB_TIMING_WAP2PRE,
MC_EMEM_ARB_TIMING_R2R,
MC_EMEM_ARB_TIMING_W2W,
MC_EMEM_ARB_TIMING_R2W,
MC_EMEM_ARB_TIMING_W2R,
MC_EMEM_ARB_DA_TURNS,
MC_EMEM_ARB_DA_COVERS,
MC_EMEM_ARB_MISC0,
MC_EMEM_ARB_MISC1,
MC_EMEM_ARB_RING1_THROTTLE
};
static const struct tegra_mc_client tegra124_mc_clients[] = {
{
.id = 0x00,
......@@ -1046,6 +1024,28 @@ static const struct tegra_mc_reset tegra124_mc_resets[] = {
};
#ifdef CONFIG_ARCH_TEGRA_124_SOC
static const unsigned long tegra124_mc_emem_regs[] = {
MC_EMEM_ARB_CFG,
MC_EMEM_ARB_OUTSTANDING_REQ,
MC_EMEM_ARB_TIMING_RCD,
MC_EMEM_ARB_TIMING_RP,
MC_EMEM_ARB_TIMING_RC,
MC_EMEM_ARB_TIMING_RAS,
MC_EMEM_ARB_TIMING_FAW,
MC_EMEM_ARB_TIMING_RRD,
MC_EMEM_ARB_TIMING_RAP2PRE,
MC_EMEM_ARB_TIMING_WAP2PRE,
MC_EMEM_ARB_TIMING_R2R,
MC_EMEM_ARB_TIMING_W2W,
MC_EMEM_ARB_TIMING_R2W,
MC_EMEM_ARB_TIMING_W2R,
MC_EMEM_ARB_DA_TURNS,
MC_EMEM_ARB_DA_COVERS,
MC_EMEM_ARB_MISC0,
MC_EMEM_ARB_MISC1,
MC_EMEM_ARB_RING1_THROTTLE
};
static const struct tegra_smmu_soc tegra124_smmu_soc = {
.clients = tegra124_mc_clients,
.num_clients = ARRAY_SIZE(tegra124_mc_clients),
......
......@@ -118,7 +118,7 @@ config RESET_QCOM_PDC
config RESET_SIMPLE
bool "Simple Reset Controller Driver" if COMPILE_TEST
default ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED
default ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED || ARCH_BITMAIN
help
This enables a simple reset controller driver for reset lines that
that can be asserted and deasserted by toggling bits in a contiguous,
......@@ -130,6 +130,7 @@ config RESET_SIMPLE
- RCC reset controller in STM32 MCUs
- Allwinner SoCs
- ZTE's zx2967 family
- Bitmain BM1880 SoC
config RESET_STM32MP157
bool "STM32MP157 Reset Driver" if COMPILE_TEST
......
......@@ -690,9 +690,6 @@ __reset_control_get_from_lookup(struct device *dev, const char *con_id,
const char *dev_id = dev_name(dev);
struct reset_control *rstc = NULL;
if (!dev)
return ERR_PTR(-EINVAL);
mutex_lock(&reset_lookup_mutex);
list_for_each_entry(lookup, &reset_lookup_list, list) {
......
......@@ -125,6 +125,8 @@ static const struct of_device_id reset_simple_dt_ids[] = {
.data = &reset_simple_active_low },
{ .compatible = "aspeed,ast2400-lpc-reset" },
{ .compatible = "aspeed,ast2500-lpc-reset" },
{ .compatible = "bitmain,bm1880-reset",
.data = &reset_simple_active_low },
{ /* sentinel */ },
};
......
......@@ -35,6 +35,7 @@ struct meson_canvas {
void __iomem *reg_base;
spinlock_t lock; /* canvas device lock */
u8 used[NUM_CANVAS];
bool supports_endianness;
};
static void canvas_write(struct meson_canvas *canvas, u32 reg, u32 val)
......@@ -86,6 +87,12 @@ int meson_canvas_config(struct meson_canvas *canvas, u8 canvas_index,
{
unsigned long flags;
if (endian && !canvas->supports_endianness) {
dev_err(canvas->dev,
"Endianness is not supported on this SoC\n");
return -EINVAL;
}
spin_lock_irqsave(&canvas->lock, flags);
if (!canvas->used[canvas_index]) {
dev_err(canvas->dev,
......@@ -172,6 +179,8 @@ static int meson_canvas_probe(struct platform_device *pdev)
if (IS_ERR(canvas->reg_base))
return PTR_ERR(canvas->reg_base);
canvas->supports_endianness = of_device_get_match_data(dev);
canvas->dev = dev;
spin_lock_init(&canvas->lock);
dev_set_drvdata(dev, canvas);
......@@ -180,7 +189,10 @@ static int meson_canvas_probe(struct platform_device *pdev)
}
static const struct of_device_id canvas_dt_match[] = {
{ .compatible = "amlogic,canvas" },
{ .compatible = "amlogic,meson8-canvas", .data = (void *)false, },
{ .compatible = "amlogic,meson8b-canvas", .data = (void *)false, },
{ .compatible = "amlogic,meson8m2-canvas", .data = (void *)false, },
{ .compatible = "amlogic,canvas", .data = (void *)true, },
{}
};
MODULE_DEVICE_TABLE(of, canvas_dt_match);
......
......@@ -64,6 +64,7 @@ static long aspeed_lpc_ctrl_ioctl(struct file *file, unsigned int cmd,
unsigned long param)
{
struct aspeed_lpc_ctrl *lpc_ctrl = file_aspeed_lpc_ctrl(file);
struct device *dev = file->private_data;
void __user *p = (void __user *)param;
struct aspeed_lpc_ctrl_mapping map;
u32 addr;
......@@ -86,6 +87,12 @@ static long aspeed_lpc_ctrl_ioctl(struct file *file, unsigned int cmd,
if (map.window_id != 0)
return -EINVAL;
/* If memory-region is not described in device tree */
if (!lpc_ctrl->mem_size) {
dev_dbg(dev, "Didn't find reserved memory\n");
return -ENXIO;
}
map.size = lpc_ctrl->mem_size;
return copy_to_user(p, &map, sizeof(map)) ? -EFAULT : 0;
......@@ -122,9 +129,18 @@ static long aspeed_lpc_ctrl_ioctl(struct file *file, unsigned int cmd,
return -EINVAL;
if (map.window_type == ASPEED_LPC_CTRL_WINDOW_FLASH) {
if (!lpc_ctrl->pnor_size) {
dev_dbg(dev, "Didn't find host pnor flash\n");
return -ENXIO;
}
addr = lpc_ctrl->pnor_base;
size = lpc_ctrl->pnor_size;
} else if (map.window_type == ASPEED_LPC_CTRL_WINDOW_MEMORY) {
/* If memory-region is not described in device tree */
if (!lpc_ctrl->mem_size) {
dev_dbg(dev, "Didn't find reserved memory\n");
return -ENXIO;
}
addr = lpc_ctrl->mem_base;
size = lpc_ctrl->mem_size;
} else {
......@@ -192,12 +208,11 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
if (!lpc_ctrl)
return -ENOMEM;
/* If flash is described in device tree then store */
node = of_parse_phandle(dev->of_node, "flash", 0);
if (!node) {
dev_err(dev, "Didn't find host pnor flash node\n");
return -ENODEV;
}
dev_dbg(dev, "Didn't find host pnor flash node\n");
} else {
rc = of_address_to_resource(node, 1, &resm);
of_node_put(node);
if (rc) {
......@@ -207,24 +222,26 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
lpc_ctrl->pnor_size = resource_size(&resm);
lpc_ctrl->pnor_base = resm.start;
}
dev_set_drvdata(&pdev->dev, lpc_ctrl);
/* If memory-region is described in device tree then store */
node = of_parse_phandle(dev->of_node, "memory-region", 0);
if (!node) {
dev_err(dev, "Didn't find reserved memory\n");
return -EINVAL;
}
dev_dbg(dev, "Didn't find reserved memory\n");
} else {
rc = of_address_to_resource(node, 0, &resm);
of_node_put(node);
if (rc) {
dev_err(dev, "Couldn't address to resource for reserved memory\n");
return -ENOMEM;
return -ENXIO;
}
lpc_ctrl->mem_size = resource_size(&resm);
lpc_ctrl->mem_base = resm.start;
}
lpc_ctrl->regmap = syscon_node_to_regmap(
pdev->dev.parent->of_node);
......@@ -254,8 +271,6 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
goto err;
}
dev_info(dev, "Loaded at %pr\n", &resm);
return 0;
err:
......
......@@ -30,4 +30,14 @@ config FSL_MC_DPIO
other DPAA2 objects. This driver does not expose the DPIO
objects individually, but groups them under a service layer
API.
config DPAA2_CONSOLE
tristate "QorIQ DPAA2 console driver"
depends on OF && (ARCH_LAYERSCAPE || COMPILE_TEST)
default y
help
Console driver for DPAA2 platforms. Exports 2 char devices,
/dev/dpaa2_mc_console and /dev/dpaa2_aiop_console,
which can be used to dump the Management Complex and AIOP
firmware logs.
endmenu
......@@ -8,3 +8,4 @@ obj-$(CONFIG_QUICC_ENGINE) += qe/
obj-$(CONFIG_CPM) += qe/
obj-$(CONFIG_FSL_GUTS) += guts.o
obj-$(CONFIG_FSL_MC_DPIO) += dpio/
obj-$(CONFIG_DPAA2_CONSOLE) += dpaa2-console.o
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
* Freescale DPAA2 Platforms Console Driver
*
* Copyright 2015-2016 Freescale Semiconductor Inc.
* Copyright 2018 NXP
*/
#define pr_fmt(fmt) "dpaa2-console: " fmt
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/io.h>
/* MC firmware base low/high registers indexes */
#define MCFBALR_OFFSET 0
#define MCFBAHR_OFFSET 1
/* Bit masks used to get the most/least significant part of the MC base addr */
#define MC_FW_ADDR_MASK_HIGH 0x1FFFF
#define MC_FW_ADDR_MASK_LOW 0xE0000000
#define MC_BUFFER_OFFSET 0x01000000
#define MC_BUFFER_SIZE (1024 * 1024 * 16)
#define MC_OFFSET_DELTA MC_BUFFER_OFFSET
#define AIOP_BUFFER_OFFSET 0x06000000
#define AIOP_BUFFER_SIZE (1024 * 1024 * 16)
#define AIOP_OFFSET_DELTA 0
#define LOG_HEADER_FLAG_BUFFER_WRAPAROUND 0x80000000
#define LAST_BYTE(a) ((a) & ~(LOG_HEADER_FLAG_BUFFER_WRAPAROUND))
/* MC and AIOP Magic words */
#define MAGIC_MC 0x4d430100
#define MAGIC_AIOP 0x41494F50
struct log_header {
__le32 magic_word;
char reserved[4];
__le32 buf_start;
__le32 buf_length;
__le32 last_byte;
};
struct console_data {
void __iomem *map_addr;
struct log_header __iomem *hdr;
void __iomem *start_addr;
void __iomem *end_addr;
void __iomem *end_of_data;
void __iomem *cur_ptr;
};
static struct resource mc_base_addr;
static inline void adjust_end(struct console_data *cd)
{
u32 last_byte = readl(&cd->hdr->last_byte);
cd->end_of_data = cd->start_addr + LAST_BYTE(last_byte);
}
static u64 get_mc_fw_base_address(void)
{
u64 mcfwbase = 0ULL;
u32 __iomem *mcfbaregs;
mcfbaregs = ioremap(mc_base_addr.start, resource_size(&mc_base_addr));
if (!mcfbaregs) {
pr_err("could not map MC Firmaware Base registers\n");
return 0;
}
mcfwbase = readl(mcfbaregs + MCFBAHR_OFFSET) &
MC_FW_ADDR_MASK_HIGH;
mcfwbase <<= 32;
mcfwbase |= readl(mcfbaregs + MCFBALR_OFFSET) & MC_FW_ADDR_MASK_LOW;
iounmap(mcfbaregs);
pr_debug("MC base address at 0x%016llx\n", mcfwbase);
return mcfwbase;
}
static ssize_t dpaa2_console_size(struct console_data *cd)
{
ssize_t size;
if (cd->cur_ptr <= cd->end_of_data)
size = cd->end_of_data - cd->cur_ptr;
else
size = (cd->end_addr - cd->cur_ptr) +
(cd->end_of_data - cd->start_addr);
return size;
}
static int dpaa2_generic_console_open(struct inode *node, struct file *fp,
u64 offset, u64 size,
u32 expected_magic,
u32 offset_delta)
{
u32 read_magic, wrapped, last_byte, buf_start, buf_length;
struct console_data *cd;
u64 base_addr;
int err;
cd = kmalloc(sizeof(*cd), GFP_KERNEL);
if (!cd)
return -ENOMEM;
base_addr = get_mc_fw_base_address();
if (!base_addr) {
err = -EIO;
goto err_fwba;
}
cd->map_addr = ioremap(base_addr + offset, size);
if (!cd->map_addr) {
pr_err("cannot map console log memory\n");
err = -EIO;
goto err_ioremap;
}
cd->hdr = (struct log_header __iomem *)cd->map_addr;
read_magic = readl(&cd->hdr->magic_word);
last_byte = readl(&cd->hdr->last_byte);
buf_start = readl(&cd->hdr->buf_start);
buf_length = readl(&cd->hdr->buf_length);
if (read_magic != expected_magic) {
pr_warn("expected = %08x, read = %08x\n",
expected_magic, read_magic);
err = -EIO;
goto err_magic;
}
cd->start_addr = cd->map_addr + buf_start - offset_delta;
cd->end_addr = cd->start_addr + buf_length;
wrapped = last_byte & LOG_HEADER_FLAG_BUFFER_WRAPAROUND;
adjust_end(cd);
if (wrapped && cd->end_of_data != cd->end_addr)
cd->cur_ptr = cd->end_of_data + 1;
else
cd->cur_ptr = cd->start_addr;
fp->private_data = cd;
return 0;
err_magic:
iounmap(cd->map_addr);
err_ioremap:
err_fwba:
kfree(cd);
return err;
}
static int dpaa2_mc_console_open(struct inode *node, struct file *fp)
{
return dpaa2_generic_console_open(node, fp,
MC_BUFFER_OFFSET, MC_BUFFER_SIZE,
MAGIC_MC, MC_OFFSET_DELTA);
}
static int dpaa2_aiop_console_open(struct inode *node, struct file *fp)
{
return dpaa2_generic_console_open(node, fp,
AIOP_BUFFER_OFFSET, AIOP_BUFFER_SIZE,
MAGIC_AIOP, AIOP_OFFSET_DELTA);
}
static int dpaa2_console_close(struct inode *node, struct file *fp)
{
struct console_data *cd = fp->private_data;
iounmap(cd->map_addr);
kfree(cd);
return 0;
}
static ssize_t dpaa2_console_read(struct file *fp, char __user *buf,
size_t count, loff_t *f_pos)
{
struct console_data *cd = fp->private_data;
size_t bytes = dpaa2_console_size(cd);
size_t bytes_end = cd->end_addr - cd->cur_ptr;
size_t written = 0;
void *kbuf;
int err;
/* Check if we need to adjust the end of data addr */
adjust_end(cd);
if (cd->end_of_data == cd->cur_ptr)
return 0;
if (count < bytes)
bytes = count;
kbuf = kmalloc(bytes, GFP_KERNEL);
if (!kbuf)
return -ENOMEM;
if (bytes > bytes_end) {
memcpy_fromio(kbuf, cd->cur_ptr, bytes_end);
if (copy_to_user(buf, kbuf, bytes_end)) {
err = -EFAULT;
goto err_free_buf;
}
buf += bytes_end;
cd->cur_ptr = cd->start_addr;
bytes -= bytes_end;
written += bytes_end;
}
memcpy_fromio(kbuf, cd->cur_ptr, bytes);
if (copy_to_user(buf, kbuf, bytes)) {
err = -EFAULT;
goto err_free_buf;
}
cd->cur_ptr += bytes;
written += bytes;
return written;
err_free_buf:
kfree(kbuf);
return err;
}
static const struct file_operations dpaa2_mc_console_fops = {
.owner = THIS_MODULE,
.open = dpaa2_mc_console_open,
.release = dpaa2_console_close,
.read = dpaa2_console_read,
};
static struct miscdevice dpaa2_mc_console_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "dpaa2_mc_console",
.fops = &dpaa2_mc_console_fops
};
static const struct file_operations dpaa2_aiop_console_fops = {
.owner = THIS_MODULE,
.open = dpaa2_aiop_console_open,
.release = dpaa2_console_close,
.read = dpaa2_console_read,
};
static struct miscdevice dpaa2_aiop_console_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "dpaa2_aiop_console",
.fops = &dpaa2_aiop_console_fops
};
static int dpaa2_console_probe(struct platform_device *pdev)
{
int error;
error = of_address_to_resource(pdev->dev.of_node, 0, &mc_base_addr);
if (error < 0) {
pr_err("of_address_to_resource() failed for %pOF with %d\n",
pdev->dev.of_node, error);
return error;
}
error = misc_register(&dpaa2_mc_console_dev);
if (error) {
pr_err("cannot register device %s\n",
dpaa2_mc_console_dev.name);
goto err_register_mc;
}
error = misc_register(&dpaa2_aiop_console_dev);
if (error) {
pr_err("cannot register device %s\n",
dpaa2_aiop_console_dev.name);
goto err_register_aiop;
}
return 0;
err_register_aiop:
misc_deregister(&dpaa2_mc_console_dev);
err_register_mc:
return error;
}
static int dpaa2_console_remove(struct platform_device *pdev)
{
misc_deregister(&dpaa2_mc_console_dev);
misc_deregister(&dpaa2_aiop_console_dev);
return 0;
}
static const struct of_device_id dpaa2_console_match_table[] = {
{ .compatible = "fsl,dpaa2-console",},
{},
};
MODULE_DEVICE_TABLE(of, dpaa2_console_match_table);
static struct platform_driver dpaa2_console_driver = {
.driver = {
.name = "dpaa2-console",
.pm = NULL,
.of_match_table = dpaa2_console_match_table,
},
.probe = dpaa2_console_probe,
.remove = dpaa2_console_remove,
};
module_platform_driver(dpaa2_console_driver);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Roy Pledge <roy.pledge@nxp.com>");
MODULE_DESCRIPTION("DPAA2 console driver");
......@@ -197,13 +197,22 @@ static int dpaa2_dpio_probe(struct fsl_mc_device *dpio_dev)
desc.cpu);
}
if (dpio_dev->obj_desc.region_count < 3) {
/* No support for DDR backed portals, use classic mapping */
/*
* Set the CENA regs to be the cache inhibited area of the portal to
* avoid coherency issues if a user migrates to another core.
* Set the CENA regs to be the cache inhibited area of the
* portal to avoid coherency issues if a user migrates to
* another core.
*/
desc.regs_cena = devm_memremap(dev, dpio_dev->regions[1].start,
resource_size(&dpio_dev->regions[1]),
MEMREMAP_WC);
} else {
desc.regs_cena = devm_memremap(dev, dpio_dev->regions[2].start,
resource_size(&dpio_dev->regions[2]),
MEMREMAP_WB);
}
if (IS_ERR(desc.regs_cena)) {
dev_err(dev, "devm_memremap failed\n");
err = PTR_ERR(desc.regs_cena);
......
......@@ -15,6 +15,8 @@
#define QMAN_REV_4000 0x04000000
#define QMAN_REV_4100 0x04010000
#define QMAN_REV_4101 0x04010001
#define QMAN_REV_5000 0x05000000
#define QMAN_REV_MASK 0xffff0000
/* All QBMan command and result structures use this "valid bit" encoding */
......@@ -25,10 +27,17 @@
#define QBMAN_WQCHAN_CONFIGURE 0x46
/* CINH register offsets */
#define QBMAN_CINH_SWP_EQCR_PI 0x800
#define QBMAN_CINH_SWP_EQAR 0x8c0
#define QBMAN_CINH_SWP_CR_RT 0x900
#define QBMAN_CINH_SWP_VDQCR_RT 0x940
#define QBMAN_CINH_SWP_EQCR_AM_RT 0x980
#define QBMAN_CINH_SWP_RCR_AM_RT 0x9c0
#define QBMAN_CINH_SWP_DQPI 0xa00
#define QBMAN_CINH_SWP_DCAP 0xac0
#define QBMAN_CINH_SWP_SDQCR 0xb00
#define QBMAN_CINH_SWP_EQCR_AM_RT2 0xb40
#define QBMAN_CINH_SWP_RCR_PI 0xc00
#define QBMAN_CINH_SWP_RAR 0xcc0
#define QBMAN_CINH_SWP_ISR 0xe00
#define QBMAN_CINH_SWP_IER 0xe40
......@@ -43,6 +52,13 @@
#define QBMAN_CENA_SWP_RR(vb) (0x700 + ((u32)(vb) >> 1))
#define QBMAN_CENA_SWP_VDQCR 0x780
/* CENA register offsets in memory-backed mode */
#define QBMAN_CENA_SWP_DQRR_MEM(n) (0x800 + ((u32)(n) << 6))
#define QBMAN_CENA_SWP_RCR_MEM(n) (0x1400 + ((u32)(n) << 6))
#define QBMAN_CENA_SWP_CR_MEM 0x1600
#define QBMAN_CENA_SWP_RR_MEM 0x1680
#define QBMAN_CENA_SWP_VDQCR_MEM 0x1780
/* Reverse mapping of QBMAN_CENA_SWP_DQRR() */
#define QBMAN_IDX_FROM_DQRR(p) (((unsigned long)(p) & 0x1ff) >> 6)
......@@ -96,10 +112,13 @@ static inline void *qbman_get_cmd(struct qbman_swp *p, u32 offset)
#define SWP_CFG_DQRR_MF_SHIFT 20
#define SWP_CFG_EST_SHIFT 16
#define SWP_CFG_CPBS_SHIFT 15
#define SWP_CFG_WN_SHIFT 14
#define SWP_CFG_RPM_SHIFT 12
#define SWP_CFG_DCM_SHIFT 10
#define SWP_CFG_EPM_SHIFT 8
#define SWP_CFG_VPM_SHIFT 7
#define SWP_CFG_CPM_SHIFT 6
#define SWP_CFG_SD_SHIFT 5
#define SWP_CFG_SP_SHIFT 4
#define SWP_CFG_SE_SHIFT 3
......@@ -125,6 +144,8 @@ static inline u32 qbman_set_swp_cfg(u8 max_fill, u8 wn, u8 est, u8 rpm, u8 dcm,
ep << SWP_CFG_EP_SHIFT);
}
#define QMAN_RT_MODE 0x00000100
/**
* qbman_swp_init() - Create a functional object representing the given
* QBMan portal descriptor.
......@@ -146,6 +167,8 @@ struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d)
p->sdq |= qbman_sdqcr_dct_prio_ics << QB_SDQCR_DCT_SHIFT;
p->sdq |= qbman_sdqcr_fc_up_to_3 << QB_SDQCR_FC_SHIFT;
p->sdq |= QMAN_SDQCR_TOKEN << QB_SDQCR_TOK_SHIFT;
if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000)
p->mr.valid_bit = QB_VALID_BIT;
atomic_set(&p->vdq.available, 1);
p->vdq.valid_bit = QB_VALID_BIT;
......@@ -163,6 +186,9 @@ struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d)
p->addr_cena = d->cena_bar;
p->addr_cinh = d->cinh_bar;
if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000)
memset(p->addr_cena, 0, 64 * 1024);
reg = qbman_set_swp_cfg(p->dqrr.dqrr_size,
1, /* Writes Non-cacheable */
0, /* EQCR_CI stashing threshold */
......@@ -175,6 +201,10 @@ struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d)
1, /* dequeue stashing priority == TRUE */
0, /* dequeue stashing enable == FALSE */
0); /* EQCR_CI stashing priority == FALSE */
if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000)
reg |= 1 << SWP_CFG_CPBS_SHIFT | /* memory-backed mode */
1 << SWP_CFG_VPM_SHIFT | /* VDQCR read triggered mode */
1 << SWP_CFG_CPM_SHIFT; /* CR read triggered mode */
qbman_write_register(p, QBMAN_CINH_SWP_CFG, reg);
reg = qbman_read_register(p, QBMAN_CINH_SWP_CFG);
......@@ -184,6 +214,10 @@ struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d)
return NULL;
}
if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000) {
qbman_write_register(p, QBMAN_CINH_SWP_EQCR_PI, QMAN_RT_MODE);
qbman_write_register(p, QBMAN_CINH_SWP_RCR_PI, QMAN_RT_MODE);
}
/*
* SDQCR needs to be initialized to 0 when no channels are
* being dequeued from or else the QMan HW will indicate an
......@@ -278,7 +312,10 @@ void qbman_swp_interrupt_set_inhibit(struct qbman_swp *p, int inhibit)
*/
void *qbman_swp_mc_start(struct qbman_swp *p)
{
if ((p->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000)
return qbman_get_cmd(p, QBMAN_CENA_SWP_CR);
else
return qbman_get_cmd(p, QBMAN_CENA_SWP_CR_MEM);
}
/*
......@@ -289,8 +326,14 @@ void qbman_swp_mc_submit(struct qbman_swp *p, void *cmd, u8 cmd_verb)
{
u8 *v = cmd;
if ((p->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) {
dma_wmb();
*v = cmd_verb | p->mc.valid_bit;
} else {
*v = cmd_verb | p->mc.valid_bit;
dma_wmb();
qbman_write_register(p, QBMAN_CINH_SWP_CR_RT, QMAN_RT_MODE);
}
}
/*
......@@ -301,13 +344,27 @@ void *qbman_swp_mc_result(struct qbman_swp *p)
{
u32 *ret, verb;
if ((p->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) {
ret = qbman_get_cmd(p, QBMAN_CENA_SWP_RR(p->mc.valid_bit));
/* Remove the valid-bit - command completed if the rest is non-zero */
/* Remove the valid-bit - command completed if the rest
* is non-zero.
*/
verb = ret[0] & ~QB_VALID_BIT;
if (!verb)
return NULL;
p->mc.valid_bit ^= QB_VALID_BIT;
} else {
ret = qbman_get_cmd(p, QBMAN_CENA_SWP_RR_MEM);
/* Command completed if the valid bit is toggled */
if (p->mr.valid_bit != (ret[0] & QB_VALID_BIT))
return NULL;
/* Command completed if the rest is non-zero */
verb = ret[0] & ~QB_VALID_BIT;
if (!verb)
return NULL;
p->mr.valid_bit ^= QB_VALID_BIT;
}
return ret;
}
......@@ -384,6 +441,18 @@ void qbman_eq_desc_set_qd(struct qbman_eq_desc *d, u32 qdid,
#define EQAR_VB(eqar) ((eqar) & 0x80)
#define EQAR_SUCCESS(eqar) ((eqar) & 0x100)
static inline void qbman_write_eqcr_am_rt_register(struct qbman_swp *p,
u8 idx)
{
if (idx < 16)
qbman_write_register(p, QBMAN_CINH_SWP_EQCR_AM_RT + idx * 4,
QMAN_RT_MODE);
else
qbman_write_register(p, QBMAN_CINH_SWP_EQCR_AM_RT2 +
(idx - 16) * 4,
QMAN_RT_MODE);
}
/**
* qbman_swp_enqueue() - Issue an enqueue command
* @s: the software portal used for enqueue
......@@ -408,9 +477,15 @@ int qbman_swp_enqueue(struct qbman_swp *s, const struct qbman_eq_desc *d,
memcpy(&p->dca, &d->dca, 31);
memcpy(&p->fd, fd, sizeof(*fd));
if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) {
/* Set the verb byte, have to substitute in the valid-bit */
dma_wmb();
p->verb = d->verb | EQAR_VB(eqar);
} else {
p->verb = d->verb | EQAR_VB(eqar);
dma_wmb();
qbman_write_eqcr_am_rt_register(s, EQAR_IDX(eqar));
}
return 0;
}
......@@ -587,17 +662,27 @@ int qbman_swp_pull(struct qbman_swp *s, struct qbman_pull_desc *d)
return -EBUSY;
}
s->vdq.storage = (void *)(uintptr_t)d->rsp_addr_virt;
if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000)
p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR);
else
p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR_MEM);
p->numf = d->numf;
p->tok = QMAN_DQ_TOKEN_VALID;
p->dq_src = d->dq_src;
p->rsp_addr = d->rsp_addr;
p->rsp_addr_virt = d->rsp_addr_virt;
dma_wmb();
if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) {
dma_wmb();
/* Set the verb byte, have to substitute in the valid-bit */
p->verb = d->verb | s->vdq.valid_bit;
s->vdq.valid_bit ^= QB_VALID_BIT;
} else {
p->verb = d->verb | s->vdq.valid_bit;
s->vdq.valid_bit ^= QB_VALID_BIT;
dma_wmb();
qbman_write_register(s, QBMAN_CINH_SWP_VDQCR_RT, QMAN_RT_MODE);
}
return 0;
}
......@@ -655,7 +740,10 @@ const struct dpaa2_dq *qbman_swp_dqrr_next(struct qbman_swp *s)
QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx)));
}
if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000)
p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
else
p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR_MEM(s->dqrr.next_idx));
verb = p->dq.verb;
/*
......@@ -807,18 +895,28 @@ int qbman_swp_release(struct qbman_swp *s, const struct qbman_release_desc *d,
return -EBUSY;
/* Start the release command */
if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000)
p = qbman_get_cmd(s, QBMAN_CENA_SWP_RCR(RAR_IDX(rar)));
else
p = qbman_get_cmd(s, QBMAN_CENA_SWP_RCR_MEM(RAR_IDX(rar)));
/* Copy the caller's buffer pointers to the command */
for (i = 0; i < num_buffers; i++)
p->buf[i] = cpu_to_le64(buffers[i]);
p->bpid = d->bpid;
if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) {
/*
* Set the verb byte, have to substitute in the valid-bit and the number
* of buffers.
* Set the verb byte, have to substitute in the valid-bit
* and the number of buffers.
*/
dma_wmb();
p->verb = d->verb | RAR_VB(rar) | num_buffers;
} else {
p->verb = d->verb | RAR_VB(rar) | num_buffers;
dma_wmb();
qbman_write_register(s, QBMAN_CINH_SWP_RCR_AM_RT +
RAR_IDX(rar) * 4, QMAN_RT_MODE);
}
return 0;
}
......
/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
/*
* Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
* Copyright 2016 NXP
* Copyright 2016-2019 NXP
*
*/
#ifndef __FSL_QBMAN_PORTAL_H
......@@ -110,6 +110,11 @@ struct qbman_swp {
u32 valid_bit; /* 0x00 or 0x80 */
} mc;
/* Management response */
struct {
u32 valid_bit; /* 0x00 or 0x80 */
} mr;
/* Push dequeues */
u32 sdq;
......@@ -428,7 +433,7 @@ static inline int qbman_swp_CDAN_set_context_enable(struct qbman_swp *s,
static inline void *qbman_swp_mc_complete(struct qbman_swp *swp, void *cmd,
u8 cmd_verb)
{
int loopvar = 1000;
int loopvar = 2000;
qbman_swp_mc_submit(swp, cmd, cmd_verb);
......
......@@ -97,6 +97,11 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = {
.svr = 0x87000000,
.mask = 0xfff70000,
},
/* Die: LX2160A, SoC: LX2160A/LX2120A/LX2080A */
{ .die = "LX2160A",
.svr = 0x87360000,
.mask = 0xff3f0000,
},
{ },
};
......@@ -218,6 +223,7 @@ static const struct of_device_id fsl_guts_of_match[] = {
{ .compatible = "fsl,ls1088a-dcfg", },
{ .compatible = "fsl,ls1012a-dcfg", },
{ .compatible = "fsl,ls1046a-dcfg", },
{ .compatible = "fsl,lx2160a-dcfg", },
{}
};
MODULE_DEVICE_TABLE(of, fsl_guts_of_match);
......
......@@ -32,6 +32,7 @@
static struct bman_portal *affine_bportals[NR_CPUS];
static struct cpumask portal_cpus;
static int __bman_portals_probed;
/* protect bman global registers and global data shared among portals */
static DEFINE_SPINLOCK(bman_lock);
......@@ -87,6 +88,12 @@ static int bman_online_cpu(unsigned int cpu)
return 0;
}
int bman_portals_probed(void)
{
return __bman_portals_probed;
}
EXPORT_SYMBOL_GPL(bman_portals_probed);
static int bman_portal_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
......@@ -104,8 +111,10 @@ static int bman_portal_probe(struct platform_device *pdev)
}
pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL);
if (!pcfg)
if (!pcfg) {
__bman_portals_probed = -1;
return -ENOMEM;
}
pcfg->dev = dev;
......@@ -113,14 +122,14 @@ static int bman_portal_probe(struct platform_device *pdev)
DPAA_PORTAL_CE);
if (!addr_phys[0]) {
dev_err(dev, "Can't get %pOF property 'reg::CE'\n", node);
return -ENXIO;
goto err_ioremap1;
}
addr_phys[1] = platform_get_resource(pdev, IORESOURCE_MEM,
DPAA_PORTAL_CI);
if (!addr_phys[1]) {
dev_err(dev, "Can't get %pOF property 'reg::CI'\n", node);
return -ENXIO;
goto err_ioremap1;
}
pcfg->cpu = -1;
......@@ -128,7 +137,7 @@ static int bman_portal_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
dev_err(dev, "Can't get %pOF IRQ'\n", node);
return -ENXIO;
goto err_ioremap1;
}
pcfg->irq = irq;
......@@ -150,6 +159,7 @@ static int bman_portal_probe(struct platform_device *pdev)
spin_lock(&bman_lock);
cpu = cpumask_next_zero(-1, &portal_cpus);
if (cpu >= nr_cpu_ids) {
__bman_portals_probed = 1;
/* unassigned portal, skip init */
spin_unlock(&bman_lock);
return 0;
......@@ -175,6 +185,8 @@ static int bman_portal_probe(struct platform_device *pdev)
err_ioremap2:
memunmap(pcfg->addr_virt_ce);
err_ioremap1:
__bman_portals_probed = -1;
return -ENXIO;
}
......
......@@ -596,7 +596,7 @@ static int qman_init_ccsr(struct device *dev)
}
#define LIO_CFG_LIODN_MASK 0x0fff0000
void qman_liodn_fixup(u16 channel)
void __qman_liodn_fixup(u16 channel)
{
static int done;
static u32 liodn_offset;
......
This diff is collapsed.
......@@ -193,7 +193,14 @@ extern struct gen_pool *qm_cgralloc; /* CGR ID allocator */
u32 qm_get_pools_sdqcr(void);
int qman_wq_alloc(void);
void qman_liodn_fixup(u16 channel);
#ifdef CONFIG_FSL_PAMU
#define qman_liodn_fixup __qman_liodn_fixup
#else
static inline void qman_liodn_fixup(u16 channel)
{
}
#endif
void __qman_liodn_fixup(u16 channel);
void qman_set_sdest(u16 channel, unsigned int cpu_idx);
struct qman_portal *qman_create_affine_portal(
......
......@@ -8,4 +8,13 @@ config IMX_GPCV2_PM_DOMAINS
select PM_GENERIC_DOMAINS
default y if SOC_IMX7D
config IMX_SCU_SOC
bool "i.MX System Controller Unit SoC info support"
depends on IMX_SCU
select SOC_BUS
help
If you say yes here you get support for the NXP i.MX System
Controller Unit SoC info module, it will provide the SoC info
like SoC family, ID and revision etc.
endmenu
......@@ -2,3 +2,4 @@
obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o
obj-$(CONFIG_ARCH_MXC) += soc-imx8.o
obj-$(CONFIG_IMX_SCU_SOC) += soc-imx-scu.o
This diff is collapsed.
This diff is collapsed.
......@@ -4,6 +4,18 @@
#
menu "Qualcomm SoC drivers"
config QCOM_AOSS_QMP
tristate "Qualcomm AOSS Driver"
depends on ARCH_QCOM || COMPILE_TEST
depends on MAILBOX
depends on COMMON_CLK && PM
select PM_GENERIC_DOMAINS
help
This driver provides the means of communicating with and controlling
the low-power state for resources related to the remoteproc
subsystems as well as controlling the debug clocks exposed by the Always On
Subsystem (AOSS) using Qualcomm Messaging Protocol (QMP).
config QCOM_COMMAND_DB
bool "Qualcomm Command DB"
depends on ARCH_QCOM || COMPILE_TEST
......
# SPDX-License-Identifier: GPL-2.0
CFLAGS_rpmh-rsc.o := -I$(src)
obj-$(CONFIG_QCOM_AOSS_QMP) += qcom_aoss.o
obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o
obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o
obj-$(CONFIG_QCOM_GLINK_SSR) += glink_ssr.o
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment