Skip to content
Snippets Groups Projects
Commit 00f8ccd0 authored by Olof Johansson's avatar Olof Johansson
Browse files

Merge branch 'next/drivers' into next/late


Merge in a few missing patches from the pull request (my copy of the
branch was behind the staged version in linux-next).

* next/drivers:
  memory: pl353: Add driver for arm pl353 static memory controller
  dt-bindings: memory: Add pl353 smc controller devicetree binding information
  firmware: qcom: scm: fix compilation error when disabled

Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
parents 8e564895 3e730e85
No related branches found
No related tags found
No related merge requests found
Showing
with 637 additions and 152 deletions
...@@ -58,19 +58,11 @@ This binding for the SCU power domain providers uses the generic power ...@@ -58,19 +58,11 @@ This binding for the SCU power domain providers uses the generic power
domain binding[2]. domain binding[2].
Required properties: Required properties:
- compatible: Should be "fsl,scu-pd". - compatible: Should be "fsl,imx8qxp-scu-pd".
- #address-cells: Should be 1. - #power-domain-cells: Must be 1. Contains the Resource ID used by
- #size-cells: Should be 0. SCU commands.
Required properties for power domain sub nodes:
- #power-domain-cells: Must be 0.
Optional Properties:
- reg: Resource ID of this power domain.
No exist means uncontrollable by user.
See detailed Resource ID list from: See detailed Resource ID list from:
include/dt-bindings/power/imx-rsrc.h include/dt-bindings/firmware/imx/rsrc.h
- power-domains: phandle pointing to the parent power domain.
Clock bindings based on SCU Message Protocol Clock bindings based on SCU Message Protocol
------------------------------------------------------------ ------------------------------------------------------------
...@@ -152,22 +144,9 @@ firmware { ...@@ -152,22 +144,9 @@ firmware {
... ...
}; };
imx8qx-pm { pd: imx8qx-pd {
compatible = "fsl,scu-pd"; compatible = "fsl,imx8qxp-scu-pd";
#address-cells = <1>; #power-domain-cells = <1>;
#size-cells = <0>;
pd_dma: dma-power-domain {
#power-domain-cells = <0>;
pd_dma_lpuart0: dma-lpuart0@57 {
reg = <SC_R_UART_0>;
#power-domain-cells = <0>;
power-domains = <&pd_dma>;
};
...
};
...
}; };
}; };
}; };
...@@ -179,5 +158,5 @@ serial@5a060000 { ...@@ -179,5 +158,5 @@ serial@5a060000 {
clocks = <&clk IMX8QXP_UART0_CLK>, clocks = <&clk IMX8QXP_UART0_CLK>,
<&clk IMX8QXP_UART0_IPG_CLK>; <&clk IMX8QXP_UART0_IPG_CLK>;
clock-names = "per", "ipg"; clock-names = "per", "ipg";
power-domains = <&pd_dma_lpuart0>; power-domains = <&pd IMX_SC_R_UART_0>;
}; };
...@@ -35,6 +35,7 @@ Required standard properties: ...@@ -35,6 +35,7 @@ Required standard properties:
"ti,sysc-omap3-sham" "ti,sysc-omap3-sham"
"ti,sysc-omap-aes" "ti,sysc-omap-aes"
"ti,sysc-mcasp" "ti,sysc-mcasp"
"ti,sysc-dra7-mcasp"
"ti,sysc-usb-host-fs" "ti,sysc-usb-host-fs"
"ti,sysc-dra7-mcan" "ti,sysc-dra7-mcan"
......
Device tree bindings for ARM PL353 static memory controller
PL353 static memory controller supports two kinds of memory
interfaces.i.e NAND and SRAM/NOR interfaces.
The actual devices are instantiated from the child nodes of pl353 smc node.
Required properties:
- compatible : Should be "arm,pl353-smc-r2p1", "arm,primecell".
- reg : Controller registers map and length.
- clock-names : List of input clock names - "memclk", "apb_pclk"
(See clock bindings for details).
- clocks : Clock phandles (see clock bindings for details).
- address-cells : Must be 2.
- size-cells : Must be 1.
Child nodes:
For NAND the "arm,pl353-nand-r2p1" and for NOR the "cfi-flash" drivers are
supported as child nodes.
for NAND partition information please refer the below file
Documentation/devicetree/bindings/mtd/partition.txt
Example:
smcc: memory-controller@e000e000
compatible = "arm,pl353-smc-r2p1", "arm,primecell";
clock-names = "memclk", "apb_pclk";
clocks = <&clkc 11>, <&clkc 44>;
reg = <0xe000e000 0x1000>;
#address-cells = <2>;
#size-cells = <1>;
ranges = <0x0 0x0 0xe1000000 0x1000000 //Nand CS Region
0x1 0x0 0xe2000000 0x2000000 //SRAM/NOR CS Region
0x2 0x0 0xe4000000 0x2000000>; //SRAM/NOR CS Region
nand_0: flash@e1000000 {
compatible = "arm,pl353-nand-r2p1"
reg = <0 0 0x1000000>;
(...)
};
nor0: flash@e2000000 {
compatible = "cfi-flash";
reg = <1 0 0x2000000>;
};
nor1: flash@e4000000 {
compatible = "cfi-flash";
reg = <2 0 0x2000000>;
};
};
...@@ -6,7 +6,9 @@ Control (PGC) for various power domains. ...@@ -6,7 +6,9 @@ Control (PGC) for various power domains.
Required properties: Required properties:
- compatible: Should be "fsl,imx7d-gpc" - compatible: Should be one of:
- "fsl,imx7d-gpc"
- "fsl,imx8mq-gpc"
- reg: should be register base and length as documented in the - reg: should be register base and length as documented in the
datasheet datasheet
...@@ -22,7 +24,8 @@ which, in turn, is expected to contain the following: ...@@ -22,7 +24,8 @@ which, in turn, is expected to contain the following:
Required properties: Required properties:
- reg: Power domain index. Valid values are defined in - reg: Power domain index. Valid values are defined in
include/dt-bindings/power/imx7-power.h include/dt-bindings/power/imx7-power.h for fsl,imx7d-gpc and
include/dt-bindings/power/imx8m-power.h for fsl,imx8mq-gpc
- #power-domain-cells: Should be 0 - #power-domain-cells: Should be 0
......
Amlogic Internal Clock Measurer
===============================
The Amlogic SoCs contains an IP to measure the internal clocks.
The precision is multiple of MHz, useful to debug the clock states.
Required properties:
- compatible: Shall contain one of the following :
"amlogic,meson-gx-clk-measure" for GX SoCs
"amlogic,meson8-clk-measure" for Meson8 SoCs
"amlogic,meson8b-clk-measure" for Meson8b SoCs
- reg: base address and size of the Clock Measurer register space.
Example:
clock-measure@8758 {
compatible = "amlogic,meson-gx-clk-measure";
reg = <0x0 0x8758 0x0 0x10>;
};
...@@ -23,6 +23,7 @@ resources. ...@@ -23,6 +23,7 @@ resources.
"qcom,rpm-msm8916" "qcom,rpm-msm8916"
"qcom,rpm-msm8974" "qcom,rpm-msm8974"
"qcom,rpm-msm8998" "qcom,rpm-msm8998"
"qcom,rpm-qcs404"
- qcom,smd-channels: - qcom,smd-channels:
Usage: required Usage: required
......
...@@ -7,7 +7,9 @@ Required properties for power domain controller: ...@@ -7,7 +7,9 @@ Required properties for power domain controller:
- compatible: Should be one of the following. - compatible: Should be one of the following.
"rockchip,px30-power-controller" - for PX30 SoCs. "rockchip,px30-power-controller" - for PX30 SoCs.
"rockchip,rk3036-power-controller" - for RK3036 SoCs. "rockchip,rk3036-power-controller" - for RK3036 SoCs.
"rockchip,rk3066-power-controller" - for RK3066 SoCs.
"rockchip,rk3128-power-controller" - for RK3128 SoCs. "rockchip,rk3128-power-controller" - for RK3128 SoCs.
"rockchip,rk3188-power-controller" - for RK3188 SoCs.
"rockchip,rk3228-power-controller" - for RK3228 SoCs. "rockchip,rk3228-power-controller" - for RK3228 SoCs.
"rockchip,rk3288-power-controller" - for RK3288 SoCs. "rockchip,rk3288-power-controller" - for RK3288 SoCs.
"rockchip,rk3328-power-controller" - for RK3328 SoCs. "rockchip,rk3328-power-controller" - for RK3328 SoCs.
...@@ -23,7 +25,9 @@ Required properties for power domain sub nodes: ...@@ -23,7 +25,9 @@ Required properties for power domain sub nodes:
- reg: index of the power domain, should use macros in: - reg: index of the power domain, should use macros in:
"include/dt-bindings/power/px30-power.h" - for PX30 type power domain. "include/dt-bindings/power/px30-power.h" - for PX30 type power domain.
"include/dt-bindings/power/rk3036-power.h" - for RK3036 type power domain. "include/dt-bindings/power/rk3036-power.h" - for RK3036 type power domain.
"include/dt-bindings/power/rk3066-power.h" - for RK3066 type power domain.
"include/dt-bindings/power/rk3128-power.h" - for RK3128 type power domain. "include/dt-bindings/power/rk3128-power.h" - for RK3128 type power domain.
"include/dt-bindings/power/rk3188-power.h" - for RK3188 type power domain.
"include/dt-bindings/power/rk3228-power.h" - for RK3228 type power domain. "include/dt-bindings/power/rk3228-power.h" - for RK3228 type power domain.
"include/dt-bindings/power/rk3288-power.h" - for RK3288 type power domain. "include/dt-bindings/power/rk3288-power.h" - for RK3288 type power domain.
"include/dt-bindings/power/rk3328-power.h" - for RK3328 type power domain. "include/dt-bindings/power/rk3328-power.h" - for RK3328 type power domain.
......
...@@ -18,7 +18,9 @@ Required properties: ...@@ -18,7 +18,9 @@ Required properties:
- "allwinner,sun8i-h3-system-control" - "allwinner,sun8i-h3-system-control"
- "allwinner,sun50i-a64-sram-controller" (deprecated) - "allwinner,sun50i-a64-sram-controller" (deprecated)
- "allwinner,sun50i-a64-system-control" - "allwinner,sun50i-a64-system-control"
- "allwinner,sun50i-h5-system-control"
- "allwinner,sun50i-h6-system-control", "allwinner,sun50i-a64-system-control" - "allwinner,sun50i-h6-system-control", "allwinner,sun50i-a64-system-control"
- "allwinner,suniv-f1c100s-system-control", "allwinner,sun4i-a10-system-control"
- reg : sram controller register offset + length - reg : sram controller register offset + length
SRAM nodes SRAM nodes
...@@ -54,10 +56,17 @@ The valid sections compatible for H3 are: ...@@ -54,10 +56,17 @@ The valid sections compatible for H3 are:
The valid sections compatible for A64 are: The valid sections compatible for A64 are:
- allwinner,sun50i-a64-sram-c - allwinner,sun50i-a64-sram-c
- allwinner,sun50i-a64-sram-c1, allwinner,sun4i-a10-sram-c1
The valid sections compatible for H5 are:
- allwinner,sun50i-h5-sram-c1, allwinner,sun4i-a10-sram-c1
The valid sections compatible for H6 are: The valid sections compatible for H6 are:
- allwinner,sun50i-h6-sram-c, allwinner,sun50i-a64-sram-c - allwinner,sun50i-h6-sram-c, allwinner,sun50i-a64-sram-c
The valid sections compatible for F1C100s are:
- allwinner,suniv-f1c100s-sram-d, allwinner,sun4i-a10-sram-d
Devices using SRAM sections Devices using SRAM sections
--------------------------- ---------------------------
......
...@@ -2345,6 +2345,17 @@ static int __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data, ...@@ -2345,6 +2345,17 @@ static int __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data,
return 0; return 0;
} }
static void __init parse_module_flags(struct omap_hwmod *oh,
struct device_node *np)
{
if (of_find_property(np, "ti,no-reset-on-init", NULL))
oh->flags |= HWMOD_INIT_NO_RESET;
if (of_find_property(np, "ti,no-idle-on-init", NULL))
oh->flags |= HWMOD_INIT_NO_IDLE;
if (of_find_property(np, "ti,no-idle", NULL))
oh->flags |= HWMOD_NO_IDLE;
}
/** /**
* _init - initialize internal data for the hwmod @oh * _init - initialize internal data for the hwmod @oh
* @oh: struct omap_hwmod * * @oh: struct omap_hwmod *
...@@ -2392,12 +2403,12 @@ static int __init _init(struct omap_hwmod *oh, void *data) ...@@ -2392,12 +2403,12 @@ static int __init _init(struct omap_hwmod *oh, void *data)
} }
if (np) { if (np) {
if (of_find_property(np, "ti,no-reset-on-init", NULL)) struct device_node *child;
oh->flags |= HWMOD_INIT_NO_RESET;
if (of_find_property(np, "ti,no-idle-on-init", NULL)) parse_module_flags(oh, np);
oh->flags |= HWMOD_INIT_NO_IDLE; child = of_get_next_child(np, NULL);
if (of_find_property(np, "ti,no-idle", NULL)) if (child)
oh->flags |= HWMOD_NO_IDLE; parse_module_flags(oh, child);
} }
oh->_state = _HWMOD_STATE_INITIALIZED; oh->_state = _HWMOD_STATE_INITIALIZED;
......
...@@ -150,8 +150,7 @@ static ssize_t gisb_arb_get_timeout(struct device *dev, ...@@ -150,8 +150,7 @@ static ssize_t gisb_arb_get_timeout(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct platform_device *pdev = to_platform_device(dev); struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev);
struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev);
u32 timeout; u32 timeout;
mutex_lock(&gdev->lock); mutex_lock(&gdev->lock);
...@@ -165,8 +164,7 @@ static ssize_t gisb_arb_set_timeout(struct device *dev, ...@@ -165,8 +164,7 @@ static ssize_t gisb_arb_set_timeout(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct platform_device *pdev = to_platform_device(dev); struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev);
struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev);
int val, ret; int val, ret;
ret = kstrtoint(buf, 10, &val); ret = kstrtoint(buf, 10, &val);
...@@ -418,8 +416,7 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev) ...@@ -418,8 +416,7 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int brcmstb_gisb_arb_suspend(struct device *dev) static int brcmstb_gisb_arb_suspend(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev);
struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev);
gdev->saved_timeout = gisb_read(gdev, ARB_TIMER); gdev->saved_timeout = gisb_read(gdev, ARB_TIMER);
...@@ -431,8 +428,7 @@ static int brcmstb_gisb_arb_suspend(struct device *dev) ...@@ -431,8 +428,7 @@ static int brcmstb_gisb_arb_suspend(struct device *dev)
*/ */
static int brcmstb_gisb_arb_resume_noirq(struct device *dev) static int brcmstb_gisb_arb_resume_noirq(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev);
struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev);
gisb_write(gdev, gdev->saved_timeout, ARB_TIMER); gisb_write(gdev, gdev->saved_timeout, ARB_TIMER);
......
...@@ -91,6 +91,9 @@ struct sysc { ...@@ -91,6 +91,9 @@ struct sysc {
struct delayed_work idle_work; struct delayed_work idle_work;
}; };
static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np,
bool is_child);
void sysc_write(struct sysc *ddata, int offset, u32 value) void sysc_write(struct sysc *ddata, int offset, u32 value)
{ {
writel_relaxed(value, ddata->module_va + offset); writel_relaxed(value, ddata->module_va + offset);
...@@ -214,8 +217,13 @@ static int sysc_get_clocks(struct sysc *ddata) ...@@ -214,8 +217,13 @@ static int sysc_get_clocks(struct sysc *ddata)
if (!ddata->clocks) if (!ddata->clocks)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < ddata->nr_clocks; i++) { for (i = 0; i < SYSC_MAX_CLOCKS; i++) {
error = sysc_get_one_clock(ddata, ddata->clock_roles[i]); const char *name = ddata->clock_roles[i];
if (!name)
continue;
error = sysc_get_one_clock(ddata, name);
if (error && error != -ENOENT) if (error && error != -ENOENT)
return error; return error;
} }
...@@ -374,6 +382,7 @@ static int sysc_check_one_child(struct sysc *ddata, ...@@ -374,6 +382,7 @@ static int sysc_check_one_child(struct sysc *ddata,
dev_warn(ddata->dev, "really a child ti,hwmods property?"); dev_warn(ddata->dev, "really a child ti,hwmods property?");
sysc_check_quirk_stdout(ddata, np); sysc_check_quirk_stdout(ddata, np);
sysc_parse_dts_quirks(ddata, np, true);
return 0; return 0;
} }
...@@ -815,6 +824,7 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { ...@@ -815,6 +824,7 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
SYSC_QUIRK("ocp2scp", 0, 0, 0x10, 0x14, 0x50060005, 0xfffffff0, 0), SYSC_QUIRK("ocp2scp", 0, 0, 0x10, 0x14, 0x50060005, 0xfffffff0, 0),
SYSC_QUIRK("ocp2scp", 0, 0, -1, -1, 0x50060007, 0xffffffff, 0), SYSC_QUIRK("ocp2scp", 0, 0, -1, -1, 0x50060007, 0xffffffff, 0),
SYSC_QUIRK("padconf", 0, 0, 0x10, -1, 0x4fff0800, 0xffffffff, 0), SYSC_QUIRK("padconf", 0, 0, 0x10, -1, 0x4fff0800, 0xffffffff, 0),
SYSC_QUIRK("padconf", 0, 0, -1, -1, 0x40001100, 0xffffffff, 0),
SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000100, 0xffffffff, 0), SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000100, 0xffffffff, 0),
SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x00004102, 0xffffffff, 0), SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x00004102, 0xffffffff, 0),
SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000400, 0xffffffff, 0), SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000400, 0xffffffff, 0),
...@@ -833,7 +843,9 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { ...@@ -833,7 +843,9 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
SYSC_QUIRK("rtc", 0, 0x74, 0x78, -1, 0x4eb01908, 0xffff00f0, 0), SYSC_QUIRK("rtc", 0, 0x74, 0x78, -1, 0x4eb01908, 0xffff00f0, 0),
SYSC_QUIRK("timer32k", 0, 0, 0x4, -1, 0x00000060, 0xffffffff, 0), SYSC_QUIRK("timer32k", 0, 0, 0x4, -1, 0x00000060, 0xffffffff, 0),
SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000004, 0xffffffff, 0), SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000004, 0xffffffff, 0),
SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000008, 0xffffffff, 0),
SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff, 0), SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff, 0),
SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -1, 0x50700101, 0xffffffff, 0),
SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050, SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
0xffffffff, 0), 0xffffffff, 0),
SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0, 0), SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0, 0),
...@@ -1271,23 +1283,37 @@ static const struct sysc_dts_quirk sysc_dts_quirks[] = { ...@@ -1271,23 +1283,37 @@ static const struct sysc_dts_quirk sysc_dts_quirks[] = {
.mask = SYSC_QUIRK_NO_RESET_ON_INIT, }, .mask = SYSC_QUIRK_NO_RESET_ON_INIT, },
}; };
static int sysc_init_dts_quirks(struct sysc *ddata) static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np,
bool is_child)
{ {
struct device_node *np = ddata->dev->of_node;
const struct property *prop; const struct property *prop;
int i, len, error; int i, len;
u32 val;
ddata->legacy_mode = of_get_property(np, "ti,hwmods", NULL);
for (i = 0; i < ARRAY_SIZE(sysc_dts_quirks); i++) { for (i = 0; i < ARRAY_SIZE(sysc_dts_quirks); i++) {
prop = of_get_property(np, sysc_dts_quirks[i].name, &len); const char *name = sysc_dts_quirks[i].name;
prop = of_get_property(np, name, &len);
if (!prop) if (!prop)
continue; continue;
ddata->cfg.quirks |= sysc_dts_quirks[i].mask; ddata->cfg.quirks |= sysc_dts_quirks[i].mask;
if (is_child) {
dev_warn(ddata->dev,
"dts flag should be at module level for %s\n",
name);
}
} }
}
static int sysc_init_dts_quirks(struct sysc *ddata)
{
struct device_node *np = ddata->dev->of_node;
int error;
u32 val;
ddata->legacy_mode = of_get_property(np, "ti,hwmods", NULL);
sysc_parse_dts_quirks(ddata, np, false);
error = of_property_read_u32(np, "ti,sysc-delay-us", &val); error = of_property_read_u32(np, "ti,sysc-delay-us", &val);
if (!error) { if (!error) {
if (val > 255) { if (val > 255) {
...@@ -1498,6 +1524,16 @@ static const struct sysc_regbits sysc_regbits_omap4_mcasp = { ...@@ -1498,6 +1524,16 @@ static const struct sysc_regbits sysc_regbits_omap4_mcasp = {
static const struct sysc_capabilities sysc_omap4_mcasp = { static const struct sysc_capabilities sysc_omap4_mcasp = {
.type = TI_SYSC_OMAP4_MCASP, .type = TI_SYSC_OMAP4_MCASP,
.regbits = &sysc_regbits_omap4_mcasp, .regbits = &sysc_regbits_omap4_mcasp,
.mod_quirks = SYSC_QUIRK_OPT_CLKS_NEEDED,
};
/*
* McASP found on dra7 and later
*/
static const struct sysc_capabilities sysc_dra7_mcasp = {
.type = TI_SYSC_OMAP4_SIMPLE,
.regbits = &sysc_regbits_omap4_simple,
.mod_quirks = SYSC_QUIRK_OPT_CLKS_NEEDED,
}; };
/* /*
...@@ -1726,6 +1762,7 @@ static const struct of_device_id sysc_match[] = { ...@@ -1726,6 +1762,7 @@ static const struct of_device_id sysc_match[] = {
{ .compatible = "ti,sysc-omap3-sham", .data = &sysc_omap3_sham, }, { .compatible = "ti,sysc-omap3-sham", .data = &sysc_omap3_sham, },
{ .compatible = "ti,sysc-omap-aes", .data = &sysc_omap3_aes, }, { .compatible = "ti,sysc-omap-aes", .data = &sysc_omap3_aes, },
{ .compatible = "ti,sysc-mcasp", .data = &sysc_omap4_mcasp, }, { .compatible = "ti,sysc-mcasp", .data = &sysc_omap4_mcasp, },
{ .compatible = "ti,sysc-dra7-mcasp", .data = &sysc_dra7_mcasp, },
{ .compatible = "ti,sysc-usb-host-fs", { .compatible = "ti,sysc-usb-host-fs",
.data = &sysc_omap4_usb_host_fs, }, .data = &sysc_omap4_usb_host_fs, },
{ .compatible = "ti,sysc-dra7-mcan", .data = &sysc_dra7_mcan, }, { .compatible = "ti,sysc-dra7-mcan", .data = &sysc_dra7_mcan, },
......
...@@ -179,7 +179,7 @@ static unsigned int pxad_drcmr(unsigned int line) ...@@ -179,7 +179,7 @@ static unsigned int pxad_drcmr(unsigned int line)
return 0x1000 + line * 4; return 0x1000 + line * 4;
} }
bool pxad_filter_fn(struct dma_chan *chan, void *param); static bool pxad_filter_fn(struct dma_chan *chan, void *param);
/* /*
* Debug fs * Debug fs
...@@ -1500,7 +1500,7 @@ static struct platform_driver pxad_driver = { ...@@ -1500,7 +1500,7 @@ static struct platform_driver pxad_driver = {
.remove = pxad_remove, .remove = pxad_remove,
}; };
bool pxad_filter_fn(struct dma_chan *chan, void *param) static bool pxad_filter_fn(struct dma_chan *chan, void *param)
{ {
struct pxad_chan *c = to_pxad_chan(chan); struct pxad_chan *c = to_pxad_chan(chan);
struct pxad_param *p = param; struct pxad_param *p = param;
...@@ -1513,7 +1513,6 @@ bool pxad_filter_fn(struct dma_chan *chan, void *param) ...@@ -1513,7 +1513,6 @@ bool pxad_filter_fn(struct dma_chan *chan, void *param)
return true; return true;
} }
EXPORT_SYMBOL_GPL(pxad_filter_fn);
module_platform_driver(pxad_driver); module_platform_driver(pxad_driver);
......
...@@ -9,3 +9,9 @@ config IMX_SCU ...@@ -9,3 +9,9 @@ config IMX_SCU
This driver manages the IPC interface between host CPU and the This driver manages the IPC interface between host CPU and the
SCU firmware running on M4. SCU firmware running on M4.
config IMX_SCU_PD
bool "IMX SCU Power Domain driver"
depends on IMX_SCU
help
The System Controller Firmware (SCFW) based power domain driver.
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o
obj-$(CONFIG_IMX_SCU_PD) += scu-pd.o
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Freescale Semiconductor, Inc.
* Copyright 2017-2018 NXP
* Dong Aisheng <aisheng.dong@nxp.com>
*
* Implementation of the SCU based Power Domains
*
* NOTE: a better implementation suggested by Ulf Hansson is using a
* single global power domain and implement the ->attach|detach_dev()
* callback for the genpd and use the regular of_genpd_add_provider_simple().
* From within the ->attach_dev(), we could get the OF node for
* the device that is being attached and then parse the power-domain
* cell containing the "resource id" and store that in the per device
* struct generic_pm_domain_data (we have void pointer there for
* storing these kind of things).
*
* Additionally, we need to implement the ->stop() and ->start()
* callbacks of genpd, which is where you "power on/off" devices,
* rather than using the above ->power_on|off() callbacks.
*
* However, there're two known issues:
* 1. The ->attach_dev() of power domain infrastructure still does
* not support multi domains case as the struct device *dev passed
* in is a virtual PD device, it does not help for parsing the real
* device resource id from device tree, so it's unware of which
* real sub power domain of device should be attached.
*
* The framework needs some proper extension to support multi power
* domain cases.
*
* 2. It also breaks most of current drivers as the driver probe sequence
* behavior changed if removing ->power_on|off() callback and use
* ->start() and ->stop() instead. genpd_dev_pm_attach will only power
* up the domain and attach device, but will not call .start() which
* relies on device runtime pm. That means the device power is still
* not up before running driver probe function. For SCU enabled
* platforms, all device drivers accessing registers/clock without power
* domain enabled will trigger a HW access error. That means we need fix
* most drivers probe sequence with proper runtime pm.
*
* In summary, we need fix above two issue before being able to switch to
* the "single global power domain" way.
*
*/
#include <dt-bindings/firmware/imx/rsrc.h>
#include <linux/firmware/imx/sci.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_domain.h>
#include <linux/slab.h>
/* SCU Power Mode Protocol definition */
struct imx_sc_msg_req_set_resource_power_mode {
struct imx_sc_rpc_msg hdr;
u16 resource;
u8 mode;
} __packed;
#define IMX_SCU_PD_NAME_SIZE 20
struct imx_sc_pm_domain {
struct generic_pm_domain pd;
char name[IMX_SCU_PD_NAME_SIZE];
u32 rsrc;
};
struct imx_sc_pd_range {
char *name;
u32 rsrc;
u8 num;
bool postfix;
};
struct imx_sc_pd_soc {
const struct imx_sc_pd_range *pd_ranges;
u8 num_ranges;
};
static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
/* LSIO SS */
{ "lsio-pwm", IMX_SC_R_PWM_0, 8, 1 },
{ "lsio-gpio", IMX_SC_R_GPIO_0, 8, 1 },
{ "lsio-gpt", IMX_SC_R_GPT_0, 5, 1 },
{ "lsio-kpp", IMX_SC_R_KPP, 1, 0 },
{ "lsio-fspi", IMX_SC_R_FSPI_0, 2, 1 },
{ "lsio-mu", IMX_SC_R_MU_0A, 14, 1 },
/* CONN SS */
{ "con-usb", IMX_SC_R_USB_0, 2, 1 },
{ "con-usb0phy", IMX_SC_R_USB_0_PHY, 1, 0 },
{ "con-usb2", IMX_SC_R_USB_2, 1, 0 },
{ "con-usb2phy", IMX_SC_R_USB_2_PHY, 1, 0 },
{ "con-sdhc", IMX_SC_R_SDHC_0, 3, 1 },
{ "con-enet", IMX_SC_R_ENET_0, 2, 1 },
{ "con-nand", IMX_SC_R_NAND, 1, 0 },
{ "con-mlb", IMX_SC_R_MLB_0, 1, 1 },
/* Audio DMA SS */
{ "adma-audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, 0 },
{ "adma-audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, 0 },
{ "adma-audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, 0 },
{ "adma-dma0-ch", IMX_SC_R_DMA_0_CH0, 16, 1 },
{ "adma-dma1-ch", IMX_SC_R_DMA_1_CH0, 16, 1 },
{ "adma-dma2-ch", IMX_SC_R_DMA_2_CH0, 5, 1 },
{ "adma-asrc0", IMX_SC_R_ASRC_0, 1, 0 },
{ "adma-asrc1", IMX_SC_R_ASRC_1, 1, 0 },
{ "adma-esai0", IMX_SC_R_ESAI_0, 1, 0 },
{ "adma-spdif0", IMX_SC_R_SPDIF_0, 1, 0 },
{ "adma-sai", IMX_SC_R_SAI_0, 3, 1 },
{ "adma-amix", IMX_SC_R_AMIX, 1, 0 },
{ "adma-mqs0", IMX_SC_R_MQS_0, 1, 0 },
{ "adma-dsp", IMX_SC_R_DSP, 1, 0 },
{ "adma-dsp-ram", IMX_SC_R_DSP_RAM, 1, 0 },
{ "adma-can", IMX_SC_R_CAN_0, 3, 1 },
{ "adma-ftm", IMX_SC_R_FTM_0, 2, 1 },
{ "adma-lpi2c", IMX_SC_R_I2C_0, 4, 1 },
{ "adma-adc", IMX_SC_R_ADC_0, 1, 1 },
{ "adma-lcd", IMX_SC_R_LCD_0, 1, 1 },
{ "adma-lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, 1 },
{ "adma-lpuart", IMX_SC_R_UART_0, 4, 1 },
{ "adma-lpspi", IMX_SC_R_SPI_0, 4, 1 },
/* VPU SS */
{ "vpu", IMX_SC_R_VPU, 1, 0 },
{ "vpu-pid", IMX_SC_R_VPU_PID0, 8, 1 },
{ "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, 0 },
{ "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, 0 },
/* GPU SS */
{ "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, 1 },
/* HSIO SS */
{ "hsio-pcie-b", IMX_SC_R_PCIE_B, 1, 0 },
{ "hsio-serdes-1", IMX_SC_R_SERDES_1, 1, 0 },
{ "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, 0 },
/* MIPI/LVDS SS */
{ "mipi0", IMX_SC_R_MIPI_0, 1, 0 },
{ "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, 0 },
{ "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, 1 },
{ "lvds0", IMX_SC_R_LVDS_0, 1, 0 },
/* DC SS */
{ "dc0", IMX_SC_R_DC_0, 1, 0 },
{ "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, 1 },
};
static const struct imx_sc_pd_soc imx8qxp_scu_pd = {
.pd_ranges = imx8qxp_scu_pd_ranges,
.num_ranges = ARRAY_SIZE(imx8qxp_scu_pd_ranges),
};
static struct imx_sc_ipc *pm_ipc_handle;
static inline struct imx_sc_pm_domain *
to_imx_sc_pd(struct generic_pm_domain *genpd)
{
return container_of(genpd, struct imx_sc_pm_domain, pd);
}
static int imx_sc_pd_power(struct generic_pm_domain *domain, bool power_on)
{
struct imx_sc_msg_req_set_resource_power_mode msg;
struct imx_sc_rpc_msg *hdr = &msg.hdr;
struct imx_sc_pm_domain *pd;
int ret;
pd = to_imx_sc_pd(domain);
hdr->ver = IMX_SC_RPC_VERSION;
hdr->svc = IMX_SC_RPC_SVC_PM;
hdr->func = IMX_SC_PM_FUNC_SET_RESOURCE_POWER_MODE;
hdr->size = 2;
msg.resource = pd->rsrc;
msg.mode = power_on ? IMX_SC_PM_PW_MODE_ON : IMX_SC_PM_PW_MODE_LP;
ret = imx_scu_call_rpc(pm_ipc_handle, &msg, true);
if (ret)
dev_err(&domain->dev, "failed to power %s resource %d ret %d\n",
power_on ? "up" : "off", pd->rsrc, ret);
return ret;
}
static int imx_sc_pd_power_on(struct generic_pm_domain *domain)
{
return imx_sc_pd_power(domain, true);
}
static int imx_sc_pd_power_off(struct generic_pm_domain *domain)
{
return imx_sc_pd_power(domain, false);
}
static struct generic_pm_domain *imx_scu_pd_xlate(struct of_phandle_args *spec,
void *data)
{
struct generic_pm_domain *domain = ERR_PTR(-ENOENT);
struct genpd_onecell_data *pd_data = data;
unsigned int i;
for (i = 0; i < pd_data->num_domains; i++) {
struct imx_sc_pm_domain *sc_pd;
sc_pd = to_imx_sc_pd(pd_data->domains[i]);
if (sc_pd->rsrc == spec->args[0]) {
domain = &sc_pd->pd;
break;
}
}
return domain;
}
static struct imx_sc_pm_domain *
imx_scu_add_pm_domain(struct device *dev, int idx,
const struct imx_sc_pd_range *pd_ranges)
{
struct imx_sc_pm_domain *sc_pd;
int ret;
sc_pd = devm_kzalloc(dev, sizeof(*sc_pd), GFP_KERNEL);
if (!sc_pd)
return ERR_PTR(-ENOMEM);
sc_pd->rsrc = pd_ranges->rsrc + idx;
sc_pd->pd.power_off = imx_sc_pd_power_off;
sc_pd->pd.power_on = imx_sc_pd_power_on;
if (pd_ranges->postfix)
snprintf(sc_pd->name, sizeof(sc_pd->name),
"%s%i", pd_ranges->name, idx);
else
snprintf(sc_pd->name, sizeof(sc_pd->name),
"%s", pd_ranges->name);
sc_pd->pd.name = sc_pd->name;
if (sc_pd->rsrc >= IMX_SC_R_LAST) {
dev_warn(dev, "invalid pd %s rsrc id %d found",
sc_pd->name, sc_pd->rsrc);
devm_kfree(dev, sc_pd);
return NULL;
}
ret = pm_genpd_init(&sc_pd->pd, NULL, true);
if (ret) {
dev_warn(dev, "failed to init pd %s rsrc id %d",
sc_pd->name, sc_pd->rsrc);
devm_kfree(dev, sc_pd);
return NULL;
}
return sc_pd;
}
static int imx_scu_init_pm_domains(struct device *dev,
const struct imx_sc_pd_soc *pd_soc)
{
const struct imx_sc_pd_range *pd_ranges = pd_soc->pd_ranges;
struct generic_pm_domain **domains;
struct genpd_onecell_data *pd_data;
struct imx_sc_pm_domain *sc_pd;
u32 count = 0;
int i, j;
for (i = 0; i < pd_soc->num_ranges; i++)
count += pd_ranges[i].num;
domains = devm_kcalloc(dev, count, sizeof(*domains), GFP_KERNEL);
if (!domains)
return -ENOMEM;
pd_data = devm_kzalloc(dev, sizeof(*pd_data), GFP_KERNEL);
if (!pd_data)
return -ENOMEM;
count = 0;
for (i = 0; i < pd_soc->num_ranges; i++) {
for (j = 0; j < pd_ranges[i].num; j++) {
sc_pd = imx_scu_add_pm_domain(dev, j, &pd_ranges[i]);
if (IS_ERR_OR_NULL(sc_pd))
continue;
domains[count++] = &sc_pd->pd;
dev_dbg(dev, "added power domain %s\n", sc_pd->pd.name);
}
}
pd_data->domains = domains;
pd_data->num_domains = count;
pd_data->xlate = imx_scu_pd_xlate;
of_genpd_add_provider_onecell(dev->of_node, pd_data);
return 0;
}
static int imx_sc_pd_probe(struct platform_device *pdev)
{
const struct imx_sc_pd_soc *pd_soc;
int ret;
ret = imx_scu_get_handle(&pm_ipc_handle);
if (ret)
return ret;
pd_soc = of_device_get_match_data(&pdev->dev);
if (!pd_soc)
return -ENODEV;
return imx_scu_init_pm_domains(&pdev->dev, pd_soc);
}
static const struct of_device_id imx_sc_pd_match[] = {
{ .compatible = "fsl,imx8qxp-scu-pd", &imx8qxp_scu_pd},
{ /* sentinel */ }
};
static struct platform_driver imx_sc_pd_driver = {
.driver = {
.name = "imx-scu-pd",
.of_match_table = imx_sc_pd_match,
},
.probe = imx_sc_pd_probe,
};
builtin_platform_driver(imx_sc_pd_driver);
MODULE_AUTHOR("Dong Aisheng <aisheng.dong@nxp.com>");
MODULE_DESCRIPTION("IMX SCU Power Domain driver");
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0
/* /*
* Defines interfaces for interacting wtih the Raspberry Pi firmware's * Defines interfaces for interacting wtih the Raspberry Pi firmware's
* property channel. * property channel.
* *
* Copyright © 2015 Broadcom * Copyright © 2015 Broadcom
*
* 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.
*/ */
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
...@@ -14,6 +11,7 @@ ...@@ -14,6 +11,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h>
#include <soc/bcm2835/raspberrypi-firmware.h> #include <soc/bcm2835/raspberrypi-firmware.h>
#define MBOX_MSG(chan, data28) (((data28) & ~0xf) | ((chan) & 0xf)) #define MBOX_MSG(chan, data28) (((data28) & ~0xf) | ((chan) & 0xf))
...@@ -21,8 +19,6 @@ ...@@ -21,8 +19,6 @@
#define MBOX_DATA28(msg) ((msg) & ~0xf) #define MBOX_DATA28(msg) ((msg) & ~0xf)
#define MBOX_CHAN_PROPERTY 8 #define MBOX_CHAN_PROPERTY 8
#define MAX_RPI_FW_PROP_BUF_SIZE 32
static struct platform_device *rpi_hwmon; static struct platform_device *rpi_hwmon;
struct rpi_firmware { struct rpi_firmware {
...@@ -56,8 +52,12 @@ rpi_firmware_transaction(struct rpi_firmware *fw, u32 chan, u32 data) ...@@ -56,8 +52,12 @@ rpi_firmware_transaction(struct rpi_firmware *fw, u32 chan, u32 data)
reinit_completion(&fw->c); reinit_completion(&fw->c);
ret = mbox_send_message(fw->chan, &message); ret = mbox_send_message(fw->chan, &message);
if (ret >= 0) { if (ret >= 0) {
wait_for_completion(&fw->c); if (wait_for_completion_timeout(&fw->c, HZ)) {
ret = 0; ret = 0;
} else {
ret = -ETIMEDOUT;
WARN_ONCE(1, "Firmware transaction timeout");
}
} else { } else {
dev_err(fw->cl.dev, "mbox_send_message returned %d\n", ret); dev_err(fw->cl.dev, "mbox_send_message returned %d\n", ret);
} }
...@@ -144,28 +144,30 @@ EXPORT_SYMBOL_GPL(rpi_firmware_property_list); ...@@ -144,28 +144,30 @@ EXPORT_SYMBOL_GPL(rpi_firmware_property_list);
int rpi_firmware_property(struct rpi_firmware *fw, int rpi_firmware_property(struct rpi_firmware *fw,
u32 tag, void *tag_data, size_t buf_size) u32 tag, void *tag_data, size_t buf_size)
{ {
/* Single tags are very small (generally 8 bytes), so the struct rpi_firmware_property_tag_header *header;
* stack should be safe.
*/
u8 data[sizeof(struct rpi_firmware_property_tag_header) +
MAX_RPI_FW_PROP_BUF_SIZE];
struct rpi_firmware_property_tag_header *header =
(struct rpi_firmware_property_tag_header *)data;
int ret; int ret;
if (WARN_ON(buf_size > sizeof(data) - sizeof(*header))) /* Some mailboxes can use over 1k bytes. Rather than checking
return -EINVAL; * size and using stack or kmalloc depending on requirements,
* just use kmalloc. Mailboxes don't get called enough to worry
* too much about the time taken in the allocation.
*/
void *data = kmalloc(sizeof(*header) + buf_size, GFP_KERNEL);
if (!data)
return -ENOMEM;
header = data;
header->tag = tag; header->tag = tag;
header->buf_size = buf_size; header->buf_size = buf_size;
header->req_resp_size = 0; header->req_resp_size = 0;
memcpy(data + sizeof(struct rpi_firmware_property_tag_header), memcpy(data + sizeof(*header), tag_data, buf_size);
tag_data, buf_size);
ret = rpi_firmware_property_list(fw, data, buf_size + sizeof(*header));
memcpy(tag_data, data + sizeof(*header), buf_size);
ret = rpi_firmware_property_list(fw, &data, buf_size + sizeof(*header)); kfree(data);
memcpy(tag_data,
data + sizeof(struct rpi_firmware_property_tag_header),
buf_size);
return ret; return ret;
} }
......
...@@ -379,33 +379,6 @@ static int create_debugfs_mirror(struct tegra_bpmp *bpmp, void *buf, ...@@ -379,33 +379,6 @@ static int create_debugfs_mirror(struct tegra_bpmp *bpmp, void *buf,
return err; return err;
} }
static int mrq_is_supported(struct tegra_bpmp *bpmp, unsigned int mrq)
{
struct mrq_query_abi_request req = { .mrq = cpu_to_le32(mrq) };
struct mrq_query_abi_response resp;
struct tegra_bpmp_message msg = {
.mrq = MRQ_QUERY_ABI,
.tx = {
.data = &req,
.size = sizeof(req),
},
.rx = {
.data = &resp,
.size = sizeof(resp),
},
};
int ret;
ret = tegra_bpmp_transfer(bpmp, &msg);
if (ret < 0) {
/* something went wrong; assume not supported */
dev_warn(bpmp->dev, "tegra_bpmp_transfer failed (%d)\n", ret);
return 0;
}
return resp.status ? 0 : 1;
}
int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp) int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp)
{ {
dma_addr_t phys; dma_addr_t phys;
...@@ -415,7 +388,7 @@ int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp) ...@@ -415,7 +388,7 @@ int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp)
int ret; int ret;
struct dentry *root; struct dentry *root;
if (!mrq_is_supported(bpmp, MRQ_DEBUGFS)) if (!tegra_bpmp_mrq_is_supported(bpmp, MRQ_DEBUGFS))
return 0; return 0;
root = debugfs_create_dir("bpmp", NULL); root = debugfs_create_dir("bpmp", NULL);
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#define MSG_ACK BIT(0) #define MSG_ACK BIT(0)
#define MSG_RING BIT(1) #define MSG_RING BIT(1)
#define TAG_SZ 32
static inline struct tegra_bpmp * static inline struct tegra_bpmp *
mbox_client_to_bpmp(struct mbox_client *client) mbox_client_to_bpmp(struct mbox_client *client)
...@@ -470,6 +471,31 @@ unlock: ...@@ -470,6 +471,31 @@ unlock:
} }
EXPORT_SYMBOL_GPL(tegra_bpmp_free_mrq); EXPORT_SYMBOL_GPL(tegra_bpmp_free_mrq);
bool tegra_bpmp_mrq_is_supported(struct tegra_bpmp *bpmp, unsigned int mrq)
{
struct mrq_query_abi_request req = { .mrq = cpu_to_le32(mrq) };
struct mrq_query_abi_response resp;
struct tegra_bpmp_message msg = {
.mrq = MRQ_QUERY_ABI,
.tx = {
.data = &req,
.size = sizeof(req),
},
.rx = {
.data = &resp,
.size = sizeof(resp),
},
};
int ret;
ret = tegra_bpmp_transfer(bpmp, &msg);
if (ret || msg.rx.ret)
return false;
return resp.status == 0;
}
EXPORT_SYMBOL_GPL(tegra_bpmp_mrq_is_supported);
static void tegra_bpmp_mrq_handle_ping(unsigned int mrq, static void tegra_bpmp_mrq_handle_ping(unsigned int mrq,
struct tegra_bpmp_channel *channel, struct tegra_bpmp_channel *channel,
void *data) void *data)
...@@ -521,8 +547,9 @@ static int tegra_bpmp_ping(struct tegra_bpmp *bpmp) ...@@ -521,8 +547,9 @@ static int tegra_bpmp_ping(struct tegra_bpmp *bpmp)
return err; return err;
} }
static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag, /* deprecated version of tag query */
size_t size) static int tegra_bpmp_get_firmware_tag_old(struct tegra_bpmp *bpmp, char *tag,
size_t size)
{ {
struct mrq_query_tag_request request; struct mrq_query_tag_request request;
struct tegra_bpmp_message msg; struct tegra_bpmp_message msg;
...@@ -531,7 +558,10 @@ static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag, ...@@ -531,7 +558,10 @@ static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag,
void *virt; void *virt;
int err; int err;
virt = dma_alloc_coherent(bpmp->dev, MSG_DATA_MIN_SZ, &phys, if (size != TAG_SZ)
return -EINVAL;
virt = dma_alloc_coherent(bpmp->dev, TAG_SZ, &phys,
GFP_KERNEL | GFP_DMA32); GFP_KERNEL | GFP_DMA32);
if (!virt) if (!virt)
return -ENOMEM; return -ENOMEM;
...@@ -549,13 +579,44 @@ static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag, ...@@ -549,13 +579,44 @@ static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag,
local_irq_restore(flags); local_irq_restore(flags);
if (err == 0) if (err == 0)
strlcpy(tag, virt, size); memcpy(tag, virt, TAG_SZ);
dma_free_coherent(bpmp->dev, MSG_DATA_MIN_SZ, virt, phys); dma_free_coherent(bpmp->dev, TAG_SZ, virt, phys);
return err; return err;
} }
static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag,
size_t size)
{
if (tegra_bpmp_mrq_is_supported(bpmp, MRQ_QUERY_FW_TAG)) {
struct mrq_query_fw_tag_response resp;
struct tegra_bpmp_message msg = {
.mrq = MRQ_QUERY_FW_TAG,
.rx = {
.data = &resp,
.size = sizeof(resp),
},
};
int err;
if (size != sizeof(resp.tag))
return -EINVAL;
err = tegra_bpmp_transfer(bpmp, &msg);
if (err)
return err;
if (msg.rx.ret < 0)
return -EINVAL;
memcpy(tag, resp.tag, sizeof(resp.tag));
return 0;
}
return tegra_bpmp_get_firmware_tag_old(bpmp, tag, size);
}
static void tegra_bpmp_channel_signal(struct tegra_bpmp_channel *channel) static void tegra_bpmp_channel_signal(struct tegra_bpmp_channel *channel)
{ {
unsigned long flags = channel->ob->flags; unsigned long flags = channel->ob->flags;
...@@ -664,7 +725,7 @@ static int tegra_bpmp_probe(struct platform_device *pdev) ...@@ -664,7 +725,7 @@ static int tegra_bpmp_probe(struct platform_device *pdev)
{ {
struct tegra_bpmp *bpmp; struct tegra_bpmp *bpmp;
unsigned int i; unsigned int i;
char tag[32]; char tag[TAG_SZ];
size_t size; size_t size;
int err; int err;
...@@ -792,13 +853,13 @@ static int tegra_bpmp_probe(struct platform_device *pdev) ...@@ -792,13 +853,13 @@ static int tegra_bpmp_probe(struct platform_device *pdev)
goto free_mrq; goto free_mrq;
} }
err = tegra_bpmp_get_firmware_tag(bpmp, tag, sizeof(tag) - 1); err = tegra_bpmp_get_firmware_tag(bpmp, tag, sizeof(tag));
if (err < 0) { if (err < 0) {
dev_err(&pdev->dev, "failed to get firmware tag: %d\n", err); dev_err(&pdev->dev, "failed to get firmware tag: %d\n", err);
goto free_mrq; goto free_mrq;
} }
dev_info(&pdev->dev, "firmware: %s\n", tag); dev_info(&pdev->dev, "firmware: %.*s\n", (int)sizeof(tag), tag);
platform_set_drvdata(pdev, bpmp); platform_set_drvdata(pdev, bpmp);
......
...@@ -902,26 +902,6 @@ static int a6xx_gmu_memory_probe(struct a6xx_gmu *gmu) ...@@ -902,26 +902,6 @@ static int a6xx_gmu_memory_probe(struct a6xx_gmu *gmu)
return ret; return ret;
} }
/* Get the list of RPMh voltage levels from cmd-db */
static int a6xx_gmu_rpmh_arc_cmds(const char *id, void *vals, int size)
{
u32 len = cmd_db_read_aux_data_len(id);
if (!len)
return 0;
if (WARN_ON(len > size))
return -EINVAL;
cmd_db_read_aux_data(id, vals, len);
/*
* The data comes back as an array of unsigned shorts so adjust the
* count accordingly
*/
return len >> 1;
}
/* Return the 'arc-level' for the given frequency */ /* Return the 'arc-level' for the given frequency */
static u32 a6xx_gmu_get_arc_level(struct device *dev, unsigned long freq) static u32 a6xx_gmu_get_arc_level(struct device *dev, unsigned long freq)
{ {
...@@ -949,11 +929,30 @@ static u32 a6xx_gmu_get_arc_level(struct device *dev, unsigned long freq) ...@@ -949,11 +929,30 @@ static u32 a6xx_gmu_get_arc_level(struct device *dev, unsigned long freq)
} }
static int a6xx_gmu_rpmh_arc_votes_init(struct device *dev, u32 *votes, static int a6xx_gmu_rpmh_arc_votes_init(struct device *dev, u32 *votes,
unsigned long *freqs, int freqs_count, unsigned long *freqs, int freqs_count, const char *id)
u16 *pri, int pri_count,
u16 *sec, int sec_count)
{ {
int i, j; int i, j;
const u16 *pri, *sec;
size_t pri_count, sec_count;
pri = cmd_db_read_aux_data(id, &pri_count);
if (IS_ERR(pri))
return PTR_ERR(pri);
/*
* The data comes back as an array of unsigned shorts so adjust the
* count accordingly
*/
pri_count >>= 1;
if (!pri_count)
return -EINVAL;
sec = cmd_db_read_aux_data("mx.lvl", &sec_count);
if (IS_ERR(sec))
return PTR_ERR(sec);
sec_count >>= 1;
if (!sec_count)
return -EINVAL;
/* Construct a vote for each frequency */ /* Construct a vote for each frequency */
for (i = 0; i < freqs_count; i++) { for (i = 0; i < freqs_count; i++) {
...@@ -1012,25 +1011,15 @@ static int a6xx_gmu_rpmh_votes_init(struct a6xx_gmu *gmu) ...@@ -1012,25 +1011,15 @@ static int a6xx_gmu_rpmh_votes_init(struct a6xx_gmu *gmu)
struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu);
struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
struct msm_gpu *gpu = &adreno_gpu->base; struct msm_gpu *gpu = &adreno_gpu->base;
u16 gx[16], cx[16], mx[16];
u32 gxcount, cxcount, mxcount;
int ret; int ret;
/* Get the list of available voltage levels for each component */
gxcount = a6xx_gmu_rpmh_arc_cmds("gfx.lvl", gx, sizeof(gx));
cxcount = a6xx_gmu_rpmh_arc_cmds("cx.lvl", cx, sizeof(cx));
mxcount = a6xx_gmu_rpmh_arc_cmds("mx.lvl", mx, sizeof(mx));
/* Build the GX votes */ /* Build the GX votes */
ret = a6xx_gmu_rpmh_arc_votes_init(&gpu->pdev->dev, gmu->gx_arc_votes, ret = a6xx_gmu_rpmh_arc_votes_init(&gpu->pdev->dev, gmu->gx_arc_votes,
gmu->gpu_freqs, gmu->nr_gpu_freqs, gmu->gpu_freqs, gmu->nr_gpu_freqs, "gfx.lvl");
gx, gxcount, mx, mxcount);
/* Build the CX votes */ /* Build the CX votes */
ret |= a6xx_gmu_rpmh_arc_votes_init(gmu->dev, gmu->cx_arc_votes, ret |= a6xx_gmu_rpmh_arc_votes_init(gmu->dev, gmu->cx_arc_votes,
gmu->gmu_freqs, gmu->nr_gmu_freqs, gmu->gmu_freqs, gmu->nr_gmu_freqs, "cx.lvl");
cx, cxcount, mx, mxcount);
return ret; return ret;
} }
......
...@@ -145,6 +145,15 @@ config DA8XX_DDRCTL ...@@ -145,6 +145,15 @@ config DA8XX_DDRCTL
Texas Instruments da8xx SoCs. It's used to tweak various memory Texas Instruments da8xx SoCs. It's used to tweak various memory
controller configuration options. controller configuration options.
config PL353_SMC
tristate "ARM PL35X Static Memory Controller(SMC) driver"
default y
depends on ARM
depends on ARM_AMBA
help
This driver is for the ARM PL351/PL353 Static Memory
Controller(SMC) module.
source "drivers/memory/samsung/Kconfig" source "drivers/memory/samsung/Kconfig"
source "drivers/memory/tegra/Kconfig" source "drivers/memory/tegra/Kconfig"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment