diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-12-31 20:32:35 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-12-31 20:32:35 -0500 |
| commit | d36377c6eb071e3d0751e9e0e3c19198c58d9a5d (patch) | |
| tree | bf1d28abd5fac5c826079c4b760ca34263f0fab4 /drivers | |
| parent | 0922275ef157ba8ac93e7e7857087eb0442d5397 (diff) | |
| parent | a6f119a06960ef1dc30570401e43b71f9ebdd2c2 (diff) | |
Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC driver updates from Olof Johansson:
"Misc driver updates for platforms, many of them power related.
- Rockchip adds power domain support for rk3066 and rk3188
- Amlogic adds a power measurement driver
- Allwinner adds SRAM support for three platforms (F1C100, H5, A64
C1)
- Wakeup and ti-sysc (platform bus) fixes for OMAP/DRA7
- Broadcom fixes suspend/resume with Thumb2 kernels, and improves
stability of a handful of firmware/platform interfaces
- PXA completes their conversion to dmaengine framework
- Renesas does a bunch of PM cleanups across many platforms
- Tegra adds support for suspend/resume on T186/T194, which includes
some driver cleanups and addition of wake events
- Tegra also adds a driver for memory controller (EMC) on Tegra2
- i.MX tweaks power domain bindings, and adds support for i.MX8MQ in
GPC
- Atmel adds identifiers and LPDDR2 support for a new SoC, SAM9X60
and misc cleanups across several platforms"
* tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (73 commits)
ARM: at91: add support in soc driver for new SAM9X60
ARM: at91: add support in soc driver for LPDDR2 SiP
memory: omap-gpmc: Use of_node_name_eq for node name comparisons
bus: ti-sysc: Check for no-reset and no-idle flags at the child level
ARM: OMAP2+: Check also the first dts child for hwmod flags
soc: amlogic: meson-clk-measure: Add missing REGMAP_MMIO dependency
soc: imx: gpc: Increase GPC_CLK_MAX to 7
soc: renesas: rcar-sysc: Fix power domain control after system resume
soc: renesas: rcar-sysc: Merge PM Domain registration and linking
soc: renesas: rcar-sysc: Remove rcar_sysc_power_{down,up}() helpers
soc: renesas: r8a77990-sysc: Fix initialization order of 3DG-{A,B}
dt-bindings: sram: sunxi: Add compatible for the A64 SRAM C1
dt-bindings: sram: sunxi: Add bindings for the H5 with SRAM C1
dt-bindings: sram: Add Allwinner suniv F1C100s
soc: sunxi: sram: Add support for the H5 SoC system control
soc: sunxi: sram: Enable EMAC clock access for H3 variant
soc: imx: gpcv2: add support for i.MX8MQ SoC
soc: imx: gpcv2: move register access table to domain data
soc: imx: gpcv2: prefix i.MX7 specific defines
dmaengine: pxa: make the filter function internal
...
Diffstat (limited to 'drivers')
46 files changed, 2668 insertions, 382 deletions
diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c index 68ac3e93b600..f58ff67e97ac 100644 --- a/drivers/bus/brcmstb_gisb.c +++ b/drivers/bus/brcmstb_gisb.c | |||
| @@ -150,8 +150,7 @@ static ssize_t gisb_arb_get_timeout(struct device *dev, | |||
| 150 | struct device_attribute *attr, | 150 | struct device_attribute *attr, |
| 151 | char *buf) | 151 | char *buf) |
| 152 | { | 152 | { |
| 153 | struct platform_device *pdev = to_platform_device(dev); | 153 | struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev); |
| 154 | struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev); | ||
| 155 | u32 timeout; | 154 | u32 timeout; |
| 156 | 155 | ||
| 157 | mutex_lock(&gdev->lock); | 156 | mutex_lock(&gdev->lock); |
| @@ -165,8 +164,7 @@ static ssize_t gisb_arb_set_timeout(struct device *dev, | |||
| 165 | struct device_attribute *attr, | 164 | struct device_attribute *attr, |
| 166 | const char *buf, size_t count) | 165 | const char *buf, size_t count) |
| 167 | { | 166 | { |
| 168 | struct platform_device *pdev = to_platform_device(dev); | 167 | struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev); |
| 169 | struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev); | ||
| 170 | int val, ret; | 168 | int val, ret; |
| 171 | 169 | ||
| 172 | ret = kstrtoint(buf, 10, &val); | 170 | ret = kstrtoint(buf, 10, &val); |
| @@ -418,8 +416,7 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev) | |||
| 418 | #ifdef CONFIG_PM_SLEEP | 416 | #ifdef CONFIG_PM_SLEEP |
| 419 | static int brcmstb_gisb_arb_suspend(struct device *dev) | 417 | static int brcmstb_gisb_arb_suspend(struct device *dev) |
| 420 | { | 418 | { |
| 421 | struct platform_device *pdev = to_platform_device(dev); | 419 | struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev); |
| 422 | struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev); | ||
| 423 | 420 | ||
| 424 | gdev->saved_timeout = gisb_read(gdev, ARB_TIMER); | 421 | gdev->saved_timeout = gisb_read(gdev, ARB_TIMER); |
| 425 | 422 | ||
| @@ -431,8 +428,7 @@ static int brcmstb_gisb_arb_suspend(struct device *dev) | |||
| 431 | */ | 428 | */ |
| 432 | static int brcmstb_gisb_arb_resume_noirq(struct device *dev) | 429 | static int brcmstb_gisb_arb_resume_noirq(struct device *dev) |
| 433 | { | 430 | { |
| 434 | struct platform_device *pdev = to_platform_device(dev); | 431 | struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev); |
| 435 | struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev); | ||
| 436 | 432 | ||
| 437 | gisb_write(gdev, gdev->saved_timeout, ARB_TIMER); | 433 | gisb_write(gdev, gdev->saved_timeout, ARB_TIMER); |
| 438 | 434 | ||
diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index a3a2d39280d9..f94d33525771 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c | |||
| @@ -91,6 +91,9 @@ struct sysc { | |||
| 91 | struct delayed_work idle_work; | 91 | struct delayed_work idle_work; |
| 92 | }; | 92 | }; |
| 93 | 93 | ||
| 94 | static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np, | ||
| 95 | bool is_child); | ||
| 96 | |||
| 94 | void sysc_write(struct sysc *ddata, int offset, u32 value) | 97 | void sysc_write(struct sysc *ddata, int offset, u32 value) |
| 95 | { | 98 | { |
| 96 | writel_relaxed(value, ddata->module_va + offset); | 99 | writel_relaxed(value, ddata->module_va + offset); |
| @@ -214,8 +217,13 @@ static int sysc_get_clocks(struct sysc *ddata) | |||
| 214 | if (!ddata->clocks) | 217 | if (!ddata->clocks) |
| 215 | return -ENOMEM; | 218 | return -ENOMEM; |
| 216 | 219 | ||
| 217 | for (i = 0; i < ddata->nr_clocks; i++) { | 220 | for (i = 0; i < SYSC_MAX_CLOCKS; i++) { |
| 218 | error = sysc_get_one_clock(ddata, ddata->clock_roles[i]); | 221 | const char *name = ddata->clock_roles[i]; |
| 222 | |||
| 223 | if (!name) | ||
| 224 | continue; | ||
| 225 | |||
| 226 | error = sysc_get_one_clock(ddata, name); | ||
| 219 | if (error && error != -ENOENT) | 227 | if (error && error != -ENOENT) |
| 220 | return error; | 228 | return error; |
| 221 | } | 229 | } |
| @@ -374,6 +382,7 @@ static int sysc_check_one_child(struct sysc *ddata, | |||
| 374 | dev_warn(ddata->dev, "really a child ti,hwmods property?"); | 382 | dev_warn(ddata->dev, "really a child ti,hwmods property?"); |
| 375 | 383 | ||
| 376 | sysc_check_quirk_stdout(ddata, np); | 384 | sysc_check_quirk_stdout(ddata, np); |
| 385 | sysc_parse_dts_quirks(ddata, np, true); | ||
| 377 | 386 | ||
| 378 | return 0; | 387 | return 0; |
| 379 | } | 388 | } |
| @@ -815,6 +824,7 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { | |||
| 815 | SYSC_QUIRK("ocp2scp", 0, 0, 0x10, 0x14, 0x50060005, 0xfffffff0, 0), | 824 | SYSC_QUIRK("ocp2scp", 0, 0, 0x10, 0x14, 0x50060005, 0xfffffff0, 0), |
| 816 | SYSC_QUIRK("ocp2scp", 0, 0, -1, -1, 0x50060007, 0xffffffff, 0), | 825 | SYSC_QUIRK("ocp2scp", 0, 0, -1, -1, 0x50060007, 0xffffffff, 0), |
| 817 | SYSC_QUIRK("padconf", 0, 0, 0x10, -1, 0x4fff0800, 0xffffffff, 0), | 826 | SYSC_QUIRK("padconf", 0, 0, 0x10, -1, 0x4fff0800, 0xffffffff, 0), |
| 827 | SYSC_QUIRK("padconf", 0, 0, -1, -1, 0x40001100, 0xffffffff, 0), | ||
| 818 | SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000100, 0xffffffff, 0), | 828 | SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000100, 0xffffffff, 0), |
| 819 | SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x00004102, 0xffffffff, 0), | 829 | SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x00004102, 0xffffffff, 0), |
| 820 | SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000400, 0xffffffff, 0), | 830 | SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000400, 0xffffffff, 0), |
| @@ -833,7 +843,9 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { | |||
| 833 | SYSC_QUIRK("rtc", 0, 0x74, 0x78, -1, 0x4eb01908, 0xffff00f0, 0), | 843 | SYSC_QUIRK("rtc", 0, 0x74, 0x78, -1, 0x4eb01908, 0xffff00f0, 0), |
| 834 | SYSC_QUIRK("timer32k", 0, 0, 0x4, -1, 0x00000060, 0xffffffff, 0), | 844 | SYSC_QUIRK("timer32k", 0, 0, 0x4, -1, 0x00000060, 0xffffffff, 0), |
| 835 | SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000004, 0xffffffff, 0), | 845 | SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000004, 0xffffffff, 0), |
| 846 | SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000008, 0xffffffff, 0), | ||
| 836 | SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff, 0), | 847 | SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff, 0), |
| 848 | SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -1, 0x50700101, 0xffffffff, 0), | ||
| 837 | SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050, | 849 | SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050, |
| 838 | 0xffffffff, 0), | 850 | 0xffffffff, 0), |
| 839 | SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0, 0), | 851 | SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0, 0), |
| @@ -1271,23 +1283,37 @@ static const struct sysc_dts_quirk sysc_dts_quirks[] = { | |||
| 1271 | .mask = SYSC_QUIRK_NO_RESET_ON_INIT, }, | 1283 | .mask = SYSC_QUIRK_NO_RESET_ON_INIT, }, |
| 1272 | }; | 1284 | }; |
| 1273 | 1285 | ||
| 1274 | static int sysc_init_dts_quirks(struct sysc *ddata) | 1286 | static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np, |
| 1287 | bool is_child) | ||
| 1275 | { | 1288 | { |
| 1276 | struct device_node *np = ddata->dev->of_node; | ||
| 1277 | const struct property *prop; | 1289 | const struct property *prop; |
| 1278 | int i, len, error; | 1290 | int i, len; |
| 1279 | u32 val; | ||
| 1280 | |||
| 1281 | ddata->legacy_mode = of_get_property(np, "ti,hwmods", NULL); | ||
| 1282 | 1291 | ||
| 1283 | for (i = 0; i < ARRAY_SIZE(sysc_dts_quirks); i++) { | 1292 | for (i = 0; i < ARRAY_SIZE(sysc_dts_quirks); i++) { |
| 1284 | prop = of_get_property(np, sysc_dts_quirks[i].name, &len); | 1293 | const char *name = sysc_dts_quirks[i].name; |
| 1294 | |||
| 1295 | prop = of_get_property(np, name, &len); | ||
| 1285 | if (!prop) | 1296 | if (!prop) |
| 1286 | continue; | 1297 | continue; |
| 1287 | 1298 | ||
| 1288 | ddata->cfg.quirks |= sysc_dts_quirks[i].mask; | 1299 | ddata->cfg.quirks |= sysc_dts_quirks[i].mask; |
| 1300 | if (is_child) { | ||
| 1301 | dev_warn(ddata->dev, | ||
| 1302 | "dts flag should be at module level for %s\n", | ||
| 1303 | name); | ||
| 1304 | } | ||
| 1289 | } | 1305 | } |
| 1306 | } | ||
| 1290 | 1307 | ||
| 1308 | static int sysc_init_dts_quirks(struct sysc *ddata) | ||
| 1309 | { | ||
| 1310 | struct device_node *np = ddata->dev->of_node; | ||
| 1311 | int error; | ||
| 1312 | u32 val; | ||
| 1313 | |||
| 1314 | ddata->legacy_mode = of_get_property(np, "ti,hwmods", NULL); | ||
| 1315 | |||
| 1316 | sysc_parse_dts_quirks(ddata, np, false); | ||
| 1291 | error = of_property_read_u32(np, "ti,sysc-delay-us", &val); | 1317 | error = of_property_read_u32(np, "ti,sysc-delay-us", &val); |
| 1292 | if (!error) { | 1318 | if (!error) { |
| 1293 | if (val > 255) { | 1319 | if (val > 255) { |
| @@ -1498,6 +1524,16 @@ static const struct sysc_regbits sysc_regbits_omap4_mcasp = { | |||
| 1498 | static const struct sysc_capabilities sysc_omap4_mcasp = { | 1524 | static const struct sysc_capabilities sysc_omap4_mcasp = { |
| 1499 | .type = TI_SYSC_OMAP4_MCASP, | 1525 | .type = TI_SYSC_OMAP4_MCASP, |
| 1500 | .regbits = &sysc_regbits_omap4_mcasp, | 1526 | .regbits = &sysc_regbits_omap4_mcasp, |
| 1527 | .mod_quirks = SYSC_QUIRK_OPT_CLKS_NEEDED, | ||
| 1528 | }; | ||
| 1529 | |||
| 1530 | /* | ||
| 1531 | * McASP found on dra7 and later | ||
| 1532 | */ | ||
| 1533 | static const struct sysc_capabilities sysc_dra7_mcasp = { | ||
| 1534 | .type = TI_SYSC_OMAP4_SIMPLE, | ||
| 1535 | .regbits = &sysc_regbits_omap4_simple, | ||
| 1536 | .mod_quirks = SYSC_QUIRK_OPT_CLKS_NEEDED, | ||
| 1501 | }; | 1537 | }; |
| 1502 | 1538 | ||
| 1503 | /* | 1539 | /* |
| @@ -1726,6 +1762,7 @@ static const struct of_device_id sysc_match[] = { | |||
| 1726 | { .compatible = "ti,sysc-omap3-sham", .data = &sysc_omap3_sham, }, | 1762 | { .compatible = "ti,sysc-omap3-sham", .data = &sysc_omap3_sham, }, |
| 1727 | { .compatible = "ti,sysc-omap-aes", .data = &sysc_omap3_aes, }, | 1763 | { .compatible = "ti,sysc-omap-aes", .data = &sysc_omap3_aes, }, |
| 1728 | { .compatible = "ti,sysc-mcasp", .data = &sysc_omap4_mcasp, }, | 1764 | { .compatible = "ti,sysc-mcasp", .data = &sysc_omap4_mcasp, }, |
| 1765 | { .compatible = "ti,sysc-dra7-mcasp", .data = &sysc_dra7_mcasp, }, | ||
| 1729 | { .compatible = "ti,sysc-usb-host-fs", | 1766 | { .compatible = "ti,sysc-usb-host-fs", |
| 1730 | .data = &sysc_omap4_usb_host_fs, }, | 1767 | .data = &sysc_omap4_usb_host_fs, }, |
| 1731 | { .compatible = "ti,sysc-dra7-mcan", .data = &sysc_dra7_mcan, }, | 1768 | { .compatible = "ti,sysc-dra7-mcan", .data = &sysc_dra7_mcan, }, |
diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c index 825725057e00..c7a328f81485 100644 --- a/drivers/dma/pxa_dma.c +++ b/drivers/dma/pxa_dma.c | |||
| @@ -179,7 +179,7 @@ static unsigned int pxad_drcmr(unsigned int line) | |||
| 179 | return 0x1000 + line * 4; | 179 | return 0x1000 + line * 4; |
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | bool pxad_filter_fn(struct dma_chan *chan, void *param); | 182 | static bool pxad_filter_fn(struct dma_chan *chan, void *param); |
| 183 | 183 | ||
| 184 | /* | 184 | /* |
| 185 | * Debug fs | 185 | * Debug fs |
| @@ -1500,7 +1500,7 @@ static struct platform_driver pxad_driver = { | |||
| 1500 | .remove = pxad_remove, | 1500 | .remove = pxad_remove, |
| 1501 | }; | 1501 | }; |
| 1502 | 1502 | ||
| 1503 | bool pxad_filter_fn(struct dma_chan *chan, void *param) | 1503 | static bool pxad_filter_fn(struct dma_chan *chan, void *param) |
| 1504 | { | 1504 | { |
| 1505 | struct pxad_chan *c = to_pxad_chan(chan); | 1505 | struct pxad_chan *c = to_pxad_chan(chan); |
| 1506 | struct pxad_param *p = param; | 1506 | struct pxad_param *p = param; |
| @@ -1513,7 +1513,6 @@ bool pxad_filter_fn(struct dma_chan *chan, void *param) | |||
| 1513 | 1513 | ||
| 1514 | return true; | 1514 | return true; |
| 1515 | } | 1515 | } |
| 1516 | EXPORT_SYMBOL_GPL(pxad_filter_fn); | ||
| 1517 | 1516 | ||
| 1518 | module_platform_driver(pxad_driver); | 1517 | module_platform_driver(pxad_driver); |
| 1519 | 1518 | ||
diff --git a/drivers/firmware/imx/Kconfig b/drivers/firmware/imx/Kconfig index b170c2851e48..6a7a7c2c5b5f 100644 --- a/drivers/firmware/imx/Kconfig +++ b/drivers/firmware/imx/Kconfig | |||
| @@ -9,3 +9,9 @@ config IMX_SCU | |||
| 9 | 9 | ||
| 10 | This driver manages the IPC interface between host CPU and the | 10 | This driver manages the IPC interface between host CPU and the |
| 11 | SCU firmware running on M4. | 11 | SCU firmware running on M4. |
| 12 | |||
| 13 | config IMX_SCU_PD | ||
| 14 | bool "IMX SCU Power Domain driver" | ||
| 15 | depends on IMX_SCU | ||
| 16 | help | ||
| 17 | The System Controller Firmware (SCFW) based power domain driver. | ||
diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile index 0ac04dfda8d4..1b2e15b3c9ca 100644 --- a/drivers/firmware/imx/Makefile +++ b/drivers/firmware/imx/Makefile | |||
| @@ -1,2 +1,3 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | 1 | # SPDX-License-Identifier: GPL-2.0 |
| 2 | obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o | 2 | obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o |
| 3 | obj-$(CONFIG_IMX_SCU_PD) += scu-pd.o | ||
diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c new file mode 100644 index 000000000000..407245f2efd0 --- /dev/null +++ b/drivers/firmware/imx/scu-pd.c | |||
| @@ -0,0 +1,339 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0+ | ||
| 2 | /* | ||
| 3 | * Copyright (C) 2016 Freescale Semiconductor, Inc. | ||
| 4 | * Copyright 2017-2018 NXP | ||
| 5 | * Dong Aisheng <aisheng.dong@nxp.com> | ||
| 6 | * | ||
| 7 | * Implementation of the SCU based Power Domains | ||
| 8 | * | ||
| 9 | * NOTE: a better implementation suggested by Ulf Hansson is using a | ||
| 10 | * single global power domain and implement the ->attach|detach_dev() | ||
| 11 | * callback for the genpd and use the regular of_genpd_add_provider_simple(). | ||
| 12 | * From within the ->attach_dev(), we could get the OF node for | ||
| 13 | * the device that is being attached and then parse the power-domain | ||
| 14 | * cell containing the "resource id" and store that in the per device | ||
| 15 | * struct generic_pm_domain_data (we have void pointer there for | ||
| 16 | * storing these kind of things). | ||
| 17 | * | ||
| 18 | * Additionally, we need to implement the ->stop() and ->start() | ||
| 19 | * callbacks of genpd, which is where you "power on/off" devices, | ||
| 20 | * rather than using the above ->power_on|off() callbacks. | ||
| 21 | * | ||
| 22 | * However, there're two known issues: | ||
| 23 | * 1. The ->attach_dev() of power domain infrastructure still does | ||
| 24 | * not support multi domains case as the struct device *dev passed | ||
| 25 | * in is a virtual PD device, it does not help for parsing the real | ||
| 26 | * device resource id from device tree, so it's unware of which | ||
| 27 | * real sub power domain of device should be attached. | ||
| 28 | * | ||
| 29 | * The framework needs some proper extension to support multi power | ||
| 30 | * domain cases. | ||
| 31 | * | ||
| 32 | * 2. It also breaks most of current drivers as the driver probe sequence | ||
| 33 | * behavior changed if removing ->power_on|off() callback and use | ||
| 34 | * ->start() and ->stop() instead. genpd_dev_pm_attach will only power | ||
| 35 | * up the domain and attach device, but will not call .start() which | ||
| 36 | * relies on device runtime pm. That means the device power is still | ||
| 37 | * not up before running driver probe function. For SCU enabled | ||
| 38 | * platforms, all device drivers accessing registers/clock without power | ||
| 39 | * domain enabled will trigger a HW access error. That means we need fix | ||
| 40 | * most drivers probe sequence with proper runtime pm. | ||
| 41 | * | ||
| 42 | * In summary, we need fix above two issue before being able to switch to | ||
| 43 | * the "single global power domain" way. | ||
| 44 | * | ||
| 45 | */ | ||
| 46 | |||
| 47 | #include <dt-bindings/firmware/imx/rsrc.h> | ||
| 48 | #include <linux/firmware/imx/sci.h> | ||
| 49 | #include <linux/io.h> | ||
| 50 | #include <linux/module.h> | ||
| 51 | #include <linux/of.h> | ||
| 52 | #include <linux/of_address.h> | ||
| 53 | #include <linux/of_platform.h> | ||
| 54 | #include <linux/platform_device.h> | ||
| 55 | #include <linux/pm.h> | ||
| 56 | #include <linux/pm_domain.h> | ||
| 57 | #include <linux/slab.h> | ||
| 58 | |||
| 59 | /* SCU Power Mode Protocol definition */ | ||
| 60 | struct imx_sc_msg_req_set_resource_power_mode { | ||
| 61 | struct imx_sc_rpc_msg hdr; | ||
| 62 | u16 resource; | ||
| 63 | u8 mode; | ||
| 64 | } __packed; | ||
| 65 | |||
| 66 | #define IMX_SCU_PD_NAME_SIZE 20 | ||
| 67 | struct imx_sc_pm_domain { | ||
| 68 | struct generic_pm_domain pd; | ||
| 69 | char name[IMX_SCU_PD_NAME_SIZE]; | ||
| 70 | u32 rsrc; | ||
| 71 | }; | ||
| 72 | |||
| 73 | struct imx_sc_pd_range { | ||
| 74 | char *name; | ||
| 75 | u32 rsrc; | ||
| 76 | u8 num; | ||
| 77 | bool postfix; | ||
| 78 | }; | ||
| 79 | |||
| 80 | struct imx_sc_pd_soc { | ||
| 81 | const struct imx_sc_pd_range *pd_ranges; | ||
| 82 | u8 num_ranges; | ||
| 83 | }; | ||
| 84 | |||
| 85 | static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { | ||
| 86 | /* LSIO SS */ | ||
| 87 | { "lsio-pwm", IMX_SC_R_PWM_0, 8, 1 }, | ||
| 88 | { "lsio-gpio", IMX_SC_R_GPIO_0, 8, 1 }, | ||
| 89 | { "lsio-gpt", IMX_SC_R_GPT_0, 5, 1 }, | ||
| 90 | { "lsio-kpp", IMX_SC_R_KPP, 1, 0 }, | ||
| 91 | { "lsio-fspi", IMX_SC_R_FSPI_0, 2, 1 }, | ||
| 92 | { "lsio-mu", IMX_SC_R_MU_0A, 14, 1 }, | ||
| 93 | |||
| 94 | /* CONN SS */ | ||
| 95 | { "con-usb", IMX_SC_R_USB_0, 2, 1 }, | ||
| 96 | { "con-usb0phy", IMX_SC_R_USB_0_PHY, 1, 0 }, | ||
| 97 | { "con-usb2", IMX_SC_R_USB_2, 1, 0 }, | ||
| 98 | { "con-usb2phy", IMX_SC_R_USB_2_PHY, 1, 0 }, | ||
| 99 | { "con-sdhc", IMX_SC_R_SDHC_0, 3, 1 }, | ||
| 100 | { "con-enet", IMX_SC_R_ENET_0, 2, 1 }, | ||
| 101 | { "con-nand", IMX_SC_R_NAND, 1, 0 }, | ||
| 102 | { "con-mlb", IMX_SC_R_MLB_0, 1, 1 }, | ||
| 103 | |||
| 104 | /* Audio DMA SS */ | ||
| 105 | { "adma-audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, 0 }, | ||
| 106 | { "adma-audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, 0 }, | ||
| 107 | { "adma-audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, 0 }, | ||
| 108 | { "adma-dma0-ch", IMX_SC_R_DMA_0_CH0, 16, 1 }, | ||
| 109 | { "adma-dma1-ch", IMX_SC_R_DMA_1_CH0, 16, 1 }, | ||
| 110 | { "adma-dma2-ch", IMX_SC_R_DMA_2_CH0, 5, 1 }, | ||
| 111 | { "adma-asrc0", IMX_SC_R_ASRC_0, 1, 0 }, | ||
| 112 | { "adma-asrc1", IMX_SC_R_ASRC_1, 1, 0 }, | ||
| 113 | { "adma-esai0", IMX_SC_R_ESAI_0, 1, 0 }, | ||
| 114 | { "adma-spdif0", IMX_SC_R_SPDIF_0, 1, 0 }, | ||
| 115 | { "adma-sai", IMX_SC_R_SAI_0, 3, 1 }, | ||
| 116 | { "adma-amix", IMX_SC_R_AMIX, 1, 0 }, | ||
| 117 | { "adma-mqs0", IMX_SC_R_MQS_0, 1, 0 }, | ||
| 118 | { "adma-dsp", IMX_SC_R_DSP, 1, 0 }, | ||
| 119 | { "adma-dsp-ram", IMX_SC_R_DSP_RAM, 1, 0 }, | ||
| 120 | { "adma-can", IMX_SC_R_CAN_0, 3, 1 }, | ||
| 121 | { "adma-ftm", IMX_SC_R_FTM_0, 2, 1 }, | ||
| 122 | { "adma-lpi2c", IMX_SC_R_I2C_0, 4, 1 }, | ||
| 123 | { "adma-adc", IMX_SC_R_ADC_0, 1, 1 }, | ||
| 124 | { "adma-lcd", IMX_SC_R_LCD_0, 1, 1 }, | ||
| 125 | { "adma-lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, 1 }, | ||
| 126 | { "adma-lpuart", IMX_SC_R_UART_0, 4, 1 }, | ||
| 127 | { "adma-lpspi", IMX_SC_R_SPI_0, 4, 1 }, | ||
| 128 | |||
| 129 | /* VPU SS */ | ||
| 130 | { "vpu", IMX_SC_R_VPU, 1, 0 }, | ||
| 131 | { "vpu-pid", IMX_SC_R_VPU_PID0, 8, 1 }, | ||
| 132 | { "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, 0 }, | ||
| 133 | { "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, 0 }, | ||
| 134 | |||
| 135 | /* GPU SS */ | ||
| 136 | { "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, 1 }, | ||
| 137 | |||
| 138 | /* HSIO SS */ | ||
| 139 | { "hsio-pcie-b", IMX_SC_R_PCIE_B, 1, 0 }, | ||
| 140 | { "hsio-serdes-1", IMX_SC_R_SERDES_1, 1, 0 }, | ||
| 141 | { "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, 0 }, | ||
| 142 | |||
| 143 | /* MIPI/LVDS SS */ | ||
| 144 | { "mipi0", IMX_SC_R_MIPI_0, 1, 0 }, | ||
| 145 | { "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, 0 }, | ||
| 146 | { "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, 1 }, | ||
| 147 | { "lvds0", IMX_SC_R_LVDS_0, 1, 0 }, | ||
| 148 | |||
| 149 | /* DC SS */ | ||
| 150 | { "dc0", IMX_SC_R_DC_0, 1, 0 }, | ||
| 151 | { "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, 1 }, | ||
| 152 | }; | ||
| 153 | |||
| 154 | static const struct imx_sc_pd_soc imx8qxp_scu_pd = { | ||
| 155 | .pd_ranges = imx8qxp_scu_pd_ranges, | ||
| 156 | .num_ranges = ARRAY_SIZE(imx8qxp_scu_pd_ranges), | ||
| 157 | }; | ||
| 158 | |||
| 159 | static struct imx_sc_ipc *pm_ipc_handle; | ||
| 160 | |||
| 161 | static inline struct imx_sc_pm_domain * | ||
| 162 | to_imx_sc_pd(struct generic_pm_domain *genpd) | ||
| 163 | { | ||
| 164 | return container_of(genpd, struct imx_sc_pm_domain, pd); | ||
| 165 | } | ||
| 166 | |||
| 167 | static int imx_sc_pd_power(struct generic_pm_domain *domain, bool power_on) | ||
| 168 | { | ||
| 169 | struct imx_sc_msg_req_set_resource_power_mode msg; | ||
| 170 | struct imx_sc_rpc_msg *hdr = &msg.hdr; | ||
| 171 | struct imx_sc_pm_domain *pd; | ||
| 172 | int ret; | ||
| 173 | |||
| 174 | pd = to_imx_sc_pd(domain); | ||
| 175 | |||
| 176 | hdr->ver = IMX_SC_RPC_VERSION; | ||
| 177 | hdr->svc = IMX_SC_RPC_SVC_PM; | ||
| 178 | hdr->func = IMX_SC_PM_FUNC_SET_RESOURCE_POWER_MODE; | ||
| 179 | hdr->size = 2; | ||
| 180 | |||
| 181 | msg.resource = pd->rsrc; | ||
| 182 | msg.mode = power_on ? IMX_SC_PM_PW_MODE_ON : IMX_SC_PM_PW_MODE_LP; | ||
| 183 | |||
| 184 | ret = imx_scu_call_rpc(pm_ipc_handle, &msg, true); | ||
| 185 | if (ret) | ||
| 186 | dev_err(&domain->dev, "failed to power %s resource %d ret %d\n", | ||
| 187 | power_on ? "up" : "off", pd->rsrc, ret); | ||
| 188 | |||
| 189 | return ret; | ||
| 190 | } | ||
| 191 | |||
| 192 | static int imx_sc_pd_power_on(struct generic_pm_domain *domain) | ||
| 193 | { | ||
| 194 | return imx_sc_pd_power(domain, true); | ||
| 195 | } | ||
| 196 | |||
| 197 | static int imx_sc_pd_power_off(struct generic_pm_domain *domain) | ||
| 198 | { | ||
| 199 | return imx_sc_pd_power(domain, false); | ||
| 200 | } | ||
| 201 | |||
| 202 | static struct generic_pm_domain *imx_scu_pd_xlate(struct of_phandle_args *spec, | ||
| 203 | void *data) | ||
| 204 | { | ||
| 205 | struct generic_pm_domain *domain = ERR_PTR(-ENOENT); | ||
| 206 | struct genpd_onecell_data *pd_data = data; | ||
| 207 | unsigned int i; | ||
| 208 | |||
| 209 | for (i = 0; i < pd_data->num_domains; i++) { | ||
| 210 | struct imx_sc_pm_domain *sc_pd; | ||
| 211 | |||
| 212 | sc_pd = to_imx_sc_pd(pd_data->domains[i]); | ||
| 213 | if (sc_pd->rsrc == spec->args[0]) { | ||
| 214 | domain = &sc_pd->pd; | ||
| 215 | break; | ||
| 216 | } | ||
| 217 | } | ||
| 218 | |||
| 219 | return domain; | ||
| 220 | } | ||
| 221 | |||
| 222 | static struct imx_sc_pm_domain * | ||
| 223 | imx_scu_add_pm_domain(struct device *dev, int idx, | ||
| 224 | const struct imx_sc_pd_range *pd_ranges) | ||
| 225 | { | ||
| 226 | struct imx_sc_pm_domain *sc_pd; | ||
| 227 | int ret; | ||
| 228 | |||
| 229 | sc_pd = devm_kzalloc(dev, sizeof(*sc_pd), GFP_KERNEL); | ||
| 230 | if (!sc_pd) | ||
| 231 | return ERR_PTR(-ENOMEM); | ||
| 232 | |||
| 233 | sc_pd->rsrc = pd_ranges->rsrc + idx; | ||
| 234 | sc_pd->pd.power_off = imx_sc_pd_power_off; | ||
| 235 | sc_pd->pd.power_on = imx_sc_pd_power_on; | ||
| 236 | |||
| 237 | if (pd_ranges->postfix) | ||
| 238 | snprintf(sc_pd->name, sizeof(sc_pd->name), | ||
| 239 | "%s%i", pd_ranges->name, idx); | ||
| 240 | else | ||
| 241 | snprintf(sc_pd->name, sizeof(sc_pd->name), | ||
| 242 | "%s", pd_ranges->name); | ||
| 243 | |||
| 244 | sc_pd->pd.name = sc_pd->name; | ||
| 245 | |||
| 246 | if (sc_pd->rsrc >= IMX_SC_R_LAST) { | ||
| 247 | dev_warn(dev, "invalid pd %s rsrc id %d found", | ||
| 248 | sc_pd->name, sc_pd->rsrc); | ||
| 249 | |||
| 250 | devm_kfree(dev, sc_pd); | ||
| 251 | return NULL; | ||
| 252 | } | ||
| 253 | |||
| 254 | ret = pm_genpd_init(&sc_pd->pd, NULL, true); | ||
| 255 | if (ret) { | ||
| 256 | dev_warn(dev, "failed to init pd %s rsrc id %d", | ||
| 257 | sc_pd->name, sc_pd->rsrc); | ||
| 258 | devm_kfree(dev, sc_pd); | ||
| 259 | return NULL; | ||
| 260 | } | ||
| 261 | |||
| 262 | return sc_pd; | ||
| 263 | } | ||
| 264 | |||
| 265 | static int imx_scu_init_pm_domains(struct device *dev, | ||
| 266 | const struct imx_sc_pd_soc *pd_soc) | ||
| 267 | { | ||
| 268 | const struct imx_sc_pd_range *pd_ranges = pd_soc->pd_ranges; | ||
| 269 | struct generic_pm_domain **domains; | ||
| 270 | struct genpd_onecell_data *pd_data; | ||
| 271 | struct imx_sc_pm_domain *sc_pd; | ||
| 272 | u32 count = 0; | ||
| 273 | int i, j; | ||
| 274 | |||
| 275 | for (i = 0; i < pd_soc->num_ranges; i++) | ||
| 276 | count += pd_ranges[i].num; | ||
| 277 | |||
| 278 | domains = devm_kcalloc(dev, count, sizeof(*domains), GFP_KERNEL); | ||
| 279 | if (!domains) | ||
| 280 | return -ENOMEM; | ||
| 281 | |||
| 282 | pd_data = devm_kzalloc(dev, sizeof(*pd_data), GFP_KERNEL); | ||
| 283 | if (!pd_data) | ||
| 284 | return -ENOMEM; | ||
| 285 | |||
| 286 | count = 0; | ||
| 287 | for (i = 0; i < pd_soc->num_ranges; i++) { | ||
| 288 | for (j = 0; j < pd_ranges[i].num; j++) { | ||
| 289 | sc_pd = imx_scu_add_pm_domain(dev, j, &pd_ranges[i]); | ||
| 290 | if (IS_ERR_OR_NULL(sc_pd)) | ||
| 291 | continue; | ||
| 292 | |||
| 293 | domains[count++] = &sc_pd->pd; | ||
| 294 | dev_dbg(dev, "added power domain %s\n", sc_pd->pd.name); | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | pd_data->domains = domains; | ||
| 299 | pd_data->num_domains = count; | ||
| 300 | pd_data->xlate = imx_scu_pd_xlate; | ||
| 301 | |||
| 302 | of_genpd_add_provider_onecell(dev->of_node, pd_data); | ||
| 303 | |||
| 304 | return 0; | ||
| 305 | } | ||
| 306 | |||
| 307 | static int imx_sc_pd_probe(struct platform_device *pdev) | ||
| 308 | { | ||
| 309 | const struct imx_sc_pd_soc *pd_soc; | ||
| 310 | int ret; | ||
| 311 | |||
| 312 | ret = imx_scu_get_handle(&pm_ipc_handle); | ||
| 313 | if (ret) | ||
| 314 | return ret; | ||
| 315 | |||
| 316 | pd_soc = of_device_get_match_data(&pdev->dev); | ||
| 317 | if (!pd_soc) | ||
| 318 | return -ENODEV; | ||
| 319 | |||
| 320 | return imx_scu_init_pm_domains(&pdev->dev, pd_soc); | ||
| 321 | } | ||
| 322 | |||
| 323 | static const struct of_device_id imx_sc_pd_match[] = { | ||
| 324 | { .compatible = "fsl,imx8qxp-scu-pd", &imx8qxp_scu_pd}, | ||
| 325 | { /* sentinel */ } | ||
| 326 | }; | ||
| 327 | |||
| 328 | static struct platform_driver imx_sc_pd_driver = { | ||
| 329 | .driver = { | ||
| 330 | .name = "imx-scu-pd", | ||
| 331 | .of_match_table = imx_sc_pd_match, | ||
| 332 | }, | ||
| 333 | .probe = imx_sc_pd_probe, | ||
| 334 | }; | ||
| 335 | builtin_platform_driver(imx_sc_pd_driver); | ||
| 336 | |||
| 337 | MODULE_AUTHOR("Dong Aisheng <aisheng.dong@nxp.com>"); | ||
| 338 | MODULE_DESCRIPTION("IMX SCU Power Domain driver"); | ||
| 339 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index a200a2174611..a13558154ac3 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c | |||
| @@ -1,12 +1,9 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 1 | /* | 2 | /* |
| 2 | * Defines interfaces for interacting wtih the Raspberry Pi firmware's | 3 | * Defines interfaces for interacting wtih the Raspberry Pi firmware's |
| 3 | * property channel. | 4 | * property channel. |
| 4 | * | 5 | * |
| 5 | * Copyright © 2015 Broadcom | 6 | * Copyright © 2015 Broadcom |
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | */ | 7 | */ |
| 11 | 8 | ||
| 12 | #include <linux/dma-mapping.h> | 9 | #include <linux/dma-mapping.h> |
| @@ -14,6 +11,7 @@ | |||
| 14 | #include <linux/module.h> | 11 | #include <linux/module.h> |
| 15 | #include <linux/of_platform.h> | 12 | #include <linux/of_platform.h> |
| 16 | #include <linux/platform_device.h> | 13 | #include <linux/platform_device.h> |
| 14 | #include <linux/slab.h> | ||
| 17 | #include <soc/bcm2835/raspberrypi-firmware.h> | 15 | #include <soc/bcm2835/raspberrypi-firmware.h> |
| 18 | 16 | ||
| 19 | #define MBOX_MSG(chan, data28) (((data28) & ~0xf) | ((chan) & 0xf)) | 17 | #define MBOX_MSG(chan, data28) (((data28) & ~0xf) | ((chan) & 0xf)) |
| @@ -21,8 +19,6 @@ | |||
| 21 | #define MBOX_DATA28(msg) ((msg) & ~0xf) | 19 | #define MBOX_DATA28(msg) ((msg) & ~0xf) |
| 22 | #define MBOX_CHAN_PROPERTY 8 | 20 | #define MBOX_CHAN_PROPERTY 8 |
| 23 | 21 | ||
| 24 | #define MAX_RPI_FW_PROP_BUF_SIZE 32 | ||
| 25 | |||
| 26 | static struct platform_device *rpi_hwmon; | 22 | static struct platform_device *rpi_hwmon; |
| 27 | 23 | ||
| 28 | struct rpi_firmware { | 24 | struct rpi_firmware { |
| @@ -56,8 +52,12 @@ rpi_firmware_transaction(struct rpi_firmware *fw, u32 chan, u32 data) | |||
| 56 | reinit_completion(&fw->c); | 52 | reinit_completion(&fw->c); |
| 57 | ret = mbox_send_message(fw->chan, &message); | 53 | ret = mbox_send_message(fw->chan, &message); |
| 58 | if (ret >= 0) { | 54 | if (ret >= 0) { |
| 59 | wait_for_completion(&fw->c); | 55 | if (wait_for_completion_timeout(&fw->c, HZ)) { |
| 60 | ret = 0; | 56 | ret = 0; |
| 57 | } else { | ||
| 58 | ret = -ETIMEDOUT; | ||
| 59 | WARN_ONCE(1, "Firmware transaction timeout"); | ||
| 60 | } | ||
| 61 | } else { | 61 | } else { |
| 62 | dev_err(fw->cl.dev, "mbox_send_message returned %d\n", ret); | 62 | dev_err(fw->cl.dev, "mbox_send_message returned %d\n", ret); |
| 63 | } | 63 | } |
| @@ -144,28 +144,30 @@ EXPORT_SYMBOL_GPL(rpi_firmware_property_list); | |||
| 144 | int rpi_firmware_property(struct rpi_firmware *fw, | 144 | int rpi_firmware_property(struct rpi_firmware *fw, |
| 145 | u32 tag, void *tag_data, size_t buf_size) | 145 | u32 tag, void *tag_data, size_t buf_size) |
| 146 | { | 146 | { |
| 147 | /* Single tags are very small (generally 8 bytes), so the | 147 | struct rpi_firmware_property_tag_header *header; |
| 148 | * stack should be safe. | ||
| 149 | */ | ||
| 150 | u8 data[sizeof(struct rpi_firmware_property_tag_header) + | ||
| 151 | MAX_RPI_FW_PROP_BUF_SIZE]; | ||
| 152 | struct rpi_firmware_property_tag_header *header = | ||
| 153 | (struct rpi_firmware_property_tag_header *)data; | ||
| 154 | int ret; | 148 | int ret; |
| 155 | 149 | ||
| 156 | if (WARN_ON(buf_size > sizeof(data) - sizeof(*header))) | 150 | /* Some mailboxes can use over 1k bytes. Rather than checking |
| 157 | return -EINVAL; | 151 | * size and using stack or kmalloc depending on requirements, |
| 152 | * just use kmalloc. Mailboxes don't get called enough to worry | ||
| 153 | * too much about the time taken in the allocation. | ||
| 154 | */ | ||
| 155 | void *data = kmalloc(sizeof(*header) + buf_size, GFP_KERNEL); | ||
| 158 | 156 | ||
| 157 | if (!data) | ||
| 158 | return -ENOMEM; | ||
| 159 | |||
| 160 | header = data; | ||
| 159 | header->tag = tag; | 161 | header->tag = tag; |
| 160 | header->buf_size = buf_size; | 162 | header->buf_size = buf_size; |
| 161 | header->req_resp_size = 0; | 163 | header->req_resp_size = 0; |
| 162 | memcpy(data + sizeof(struct rpi_firmware_property_tag_header), | 164 | memcpy(data + sizeof(*header), tag_data, buf_size); |
| 163 | tag_data, buf_size); | 165 | |
| 166 | ret = rpi_firmware_property_list(fw, data, buf_size + sizeof(*header)); | ||
| 167 | |||
| 168 | memcpy(tag_data, data + sizeof(*header), buf_size); | ||
| 164 | 169 | ||
| 165 | ret = rpi_firmware_property_list(fw, &data, buf_size + sizeof(*header)); | 170 | kfree(data); |
| 166 | memcpy(tag_data, | ||
| 167 | data + sizeof(struct rpi_firmware_property_tag_header), | ||
| 168 | buf_size); | ||
| 169 | 171 | ||
| 170 | return ret; | 172 | return ret; |
| 171 | } | 173 | } |
diff --git a/drivers/firmware/tegra/bpmp-debugfs.c b/drivers/firmware/tegra/bpmp-debugfs.c index f7f6a0a5cb07..a84df1a8ca2b 100644 --- a/drivers/firmware/tegra/bpmp-debugfs.c +++ b/drivers/firmware/tegra/bpmp-debugfs.c | |||
| @@ -379,33 +379,6 @@ static int create_debugfs_mirror(struct tegra_bpmp *bpmp, void *buf, | |||
| 379 | return err; | 379 | return err; |
| 380 | } | 380 | } |
| 381 | 381 | ||
| 382 | static int mrq_is_supported(struct tegra_bpmp *bpmp, unsigned int mrq) | ||
| 383 | { | ||
| 384 | struct mrq_query_abi_request req = { .mrq = cpu_to_le32(mrq) }; | ||
| 385 | struct mrq_query_abi_response resp; | ||
| 386 | struct tegra_bpmp_message msg = { | ||
| 387 | .mrq = MRQ_QUERY_ABI, | ||
| 388 | .tx = { | ||
| 389 | .data = &req, | ||
| 390 | .size = sizeof(req), | ||
| 391 | }, | ||
| 392 | .rx = { | ||
| 393 | .data = &resp, | ||
| 394 | .size = sizeof(resp), | ||
| 395 | }, | ||
| 396 | }; | ||
| 397 | int ret; | ||
| 398 | |||
| 399 | ret = tegra_bpmp_transfer(bpmp, &msg); | ||
| 400 | if (ret < 0) { | ||
| 401 | /* something went wrong; assume not supported */ | ||
| 402 | dev_warn(bpmp->dev, "tegra_bpmp_transfer failed (%d)\n", ret); | ||
| 403 | return 0; | ||
| 404 | } | ||
| 405 | |||
| 406 | return resp.status ? 0 : 1; | ||
| 407 | } | ||
| 408 | |||
| 409 | int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp) | 382 | int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp) |
| 410 | { | 383 | { |
| 411 | dma_addr_t phys; | 384 | dma_addr_t phys; |
| @@ -415,7 +388,7 @@ int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp) | |||
| 415 | int ret; | 388 | int ret; |
| 416 | struct dentry *root; | 389 | struct dentry *root; |
| 417 | 390 | ||
| 418 | if (!mrq_is_supported(bpmp, MRQ_DEBUGFS)) | 391 | if (!tegra_bpmp_mrq_is_supported(bpmp, MRQ_DEBUGFS)) |
| 419 | return 0; | 392 | return 0; |
| 420 | 393 | ||
| 421 | root = debugfs_create_dir("bpmp", NULL); | 394 | root = debugfs_create_dir("bpmp", NULL); |
diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c index a3d5b518c10e..689478b92bce 100644 --- a/drivers/firmware/tegra/bpmp.c +++ b/drivers/firmware/tegra/bpmp.c | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | 28 | ||
| 29 | #define MSG_ACK BIT(0) | 29 | #define MSG_ACK BIT(0) |
| 30 | #define MSG_RING BIT(1) | 30 | #define MSG_RING BIT(1) |
| 31 | #define TAG_SZ 32 | ||
| 31 | 32 | ||
| 32 | static inline struct tegra_bpmp * | 33 | static inline struct tegra_bpmp * |
| 33 | mbox_client_to_bpmp(struct mbox_client *client) | 34 | mbox_client_to_bpmp(struct mbox_client *client) |
| @@ -470,6 +471,31 @@ unlock: | |||
| 470 | } | 471 | } |
| 471 | EXPORT_SYMBOL_GPL(tegra_bpmp_free_mrq); | 472 | EXPORT_SYMBOL_GPL(tegra_bpmp_free_mrq); |
| 472 | 473 | ||
| 474 | bool tegra_bpmp_mrq_is_supported(struct tegra_bpmp *bpmp, unsigned int mrq) | ||
| 475 | { | ||
| 476 | struct mrq_query_abi_request req = { .mrq = cpu_to_le32(mrq) }; | ||
| 477 | struct mrq_query_abi_response resp; | ||
| 478 | struct tegra_bpmp_message msg = { | ||
| 479 | .mrq = MRQ_QUERY_ABI, | ||
| 480 | .tx = { | ||
| 481 | .data = &req, | ||
| 482 | .size = sizeof(req), | ||
| 483 | }, | ||
| 484 | .rx = { | ||
| 485 | .data = &resp, | ||
| 486 | .size = sizeof(resp), | ||
| 487 | }, | ||
| 488 | }; | ||
| 489 | int ret; | ||
| 490 | |||
| 491 | ret = tegra_bpmp_transfer(bpmp, &msg); | ||
| 492 | if (ret || msg.rx.ret) | ||
| 493 | return false; | ||
| 494 | |||
| 495 | return resp.status == 0; | ||
| 496 | } | ||
| 497 | EXPORT_SYMBOL_GPL(tegra_bpmp_mrq_is_supported); | ||
| 498 | |||
| 473 | static void tegra_bpmp_mrq_handle_ping(unsigned int mrq, | 499 | static void tegra_bpmp_mrq_handle_ping(unsigned int mrq, |
| 474 | struct tegra_bpmp_channel *channel, | 500 | struct tegra_bpmp_channel *channel, |
| 475 | void *data) | 501 | void *data) |
| @@ -521,8 +547,9 @@ static int tegra_bpmp_ping(struct tegra_bpmp *bpmp) | |||
| 521 | return err; | 547 | return err; |
| 522 | } | 548 | } |
| 523 | 549 | ||
| 524 | static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag, | 550 | /* deprecated version of tag query */ |
| 525 | size_t size) | 551 | static int tegra_bpmp_get_firmware_tag_old(struct tegra_bpmp *bpmp, char *tag, |
| 552 | size_t size) | ||
| 526 | { | 553 | { |
| 527 | struct mrq_query_tag_request request; | 554 | struct mrq_query_tag_request request; |
| 528 | struct tegra_bpmp_message msg; | 555 | struct tegra_bpmp_message msg; |
| @@ -531,7 +558,10 @@ static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag, | |||
| 531 | void *virt; | 558 | void *virt; |
| 532 | int err; | 559 | int err; |
| 533 | 560 | ||
| 534 | virt = dma_alloc_coherent(bpmp->dev, MSG_DATA_MIN_SZ, &phys, | 561 | if (size != TAG_SZ) |
| 562 | return -EINVAL; | ||
| 563 | |||
| 564 | virt = dma_alloc_coherent(bpmp->dev, TAG_SZ, &phys, | ||
| 535 | GFP_KERNEL | GFP_DMA32); | 565 | GFP_KERNEL | GFP_DMA32); |
| 536 | if (!virt) | 566 | if (!virt) |
| 537 | return -ENOMEM; | 567 | return -ENOMEM; |
| @@ -549,13 +579,44 @@ static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag, | |||
| 549 | local_irq_restore(flags); | 579 | local_irq_restore(flags); |
| 550 | 580 | ||
| 551 | if (err == 0) | 581 | if (err == 0) |
| 552 | strlcpy(tag, virt, size); | 582 | memcpy(tag, virt, TAG_SZ); |
| 553 | 583 | ||
| 554 | dma_free_coherent(bpmp->dev, MSG_DATA_MIN_SZ, virt, phys); | 584 | dma_free_coherent(bpmp->dev, TAG_SZ, virt, phys); |
| 555 | 585 | ||
| 556 | return err; | 586 | return err; |
| 557 | } | 587 | } |
| 558 | 588 | ||
| 589 | static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag, | ||
| 590 | size_t size) | ||
| 591 | { | ||
| 592 | if (tegra_bpmp_mrq_is_supported(bpmp, MRQ_QUERY_FW_TAG)) { | ||
| 593 | struct mrq_query_fw_tag_response resp; | ||
| 594 | struct tegra_bpmp_message msg = { | ||
| 595 | .mrq = MRQ_QUERY_FW_TAG, | ||
| 596 | .rx = { | ||
| 597 | .data = &resp, | ||
| 598 | .size = sizeof(resp), | ||
| 599 | }, | ||
| 600 | }; | ||
| 601 | int err; | ||
| 602 | |||
| 603 | if (size != sizeof(resp.tag)) | ||
| 604 | return -EINVAL; | ||
| 605 | |||
| 606 | err = tegra_bpmp_transfer(bpmp, &msg); | ||
| 607 | |||
| 608 | if (err) | ||
| 609 | return err; | ||
| 610 | if (msg.rx.ret < 0) | ||
| 611 | return -EINVAL; | ||
| 612 | |||
| 613 | memcpy(tag, resp.tag, sizeof(resp.tag)); | ||
| 614 | return 0; | ||
| 615 | } | ||
| 616 | |||
| 617 | return tegra_bpmp_get_firmware_tag_old(bpmp, tag, size); | ||
| 618 | } | ||
| 619 | |||
| 559 | static void tegra_bpmp_channel_signal(struct tegra_bpmp_channel *channel) | 620 | static void tegra_bpmp_channel_signal(struct tegra_bpmp_channel *channel) |
| 560 | { | 621 | { |
| 561 | unsigned long flags = channel->ob->flags; | 622 | unsigned long flags = channel->ob->flags; |
| @@ -664,7 +725,7 @@ static int tegra_bpmp_probe(struct platform_device *pdev) | |||
| 664 | { | 725 | { |
| 665 | struct tegra_bpmp *bpmp; | 726 | struct tegra_bpmp *bpmp; |
| 666 | unsigned int i; | 727 | unsigned int i; |
| 667 | char tag[32]; | 728 | char tag[TAG_SZ]; |
| 668 | size_t size; | 729 | size_t size; |
| 669 | int err; | 730 | int err; |
| 670 | 731 | ||
| @@ -792,13 +853,13 @@ static int tegra_bpmp_probe(struct platform_device *pdev) | |||
| 792 | goto free_mrq; | 853 | goto free_mrq; |
| 793 | } | 854 | } |
| 794 | 855 | ||
| 795 | err = tegra_bpmp_get_firmware_tag(bpmp, tag, sizeof(tag) - 1); | 856 | err = tegra_bpmp_get_firmware_tag(bpmp, tag, sizeof(tag)); |
| 796 | if (err < 0) { | 857 | if (err < 0) { |
| 797 | dev_err(&pdev->dev, "failed to get firmware tag: %d\n", err); | 858 | dev_err(&pdev->dev, "failed to get firmware tag: %d\n", err); |
| 798 | goto free_mrq; | 859 | goto free_mrq; |
| 799 | } | 860 | } |
| 800 | 861 | ||
| 801 | dev_info(&pdev->dev, "firmware: %s\n", tag); | 862 | dev_info(&pdev->dev, "firmware: %.*s\n", (int)sizeof(tag), tag); |
| 802 | 863 | ||
| 803 | platform_set_drvdata(pdev, bpmp); | 864 | platform_set_drvdata(pdev, bpmp); |
| 804 | 865 | ||
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index c58e953fefa3..5beb83d1cf87 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c | |||
| @@ -927,26 +927,6 @@ static int a6xx_gmu_memory_probe(struct a6xx_gmu *gmu) | |||
| 927 | return ret; | 927 | return ret; |
| 928 | } | 928 | } |
| 929 | 929 | ||
| 930 | /* Get the list of RPMh voltage levels from cmd-db */ | ||
| 931 | static int a6xx_gmu_rpmh_arc_cmds(const char *id, void *vals, int size) | ||
| 932 | { | ||
| 933 | u32 len = cmd_db_read_aux_data_len(id); | ||
| 934 | |||
| 935 | if (!len) | ||
| 936 | return 0; | ||
| 937 | |||
| 938 | if (WARN_ON(len > size)) | ||
| 939 | return -EINVAL; | ||
| 940 | |||
| 941 | cmd_db_read_aux_data(id, vals, len); | ||
| 942 | |||
| 943 | /* | ||
| 944 | * The data comes back as an array of unsigned shorts so adjust the | ||
| 945 | * count accordingly | ||
| 946 | */ | ||
| 947 | return len >> 1; | ||
| 948 | } | ||
| 949 | |||
| 950 | /* Return the 'arc-level' for the given frequency */ | 930 | /* Return the 'arc-level' for the given frequency */ |
| 951 | static u32 a6xx_gmu_get_arc_level(struct device *dev, unsigned long freq) | 931 | static u32 a6xx_gmu_get_arc_level(struct device *dev, unsigned long freq) |
| 952 | { | 932 | { |
| @@ -974,11 +954,30 @@ static u32 a6xx_gmu_get_arc_level(struct device *dev, unsigned long freq) | |||
| 974 | } | 954 | } |
| 975 | 955 | ||
| 976 | static int a6xx_gmu_rpmh_arc_votes_init(struct device *dev, u32 *votes, | 956 | static int a6xx_gmu_rpmh_arc_votes_init(struct device *dev, u32 *votes, |
| 977 | unsigned long *freqs, int freqs_count, | 957 | unsigned long *freqs, int freqs_count, const char *id) |
| 978 | u16 *pri, int pri_count, | ||
| 979 | u16 *sec, int sec_count) | ||
| 980 | { | 958 | { |
| 981 | int i, j; | 959 | int i, j; |
| 960 | const u16 *pri, *sec; | ||
| 961 | size_t pri_count, sec_count; | ||
| 962 | |||
| 963 | pri = cmd_db_read_aux_data(id, &pri_count); | ||
| 964 | if (IS_ERR(pri)) | ||
| 965 | return PTR_ERR(pri); | ||
| 966 | /* | ||
| 967 | * The data comes back as an array of unsigned shorts so adjust the | ||
| 968 | * count accordingly | ||
| 969 | */ | ||
| 970 | pri_count >>= 1; | ||
| 971 | if (!pri_count) | ||
| 972 | return -EINVAL; | ||
| 973 | |||
| 974 | sec = cmd_db_read_aux_data("mx.lvl", &sec_count); | ||
| 975 | if (IS_ERR(sec)) | ||
| 976 | return PTR_ERR(sec); | ||
| 977 | |||
| 978 | sec_count >>= 1; | ||
| 979 | if (!sec_count) | ||
| 980 | return -EINVAL; | ||
| 982 | 981 | ||
| 983 | /* Construct a vote for each frequency */ | 982 | /* Construct a vote for each frequency */ |
| 984 | for (i = 0; i < freqs_count; i++) { | 983 | for (i = 0; i < freqs_count; i++) { |
| @@ -1037,25 +1036,15 @@ static int a6xx_gmu_rpmh_votes_init(struct a6xx_gmu *gmu) | |||
| 1037 | struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); | 1036 | struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); |
| 1038 | struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; | 1037 | struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; |
| 1039 | struct msm_gpu *gpu = &adreno_gpu->base; | 1038 | struct msm_gpu *gpu = &adreno_gpu->base; |
| 1040 | |||
| 1041 | u16 gx[16], cx[16], mx[16]; | ||
| 1042 | u32 gxcount, cxcount, mxcount; | ||
| 1043 | int ret; | 1039 | int ret; |
| 1044 | 1040 | ||
| 1045 | /* Get the list of available voltage levels for each component */ | ||
| 1046 | gxcount = a6xx_gmu_rpmh_arc_cmds("gfx.lvl", gx, sizeof(gx)); | ||
| 1047 | cxcount = a6xx_gmu_rpmh_arc_cmds("cx.lvl", cx, sizeof(cx)); | ||
| 1048 | mxcount = a6xx_gmu_rpmh_arc_cmds("mx.lvl", mx, sizeof(mx)); | ||
| 1049 | |||
| 1050 | /* Build the GX votes */ | 1041 | /* Build the GX votes */ |
| 1051 | ret = a6xx_gmu_rpmh_arc_votes_init(&gpu->pdev->dev, gmu->gx_arc_votes, | 1042 | ret = a6xx_gmu_rpmh_arc_votes_init(&gpu->pdev->dev, gmu->gx_arc_votes, |
| 1052 | gmu->gpu_freqs, gmu->nr_gpu_freqs, | 1043 | gmu->gpu_freqs, gmu->nr_gpu_freqs, "gfx.lvl"); |
| 1053 | gx, gxcount, mx, mxcount); | ||
| 1054 | 1044 | ||
| 1055 | /* Build the CX votes */ | 1045 | /* Build the CX votes */ |
| 1056 | ret |= a6xx_gmu_rpmh_arc_votes_init(gmu->dev, gmu->cx_arc_votes, | 1046 | ret |= a6xx_gmu_rpmh_arc_votes_init(gmu->dev, gmu->cx_arc_votes, |
| 1057 | gmu->gmu_freqs, gmu->nr_gmu_freqs, | 1047 | gmu->gmu_freqs, gmu->nr_gmu_freqs, "cx.lvl"); |
| 1058 | cx, cxcount, mx, mxcount); | ||
| 1059 | 1048 | ||
| 1060 | return ret; | 1049 | return ret; |
| 1061 | } | 1050 | } |
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c index a2188f7c04c6..f6297599433f 100644 --- a/drivers/memory/omap-gpmc.c +++ b/drivers/memory/omap-gpmc.c | |||
| @@ -2061,7 +2061,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, | |||
| 2061 | * timings. | 2061 | * timings. |
| 2062 | */ | 2062 | */ |
| 2063 | name = gpmc_cs_get_name(cs); | 2063 | name = gpmc_cs_get_name(cs); |
| 2064 | if (name && of_node_cmp(child->name, name) == 0) | 2064 | if (name && of_node_name_eq(child, name)) |
| 2065 | goto no_timings; | 2065 | goto no_timings; |
| 2066 | 2066 | ||
| 2067 | ret = gpmc_cs_request(cs, resource_size(&res), &base); | 2067 | ret = gpmc_cs_request(cs, resource_size(&res), &base); |
| @@ -2069,7 +2069,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, | |||
| 2069 | dev_err(&pdev->dev, "cannot request GPMC CS %d\n", cs); | 2069 | dev_err(&pdev->dev, "cannot request GPMC CS %d\n", cs); |
| 2070 | return ret; | 2070 | return ret; |
| 2071 | } | 2071 | } |
| 2072 | gpmc_cs_set_name(cs, child->name); | 2072 | gpmc_cs_set_name(cs, child->full_name); |
| 2073 | 2073 | ||
| 2074 | gpmc_read_settings_dt(child, &gpmc_s); | 2074 | gpmc_read_settings_dt(child, &gpmc_s); |
| 2075 | gpmc_read_timings_dt(child, &gpmc_t); | 2075 | gpmc_read_timings_dt(child, &gpmc_t); |
| @@ -2114,7 +2114,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, | |||
| 2114 | goto err; | 2114 | goto err; |
| 2115 | } | 2115 | } |
| 2116 | 2116 | ||
| 2117 | if (of_node_cmp(child->name, "nand") == 0) { | 2117 | if (of_node_name_eq(child, "nand")) { |
| 2118 | /* Warn about older DT blobs with no compatible property */ | 2118 | /* Warn about older DT blobs with no compatible property */ |
| 2119 | if (!of_property_read_bool(child, "compatible")) { | 2119 | if (!of_property_read_bool(child, "compatible")) { |
| 2120 | dev_warn(&pdev->dev, | 2120 | dev_warn(&pdev->dev, |
| @@ -2124,7 +2124,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, | |||
| 2124 | } | 2124 | } |
| 2125 | } | 2125 | } |
| 2126 | 2126 | ||
| 2127 | if (of_node_cmp(child->name, "onenand") == 0) { | 2127 | if (of_node_name_eq(child, "onenand")) { |
| 2128 | /* Warn about older DT blobs with no compatible property */ | 2128 | /* Warn about older DT blobs with no compatible property */ |
| 2129 | if (!of_property_read_bool(child, "compatible")) { | 2129 | if (!of_property_read_bool(child, "compatible")) { |
| 2130 | dev_warn(&pdev->dev, | 2130 | dev_warn(&pdev->dev, |
diff --git a/drivers/memory/tegra/Kconfig b/drivers/memory/tegra/Kconfig index 6d74e499e18d..34e0b70f5c5f 100644 --- a/drivers/memory/tegra/Kconfig +++ b/drivers/memory/tegra/Kconfig | |||
| @@ -6,6 +6,16 @@ config TEGRA_MC | |||
| 6 | This driver supports the Memory Controller (MC) hardware found on | 6 | This driver supports the Memory Controller (MC) hardware found on |
| 7 | NVIDIA Tegra SoCs. | 7 | NVIDIA Tegra SoCs. |
| 8 | 8 | ||
| 9 | config TEGRA20_EMC | ||
| 10 | bool "NVIDIA Tegra20 External Memory Controller driver" | ||
| 11 | default y | ||
| 12 | depends on ARCH_TEGRA_2x_SOC | ||
| 13 | help | ||
| 14 | This driver is for the External Memory Controller (EMC) found on | ||
| 15 | Tegra20 chips. The EMC controls the external DRAM on the board. | ||
| 16 | This driver is required to change memory timings / clock rate for | ||
| 17 | external memory. | ||
| 18 | |||
| 9 | config TEGRA124_EMC | 19 | config TEGRA124_EMC |
| 10 | bool "NVIDIA Tegra124 External Memory Controller driver" | 20 | bool "NVIDIA Tegra124 External Memory Controller driver" |
| 11 | default y | 21 | default y |
diff --git a/drivers/memory/tegra/Makefile b/drivers/memory/tegra/Makefile index 94ab16ba075b..3971a6b7c487 100644 --- a/drivers/memory/tegra/Makefile +++ b/drivers/memory/tegra/Makefile | |||
| @@ -10,5 +10,6 @@ tegra-mc-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o | |||
| 10 | 10 | ||
| 11 | obj-$(CONFIG_TEGRA_MC) += tegra-mc.o | 11 | obj-$(CONFIG_TEGRA_MC) += tegra-mc.o |
| 12 | 12 | ||
| 13 | obj-$(CONFIG_TEGRA20_EMC) += tegra20-emc.o | ||
| 13 | obj-$(CONFIG_TEGRA124_EMC) += tegra124-emc.o | 14 | obj-$(CONFIG_TEGRA124_EMC) += tegra124-emc.o |
| 14 | obj-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186.o | 15 | obj-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186.o |
diff --git a/drivers/memory/tegra/tegra20-emc.c b/drivers/memory/tegra/tegra20-emc.c new file mode 100644 index 000000000000..9ee5bef49e47 --- /dev/null +++ b/drivers/memory/tegra/tegra20-emc.c | |||
| @@ -0,0 +1,591 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Tegra20 External Memory Controller driver | ||
| 4 | * | ||
| 5 | * Author: Dmitry Osipenko <digetx@gmail.com> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/clk.h> | ||
| 9 | #include <linux/completion.h> | ||
| 10 | #include <linux/err.h> | ||
| 11 | #include <linux/interrupt.h> | ||
| 12 | #include <linux/iopoll.h> | ||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/of.h> | ||
| 16 | #include <linux/platform_device.h> | ||
| 17 | #include <linux/sort.h> | ||
| 18 | #include <linux/types.h> | ||
| 19 | |||
| 20 | #include <soc/tegra/fuse.h> | ||
| 21 | |||
| 22 | #define EMC_INTSTATUS 0x000 | ||
| 23 | #define EMC_INTMASK 0x004 | ||
| 24 | #define EMC_TIMING_CONTROL 0x028 | ||
| 25 | #define EMC_RC 0x02c | ||
| 26 | #define EMC_RFC 0x030 | ||
| 27 | #define EMC_RAS 0x034 | ||
| 28 | #define EMC_RP 0x038 | ||
| 29 | #define EMC_R2W 0x03c | ||
| 30 | #define EMC_W2R 0x040 | ||
| 31 | #define EMC_R2P 0x044 | ||
| 32 | #define EMC_W2P 0x048 | ||
| 33 | #define EMC_RD_RCD 0x04c | ||
| 34 | #define EMC_WR_RCD 0x050 | ||
| 35 | #define EMC_RRD 0x054 | ||
| 36 | #define EMC_REXT 0x058 | ||
| 37 | #define EMC_WDV 0x05c | ||
| 38 | #define EMC_QUSE 0x060 | ||
| 39 | #define EMC_QRST 0x064 | ||
| 40 | #define EMC_QSAFE 0x068 | ||
| 41 | #define EMC_RDV 0x06c | ||
| 42 | #define EMC_REFRESH 0x070 | ||
| 43 | #define EMC_BURST_REFRESH_NUM 0x074 | ||
| 44 | #define EMC_PDEX2WR 0x078 | ||
| 45 | #define EMC_PDEX2RD 0x07c | ||
| 46 | #define EMC_PCHG2PDEN 0x080 | ||
| 47 | #define EMC_ACT2PDEN 0x084 | ||
| 48 | #define EMC_AR2PDEN 0x088 | ||
| 49 | #define EMC_RW2PDEN 0x08c | ||
| 50 | #define EMC_TXSR 0x090 | ||
| 51 | #define EMC_TCKE 0x094 | ||
| 52 | #define EMC_TFAW 0x098 | ||
| 53 | #define EMC_TRPAB 0x09c | ||
| 54 | #define EMC_TCLKSTABLE 0x0a0 | ||
| 55 | #define EMC_TCLKSTOP 0x0a4 | ||
| 56 | #define EMC_TREFBW 0x0a8 | ||
| 57 | #define EMC_QUSE_EXTRA 0x0ac | ||
| 58 | #define EMC_ODT_WRITE 0x0b0 | ||
| 59 | #define EMC_ODT_READ 0x0b4 | ||
| 60 | #define EMC_FBIO_CFG5 0x104 | ||
| 61 | #define EMC_FBIO_CFG6 0x114 | ||
| 62 | #define EMC_AUTO_CAL_INTERVAL 0x2a8 | ||
| 63 | #define EMC_CFG_2 0x2b8 | ||
| 64 | #define EMC_CFG_DIG_DLL 0x2bc | ||
| 65 | #define EMC_DLL_XFORM_DQS 0x2c0 | ||
| 66 | #define EMC_DLL_XFORM_QUSE 0x2c4 | ||
| 67 | #define EMC_ZCAL_REF_CNT 0x2e0 | ||
| 68 | #define EMC_ZCAL_WAIT_CNT 0x2e4 | ||
| 69 | #define EMC_CFG_CLKTRIM_0 0x2d0 | ||
| 70 | #define EMC_CFG_CLKTRIM_1 0x2d4 | ||
| 71 | #define EMC_CFG_CLKTRIM_2 0x2d8 | ||
| 72 | |||
| 73 | #define EMC_CLKCHANGE_REQ_ENABLE BIT(0) | ||
| 74 | #define EMC_CLKCHANGE_PD_ENABLE BIT(1) | ||
| 75 | #define EMC_CLKCHANGE_SR_ENABLE BIT(2) | ||
| 76 | |||
| 77 | #define EMC_TIMING_UPDATE BIT(0) | ||
| 78 | |||
| 79 | #define EMC_REFRESH_OVERFLOW_INT BIT(3) | ||
| 80 | #define EMC_CLKCHANGE_COMPLETE_INT BIT(4) | ||
| 81 | |||
| 82 | static const u16 emc_timing_registers[] = { | ||
| 83 | EMC_RC, | ||
| 84 | EMC_RFC, | ||
| 85 | EMC_RAS, | ||
| 86 | EMC_RP, | ||
| 87 | EMC_R2W, | ||
| 88 | EMC_W2R, | ||
| 89 | EMC_R2P, | ||
| 90 | EMC_W2P, | ||
| 91 | EMC_RD_RCD, | ||
| 92 | EMC_WR_RCD, | ||
| 93 | EMC_RRD, | ||
| 94 | EMC_REXT, | ||
| 95 | EMC_WDV, | ||
| 96 | EMC_QUSE, | ||
| 97 | EMC_QRST, | ||
| 98 | EMC_QSAFE, | ||
| 99 | EMC_RDV, | ||
| 100 | EMC_REFRESH, | ||
| 101 | EMC_BURST_REFRESH_NUM, | ||
| 102 | EMC_PDEX2WR, | ||
| 103 | EMC_PDEX2RD, | ||
| 104 | EMC_PCHG2PDEN, | ||
| 105 | EMC_ACT2PDEN, | ||
| 106 | EMC_AR2PDEN, | ||
| 107 | EMC_RW2PDEN, | ||
| 108 | EMC_TXSR, | ||
| 109 | EMC_TCKE, | ||
| 110 | EMC_TFAW, | ||
| 111 | EMC_TRPAB, | ||
| 112 | EMC_TCLKSTABLE, | ||
| 113 | EMC_TCLKSTOP, | ||
| 114 | EMC_TREFBW, | ||
| 115 | EMC_QUSE_EXTRA, | ||
| 116 | EMC_FBIO_CFG6, | ||
| 117 | EMC_ODT_WRITE, | ||
| 118 | EMC_ODT_READ, | ||
| 119 | EMC_FBIO_CFG5, | ||
| 120 | EMC_CFG_DIG_DLL, | ||
| 121 | EMC_DLL_XFORM_DQS, | ||
| 122 | EMC_DLL_XFORM_QUSE, | ||
| 123 | EMC_ZCAL_REF_CNT, | ||
| 124 | EMC_ZCAL_WAIT_CNT, | ||
| 125 | EMC_AUTO_CAL_INTERVAL, | ||
| 126 | EMC_CFG_CLKTRIM_0, | ||
| 127 | EMC_CFG_CLKTRIM_1, | ||
| 128 | EMC_CFG_CLKTRIM_2, | ||
| 129 | }; | ||
| 130 | |||
| 131 | struct emc_timing { | ||
| 132 | unsigned long rate; | ||
| 133 | u32 data[ARRAY_SIZE(emc_timing_registers)]; | ||
| 134 | }; | ||
| 135 | |||
| 136 | struct tegra_emc { | ||
| 137 | struct device *dev; | ||
| 138 | struct completion clk_handshake_complete; | ||
| 139 | struct notifier_block clk_nb; | ||
| 140 | struct clk *backup_clk; | ||
| 141 | struct clk *emc_mux; | ||
| 142 | struct clk *pll_m; | ||
| 143 | struct clk *clk; | ||
| 144 | void __iomem *regs; | ||
| 145 | |||
| 146 | struct emc_timing *timings; | ||
| 147 | unsigned int num_timings; | ||
| 148 | }; | ||
| 149 | |||
| 150 | static irqreturn_t tegra_emc_isr(int irq, void *data) | ||
| 151 | { | ||
| 152 | struct tegra_emc *emc = data; | ||
| 153 | u32 intmask = EMC_REFRESH_OVERFLOW_INT | EMC_CLKCHANGE_COMPLETE_INT; | ||
| 154 | u32 status; | ||
| 155 | |||
| 156 | status = readl_relaxed(emc->regs + EMC_INTSTATUS) & intmask; | ||
| 157 | if (!status) | ||
| 158 | return IRQ_NONE; | ||
| 159 | |||
| 160 | /* notify about EMC-CAR handshake completion */ | ||
| 161 | if (status & EMC_CLKCHANGE_COMPLETE_INT) | ||
| 162 | complete(&emc->clk_handshake_complete); | ||
| 163 | |||
| 164 | /* notify about HW problem */ | ||
| 165 | if (status & EMC_REFRESH_OVERFLOW_INT) | ||
| 166 | dev_err_ratelimited(emc->dev, | ||
| 167 | "refresh request overflow timeout\n"); | ||
| 168 | |||
| 169 | /* clear interrupts */ | ||
| 170 | writel_relaxed(status, emc->regs + EMC_INTSTATUS); | ||
| 171 | |||
| 172 | return IRQ_HANDLED; | ||
| 173 | } | ||
| 174 | |||
| 175 | static struct emc_timing *tegra_emc_find_timing(struct tegra_emc *emc, | ||
| 176 | unsigned long rate) | ||
| 177 | { | ||
| 178 | struct emc_timing *timing = NULL; | ||
| 179 | unsigned int i; | ||
| 180 | |||
| 181 | for (i = 0; i < emc->num_timings; i++) { | ||
| 182 | if (emc->timings[i].rate >= rate) { | ||
| 183 | timing = &emc->timings[i]; | ||
| 184 | break; | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | if (!timing) { | ||
| 189 | dev_err(emc->dev, "no timing for rate %lu\n", rate); | ||
| 190 | return NULL; | ||
| 191 | } | ||
| 192 | |||
| 193 | return timing; | ||
| 194 | } | ||
| 195 | |||
| 196 | static int emc_prepare_timing_change(struct tegra_emc *emc, unsigned long rate) | ||
| 197 | { | ||
| 198 | struct emc_timing *timing = tegra_emc_find_timing(emc, rate); | ||
| 199 | unsigned int i; | ||
| 200 | |||
| 201 | if (!timing) | ||
| 202 | return -EINVAL; | ||
| 203 | |||
| 204 | dev_dbg(emc->dev, "%s: using timing rate %lu for requested rate %lu\n", | ||
| 205 | __func__, timing->rate, rate); | ||
| 206 | |||
| 207 | /* program shadow registers */ | ||
| 208 | for (i = 0; i < ARRAY_SIZE(timing->data); i++) | ||
| 209 | writel_relaxed(timing->data[i], | ||
| 210 | emc->regs + emc_timing_registers[i]); | ||
| 211 | |||
| 212 | /* wait until programming has settled */ | ||
| 213 | readl_relaxed(emc->regs + emc_timing_registers[i - 1]); | ||
| 214 | |||
| 215 | reinit_completion(&emc->clk_handshake_complete); | ||
| 216 | |||
| 217 | return 0; | ||
| 218 | } | ||
| 219 | |||
| 220 | static int emc_complete_timing_change(struct tegra_emc *emc, bool flush) | ||
| 221 | { | ||
| 222 | long timeout; | ||
| 223 | |||
| 224 | dev_dbg(emc->dev, "%s: flush %d\n", __func__, flush); | ||
| 225 | |||
| 226 | if (flush) { | ||
| 227 | /* manually initiate memory timing update */ | ||
| 228 | writel_relaxed(EMC_TIMING_UPDATE, | ||
| 229 | emc->regs + EMC_TIMING_CONTROL); | ||
| 230 | return 0; | ||
| 231 | } | ||
| 232 | |||
| 233 | timeout = wait_for_completion_timeout(&emc->clk_handshake_complete, | ||
| 234 | usecs_to_jiffies(100)); | ||
| 235 | if (timeout == 0) { | ||
| 236 | dev_err(emc->dev, "EMC-CAR handshake failed\n"); | ||
| 237 | return -EIO; | ||
| 238 | } else if (timeout < 0) { | ||
| 239 | dev_err(emc->dev, "failed to wait for EMC-CAR handshake: %ld\n", | ||
| 240 | timeout); | ||
| 241 | return timeout; | ||
| 242 | } | ||
| 243 | |||
| 244 | return 0; | ||
| 245 | } | ||
| 246 | |||
| 247 | static int tegra_emc_clk_change_notify(struct notifier_block *nb, | ||
| 248 | unsigned long msg, void *data) | ||
| 249 | { | ||
| 250 | struct tegra_emc *emc = container_of(nb, struct tegra_emc, clk_nb); | ||
| 251 | struct clk_notifier_data *cnd = data; | ||
| 252 | int err; | ||
| 253 | |||
| 254 | switch (msg) { | ||
| 255 | case PRE_RATE_CHANGE: | ||
| 256 | err = emc_prepare_timing_change(emc, cnd->new_rate); | ||
| 257 | break; | ||
| 258 | |||
| 259 | case ABORT_RATE_CHANGE: | ||
| 260 | err = emc_prepare_timing_change(emc, cnd->old_rate); | ||
| 261 | if (err) | ||
| 262 | break; | ||
| 263 | |||
| 264 | err = emc_complete_timing_change(emc, true); | ||
| 265 | break; | ||
| 266 | |||
| 267 | case POST_RATE_CHANGE: | ||
| 268 | err = emc_complete_timing_change(emc, false); | ||
| 269 | break; | ||
| 270 | |||
| 271 | default: | ||
| 272 | return NOTIFY_DONE; | ||
| 273 | } | ||
| 274 | |||
| 275 | return notifier_from_errno(err); | ||
| 276 | } | ||
| 277 | |||
| 278 | static int load_one_timing_from_dt(struct tegra_emc *emc, | ||
| 279 | struct emc_timing *timing, | ||
| 280 | struct device_node *node) | ||
| 281 | { | ||
| 282 | u32 rate; | ||
| 283 | int err; | ||
| 284 | |||
| 285 | if (!of_device_is_compatible(node, "nvidia,tegra20-emc-table")) { | ||
| 286 | dev_err(emc->dev, "incompatible DT node: %pOF\n", node); | ||
| 287 | return -EINVAL; | ||
| 288 | } | ||
| 289 | |||
| 290 | err = of_property_read_u32(node, "clock-frequency", &rate); | ||
| 291 | if (err) { | ||
| 292 | dev_err(emc->dev, "timing %pOF: failed to read rate: %d\n", | ||
| 293 | node, err); | ||
| 294 | return err; | ||
| 295 | } | ||
| 296 | |||
| 297 | err = of_property_read_u32_array(node, "nvidia,emc-registers", | ||
| 298 | timing->data, | ||
| 299 | ARRAY_SIZE(emc_timing_registers)); | ||
| 300 | if (err) { | ||
| 301 | dev_err(emc->dev, | ||
| 302 | "timing %pOF: failed to read emc timing data: %d\n", | ||
| 303 | node, err); | ||
| 304 | return err; | ||
| 305 | } | ||
| 306 | |||
| 307 | /* | ||
| 308 | * The EMC clock rate is twice the bus rate, and the bus rate is | ||
| 309 | * measured in kHz. | ||
| 310 | */ | ||
| 311 | timing->rate = rate * 2 * 1000; | ||
| 312 | |||
| 313 | dev_dbg(emc->dev, "%s: %pOF: EMC rate %lu\n", | ||
| 314 | __func__, node, timing->rate); | ||
| 315 | |||
| 316 | return 0; | ||
| 317 | } | ||
| 318 | |||
| 319 | static int cmp_timings(const void *_a, const void *_b) | ||
| 320 | { | ||
| 321 | const struct emc_timing *a = _a; | ||
| 322 | const struct emc_timing *b = _b; | ||
| 323 | |||
| 324 | if (a->rate < b->rate) | ||
| 325 | return -1; | ||
| 326 | |||
| 327 | if (a->rate > b->rate) | ||
| 328 | return 1; | ||
| 329 | |||
| 330 | return 0; | ||
| 331 | } | ||
| 332 | |||
| 333 | static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc, | ||
| 334 | struct device_node *node) | ||
| 335 | { | ||
| 336 | struct device_node *child; | ||
| 337 | struct emc_timing *timing; | ||
| 338 | int child_count; | ||
| 339 | int err; | ||
| 340 | |||
| 341 | child_count = of_get_child_count(node); | ||
| 342 | if (!child_count) { | ||
| 343 | dev_err(emc->dev, "no memory timings in DT node: %pOF\n", node); | ||
| 344 | return -EINVAL; | ||
| 345 | } | ||
| 346 | |||
| 347 | emc->timings = devm_kcalloc(emc->dev, child_count, sizeof(*timing), | ||
| 348 | GFP_KERNEL); | ||
| 349 | if (!emc->timings) | ||
| 350 | return -ENOMEM; | ||
| 351 | |||
| 352 | emc->num_timings = child_count; | ||
| 353 | timing = emc->timings; | ||
| 354 | |||
| 355 | for_each_child_of_node(node, child) { | ||
| 356 | err = load_one_timing_from_dt(emc, timing++, child); | ||
| 357 | if (err) { | ||
| 358 | of_node_put(child); | ||
| 359 | return err; | ||
| 360 | } | ||
| 361 | } | ||
| 362 | |||
| 363 | sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings, | ||
| 364 | NULL); | ||
| 365 | |||
| 366 | return 0; | ||
| 367 | } | ||
| 368 | |||
| 369 | static struct device_node * | ||
| 370 | tegra_emc_find_node_by_ram_code(struct device *dev) | ||
| 371 | { | ||
| 372 | struct device_node *np; | ||
| 373 | u32 value, ram_code; | ||
| 374 | int err; | ||
| 375 | |||
| 376 | if (!of_property_read_bool(dev->of_node, "nvidia,use-ram-code")) | ||
| 377 | return of_node_get(dev->of_node); | ||
| 378 | |||
| 379 | ram_code = tegra_read_ram_code(); | ||
| 380 | |||
| 381 | for (np = of_find_node_by_name(dev->of_node, "emc-tables"); np; | ||
| 382 | np = of_find_node_by_name(np, "emc-tables")) { | ||
| 383 | err = of_property_read_u32(np, "nvidia,ram-code", &value); | ||
| 384 | if (err || value != ram_code) { | ||
| 385 | of_node_put(np); | ||
| 386 | continue; | ||
| 387 | } | ||
| 388 | |||
| 389 | return np; | ||
| 390 | } | ||
| 391 | |||
| 392 | dev_err(dev, "no memory timings for RAM code %u found in device tree\n", | ||
| 393 | ram_code); | ||
| 394 | |||
| 395 | return NULL; | ||
| 396 | } | ||
| 397 | |||
| 398 | static int emc_setup_hw(struct tegra_emc *emc) | ||
| 399 | { | ||
| 400 | u32 intmask = EMC_REFRESH_OVERFLOW_INT | EMC_CLKCHANGE_COMPLETE_INT; | ||
| 401 | u32 emc_cfg; | ||
| 402 | |||
| 403 | emc_cfg = readl_relaxed(emc->regs + EMC_CFG_2); | ||
| 404 | |||
| 405 | /* | ||
| 406 | * Depending on a memory type, DRAM should enter either self-refresh | ||
| 407 | * or power-down state on EMC clock change. | ||
| 408 | */ | ||
| 409 | if (!(emc_cfg & EMC_CLKCHANGE_PD_ENABLE) && | ||
| 410 | !(emc_cfg & EMC_CLKCHANGE_SR_ENABLE)) { | ||
| 411 | dev_err(emc->dev, | ||
| 412 | "bootloader didn't specify DRAM auto-suspend mode\n"); | ||
| 413 | return -EINVAL; | ||
| 414 | } | ||
| 415 | |||
| 416 | /* enable EMC and CAR to handshake on PLL divider/source changes */ | ||
| 417 | emc_cfg |= EMC_CLKCHANGE_REQ_ENABLE; | ||
| 418 | writel_relaxed(emc_cfg, emc->regs + EMC_CFG_2); | ||
| 419 | |||
| 420 | /* initialize interrupt */ | ||
| 421 | writel_relaxed(intmask, emc->regs + EMC_INTMASK); | ||
| 422 | writel_relaxed(intmask, emc->regs + EMC_INTSTATUS); | ||
| 423 | |||
| 424 | return 0; | ||
| 425 | } | ||
| 426 | |||
| 427 | static int emc_init(struct tegra_emc *emc, unsigned long rate) | ||
| 428 | { | ||
| 429 | int err; | ||
| 430 | |||
| 431 | err = clk_set_parent(emc->emc_mux, emc->backup_clk); | ||
| 432 | if (err) { | ||
| 433 | dev_err(emc->dev, | ||
| 434 | "failed to reparent to backup source: %d\n", err); | ||
| 435 | return err; | ||
| 436 | } | ||
| 437 | |||
| 438 | err = clk_set_rate(emc->pll_m, rate); | ||
| 439 | if (err) { | ||
| 440 | dev_err(emc->dev, | ||
| 441 | "failed to change pll_m rate: %d\n", err); | ||
| 442 | return err; | ||
| 443 | } | ||
| 444 | |||
| 445 | err = clk_set_parent(emc->emc_mux, emc->pll_m); | ||
| 446 | if (err) { | ||
| 447 | dev_err(emc->dev, | ||
| 448 | "failed to reparent to pll_m: %d\n", err); | ||
| 449 | return err; | ||
| 450 | } | ||
| 451 | |||
| 452 | err = clk_set_rate(emc->clk, rate); | ||
| 453 | if (err) { | ||
| 454 | dev_err(emc->dev, | ||
| 455 | "failed to change emc rate: %d\n", err); | ||
| 456 | return err; | ||
| 457 | } | ||
| 458 | |||
| 459 | return 0; | ||
| 460 | } | ||
| 461 | |||
| 462 | static int tegra_emc_probe(struct platform_device *pdev) | ||
| 463 | { | ||
| 464 | struct device_node *np; | ||
| 465 | struct tegra_emc *emc; | ||
| 466 | struct resource *res; | ||
| 467 | int irq, err; | ||
| 468 | |||
| 469 | /* driver has nothing to do in a case of memory timing absence */ | ||
| 470 | if (of_get_child_count(pdev->dev.of_node) == 0) { | ||
| 471 | dev_info(&pdev->dev, | ||
| 472 | "EMC device tree node doesn't have memory timings\n"); | ||
| 473 | return 0; | ||
| 474 | } | ||
| 475 | |||
| 476 | irq = platform_get_irq(pdev, 0); | ||
| 477 | if (irq < 0) { | ||
| 478 | dev_err(&pdev->dev, "interrupt not specified\n"); | ||
| 479 | dev_err(&pdev->dev, "please update your device tree\n"); | ||
| 480 | return irq; | ||
| 481 | } | ||
| 482 | |||
| 483 | np = tegra_emc_find_node_by_ram_code(&pdev->dev); | ||
| 484 | if (!np) | ||
| 485 | return -EINVAL; | ||
| 486 | |||
| 487 | emc = devm_kzalloc(&pdev->dev, sizeof(*emc), GFP_KERNEL); | ||
| 488 | if (!emc) { | ||
| 489 | of_node_put(np); | ||
| 490 | return -ENOMEM; | ||
| 491 | } | ||
| 492 | |||
| 493 | init_completion(&emc->clk_handshake_complete); | ||
| 494 | emc->clk_nb.notifier_call = tegra_emc_clk_change_notify; | ||
| 495 | emc->dev = &pdev->dev; | ||
| 496 | |||
| 497 | err = tegra_emc_load_timings_from_dt(emc, np); | ||
| 498 | of_node_put(np); | ||
| 499 | if (err) | ||
| 500 | return err; | ||
| 501 | |||
| 502 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 503 | emc->regs = devm_ioremap_resource(&pdev->dev, res); | ||
| 504 | if (IS_ERR(emc->regs)) | ||
| 505 | return PTR_ERR(emc->regs); | ||
| 506 | |||
| 507 | err = emc_setup_hw(emc); | ||
| 508 | if (err) | ||
| 509 | return err; | ||
| 510 | |||
| 511 | err = devm_request_irq(&pdev->dev, irq, tegra_emc_isr, 0, | ||
| 512 | dev_name(&pdev->dev), emc); | ||
| 513 | if (err) { | ||
| 514 | dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", irq, err); | ||
| 515 | return err; | ||
| 516 | } | ||
| 517 | |||
| 518 | emc->clk = devm_clk_get(&pdev->dev, "emc"); | ||
| 519 | if (IS_ERR(emc->clk)) { | ||
| 520 | err = PTR_ERR(emc->clk); | ||
| 521 | dev_err(&pdev->dev, "failed to get emc clock: %d\n", err); | ||
| 522 | return err; | ||
| 523 | } | ||
| 524 | |||
| 525 | emc->pll_m = clk_get_sys(NULL, "pll_m"); | ||
| 526 | if (IS_ERR(emc->pll_m)) { | ||
| 527 | err = PTR_ERR(emc->pll_m); | ||
| 528 | dev_err(&pdev->dev, "failed to get pll_m clock: %d\n", err); | ||
| 529 | return err; | ||
| 530 | } | ||
| 531 | |||
| 532 | emc->backup_clk = clk_get_sys(NULL, "pll_p"); | ||
| 533 | if (IS_ERR(emc->backup_clk)) { | ||
| 534 | err = PTR_ERR(emc->backup_clk); | ||
| 535 | dev_err(&pdev->dev, "failed to get pll_p clock: %d\n", err); | ||
| 536 | goto put_pll_m; | ||
| 537 | } | ||
| 538 | |||
| 539 | emc->emc_mux = clk_get_parent(emc->clk); | ||
| 540 | if (IS_ERR(emc->emc_mux)) { | ||
| 541 | err = PTR_ERR(emc->emc_mux); | ||
| 542 | dev_err(&pdev->dev, "failed to get emc_mux clock: %d\n", err); | ||
| 543 | goto put_backup; | ||
| 544 | } | ||
| 545 | |||
| 546 | err = clk_notifier_register(emc->clk, &emc->clk_nb); | ||
| 547 | if (err) { | ||
| 548 | dev_err(&pdev->dev, "failed to register clk notifier: %d\n", | ||
| 549 | err); | ||
| 550 | goto put_backup; | ||
| 551 | } | ||
| 552 | |||
| 553 | /* set DRAM clock rate to maximum */ | ||
| 554 | err = emc_init(emc, emc->timings[emc->num_timings - 1].rate); | ||
| 555 | if (err) { | ||
| 556 | dev_err(&pdev->dev, "failed to initialize EMC clock rate: %d\n", | ||
| 557 | err); | ||
| 558 | goto unreg_notifier; | ||
| 559 | } | ||
| 560 | |||
| 561 | return 0; | ||
| 562 | |||
| 563 | unreg_notifier: | ||
| 564 | clk_notifier_unregister(emc->clk, &emc->clk_nb); | ||
| 565 | put_backup: | ||
| 566 | clk_put(emc->backup_clk); | ||
| 567 | put_pll_m: | ||
| 568 | clk_put(emc->pll_m); | ||
| 569 | |||
| 570 | return err; | ||
| 571 | } | ||
| 572 | |||
| 573 | static const struct of_device_id tegra_emc_of_match[] = { | ||
| 574 | { .compatible = "nvidia,tegra20-emc", }, | ||
| 575 | {}, | ||
| 576 | }; | ||
| 577 | |||
| 578 | static struct platform_driver tegra_emc_driver = { | ||
| 579 | .probe = tegra_emc_probe, | ||
| 580 | .driver = { | ||
| 581 | .name = "tegra20-emc", | ||
| 582 | .of_match_table = tegra_emc_of_match, | ||
| 583 | .suppress_bind_attrs = true, | ||
| 584 | }, | ||
| 585 | }; | ||
| 586 | |||
| 587 | static int __init tegra_emc_init(void) | ||
| 588 | { | ||
| 589 | return platform_driver_register(&tegra_emc_driver); | ||
| 590 | } | ||
| 591 | subsys_initcall(tegra_emc_init); | ||
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 446166ba0bec..90b686e586c6 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile | |||
| @@ -13,7 +13,7 @@ obj-$(CONFIG_ARCH_GEMINI) += gemini/ | |||
| 13 | obj-$(CONFIG_ARCH_MXC) += imx/ | 13 | obj-$(CONFIG_ARCH_MXC) += imx/ |
| 14 | obj-$(CONFIG_SOC_XWAY) += lantiq/ | 14 | obj-$(CONFIG_SOC_XWAY) += lantiq/ |
| 15 | obj-y += mediatek/ | 15 | obj-y += mediatek/ |
| 16 | obj-$(CONFIG_ARCH_MESON) += amlogic/ | 16 | obj-y += amlogic/ |
| 17 | obj-y += qcom/ | 17 | obj-y += qcom/ |
| 18 | obj-y += renesas/ | 18 | obj-y += renesas/ |
| 19 | obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ | 19 | obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ |
diff --git a/drivers/soc/amlogic/Kconfig b/drivers/soc/amlogic/Kconfig index 2f282b472912..5501ad5650b2 100644 --- a/drivers/soc/amlogic/Kconfig +++ b/drivers/soc/amlogic/Kconfig | |||
| @@ -7,6 +7,15 @@ config MESON_CANVAS | |||
| 7 | help | 7 | help |
| 8 | Say yes to support the canvas IP for Amlogic SoCs. | 8 | Say yes to support the canvas IP for Amlogic SoCs. |
| 9 | 9 | ||
| 10 | config MESON_CLK_MEASURE | ||
| 11 | bool "Amlogic Meson SoC Clock Measure driver" | ||
| 12 | depends on ARCH_MESON || COMPILE_TEST | ||
| 13 | default ARCH_MESON | ||
| 14 | select REGMAP_MMIO | ||
| 15 | help | ||
| 16 | Say yes to support of Measuring a set of internal SoC clocks | ||
| 17 | from the debugfs interface. | ||
| 18 | |||
| 10 | config MESON_GX_SOCINFO | 19 | config MESON_GX_SOCINFO |
| 11 | bool "Amlogic Meson GX SoC Information driver" | 20 | bool "Amlogic Meson GX SoC Information driver" |
| 12 | depends on ARCH_MESON || COMPILE_TEST | 21 | depends on ARCH_MESON || COMPILE_TEST |
diff --git a/drivers/soc/amlogic/Makefile b/drivers/soc/amlogic/Makefile index 0ab16d35ac36..bf2d109f61e9 100644 --- a/drivers/soc/amlogic/Makefile +++ b/drivers/soc/amlogic/Makefile | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | obj-$(CONFIG_MESON_CANVAS) += meson-canvas.o | 1 | obj-$(CONFIG_MESON_CANVAS) += meson-canvas.o |
| 2 | obj-$(CONFIG_MESON_CLK_MEASURE) += meson-clk-measure.o | ||
| 2 | obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o | 3 | obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o |
| 3 | obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o | 4 | obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o |
| 4 | obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o | 5 | obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o |
diff --git a/drivers/soc/amlogic/meson-clk-measure.c b/drivers/soc/amlogic/meson-clk-measure.c new file mode 100644 index 000000000000..daea191a66fa --- /dev/null +++ b/drivers/soc/amlogic/meson-clk-measure.c | |||
| @@ -0,0 +1,350 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0+ | ||
| 2 | /* | ||
| 3 | * Copyright (c) 2018 BayLibre, SAS | ||
| 4 | * Author: Neil Armstrong <narmstrong@baylibre.com> | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <linux/of_address.h> | ||
| 8 | #include <linux/platform_device.h> | ||
| 9 | #include <linux/bitfield.h> | ||
| 10 | #include <linux/seq_file.h> | ||
| 11 | #include <linux/debugfs.h> | ||
| 12 | #include <linux/regmap.h> | ||
| 13 | |||
| 14 | #define MSR_CLK_DUTY 0x0 | ||
| 15 | #define MSR_CLK_REG0 0x4 | ||
| 16 | #define MSR_CLK_REG1 0x8 | ||
| 17 | #define MSR_CLK_REG2 0xc | ||
| 18 | |||
| 19 | #define MSR_DURATION GENMASK(15, 0) | ||
| 20 | #define MSR_ENABLE BIT(16) | ||
| 21 | #define MSR_CONT BIT(17) /* continuous measurement */ | ||
| 22 | #define MSR_INTR BIT(18) /* interrupts */ | ||
| 23 | #define MSR_RUN BIT(19) | ||
| 24 | #define MSR_CLK_SRC GENMASK(26, 20) | ||
| 25 | #define MSR_BUSY BIT(31) | ||
| 26 | |||
| 27 | #define MSR_VAL_MASK GENMASK(15, 0) | ||
| 28 | |||
| 29 | #define DIV_MIN 32 | ||
| 30 | #define DIV_STEP 32 | ||
| 31 | #define DIV_MAX 640 | ||
| 32 | |||
| 33 | #define CLK_MSR_MAX 128 | ||
| 34 | |||
| 35 | struct meson_msr_id { | ||
| 36 | struct meson_msr *priv; | ||
| 37 | unsigned int id; | ||
| 38 | const char *name; | ||
| 39 | }; | ||
| 40 | |||
| 41 | struct meson_msr { | ||
| 42 | struct regmap *regmap; | ||
| 43 | struct meson_msr_id msr_table[CLK_MSR_MAX]; | ||
| 44 | }; | ||
| 45 | |||
| 46 | #define CLK_MSR_ID(__id, __name) \ | ||
| 47 | [__id] = {.id = __id, .name = __name,} | ||
| 48 | |||
| 49 | static struct meson_msr_id clk_msr_m8[CLK_MSR_MAX] = { | ||
| 50 | CLK_MSR_ID(0, "ring_osc_out_ee0"), | ||
| 51 | CLK_MSR_ID(1, "ring_osc_out_ee1"), | ||
| 52 | CLK_MSR_ID(2, "ring_osc_out_ee2"), | ||
| 53 | CLK_MSR_ID(3, "a9_ring_osck"), | ||
| 54 | CLK_MSR_ID(6, "vid_pll"), | ||
| 55 | CLK_MSR_ID(7, "clk81"), | ||
| 56 | CLK_MSR_ID(8, "encp"), | ||
| 57 | CLK_MSR_ID(9, "encl"), | ||
| 58 | CLK_MSR_ID(11, "eth_rmii"), | ||
| 59 | CLK_MSR_ID(13, "amclk"), | ||
| 60 | CLK_MSR_ID(14, "fec_clk_0"), | ||
| 61 | CLK_MSR_ID(15, "fec_clk_1"), | ||
| 62 | CLK_MSR_ID(16, "fec_clk_2"), | ||
| 63 | CLK_MSR_ID(18, "a9_clk_div16"), | ||
| 64 | CLK_MSR_ID(19, "hdmi_sys"), | ||
| 65 | CLK_MSR_ID(20, "rtc_osc_clk_out"), | ||
| 66 | CLK_MSR_ID(21, "i2s_clk_in_src0"), | ||
| 67 | CLK_MSR_ID(22, "clk_rmii_from_pad"), | ||
| 68 | CLK_MSR_ID(23, "hdmi_ch0_tmds"), | ||
| 69 | CLK_MSR_ID(24, "lvds_fifo"), | ||
| 70 | CLK_MSR_ID(26, "sc_clk_int"), | ||
| 71 | CLK_MSR_ID(28, "sar_adc"), | ||
| 72 | CLK_MSR_ID(30, "mpll_clk_test_out"), | ||
| 73 | CLK_MSR_ID(31, "audac_clkpi"), | ||
| 74 | CLK_MSR_ID(32, "vdac"), | ||
| 75 | CLK_MSR_ID(33, "sdhc_rx"), | ||
| 76 | CLK_MSR_ID(34, "sdhc_sd"), | ||
| 77 | CLK_MSR_ID(35, "mali"), | ||
| 78 | CLK_MSR_ID(36, "hdmi_tx_pixel"), | ||
| 79 | CLK_MSR_ID(38, "vdin_meas"), | ||
| 80 | CLK_MSR_ID(39, "pcm_sclk"), | ||
| 81 | CLK_MSR_ID(40, "pcm_mclk"), | ||
| 82 | CLK_MSR_ID(41, "eth_rx_tx"), | ||
| 83 | CLK_MSR_ID(42, "pwm_d"), | ||
| 84 | CLK_MSR_ID(43, "pwm_c"), | ||
| 85 | CLK_MSR_ID(44, "pwm_b"), | ||
| 86 | CLK_MSR_ID(45, "pwm_a"), | ||
| 87 | CLK_MSR_ID(46, "pcm2_sclk"), | ||
| 88 | CLK_MSR_ID(47, "ddr_dpll_pt"), | ||
| 89 | CLK_MSR_ID(48, "pwm_f"), | ||
| 90 | CLK_MSR_ID(49, "pwm_e"), | ||
| 91 | CLK_MSR_ID(59, "hcodec"), | ||
| 92 | CLK_MSR_ID(60, "usb_32k_alt"), | ||
| 93 | CLK_MSR_ID(61, "gpio"), | ||
| 94 | CLK_MSR_ID(62, "vid2_pll"), | ||
| 95 | CLK_MSR_ID(63, "mipi_csi_cfg"), | ||
| 96 | }; | ||
| 97 | |||
| 98 | static struct meson_msr_id clk_msr_gx[CLK_MSR_MAX] = { | ||
| 99 | CLK_MSR_ID(0, "ring_osc_out_ee_0"), | ||
| 100 | CLK_MSR_ID(1, "ring_osc_out_ee_1"), | ||
| 101 | CLK_MSR_ID(2, "ring_osc_out_ee_2"), | ||
| 102 | CLK_MSR_ID(3, "a53_ring_osc"), | ||
| 103 | CLK_MSR_ID(4, "gp0_pll"), | ||
| 104 | CLK_MSR_ID(6, "enci"), | ||
| 105 | CLK_MSR_ID(7, "clk81"), | ||
| 106 | CLK_MSR_ID(8, "encp"), | ||
| 107 | CLK_MSR_ID(9, "encl"), | ||
| 108 | CLK_MSR_ID(10, "vdac"), | ||
| 109 | CLK_MSR_ID(11, "rgmii_tx"), | ||
| 110 | CLK_MSR_ID(12, "pdm"), | ||
| 111 | CLK_MSR_ID(13, "amclk"), | ||
| 112 | CLK_MSR_ID(14, "fec_0"), | ||
| 113 | CLK_MSR_ID(15, "fec_1"), | ||
| 114 | CLK_MSR_ID(16, "fec_2"), | ||
| 115 | CLK_MSR_ID(17, "sys_pll_div16"), | ||
| 116 | CLK_MSR_ID(18, "sys_cpu_div16"), | ||
| 117 | CLK_MSR_ID(19, "hdmitx_sys"), | ||
| 118 | CLK_MSR_ID(20, "rtc_osc_out"), | ||
| 119 | CLK_MSR_ID(21, "i2s_in_src0"), | ||
| 120 | CLK_MSR_ID(22, "eth_phy_ref"), | ||
| 121 | CLK_MSR_ID(23, "hdmi_todig"), | ||
| 122 | CLK_MSR_ID(26, "sc_int"), | ||
| 123 | CLK_MSR_ID(28, "sar_adc"), | ||
| 124 | CLK_MSR_ID(31, "mpll_test_out"), | ||
| 125 | CLK_MSR_ID(32, "vdec"), | ||
| 126 | CLK_MSR_ID(35, "mali"), | ||
| 127 | CLK_MSR_ID(36, "hdmi_tx_pixel"), | ||
| 128 | CLK_MSR_ID(37, "i958"), | ||
| 129 | CLK_MSR_ID(38, "vdin_meas"), | ||
| 130 | CLK_MSR_ID(39, "pcm_sclk"), | ||
| 131 | CLK_MSR_ID(40, "pcm_mclk"), | ||
| 132 | CLK_MSR_ID(41, "eth_rx_or_rmii"), | ||
| 133 | CLK_MSR_ID(42, "mp0_out"), | ||
| 134 | CLK_MSR_ID(43, "fclk_div5"), | ||
| 135 | CLK_MSR_ID(44, "pwm_b"), | ||
| 136 | CLK_MSR_ID(45, "pwm_a"), | ||
| 137 | CLK_MSR_ID(46, "vpu"), | ||
| 138 | CLK_MSR_ID(47, "ddr_dpll_pt"), | ||
| 139 | CLK_MSR_ID(48, "mp1_out"), | ||
| 140 | CLK_MSR_ID(49, "mp2_out"), | ||
| 141 | CLK_MSR_ID(50, "mp3_out"), | ||
| 142 | CLK_MSR_ID(51, "nand_core"), | ||
| 143 | CLK_MSR_ID(52, "sd_emmc_b"), | ||
| 144 | CLK_MSR_ID(53, "sd_emmc_a"), | ||
| 145 | CLK_MSR_ID(55, "vid_pll_div_out"), | ||
| 146 | CLK_MSR_ID(56, "cci"), | ||
| 147 | CLK_MSR_ID(57, "wave420l_c"), | ||
| 148 | CLK_MSR_ID(58, "wave420l_b"), | ||
| 149 | CLK_MSR_ID(59, "hcodec"), | ||
| 150 | CLK_MSR_ID(60, "alt_32k"), | ||
| 151 | CLK_MSR_ID(61, "gpio_msr"), | ||
| 152 | CLK_MSR_ID(62, "hevc"), | ||
| 153 | CLK_MSR_ID(66, "vid_lock"), | ||
| 154 | CLK_MSR_ID(70, "pwm_f"), | ||
| 155 | CLK_MSR_ID(71, "pwm_e"), | ||
| 156 | CLK_MSR_ID(72, "pwm_d"), | ||
| 157 | CLK_MSR_ID(73, "pwm_c"), | ||
| 158 | CLK_MSR_ID(75, "aoclkx2_int"), | ||
| 159 | CLK_MSR_ID(76, "aoclk_int"), | ||
| 160 | CLK_MSR_ID(77, "rng_ring_osc_0"), | ||
| 161 | CLK_MSR_ID(78, "rng_ring_osc_1"), | ||
| 162 | CLK_MSR_ID(79, "rng_ring_osc_2"), | ||
| 163 | CLK_MSR_ID(80, "rng_ring_osc_3"), | ||
| 164 | CLK_MSR_ID(81, "vapb"), | ||
| 165 | CLK_MSR_ID(82, "ge2d"), | ||
| 166 | }; | ||
| 167 | |||
| 168 | static int meson_measure_id(struct meson_msr_id *clk_msr_id, | ||
| 169 | unsigned int duration) | ||
| 170 | { | ||
| 171 | struct meson_msr *priv = clk_msr_id->priv; | ||
| 172 | unsigned int val; | ||
| 173 | int ret; | ||
| 174 | |||
| 175 | regmap_write(priv->regmap, MSR_CLK_REG0, 0); | ||
| 176 | |||
| 177 | /* Set measurement duration */ | ||
| 178 | regmap_update_bits(priv->regmap, MSR_CLK_REG0, MSR_DURATION, | ||
| 179 | FIELD_PREP(MSR_DURATION, duration - 1)); | ||
| 180 | |||
| 181 | /* Set ID */ | ||
| 182 | regmap_update_bits(priv->regmap, MSR_CLK_REG0, MSR_CLK_SRC, | ||
| 183 | FIELD_PREP(MSR_CLK_SRC, clk_msr_id->id)); | ||
| 184 | |||
| 185 | /* Enable & Start */ | ||
| 186 | regmap_update_bits(priv->regmap, MSR_CLK_REG0, | ||
| 187 | MSR_RUN | MSR_ENABLE, | ||
| 188 | MSR_RUN | MSR_ENABLE); | ||
| 189 | |||
| 190 | ret = regmap_read_poll_timeout(priv->regmap, MSR_CLK_REG0, | ||
| 191 | val, !(val & MSR_BUSY), 10, 10000); | ||
| 192 | if (ret) | ||
| 193 | return ret; | ||
| 194 | |||
| 195 | /* Disable */ | ||
| 196 | regmap_update_bits(priv->regmap, MSR_CLK_REG0, MSR_ENABLE, 0); | ||
| 197 | |||
| 198 | /* Get the value in multiple of gate time counts */ | ||
| 199 | regmap_read(priv->regmap, MSR_CLK_REG2, &val); | ||
| 200 | |||
| 201 | if (val >= MSR_VAL_MASK) | ||
| 202 | return -EINVAL; | ||
| 203 | |||
| 204 | return DIV_ROUND_CLOSEST_ULL((val & MSR_VAL_MASK) * 1000000ULL, | ||
| 205 | duration); | ||
| 206 | } | ||
| 207 | |||
| 208 | static int meson_measure_best_id(struct meson_msr_id *clk_msr_id, | ||
| 209 | unsigned int *precision) | ||
| 210 | { | ||
| 211 | unsigned int duration = DIV_MAX; | ||
| 212 | int ret; | ||
| 213 | |||
| 214 | /* Start from max duration and down to min duration */ | ||
| 215 | do { | ||
| 216 | ret = meson_measure_id(clk_msr_id, duration); | ||
| 217 | if (ret >= 0) | ||
| 218 | *precision = (2 * 1000000) / duration; | ||
| 219 | else | ||
| 220 | duration -= DIV_STEP; | ||
| 221 | } while (duration >= DIV_MIN && ret == -EINVAL); | ||
| 222 | |||
| 223 | return ret; | ||
| 224 | } | ||
| 225 | |||
| 226 | static int clk_msr_show(struct seq_file *s, void *data) | ||
| 227 | { | ||
| 228 | struct meson_msr_id *clk_msr_id = s->private; | ||
| 229 | unsigned int precision = 0; | ||
| 230 | int val; | ||
| 231 | |||
| 232 | val = meson_measure_best_id(clk_msr_id, &precision); | ||
| 233 | if (val < 0) | ||
| 234 | return val; | ||
| 235 | |||
| 236 | seq_printf(s, "%d\t+/-%dHz\n", val, precision); | ||
| 237 | |||
| 238 | return 0; | ||
| 239 | } | ||
| 240 | DEFINE_SHOW_ATTRIBUTE(clk_msr); | ||
| 241 | |||
| 242 | static int clk_msr_summary_show(struct seq_file *s, void *data) | ||
| 243 | { | ||
| 244 | struct meson_msr_id *msr_table = s->private; | ||
| 245 | unsigned int precision = 0; | ||
| 246 | int val, i; | ||
| 247 | |||
| 248 | seq_puts(s, " clock rate precision\n"); | ||
| 249 | seq_puts(s, "---------------------------------------------\n"); | ||
| 250 | |||
| 251 | for (i = 0 ; i < CLK_MSR_MAX ; ++i) { | ||
| 252 | if (!msr_table[i].name) | ||
| 253 | continue; | ||
| 254 | |||
| 255 | val = meson_measure_best_id(&msr_table[i], &precision); | ||
| 256 | if (val < 0) | ||
| 257 | return val; | ||
| 258 | |||
| 259 | seq_printf(s, " %-20s %10d +/-%dHz\n", | ||
| 260 | msr_table[i].name, val, precision); | ||
| 261 | } | ||
| 262 | |||
| 263 | return 0; | ||
| 264 | } | ||
| 265 | DEFINE_SHOW_ATTRIBUTE(clk_msr_summary); | ||
| 266 | |||
| 267 | static const struct regmap_config meson_clk_msr_regmap_config = { | ||
| 268 | .reg_bits = 32, | ||
| 269 | .val_bits = 32, | ||
| 270 | .reg_stride = 4, | ||
| 271 | .max_register = MSR_CLK_REG2, | ||
| 272 | }; | ||
| 273 | |||
| 274 | static int meson_msr_probe(struct platform_device *pdev) | ||
| 275 | { | ||
| 276 | const struct meson_msr_id *match_data; | ||
| 277 | struct meson_msr *priv; | ||
| 278 | struct resource *res; | ||
| 279 | struct dentry *root, *clks; | ||
| 280 | void __iomem *base; | ||
| 281 | int i; | ||
| 282 | |||
| 283 | priv = devm_kzalloc(&pdev->dev, sizeof(struct meson_msr), | ||
| 284 | GFP_KERNEL); | ||
| 285 | if (!priv) | ||
| 286 | return -ENOMEM; | ||
| 287 | |||
| 288 | match_data = device_get_match_data(&pdev->dev); | ||
| 289 | if (!match_data) { | ||
| 290 | dev_err(&pdev->dev, "failed to get match data\n"); | ||
| 291 | return -ENODEV; | ||
| 292 | } | ||
| 293 | |||
| 294 | memcpy(priv->msr_table, match_data, sizeof(priv->msr_table)); | ||
| 295 | |||
| 296 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 297 | base = devm_ioremap_resource(&pdev->dev, res); | ||
| 298 | if (IS_ERR(base)) { | ||
| 299 | dev_err(&pdev->dev, "io resource mapping failed\n"); | ||
| 300 | return PTR_ERR(base); | ||
| 301 | } | ||
| 302 | |||
| 303 | priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, | ||
| 304 | &meson_clk_msr_regmap_config); | ||
| 305 | if (IS_ERR(priv->regmap)) | ||
| 306 | return PTR_ERR(priv->regmap); | ||
| 307 | |||
| 308 | root = debugfs_create_dir("meson-clk-msr", NULL); | ||
| 309 | clks = debugfs_create_dir("clks", root); | ||
| 310 | |||
| 311 | debugfs_create_file("measure_summary", 0444, root, | ||
| 312 | priv->msr_table, &clk_msr_summary_fops); | ||
| 313 | |||
| 314 | for (i = 0 ; i < CLK_MSR_MAX ; ++i) { | ||
| 315 | if (!priv->msr_table[i].name) | ||
| 316 | continue; | ||
| 317 | |||
| 318 | priv->msr_table[i].priv = priv; | ||
| 319 | |||
| 320 | debugfs_create_file(priv->msr_table[i].name, 0444, clks, | ||
| 321 | &priv->msr_table[i], &clk_msr_fops); | ||
| 322 | } | ||
| 323 | |||
| 324 | return 0; | ||
| 325 | } | ||
| 326 | |||
| 327 | static const struct of_device_id meson_msr_match_table[] = { | ||
| 328 | { | ||
| 329 | .compatible = "amlogic,meson-gx-clk-measure", | ||
| 330 | .data = (void *)clk_msr_gx, | ||
| 331 | }, | ||
| 332 | { | ||
| 333 | .compatible = "amlogic,meson8-clk-measure", | ||
| 334 | .data = (void *)clk_msr_m8, | ||
| 335 | }, | ||
| 336 | { | ||
| 337 | .compatible = "amlogic,meson8b-clk-measure", | ||
| 338 | .data = (void *)clk_msr_m8, | ||
| 339 | }, | ||
| 340 | { /* sentinel */ } | ||
| 341 | }; | ||
| 342 | |||
| 343 | static struct platform_driver meson_msr_driver = { | ||
| 344 | .probe = meson_msr_probe, | ||
| 345 | .driver = { | ||
| 346 | .name = "meson_msr", | ||
| 347 | .of_match_table = meson_msr_match_table, | ||
| 348 | }, | ||
| 349 | }; | ||
| 350 | builtin_platform_driver(meson_msr_driver); | ||
diff --git a/drivers/soc/atmel/soc.c b/drivers/soc/atmel/soc.c index 4dd03b099c89..096a83cf0caf 100644 --- a/drivers/soc/atmel/soc.c +++ b/drivers/soc/atmel/soc.c | |||
| @@ -66,6 +66,8 @@ static const struct at91_soc __initconst socs[] = { | |||
| 66 | AT91_SOC(AT91SAM9XE128_CIDR_MATCH, 0, "at91sam9xe128", "at91sam9xe128"), | 66 | AT91_SOC(AT91SAM9XE128_CIDR_MATCH, 0, "at91sam9xe128", "at91sam9xe128"), |
| 67 | AT91_SOC(AT91SAM9XE256_CIDR_MATCH, 0, "at91sam9xe256", "at91sam9xe256"), | 67 | AT91_SOC(AT91SAM9XE256_CIDR_MATCH, 0, "at91sam9xe256", "at91sam9xe256"), |
| 68 | AT91_SOC(AT91SAM9XE512_CIDR_MATCH, 0, "at91sam9xe512", "at91sam9xe512"), | 68 | AT91_SOC(AT91SAM9XE512_CIDR_MATCH, 0, "at91sam9xe512", "at91sam9xe512"), |
| 69 | AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_EXID_MATCH, | ||
| 70 | "sam9x60", "sam9x60"), | ||
| 69 | #endif | 71 | #endif |
| 70 | #ifdef CONFIG_SOC_SAMA5 | 72 | #ifdef CONFIG_SOC_SAMA5 |
| 71 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D21CU_EXID_MATCH, | 73 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D21CU_EXID_MATCH, |
| @@ -90,12 +92,20 @@ static const struct at91_soc __initconst socs[] = { | |||
| 90 | "sama5d27c 128MiB SiP", "sama5d2"), | 92 | "sama5d27c 128MiB SiP", "sama5d2"), |
| 91 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27C_D5M_EXID_MATCH, | 93 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27C_D5M_EXID_MATCH, |
| 92 | "sama5d27c 64MiB SiP", "sama5d2"), | 94 | "sama5d27c 64MiB SiP", "sama5d2"), |
| 95 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27C_LD1G_EXID_MATCH, | ||
| 96 | "sama5d27c 128MiB LPDDR2 SiP", "sama5d2"), | ||
| 97 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27C_LD2G_EXID_MATCH, | ||
| 98 | "sama5d27c 256MiB LPDDR2 SiP", "sama5d2"), | ||
| 93 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CU_EXID_MATCH, | 99 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CU_EXID_MATCH, |
| 94 | "sama5d28", "sama5d2"), | 100 | "sama5d28", "sama5d2"), |
| 95 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CN_EXID_MATCH, | 101 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CN_EXID_MATCH, |
| 96 | "sama5d28", "sama5d2"), | 102 | "sama5d28", "sama5d2"), |
| 97 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28C_D1G_EXID_MATCH, | 103 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28C_D1G_EXID_MATCH, |
| 98 | "sama5d28c 128MiB SiP", "sama5d2"), | 104 | "sama5d28c 128MiB SiP", "sama5d2"), |
| 105 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28C_LD1G_EXID_MATCH, | ||
| 106 | "sama5d28c 128MiB LPDDR2 SiP", "sama5d2"), | ||
| 107 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28C_LD2G_EXID_MATCH, | ||
| 108 | "sama5d28c 256MiB LPDDR2 SiP", "sama5d2"), | ||
| 99 | AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D31_EXID_MATCH, | 109 | AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D31_EXID_MATCH, |
| 100 | "sama5d31", "sama5d3"), | 110 | "sama5d31", "sama5d3"), |
| 101 | AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D33_EXID_MATCH, | 111 | AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D33_EXID_MATCH, |
diff --git a/drivers/soc/atmel/soc.h b/drivers/soc/atmel/soc.h index 94cd5d1ab502..ee652e4841a5 100644 --- a/drivers/soc/atmel/soc.h +++ b/drivers/soc/atmel/soc.h | |||
| @@ -42,6 +42,7 @@ at91_soc_init(const struct at91_soc *socs); | |||
| 42 | #define AT91SAM9G45_CIDR_MATCH 0x019b05a0 | 42 | #define AT91SAM9G45_CIDR_MATCH 0x019b05a0 |
| 43 | #define AT91SAM9X5_CIDR_MATCH 0x019a05a0 | 43 | #define AT91SAM9X5_CIDR_MATCH 0x019a05a0 |
| 44 | #define AT91SAM9N12_CIDR_MATCH 0x019a07a0 | 44 | #define AT91SAM9N12_CIDR_MATCH 0x019a07a0 |
| 45 | #define SAM9X60_CIDR_MATCH 0x019b35a0 | ||
| 45 | 46 | ||
| 46 | #define AT91SAM9M11_EXID_MATCH 0x00000001 | 47 | #define AT91SAM9M11_EXID_MATCH 0x00000001 |
| 47 | #define AT91SAM9M10_EXID_MATCH 0x00000002 | 48 | #define AT91SAM9M10_EXID_MATCH 0x00000002 |
| @@ -58,6 +59,8 @@ at91_soc_init(const struct at91_soc *socs); | |||
| 58 | #define AT91SAM9N12_EXID_MATCH 0x00000006 | 59 | #define AT91SAM9N12_EXID_MATCH 0x00000006 |
| 59 | #define AT91SAM9CN11_EXID_MATCH 0x00000009 | 60 | #define AT91SAM9CN11_EXID_MATCH 0x00000009 |
| 60 | 61 | ||
| 62 | #define SAM9X60_EXID_MATCH 0x00000000 | ||
| 63 | |||
| 61 | #define AT91SAM9XE128_CIDR_MATCH 0x329973a0 | 64 | #define AT91SAM9XE128_CIDR_MATCH 0x329973a0 |
| 62 | #define AT91SAM9XE256_CIDR_MATCH 0x329a93a0 | 65 | #define AT91SAM9XE256_CIDR_MATCH 0x329a93a0 |
| 63 | #define AT91SAM9XE512_CIDR_MATCH 0x329aa3a0 | 66 | #define AT91SAM9XE512_CIDR_MATCH 0x329aa3a0 |
| @@ -73,9 +76,13 @@ at91_soc_init(const struct at91_soc *socs); | |||
| 73 | #define SAMA5D26CU_EXID_MATCH 0x00000012 | 76 | #define SAMA5D26CU_EXID_MATCH 0x00000012 |
| 74 | #define SAMA5D27C_D1G_EXID_MATCH 0x00000033 | 77 | #define SAMA5D27C_D1G_EXID_MATCH 0x00000033 |
| 75 | #define SAMA5D27C_D5M_EXID_MATCH 0x00000032 | 78 | #define SAMA5D27C_D5M_EXID_MATCH 0x00000032 |
| 79 | #define SAMA5D27C_LD1G_EXID_MATCH 0x00000061 | ||
| 80 | #define SAMA5D27C_LD2G_EXID_MATCH 0x00000062 | ||
| 76 | #define SAMA5D27CU_EXID_MATCH 0x00000011 | 81 | #define SAMA5D27CU_EXID_MATCH 0x00000011 |
| 77 | #define SAMA5D27CN_EXID_MATCH 0x00000021 | 82 | #define SAMA5D27CN_EXID_MATCH 0x00000021 |
| 78 | #define SAMA5D28C_D1G_EXID_MATCH 0x00000013 | 83 | #define SAMA5D28C_D1G_EXID_MATCH 0x00000013 |
| 84 | #define SAMA5D28C_LD1G_EXID_MATCH 0x00000071 | ||
| 85 | #define SAMA5D28C_LD2G_EXID_MATCH 0x00000072 | ||
| 79 | #define SAMA5D28CU_EXID_MATCH 0x00000010 | 86 | #define SAMA5D28CU_EXID_MATCH 0x00000010 |
| 80 | #define SAMA5D28CN_EXID_MATCH 0x00000020 | 87 | #define SAMA5D28CN_EXID_MATCH 0x00000020 |
| 81 | 88 | ||
diff --git a/drivers/soc/bcm/brcmstb/common.c b/drivers/soc/bcm/brcmstb/common.c index 14185451901d..bf9123f727e8 100644 --- a/drivers/soc/bcm/brcmstb/common.c +++ b/drivers/soc/bcm/brcmstb/common.c | |||
| @@ -31,13 +31,17 @@ static const struct of_device_id brcmstb_machine_match[] = { | |||
| 31 | 31 | ||
| 32 | bool soc_is_brcmstb(void) | 32 | bool soc_is_brcmstb(void) |
| 33 | { | 33 | { |
| 34 | const struct of_device_id *match; | ||
| 34 | struct device_node *root; | 35 | struct device_node *root; |
| 35 | 36 | ||
| 36 | root = of_find_node_by_path("/"); | 37 | root = of_find_node_by_path("/"); |
| 37 | if (!root) | 38 | if (!root) |
| 38 | return false; | 39 | return false; |
| 39 | 40 | ||
| 40 | return of_match_node(brcmstb_machine_match, root) != NULL; | 41 | match = of_match_node(brcmstb_machine_match, root); |
| 42 | of_node_put(root); | ||
| 43 | |||
| 44 | return match != NULL; | ||
| 41 | } | 45 | } |
| 42 | 46 | ||
| 43 | u32 brcmstb_get_family_id(void) | 47 | u32 brcmstb_get_family_id(void) |
diff --git a/drivers/soc/bcm/brcmstb/pm/pm-arm.c b/drivers/soc/bcm/brcmstb/pm/pm-arm.c index a5577dd5eb08..8ee06347447c 100644 --- a/drivers/soc/bcm/brcmstb/pm/pm-arm.c +++ b/drivers/soc/bcm/brcmstb/pm/pm-arm.c | |||
| @@ -404,7 +404,7 @@ noinline int brcmstb_pm_s3_finish(void) | |||
| 404 | { | 404 | { |
| 405 | struct brcmstb_s3_params *params = ctrl.s3_params; | 405 | struct brcmstb_s3_params *params = ctrl.s3_params; |
| 406 | dma_addr_t params_pa = ctrl.s3_params_pa; | 406 | dma_addr_t params_pa = ctrl.s3_params_pa; |
| 407 | phys_addr_t reentry = virt_to_phys(&cpu_resume); | 407 | phys_addr_t reentry = virt_to_phys(&cpu_resume_arm); |
| 408 | enum bsp_initiate_command cmd; | 408 | enum bsp_initiate_command cmd; |
| 409 | u32 flags; | 409 | u32 flags; |
| 410 | 410 | ||
diff --git a/drivers/soc/bcm/raspberrypi-power.c b/drivers/soc/bcm/raspberrypi-power.c index a78dfe0a2b50..5d1aacdd84ef 100644 --- a/drivers/soc/bcm/raspberrypi-power.c +++ b/drivers/soc/bcm/raspberrypi-power.c | |||
| @@ -1,9 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 1 | /* (C) 2015 Pengutronix, Alexander Aring <aar@pengutronix.de> | 2 | /* (C) 2015 Pengutronix, Alexander Aring <aar@pengutronix.de> |
| 2 | * | 3 | * |
| 3 | * This program is free software; you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License version 2 as | ||
| 5 | * published by the Free Software Foundation. | ||
| 6 | * | ||
| 7 | * Authors: | 4 | * Authors: |
| 8 | * Alexander Aring <aar@pengutronix.de> | 5 | * Alexander Aring <aar@pengutronix.de> |
| 9 | * Eric Anholt <eric@anholt.net> | 6 | * Eric Anholt <eric@anholt.net> |
diff --git a/drivers/soc/imx/Kconfig b/drivers/soc/imx/Kconfig index a5b86a28f343..2112d18dbb7b 100644 --- a/drivers/soc/imx/Kconfig +++ b/drivers/soc/imx/Kconfig | |||
| @@ -1,8 +1,8 @@ | |||
| 1 | menu "i.MX SoC drivers" | 1 | menu "i.MX SoC drivers" |
| 2 | 2 | ||
| 3 | config IMX7_PM_DOMAINS | 3 | config IMX_GPCV2_PM_DOMAINS |
| 4 | bool "i.MX7 PM domains" | 4 | bool "i.MX GPCv2 PM domains" |
| 5 | depends on SOC_IMX7D || (COMPILE_TEST && OF) | 5 | depends on SOC_IMX7D || SOC_IMX8MQ || (COMPILE_TEST && OF) |
| 6 | depends on PM | 6 | depends on PM |
| 7 | select PM_GENERIC_DOMAINS | 7 | select PM_GENERIC_DOMAINS |
| 8 | default y if SOC_IMX7D | 8 | default y if SOC_IMX7D |
diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile index aab41a5cc317..506a6f3c2b9b 100644 --- a/drivers/soc/imx/Makefile +++ b/drivers/soc/imx/Makefile | |||
| @@ -1,2 +1,2 @@ | |||
| 1 | obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o | 1 | obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o |
| 2 | obj-$(CONFIG_IMX7_PM_DOMAINS) += gpcv2.o | 2 | obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o |
diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c index aa3729ecaa9e..7d14a4b4e82a 100644 --- a/drivers/soc/imx/gpc.c +++ b/drivers/soc/imx/gpc.c | |||
| @@ -35,7 +35,7 @@ | |||
| 35 | #define GPU_VPU_PUP_REQ BIT(1) | 35 | #define GPU_VPU_PUP_REQ BIT(1) |
| 36 | #define GPU_VPU_PDN_REQ BIT(0) | 36 | #define GPU_VPU_PDN_REQ BIT(0) |
| 37 | 37 | ||
| 38 | #define GPC_CLK_MAX 6 | 38 | #define GPC_CLK_MAX 7 |
| 39 | 39 | ||
| 40 | #define PGC_DOMAIN_FLAG_NO_PD BIT(0) | 40 | #define PGC_DOMAIN_FLAG_NO_PD BIT(0) |
| 41 | 41 | ||
diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index e7b5994fee9d..8b4f48a2ca57 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c | |||
| @@ -14,23 +14,54 @@ | |||
| 14 | #include <linux/regmap.h> | 14 | #include <linux/regmap.h> |
| 15 | #include <linux/regulator/consumer.h> | 15 | #include <linux/regulator/consumer.h> |
| 16 | #include <dt-bindings/power/imx7-power.h> | 16 | #include <dt-bindings/power/imx7-power.h> |
| 17 | #include <dt-bindings/power/imx8mq-power.h> | ||
| 17 | 18 | ||
| 18 | #define GPC_LPCR_A_CORE_BSC 0x000 | 19 | #define GPC_LPCR_A_CORE_BSC 0x000 |
| 19 | 20 | ||
| 20 | #define GPC_PGC_CPU_MAPPING 0x0ec | 21 | #define GPC_PGC_CPU_MAPPING 0x0ec |
| 21 | #define USB_HSIC_PHY_A_CORE_DOMAIN BIT(6) | 22 | |
| 22 | #define USB_OTG2_PHY_A_CORE_DOMAIN BIT(5) | 23 | #define IMX7_USB_HSIC_PHY_A_CORE_DOMAIN BIT(6) |
| 23 | #define USB_OTG1_PHY_A_CORE_DOMAIN BIT(4) | 24 | #define IMX7_USB_OTG2_PHY_A_CORE_DOMAIN BIT(5) |
| 24 | #define PCIE_PHY_A_CORE_DOMAIN BIT(3) | 25 | #define IMX7_USB_OTG1_PHY_A_CORE_DOMAIN BIT(4) |
| 25 | #define MIPI_PHY_A_CORE_DOMAIN BIT(2) | 26 | #define IMX7_PCIE_PHY_A_CORE_DOMAIN BIT(3) |
| 27 | #define IMX7_MIPI_PHY_A_CORE_DOMAIN BIT(2) | ||
| 28 | |||
| 29 | #define IMX8M_PCIE2_A53_DOMAIN BIT(15) | ||
| 30 | #define IMX8M_MIPI_CSI2_A53_DOMAIN BIT(14) | ||
| 31 | #define IMX8M_MIPI_CSI1_A53_DOMAIN BIT(13) | ||
| 32 | #define IMX8M_DISP_A53_DOMAIN BIT(12) | ||
| 33 | #define IMX8M_HDMI_A53_DOMAIN BIT(11) | ||
| 34 | #define IMX8M_VPU_A53_DOMAIN BIT(10) | ||
| 35 | #define IMX8M_GPU_A53_DOMAIN BIT(9) | ||
| 36 | #define IMX8M_DDR2_A53_DOMAIN BIT(8) | ||
| 37 | #define IMX8M_DDR1_A53_DOMAIN BIT(7) | ||
| 38 | #define IMX8M_OTG2_A53_DOMAIN BIT(5) | ||
| 39 | #define IMX8M_OTG1_A53_DOMAIN BIT(4) | ||
| 40 | #define IMX8M_PCIE1_A53_DOMAIN BIT(3) | ||
| 41 | #define IMX8M_MIPI_A53_DOMAIN BIT(2) | ||
| 26 | 42 | ||
| 27 | #define GPC_PU_PGC_SW_PUP_REQ 0x0f8 | 43 | #define GPC_PU_PGC_SW_PUP_REQ 0x0f8 |
| 28 | #define GPC_PU_PGC_SW_PDN_REQ 0x104 | 44 | #define GPC_PU_PGC_SW_PDN_REQ 0x104 |
| 29 | #define USB_HSIC_PHY_SW_Pxx_REQ BIT(4) | 45 | |
| 30 | #define USB_OTG2_PHY_SW_Pxx_REQ BIT(3) | 46 | #define IMX7_USB_HSIC_PHY_SW_Pxx_REQ BIT(4) |
| 31 | #define USB_OTG1_PHY_SW_Pxx_REQ BIT(2) | 47 | #define IMX7_USB_OTG2_PHY_SW_Pxx_REQ BIT(3) |
| 32 | #define PCIE_PHY_SW_Pxx_REQ BIT(1) | 48 | #define IMX7_USB_OTG1_PHY_SW_Pxx_REQ BIT(2) |
| 33 | #define MIPI_PHY_SW_Pxx_REQ BIT(0) | 49 | #define IMX7_PCIE_PHY_SW_Pxx_REQ BIT(1) |
| 50 | #define IMX7_MIPI_PHY_SW_Pxx_REQ BIT(0) | ||
| 51 | |||
| 52 | #define IMX8M_PCIE2_SW_Pxx_REQ BIT(13) | ||
| 53 | #define IMX8M_MIPI_CSI2_SW_Pxx_REQ BIT(12) | ||
| 54 | #define IMX8M_MIPI_CSI1_SW_Pxx_REQ BIT(11) | ||
| 55 | #define IMX8M_DISP_SW_Pxx_REQ BIT(10) | ||
| 56 | #define IMX8M_HDMI_SW_Pxx_REQ BIT(9) | ||
| 57 | #define IMX8M_VPU_SW_Pxx_REQ BIT(8) | ||
| 58 | #define IMX8M_GPU_SW_Pxx_REQ BIT(7) | ||
| 59 | #define IMX8M_DDR2_SW_Pxx_REQ BIT(6) | ||
| 60 | #define IMX8M_DDR1_SW_Pxx_REQ BIT(5) | ||
| 61 | #define IMX8M_OTG2_SW_Pxx_REQ BIT(3) | ||
| 62 | #define IMX8M_OTG1_SW_Pxx_REQ BIT(2) | ||
| 63 | #define IMX8M_PCIE1_SW_Pxx_REQ BIT(1) | ||
| 64 | #define IMX8M_MIPI_SW_Pxx_REQ BIT(0) | ||
| 34 | 65 | ||
| 35 | #define GPC_M4_PU_PDN_FLG 0x1bc | 66 | #define GPC_M4_PU_PDN_FLG 0x1bc |
| 36 | 67 | ||
| @@ -40,9 +71,22 @@ | |||
| 40 | * GPC_PGC memory map are incorrect, below offset | 71 | * GPC_PGC memory map are incorrect, below offset |
| 41 | * values are from design RTL. | 72 | * values are from design RTL. |
| 42 | */ | 73 | */ |
| 43 | #define PGC_MIPI 16 | 74 | #define IMX7_PGC_MIPI 16 |
| 44 | #define PGC_PCIE 17 | 75 | #define IMX7_PGC_PCIE 17 |
| 45 | #define PGC_USB_HSIC 20 | 76 | #define IMX7_PGC_USB_HSIC 20 |
| 77 | |||
| 78 | #define IMX8M_PGC_MIPI 16 | ||
| 79 | #define IMX8M_PGC_PCIE1 17 | ||
| 80 | #define IMX8M_PGC_OTG1 18 | ||
| 81 | #define IMX8M_PGC_OTG2 19 | ||
| 82 | #define IMX8M_PGC_DDR1 21 | ||
| 83 | #define IMX8M_PGC_GPU 23 | ||
| 84 | #define IMX8M_PGC_VPU 24 | ||
| 85 | #define IMX8M_PGC_DISP 26 | ||
| 86 | #define IMX8M_PGC_MIPI_CSI1 27 | ||
| 87 | #define IMX8M_PGC_MIPI_CSI2 28 | ||
| 88 | #define IMX8M_PGC_PCIE2 29 | ||
| 89 | |||
| 46 | #define GPC_PGC_CTRL(n) (0x800 + (n) * 0x40) | 90 | #define GPC_PGC_CTRL(n) (0x800 + (n) * 0x40) |
| 47 | #define GPC_PGC_SR(n) (GPC_PGC_CTRL(n) + 0xc) | 91 | #define GPC_PGC_SR(n) (GPC_PGC_CTRL(n) + 0xc) |
| 48 | 92 | ||
| @@ -67,6 +111,7 @@ struct imx_pgc_domain { | |||
| 67 | struct imx_pgc_domain_data { | 111 | struct imx_pgc_domain_data { |
| 68 | const struct imx_pgc_domain *domains; | 112 | const struct imx_pgc_domain *domains; |
| 69 | size_t domains_num; | 113 | size_t domains_num; |
| 114 | const struct regmap_access_table *reg_access_table; | ||
| 70 | }; | 115 | }; |
| 71 | 116 | ||
| 72 | static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd, | 117 | static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd, |
| @@ -166,11 +211,11 @@ static const struct imx_pgc_domain imx7_pgc_domains[] = { | |||
| 166 | .name = "mipi-phy", | 211 | .name = "mipi-phy", |
| 167 | }, | 212 | }, |
| 168 | .bits = { | 213 | .bits = { |
| 169 | .pxx = MIPI_PHY_SW_Pxx_REQ, | 214 | .pxx = IMX7_MIPI_PHY_SW_Pxx_REQ, |
| 170 | .map = MIPI_PHY_A_CORE_DOMAIN, | 215 | .map = IMX7_MIPI_PHY_A_CORE_DOMAIN, |
| 171 | }, | 216 | }, |
| 172 | .voltage = 1000000, | 217 | .voltage = 1000000, |
| 173 | .pgc = PGC_MIPI, | 218 | .pgc = IMX7_PGC_MIPI, |
| 174 | }, | 219 | }, |
| 175 | 220 | ||
| 176 | [IMX7_POWER_DOMAIN_PCIE_PHY] = { | 221 | [IMX7_POWER_DOMAIN_PCIE_PHY] = { |
| @@ -178,11 +223,11 @@ static const struct imx_pgc_domain imx7_pgc_domains[] = { | |||
| 178 | .name = "pcie-phy", | 223 | .name = "pcie-phy", |
| 179 | }, | 224 | }, |
| 180 | .bits = { | 225 | .bits = { |
| 181 | .pxx = PCIE_PHY_SW_Pxx_REQ, | 226 | .pxx = IMX7_PCIE_PHY_SW_Pxx_REQ, |
| 182 | .map = PCIE_PHY_A_CORE_DOMAIN, | 227 | .map = IMX7_PCIE_PHY_A_CORE_DOMAIN, |
| 183 | }, | 228 | }, |
| 184 | .voltage = 1000000, | 229 | .voltage = 1000000, |
| 185 | .pgc = PGC_PCIE, | 230 | .pgc = IMX7_PGC_PCIE, |
| 186 | }, | 231 | }, |
| 187 | 232 | ||
| 188 | [IMX7_POWER_DOMAIN_USB_HSIC_PHY] = { | 233 | [IMX7_POWER_DOMAIN_USB_HSIC_PHY] = { |
| @@ -190,17 +235,195 @@ static const struct imx_pgc_domain imx7_pgc_domains[] = { | |||
| 190 | .name = "usb-hsic-phy", | 235 | .name = "usb-hsic-phy", |
| 191 | }, | 236 | }, |
| 192 | .bits = { | 237 | .bits = { |
| 193 | .pxx = USB_HSIC_PHY_SW_Pxx_REQ, | 238 | .pxx = IMX7_USB_HSIC_PHY_SW_Pxx_REQ, |
| 194 | .map = USB_HSIC_PHY_A_CORE_DOMAIN, | 239 | .map = IMX7_USB_HSIC_PHY_A_CORE_DOMAIN, |
| 195 | }, | 240 | }, |
| 196 | .voltage = 1200000, | 241 | .voltage = 1200000, |
| 197 | .pgc = PGC_USB_HSIC, | 242 | .pgc = IMX7_PGC_USB_HSIC, |
| 198 | }, | 243 | }, |
| 199 | }; | 244 | }; |
| 200 | 245 | ||
| 246 | static const struct regmap_range imx7_yes_ranges[] = { | ||
| 247 | regmap_reg_range(GPC_LPCR_A_CORE_BSC, | ||
| 248 | GPC_M4_PU_PDN_FLG), | ||
| 249 | regmap_reg_range(GPC_PGC_CTRL(IMX7_PGC_MIPI), | ||
| 250 | GPC_PGC_SR(IMX7_PGC_MIPI)), | ||
| 251 | regmap_reg_range(GPC_PGC_CTRL(IMX7_PGC_PCIE), | ||
| 252 | GPC_PGC_SR(IMX7_PGC_PCIE)), | ||
| 253 | regmap_reg_range(GPC_PGC_CTRL(IMX7_PGC_USB_HSIC), | ||
| 254 | GPC_PGC_SR(IMX7_PGC_USB_HSIC)), | ||
| 255 | }; | ||
| 256 | |||
| 257 | static const struct regmap_access_table imx7_access_table = { | ||
| 258 | .yes_ranges = imx7_yes_ranges, | ||
| 259 | .n_yes_ranges = ARRAY_SIZE(imx7_yes_ranges), | ||
| 260 | }; | ||
| 261 | |||
| 201 | static const struct imx_pgc_domain_data imx7_pgc_domain_data = { | 262 | static const struct imx_pgc_domain_data imx7_pgc_domain_data = { |
| 202 | .domains = imx7_pgc_domains, | 263 | .domains = imx7_pgc_domains, |
| 203 | .domains_num = ARRAY_SIZE(imx7_pgc_domains), | 264 | .domains_num = ARRAY_SIZE(imx7_pgc_domains), |
| 265 | .reg_access_table = &imx7_access_table, | ||
| 266 | }; | ||
| 267 | |||
| 268 | static const struct imx_pgc_domain imx8m_pgc_domains[] = { | ||
| 269 | [IMX8M_POWER_DOMAIN_MIPI] = { | ||
| 270 | .genpd = { | ||
| 271 | .name = "mipi", | ||
| 272 | }, | ||
| 273 | .bits = { | ||
| 274 | .pxx = IMX8M_MIPI_SW_Pxx_REQ, | ||
| 275 | .map = IMX8M_MIPI_A53_DOMAIN, | ||
| 276 | }, | ||
| 277 | .pgc = IMX8M_PGC_MIPI, | ||
| 278 | }, | ||
| 279 | |||
| 280 | [IMX8M_POWER_DOMAIN_PCIE1] = { | ||
| 281 | .genpd = { | ||
| 282 | .name = "pcie1", | ||
| 283 | }, | ||
| 284 | .bits = { | ||
| 285 | .pxx = IMX8M_PCIE1_SW_Pxx_REQ, | ||
| 286 | .map = IMX8M_PCIE1_A53_DOMAIN, | ||
| 287 | }, | ||
| 288 | .pgc = IMX8M_PGC_PCIE1, | ||
| 289 | }, | ||
| 290 | |||
| 291 | [IMX8M_POWER_DOMAIN_USB_OTG1] = { | ||
| 292 | .genpd = { | ||
| 293 | .name = "usb-otg1", | ||
| 294 | }, | ||
| 295 | .bits = { | ||
| 296 | .pxx = IMX8M_OTG1_SW_Pxx_REQ, | ||
| 297 | .map = IMX8M_OTG1_A53_DOMAIN, | ||
| 298 | }, | ||
| 299 | .pgc = IMX8M_PGC_OTG1, | ||
| 300 | }, | ||
| 301 | |||
| 302 | [IMX8M_POWER_DOMAIN_USB_OTG2] = { | ||
| 303 | .genpd = { | ||
| 304 | .name = "usb-otg2", | ||
| 305 | }, | ||
| 306 | .bits = { | ||
| 307 | .pxx = IMX8M_OTG2_SW_Pxx_REQ, | ||
| 308 | .map = IMX8M_OTG2_A53_DOMAIN, | ||
| 309 | }, | ||
| 310 | .pgc = IMX8M_PGC_OTG2, | ||
| 311 | }, | ||
| 312 | |||
| 313 | [IMX8M_POWER_DOMAIN_DDR1] = { | ||
| 314 | .genpd = { | ||
| 315 | .name = "ddr1", | ||
| 316 | }, | ||
| 317 | .bits = { | ||
| 318 | .pxx = IMX8M_DDR1_SW_Pxx_REQ, | ||
| 319 | .map = IMX8M_DDR2_A53_DOMAIN, | ||
| 320 | }, | ||
| 321 | .pgc = IMX8M_PGC_DDR1, | ||
| 322 | }, | ||
| 323 | |||
| 324 | [IMX8M_POWER_DOMAIN_GPU] = { | ||
| 325 | .genpd = { | ||
| 326 | .name = "gpu", | ||
| 327 | }, | ||
| 328 | .bits = { | ||
| 329 | .pxx = IMX8M_GPU_SW_Pxx_REQ, | ||
| 330 | .map = IMX8M_GPU_A53_DOMAIN, | ||
| 331 | }, | ||
| 332 | .pgc = IMX8M_PGC_GPU, | ||
| 333 | }, | ||
| 334 | |||
| 335 | [IMX8M_POWER_DOMAIN_VPU] = { | ||
| 336 | .genpd = { | ||
| 337 | .name = "vpu", | ||
| 338 | }, | ||
| 339 | .bits = { | ||
| 340 | .pxx = IMX8M_VPU_SW_Pxx_REQ, | ||
| 341 | .map = IMX8M_VPU_A53_DOMAIN, | ||
| 342 | }, | ||
| 343 | .pgc = IMX8M_PGC_VPU, | ||
| 344 | }, | ||
| 345 | |||
| 346 | [IMX8M_POWER_DOMAIN_DISP] = { | ||
| 347 | .genpd = { | ||
| 348 | .name = "disp", | ||
| 349 | }, | ||
| 350 | .bits = { | ||
| 351 | .pxx = IMX8M_DISP_SW_Pxx_REQ, | ||
| 352 | .map = IMX8M_DISP_A53_DOMAIN, | ||
| 353 | }, | ||
| 354 | .pgc = IMX8M_PGC_DISP, | ||
| 355 | }, | ||
| 356 | |||
| 357 | [IMX8M_POWER_DOMAIN_MIPI_CSI1] = { | ||
| 358 | .genpd = { | ||
| 359 | .name = "mipi-csi1", | ||
| 360 | }, | ||
| 361 | .bits = { | ||
| 362 | .pxx = IMX8M_MIPI_CSI1_SW_Pxx_REQ, | ||
| 363 | .map = IMX8M_MIPI_CSI1_A53_DOMAIN, | ||
| 364 | }, | ||
| 365 | .pgc = IMX8M_PGC_MIPI_CSI1, | ||
| 366 | }, | ||
| 367 | |||
| 368 | [IMX8M_POWER_DOMAIN_MIPI_CSI2] = { | ||
| 369 | .genpd = { | ||
| 370 | .name = "mipi-csi2", | ||
| 371 | }, | ||
| 372 | .bits = { | ||
| 373 | .pxx = IMX8M_MIPI_CSI2_SW_Pxx_REQ, | ||
| 374 | .map = IMX8M_MIPI_CSI2_A53_DOMAIN, | ||
| 375 | }, | ||
| 376 | .pgc = IMX8M_PGC_MIPI_CSI2, | ||
| 377 | }, | ||
| 378 | |||
| 379 | [IMX8M_POWER_DOMAIN_PCIE2] = { | ||
| 380 | .genpd = { | ||
| 381 | .name = "pcie2", | ||
| 382 | }, | ||
| 383 | .bits = { | ||
| 384 | .pxx = IMX8M_PCIE2_SW_Pxx_REQ, | ||
| 385 | .map = IMX8M_PCIE2_A53_DOMAIN, | ||
| 386 | }, | ||
| 387 | .pgc = IMX8M_PGC_PCIE2, | ||
| 388 | }, | ||
| 389 | }; | ||
| 390 | |||
| 391 | static const struct regmap_range imx8m_yes_ranges[] = { | ||
| 392 | regmap_reg_range(GPC_LPCR_A_CORE_BSC, | ||
| 393 | GPC_M4_PU_PDN_FLG), | ||
| 394 | regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_MIPI), | ||
| 395 | GPC_PGC_SR(IMX8M_PGC_MIPI)), | ||
| 396 | regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_PCIE1), | ||
| 397 | GPC_PGC_SR(IMX8M_PGC_PCIE1)), | ||
| 398 | regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_OTG1), | ||
| 399 | GPC_PGC_SR(IMX8M_PGC_OTG1)), | ||
| 400 | regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_OTG2), | ||
| 401 | GPC_PGC_SR(IMX8M_PGC_OTG2)), | ||
| 402 | regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_DDR1), | ||
| 403 | GPC_PGC_SR(IMX8M_PGC_DDR1)), | ||
| 404 | regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_GPU), | ||
| 405 | GPC_PGC_SR(IMX8M_PGC_GPU)), | ||
| 406 | regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_VPU), | ||
| 407 | GPC_PGC_SR(IMX8M_PGC_VPU)), | ||
| 408 | regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_DISP), | ||
| 409 | GPC_PGC_SR(IMX8M_PGC_DISP)), | ||
| 410 | regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_MIPI_CSI1), | ||
| 411 | GPC_PGC_SR(IMX8M_PGC_MIPI_CSI1)), | ||
| 412 | regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_MIPI_CSI2), | ||
| 413 | GPC_PGC_SR(IMX8M_PGC_MIPI_CSI2)), | ||
| 414 | regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_PCIE2), | ||
| 415 | GPC_PGC_SR(IMX8M_PGC_PCIE2)), | ||
| 416 | }; | ||
| 417 | |||
| 418 | static const struct regmap_access_table imx8m_access_table = { | ||
| 419 | .yes_ranges = imx8m_yes_ranges, | ||
| 420 | .n_yes_ranges = ARRAY_SIZE(imx8m_yes_ranges), | ||
| 421 | }; | ||
| 422 | |||
| 423 | static const struct imx_pgc_domain_data imx8m_pgc_domain_data = { | ||
| 424 | .domains = imx8m_pgc_domains, | ||
| 425 | .domains_num = ARRAY_SIZE(imx8m_pgc_domains), | ||
| 426 | .reg_access_table = &imx8m_access_table, | ||
| 204 | }; | 427 | }; |
| 205 | 428 | ||
| 206 | static int imx_pgc_domain_probe(struct platform_device *pdev) | 429 | static int imx_pgc_domain_probe(struct platform_device *pdev) |
| @@ -217,7 +440,7 @@ static int imx_pgc_domain_probe(struct platform_device *pdev) | |||
| 217 | dev_err(domain->dev, "Failed to get domain's regulator\n"); | 440 | dev_err(domain->dev, "Failed to get domain's regulator\n"); |
| 218 | return PTR_ERR(domain->regulator); | 441 | return PTR_ERR(domain->regulator); |
| 219 | } | 442 | } |
| 220 | } else { | 443 | } else if (domain->voltage) { |
| 221 | regulator_set_voltage(domain->regulator, | 444 | regulator_set_voltage(domain->regulator, |
| 222 | domain->voltage, domain->voltage); | 445 | domain->voltage, domain->voltage); |
| 223 | } | 446 | } |
| @@ -265,27 +488,15 @@ builtin_platform_driver(imx_pgc_domain_driver) | |||
| 265 | 488 | ||
| 266 | static int imx_gpcv2_probe(struct platform_device *pdev) | 489 | static int imx_gpcv2_probe(struct platform_device *pdev) |
| 267 | { | 490 | { |
| 268 | static const struct imx_pgc_domain_data *domain_data; | 491 | const struct imx_pgc_domain_data *domain_data = |
| 269 | static const struct regmap_range yes_ranges[] = { | 492 | of_device_get_match_data(&pdev->dev); |
| 270 | regmap_reg_range(GPC_LPCR_A_CORE_BSC, | 493 | |
| 271 | GPC_M4_PU_PDN_FLG), | 494 | struct regmap_config regmap_config = { |
| 272 | regmap_reg_range(GPC_PGC_CTRL(PGC_MIPI), | ||
| 273 | GPC_PGC_SR(PGC_MIPI)), | ||
| 274 | regmap_reg_range(GPC_PGC_CTRL(PGC_PCIE), | ||
| 275 | GPC_PGC_SR(PGC_PCIE)), | ||
| 276 | regmap_reg_range(GPC_PGC_CTRL(PGC_USB_HSIC), | ||
| 277 | GPC_PGC_SR(PGC_USB_HSIC)), | ||
| 278 | }; | ||
| 279 | static const struct regmap_access_table access_table = { | ||
| 280 | .yes_ranges = yes_ranges, | ||
| 281 | .n_yes_ranges = ARRAY_SIZE(yes_ranges), | ||
| 282 | }; | ||
| 283 | static const struct regmap_config regmap_config = { | ||
| 284 | .reg_bits = 32, | 495 | .reg_bits = 32, |
| 285 | .val_bits = 32, | 496 | .val_bits = 32, |
| 286 | .reg_stride = 4, | 497 | .reg_stride = 4, |
| 287 | .rd_table = &access_table, | 498 | .rd_table = domain_data->reg_access_table, |
| 288 | .wr_table = &access_table, | 499 | .wr_table = domain_data->reg_access_table, |
| 289 | .max_register = SZ_4K, | 500 | .max_register = SZ_4K, |
| 290 | }; | 501 | }; |
| 291 | struct device *dev = &pdev->dev; | 502 | struct device *dev = &pdev->dev; |
| @@ -313,8 +524,6 @@ static int imx_gpcv2_probe(struct platform_device *pdev) | |||
| 313 | return ret; | 524 | return ret; |
| 314 | } | 525 | } |
| 315 | 526 | ||
| 316 | domain_data = of_device_get_match_data(&pdev->dev); | ||
| 317 | |||
| 318 | for_each_child_of_node(pgc_np, np) { | 527 | for_each_child_of_node(pgc_np, np) { |
| 319 | struct platform_device *pd_pdev; | 528 | struct platform_device *pd_pdev; |
| 320 | struct imx_pgc_domain *domain; | 529 | struct imx_pgc_domain *domain; |
| @@ -372,6 +581,7 @@ static int imx_gpcv2_probe(struct platform_device *pdev) | |||
| 372 | 581 | ||
| 373 | static const struct of_device_id imx_gpcv2_dt_ids[] = { | 582 | static const struct of_device_id imx_gpcv2_dt_ids[] = { |
| 374 | { .compatible = "fsl,imx7d-gpc", .data = &imx7_pgc_domain_data, }, | 583 | { .compatible = "fsl,imx7d-gpc", .data = &imx7_pgc_domain_data, }, |
| 584 | { .compatible = "fsl,imx8mq-gpc", .data = &imx8m_pgc_domain_data, }, | ||
| 375 | { } | 585 | { } |
| 376 | }; | 586 | }; |
| 377 | 587 | ||
diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig index a7d0667338f2..17bd7590464f 100644 --- a/drivers/soc/mediatek/Kconfig +++ b/drivers/soc/mediatek/Kconfig | |||
| @@ -4,6 +4,18 @@ | |||
| 4 | menu "MediaTek SoC drivers" | 4 | menu "MediaTek SoC drivers" |
| 5 | depends on ARCH_MEDIATEK || COMPILE_TEST | 5 | depends on ARCH_MEDIATEK || COMPILE_TEST |
| 6 | 6 | ||
| 7 | config MTK_CMDQ | ||
| 8 | tristate "MediaTek CMDQ Support" | ||
| 9 | depends on ARCH_MEDIATEK || COMPILE_TEST | ||
| 10 | select MAILBOX | ||
| 11 | select MTK_CMDQ_MBOX | ||
| 12 | select MTK_INFRACFG | ||
| 13 | help | ||
| 14 | Say yes here to add support for the MediaTek Command Queue (CMDQ) | ||
| 15 | driver. The CMDQ is used to help read/write registers with critical | ||
| 16 | time limitation, such as updating display configuration during the | ||
| 17 | vblank. | ||
| 18 | |||
| 7 | config MTK_INFRACFG | 19 | config MTK_INFRACFG |
| 8 | bool "MediaTek INFRACFG Support" | 20 | bool "MediaTek INFRACFG Support" |
| 9 | select REGMAP | 21 | select REGMAP |
diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile index 12998b08819e..64ce5eeaba32 100644 --- a/drivers/soc/mediatek/Makefile +++ b/drivers/soc/mediatek/Makefile | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq-helper.o | ||
| 1 | obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o | 2 | obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o |
| 2 | obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o | 3 | obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o |
| 3 | obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o | 4 | obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o |
diff --git a/drivers/soc/mediatek/mtk-cmdq-helper.c b/drivers/soc/mediatek/mtk-cmdq-helper.c new file mode 100644 index 000000000000..ff9fef5a032b --- /dev/null +++ b/drivers/soc/mediatek/mtk-cmdq-helper.c | |||
| @@ -0,0 +1,300 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | // | ||
| 3 | // Copyright (c) 2018 MediaTek Inc. | ||
| 4 | |||
| 5 | #include <linux/completion.h> | ||
| 6 | #include <linux/errno.h> | ||
| 7 | #include <linux/dma-mapping.h> | ||
| 8 | #include <linux/module.h> | ||
| 9 | #include <linux/mailbox_controller.h> | ||
| 10 | #include <linux/soc/mediatek/mtk-cmdq.h> | ||
| 11 | |||
| 12 | #define CMDQ_ARG_A_WRITE_MASK 0xffff | ||
| 13 | #define CMDQ_WRITE_ENABLE_MASK BIT(0) | ||
| 14 | #define CMDQ_EOC_IRQ_EN BIT(0) | ||
| 15 | #define CMDQ_EOC_CMD ((u64)((CMDQ_CODE_EOC << CMDQ_OP_CODE_SHIFT)) \ | ||
| 16 | << 32 | CMDQ_EOC_IRQ_EN) | ||
| 17 | |||
| 18 | static void cmdq_client_timeout(struct timer_list *t) | ||
| 19 | { | ||
| 20 | struct cmdq_client *client = from_timer(client, t, timer); | ||
| 21 | |||
| 22 | dev_err(client->client.dev, "cmdq timeout!\n"); | ||
| 23 | } | ||
| 24 | |||
| 25 | struct cmdq_client *cmdq_mbox_create(struct device *dev, int index, u32 timeout) | ||
| 26 | { | ||
| 27 | struct cmdq_client *client; | ||
| 28 | |||
| 29 | client = kzalloc(sizeof(*client), GFP_KERNEL); | ||
| 30 | if (!client) | ||
| 31 | return (struct cmdq_client *)-ENOMEM; | ||
| 32 | |||
| 33 | client->timeout_ms = timeout; | ||
| 34 | if (timeout != CMDQ_NO_TIMEOUT) { | ||
| 35 | spin_lock_init(&client->lock); | ||
| 36 | timer_setup(&client->timer, cmdq_client_timeout, 0); | ||
| 37 | } | ||
| 38 | client->pkt_cnt = 0; | ||
| 39 | client->client.dev = dev; | ||
| 40 | client->client.tx_block = false; | ||
| 41 | client->chan = mbox_request_channel(&client->client, index); | ||
| 42 | |||
| 43 | if (IS_ERR(client->chan)) { | ||
| 44 | long err; | ||
| 45 | |||
| 46 | dev_err(dev, "failed to request channel\n"); | ||
| 47 | err = PTR_ERR(client->chan); | ||
| 48 | kfree(client); | ||
| 49 | |||
| 50 | return ERR_PTR(err); | ||
| 51 | } | ||
| 52 | |||
| 53 | return client; | ||
| 54 | } | ||
| 55 | EXPORT_SYMBOL(cmdq_mbox_create); | ||
| 56 | |||
| 57 | void cmdq_mbox_destroy(struct cmdq_client *client) | ||
| 58 | { | ||
| 59 | if (client->timeout_ms != CMDQ_NO_TIMEOUT) { | ||
| 60 | spin_lock(&client->lock); | ||
| 61 | del_timer_sync(&client->timer); | ||
| 62 | spin_unlock(&client->lock); | ||
| 63 | } | ||
| 64 | mbox_free_channel(client->chan); | ||
| 65 | kfree(client); | ||
| 66 | } | ||
| 67 | EXPORT_SYMBOL(cmdq_mbox_destroy); | ||
| 68 | |||
| 69 | struct cmdq_pkt *cmdq_pkt_create(struct cmdq_client *client, size_t size) | ||
| 70 | { | ||
| 71 | struct cmdq_pkt *pkt; | ||
| 72 | struct device *dev; | ||
| 73 | dma_addr_t dma_addr; | ||
| 74 | |||
| 75 | pkt = kzalloc(sizeof(*pkt), GFP_KERNEL); | ||
| 76 | if (!pkt) | ||
| 77 | return ERR_PTR(-ENOMEM); | ||
| 78 | pkt->va_base = kzalloc(size, GFP_KERNEL); | ||
| 79 | if (!pkt->va_base) { | ||
| 80 | kfree(pkt); | ||
| 81 | return ERR_PTR(-ENOMEM); | ||
| 82 | } | ||
| 83 | pkt->buf_size = size; | ||
| 84 | pkt->cl = (void *)client; | ||
| 85 | |||
| 86 | dev = client->chan->mbox->dev; | ||
| 87 | dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size, | ||
| 88 | DMA_TO_DEVICE); | ||
| 89 | if (dma_mapping_error(dev, dma_addr)) { | ||
| 90 | dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size); | ||
| 91 | kfree(pkt->va_base); | ||
| 92 | kfree(pkt); | ||
| 93 | return ERR_PTR(-ENOMEM); | ||
| 94 | } | ||
| 95 | |||
| 96 | pkt->pa_base = dma_addr; | ||
| 97 | |||
| 98 | return pkt; | ||
| 99 | } | ||
| 100 | EXPORT_SYMBOL(cmdq_pkt_create); | ||
| 101 | |||
| 102 | void cmdq_pkt_destroy(struct cmdq_pkt *pkt) | ||
| 103 | { | ||
| 104 | struct cmdq_client *client = (struct cmdq_client *)pkt->cl; | ||
| 105 | |||
| 106 | dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size, | ||
| 107 | DMA_TO_DEVICE); | ||
| 108 | kfree(pkt->va_base); | ||
| 109 | kfree(pkt); | ||
| 110 | } | ||
| 111 | EXPORT_SYMBOL(cmdq_pkt_destroy); | ||
| 112 | |||
| 113 | static int cmdq_pkt_append_command(struct cmdq_pkt *pkt, enum cmdq_code code, | ||
| 114 | u32 arg_a, u32 arg_b) | ||
| 115 | { | ||
| 116 | u64 *cmd_ptr; | ||
| 117 | |||
| 118 | if (unlikely(pkt->cmd_buf_size + CMDQ_INST_SIZE > pkt->buf_size)) { | ||
| 119 | /* | ||
| 120 | * In the case of allocated buffer size (pkt->buf_size) is used | ||
| 121 | * up, the real required size (pkt->cmdq_buf_size) is still | ||
| 122 | * increased, so that the user knows how much memory should be | ||
| 123 | * ultimately allocated after appending all commands and | ||
| 124 | * flushing the command packet. Therefor, the user can call | ||
| 125 | * cmdq_pkt_create() again with the real required buffer size. | ||
| 126 | */ | ||
| 127 | pkt->cmd_buf_size += CMDQ_INST_SIZE; | ||
| 128 | WARN_ONCE(1, "%s: buffer size %u is too small !\n", | ||
| 129 | __func__, (u32)pkt->buf_size); | ||
| 130 | return -ENOMEM; | ||
| 131 | } | ||
| 132 | cmd_ptr = pkt->va_base + pkt->cmd_buf_size; | ||
| 133 | (*cmd_ptr) = (u64)((code << CMDQ_OP_CODE_SHIFT) | arg_a) << 32 | arg_b; | ||
| 134 | pkt->cmd_buf_size += CMDQ_INST_SIZE; | ||
| 135 | |||
| 136 | return 0; | ||
| 137 | } | ||
| 138 | |||
| 139 | int cmdq_pkt_write(struct cmdq_pkt *pkt, u32 value, u32 subsys, u32 offset) | ||
| 140 | { | ||
| 141 | u32 arg_a = (offset & CMDQ_ARG_A_WRITE_MASK) | | ||
| 142 | (subsys << CMDQ_SUBSYS_SHIFT); | ||
| 143 | |||
| 144 | return cmdq_pkt_append_command(pkt, CMDQ_CODE_WRITE, arg_a, value); | ||
| 145 | } | ||
| 146 | EXPORT_SYMBOL(cmdq_pkt_write); | ||
| 147 | |||
| 148 | int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u32 value, | ||
| 149 | u32 subsys, u32 offset, u32 mask) | ||
| 150 | { | ||
| 151 | u32 offset_mask = offset; | ||
| 152 | int err = 0; | ||
| 153 | |||
| 154 | if (mask != 0xffffffff) { | ||
| 155 | err = cmdq_pkt_append_command(pkt, CMDQ_CODE_MASK, 0, ~mask); | ||
| 156 | offset_mask |= CMDQ_WRITE_ENABLE_MASK; | ||
| 157 | } | ||
| 158 | err |= cmdq_pkt_write(pkt, value, subsys, offset_mask); | ||
| 159 | |||
| 160 | return err; | ||
| 161 | } | ||
| 162 | EXPORT_SYMBOL(cmdq_pkt_write_mask); | ||
| 163 | |||
| 164 | int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u32 event) | ||
| 165 | { | ||
| 166 | u32 arg_b; | ||
| 167 | |||
| 168 | if (event >= CMDQ_MAX_EVENT) | ||
| 169 | return -EINVAL; | ||
| 170 | |||
| 171 | /* | ||
| 172 | * WFE arg_b | ||
| 173 | * bit 0-11: wait value | ||
| 174 | * bit 15: 1 - wait, 0 - no wait | ||
| 175 | * bit 16-27: update value | ||
| 176 | * bit 31: 1 - update, 0 - no update | ||
| 177 | */ | ||
| 178 | arg_b = CMDQ_WFE_UPDATE | CMDQ_WFE_WAIT | CMDQ_WFE_WAIT_VALUE; | ||
| 179 | |||
| 180 | return cmdq_pkt_append_command(pkt, CMDQ_CODE_WFE, event, arg_b); | ||
| 181 | } | ||
| 182 | EXPORT_SYMBOL(cmdq_pkt_wfe); | ||
| 183 | |||
| 184 | int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u32 event) | ||
| 185 | { | ||
| 186 | if (event >= CMDQ_MAX_EVENT) | ||
| 187 | return -EINVAL; | ||
| 188 | |||
| 189 | return cmdq_pkt_append_command(pkt, CMDQ_CODE_WFE, event, | ||
| 190 | CMDQ_WFE_UPDATE); | ||
| 191 | } | ||
| 192 | EXPORT_SYMBOL(cmdq_pkt_clear_event); | ||
| 193 | |||
| 194 | static int cmdq_pkt_finalize(struct cmdq_pkt *pkt) | ||
| 195 | { | ||
| 196 | int err; | ||
| 197 | |||
| 198 | /* insert EOC and generate IRQ for each command iteration */ | ||
| 199 | err = cmdq_pkt_append_command(pkt, CMDQ_CODE_EOC, 0, CMDQ_EOC_IRQ_EN); | ||
| 200 | |||
| 201 | /* JUMP to end */ | ||
| 202 | err |= cmdq_pkt_append_command(pkt, CMDQ_CODE_JUMP, 0, CMDQ_JUMP_PASS); | ||
| 203 | |||
| 204 | return err; | ||
| 205 | } | ||
| 206 | |||
| 207 | static void cmdq_pkt_flush_async_cb(struct cmdq_cb_data data) | ||
| 208 | { | ||
| 209 | struct cmdq_pkt *pkt = (struct cmdq_pkt *)data.data; | ||
| 210 | struct cmdq_task_cb *cb = &pkt->cb; | ||
| 211 | struct cmdq_client *client = (struct cmdq_client *)pkt->cl; | ||
| 212 | |||
| 213 | if (client->timeout_ms != CMDQ_NO_TIMEOUT) { | ||
| 214 | unsigned long flags = 0; | ||
| 215 | |||
| 216 | spin_lock_irqsave(&client->lock, flags); | ||
| 217 | if (--client->pkt_cnt == 0) | ||
| 218 | del_timer(&client->timer); | ||
| 219 | else | ||
| 220 | mod_timer(&client->timer, jiffies + | ||
| 221 | msecs_to_jiffies(client->timeout_ms)); | ||
| 222 | spin_unlock_irqrestore(&client->lock, flags); | ||
| 223 | } | ||
| 224 | |||
| 225 | dma_sync_single_for_cpu(client->chan->mbox->dev, pkt->pa_base, | ||
| 226 | pkt->cmd_buf_size, DMA_TO_DEVICE); | ||
| 227 | if (cb->cb) { | ||
| 228 | data.data = cb->data; | ||
| 229 | cb->cb(data); | ||
| 230 | } | ||
| 231 | } | ||
| 232 | |||
| 233 | int cmdq_pkt_flush_async(struct cmdq_pkt *pkt, cmdq_async_flush_cb cb, | ||
| 234 | void *data) | ||
| 235 | { | ||
| 236 | int err; | ||
| 237 | unsigned long flags = 0; | ||
| 238 | struct cmdq_client *client = (struct cmdq_client *)pkt->cl; | ||
| 239 | |||
| 240 | err = cmdq_pkt_finalize(pkt); | ||
| 241 | if (err < 0) | ||
| 242 | return err; | ||
| 243 | |||
| 244 | pkt->cb.cb = cb; | ||
| 245 | pkt->cb.data = data; | ||
| 246 | pkt->async_cb.cb = cmdq_pkt_flush_async_cb; | ||
| 247 | pkt->async_cb.data = pkt; | ||
| 248 | |||
| 249 | dma_sync_single_for_device(client->chan->mbox->dev, pkt->pa_base, | ||
| 250 | pkt->cmd_buf_size, DMA_TO_DEVICE); | ||
| 251 | |||
| 252 | if (client->timeout_ms != CMDQ_NO_TIMEOUT) { | ||
| 253 | spin_lock_irqsave(&client->lock, flags); | ||
| 254 | if (client->pkt_cnt++ == 0) | ||
| 255 | mod_timer(&client->timer, jiffies + | ||
| 256 | msecs_to_jiffies(client->timeout_ms)); | ||
| 257 | spin_unlock_irqrestore(&client->lock, flags); | ||
| 258 | } | ||
| 259 | |||
| 260 | mbox_send_message(client->chan, pkt); | ||
| 261 | /* We can send next packet immediately, so just call txdone. */ | ||
| 262 | mbox_client_txdone(client->chan, 0); | ||
| 263 | |||
| 264 | return 0; | ||
| 265 | } | ||
| 266 | EXPORT_SYMBOL(cmdq_pkt_flush_async); | ||
| 267 | |||
| 268 | struct cmdq_flush_completion { | ||
| 269 | struct completion cmplt; | ||
| 270 | bool err; | ||
| 271 | }; | ||
| 272 | |||
| 273 | static void cmdq_pkt_flush_cb(struct cmdq_cb_data data) | ||
| 274 | { | ||
| 275 | struct cmdq_flush_completion *cmplt; | ||
| 276 | |||
| 277 | cmplt = (struct cmdq_flush_completion *)data.data; | ||
| 278 | if (data.sta != CMDQ_CB_NORMAL) | ||
| 279 | cmplt->err = true; | ||
| 280 | else | ||
| 281 | cmplt->err = false; | ||
| 282 | complete(&cmplt->cmplt); | ||
| 283 | } | ||
| 284 | |||
| 285 | int cmdq_pkt_flush(struct cmdq_pkt *pkt) | ||
| 286 | { | ||
| 287 | struct cmdq_flush_completion cmplt; | ||
| 288 | int err; | ||
| 289 | |||
| 290 | init_completion(&cmplt.cmplt); | ||
| 291 | err = cmdq_pkt_flush_async(pkt, cmdq_pkt_flush_cb, &cmplt); | ||
| 292 | if (err < 0) | ||
| 293 | return err; | ||
| 294 | wait_for_completion(&cmplt.cmplt); | ||
| 295 | |||
| 296 | return cmplt.err ? -EFAULT : 0; | ||
| 297 | } | ||
| 298 | EXPORT_SYMBOL(cmdq_pkt_flush); | ||
| 299 | |||
| 300 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 684cb51694d1..fcbf8a2e4080 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig | |||
| @@ -75,11 +75,6 @@ config QCOM_QMI_HELPERS | |||
| 75 | tristate | 75 | tristate |
| 76 | depends on ARCH_QCOM || COMPILE_TEST | 76 | depends on ARCH_QCOM || COMPILE_TEST |
| 77 | depends on NET | 77 | depends on NET |
| 78 | help | ||
| 79 | Helper library for handling QMI encoded messages. QMI encoded | ||
| 80 | messages are used in communication between the majority of QRTR | ||
| 81 | clients and this helpers provide the common functionality needed for | ||
| 82 | doing this from a kernel driver. | ||
| 83 | 78 | ||
| 84 | config QCOM_RMTFS_MEM | 79 | config QCOM_RMTFS_MEM |
| 85 | tristate "Qualcomm Remote Filesystem memory driver" | 80 | tristate "Qualcomm Remote Filesystem memory driver" |
diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c index a6f646295f06..c701b3b010f1 100644 --- a/drivers/soc/qcom/cmd-db.c +++ b/drivers/soc/qcom/cmd-db.c | |||
| @@ -101,8 +101,7 @@ static bool cmd_db_magic_matches(const struct cmd_db_header *header) | |||
| 101 | 101 | ||
| 102 | static struct cmd_db_header *cmd_db_header; | 102 | static struct cmd_db_header *cmd_db_header; |
| 103 | 103 | ||
| 104 | 104 | static inline const void *rsc_to_entry_header(const struct rsc_hdr *hdr) | |
| 105 | static inline void *rsc_to_entry_header(struct rsc_hdr *hdr) | ||
| 106 | { | 105 | { |
| 107 | u16 offset = le16_to_cpu(hdr->header_offset); | 106 | u16 offset = le16_to_cpu(hdr->header_offset); |
| 108 | 107 | ||
| @@ -110,7 +109,7 @@ static inline void *rsc_to_entry_header(struct rsc_hdr *hdr) | |||
| 110 | } | 109 | } |
| 111 | 110 | ||
| 112 | static inline void * | 111 | static inline void * |
| 113 | rsc_offset(struct rsc_hdr *hdr, struct entry_header *ent) | 112 | rsc_offset(const struct rsc_hdr *hdr, const struct entry_header *ent) |
| 114 | { | 113 | { |
| 115 | u16 offset = le16_to_cpu(hdr->data_offset); | 114 | u16 offset = le16_to_cpu(hdr->data_offset); |
| 116 | u16 loffset = le16_to_cpu(ent->offset); | 115 | u16 loffset = le16_to_cpu(ent->offset); |
| @@ -134,11 +133,11 @@ int cmd_db_ready(void) | |||
| 134 | } | 133 | } |
| 135 | EXPORT_SYMBOL(cmd_db_ready); | 134 | EXPORT_SYMBOL(cmd_db_ready); |
| 136 | 135 | ||
| 137 | static int cmd_db_get_header(const char *id, struct entry_header *eh, | 136 | static int cmd_db_get_header(const char *id, const struct entry_header **eh, |
| 138 | struct rsc_hdr *rh) | 137 | const struct rsc_hdr **rh) |
| 139 | { | 138 | { |
| 140 | struct rsc_hdr *rsc_hdr; | 139 | const struct rsc_hdr *rsc_hdr; |
| 141 | struct entry_header *ent; | 140 | const struct entry_header *ent; |
| 142 | int ret, i, j; | 141 | int ret, i, j; |
| 143 | u8 query[8]; | 142 | u8 query[8]; |
| 144 | 143 | ||
| @@ -146,9 +145,6 @@ static int cmd_db_get_header(const char *id, struct entry_header *eh, | |||
| 146 | if (ret) | 145 | if (ret) |
| 147 | return ret; | 146 | return ret; |
| 148 | 147 | ||
| 149 | if (!eh || !rh) | ||
| 150 | return -EINVAL; | ||
| 151 | |||
| 152 | /* Pad out query string to same length as in DB */ | 148 | /* Pad out query string to same length as in DB */ |
| 153 | strncpy(query, id, sizeof(query)); | 149 | strncpy(query, id, sizeof(query)); |
| 154 | 150 | ||
| @@ -159,14 +155,13 @@ static int cmd_db_get_header(const char *id, struct entry_header *eh, | |||
| 159 | 155 | ||
| 160 | ent = rsc_to_entry_header(rsc_hdr); | 156 | ent = rsc_to_entry_header(rsc_hdr); |
| 161 | for (j = 0; j < le16_to_cpu(rsc_hdr->cnt); j++, ent++) { | 157 | for (j = 0; j < le16_to_cpu(rsc_hdr->cnt); j++, ent++) { |
| 162 | if (memcmp(ent->id, query, sizeof(ent->id)) == 0) | 158 | if (memcmp(ent->id, query, sizeof(ent->id)) == 0) { |
| 163 | break; | 159 | if (eh) |
| 164 | } | 160 | *eh = ent; |
| 165 | 161 | if (rh) | |
| 166 | if (j < le16_to_cpu(rsc_hdr->cnt)) { | 162 | *rh = rsc_hdr; |
| 167 | memcpy(eh, ent, sizeof(*ent)); | 163 | return 0; |
| 168 | memcpy(rh, rsc_hdr, sizeof(*rh)); | 164 | } |
| 169 | return 0; | ||
| 170 | } | 165 | } |
| 171 | } | 166 | } |
| 172 | 167 | ||
| @@ -186,69 +181,40 @@ static int cmd_db_get_header(const char *id, struct entry_header *eh, | |||
| 186 | u32 cmd_db_read_addr(const char *id) | 181 | u32 cmd_db_read_addr(const char *id) |
| 187 | { | 182 | { |
| 188 | int ret; | 183 | int ret; |
| 189 | struct entry_header ent; | 184 | const struct entry_header *ent; |
| 190 | struct rsc_hdr rsc_hdr; | ||
| 191 | 185 | ||
| 192 | ret = cmd_db_get_header(id, &ent, &rsc_hdr); | 186 | ret = cmd_db_get_header(id, &ent, NULL); |
| 193 | 187 | ||
| 194 | return ret < 0 ? 0 : le32_to_cpu(ent.addr); | 188 | return ret < 0 ? 0 : le32_to_cpu(ent->addr); |
| 195 | } | 189 | } |
| 196 | EXPORT_SYMBOL(cmd_db_read_addr); | 190 | EXPORT_SYMBOL(cmd_db_read_addr); |
| 197 | 191 | ||
| 198 | /** | 192 | /** |
| 199 | * cmd_db_read_aux_data() - Query command db for aux data. | 193 | * cmd_db_read_aux_data() - Query command db for aux data. |
| 200 | * | 194 | * |
| 201 | * @id: Resource to retrieve AUX Data on. | 195 | * @id: Resource to retrieve AUX Data on |
| 202 | * @data: Data buffer to copy returned aux data to. Returns size on NULL | 196 | * @len: size of data buffer returned |
| 203 | * @len: Caller provides size of data buffer passed in. | ||
| 204 | * | 197 | * |
| 205 | * Return: size of data on success, errno otherwise | 198 | * Return: pointer to data on success, error pointer otherwise |
| 206 | */ | 199 | */ |
| 207 | int cmd_db_read_aux_data(const char *id, u8 *data, size_t len) | 200 | const void *cmd_db_read_aux_data(const char *id, size_t *len) |
| 208 | { | 201 | { |
| 209 | int ret; | 202 | int ret; |
| 210 | struct entry_header ent; | 203 | const struct entry_header *ent; |
| 211 | struct rsc_hdr rsc_hdr; | 204 | const struct rsc_hdr *rsc_hdr; |
| 212 | u16 ent_len; | ||
| 213 | |||
| 214 | if (!data) | ||
| 215 | return -EINVAL; | ||
| 216 | 205 | ||
| 217 | ret = cmd_db_get_header(id, &ent, &rsc_hdr); | 206 | ret = cmd_db_get_header(id, &ent, &rsc_hdr); |
| 218 | if (ret) | 207 | if (ret) |
| 219 | return ret; | 208 | return ERR_PTR(ret); |
| 220 | 209 | ||
| 221 | ent_len = le16_to_cpu(ent.len); | 210 | if (len) |
| 222 | if (len < ent_len) | 211 | *len = le16_to_cpu(ent->len); |
| 223 | return -EINVAL; | ||
| 224 | |||
| 225 | len = min_t(u16, ent_len, len); | ||
| 226 | memcpy(data, rsc_offset(&rsc_hdr, &ent), len); | ||
| 227 | 212 | ||
| 228 | return len; | 213 | return rsc_offset(rsc_hdr, ent); |
| 229 | } | 214 | } |
| 230 | EXPORT_SYMBOL(cmd_db_read_aux_data); | 215 | EXPORT_SYMBOL(cmd_db_read_aux_data); |
| 231 | 216 | ||
| 232 | /** | 217 | /** |
| 233 | * cmd_db_read_aux_data_len - Get the length of the auxiliary data stored in DB. | ||
| 234 | * | ||
| 235 | * @id: Resource to retrieve AUX Data. | ||
| 236 | * | ||
| 237 | * Return: size on success, 0 on error | ||
| 238 | */ | ||
| 239 | size_t cmd_db_read_aux_data_len(const char *id) | ||
| 240 | { | ||
| 241 | int ret; | ||
| 242 | struct entry_header ent; | ||
| 243 | struct rsc_hdr rsc_hdr; | ||
| 244 | |||
| 245 | ret = cmd_db_get_header(id, &ent, &rsc_hdr); | ||
| 246 | |||
| 247 | return ret < 0 ? 0 : le16_to_cpu(ent.len); | ||
| 248 | } | ||
| 249 | EXPORT_SYMBOL(cmd_db_read_aux_data_len); | ||
| 250 | |||
| 251 | /** | ||
| 252 | * cmd_db_read_slave_id - Get the slave ID for a given resource address | 218 | * cmd_db_read_slave_id - Get the slave ID for a given resource address |
| 253 | * | 219 | * |
| 254 | * @id: Resource id to query the DB for version | 220 | * @id: Resource id to query the DB for version |
| @@ -258,15 +224,14 @@ EXPORT_SYMBOL(cmd_db_read_aux_data_len); | |||
| 258 | enum cmd_db_hw_type cmd_db_read_slave_id(const char *id) | 224 | enum cmd_db_hw_type cmd_db_read_slave_id(const char *id) |
| 259 | { | 225 | { |
| 260 | int ret; | 226 | int ret; |
| 261 | struct entry_header ent; | 227 | const struct entry_header *ent; |
| 262 | struct rsc_hdr rsc_hdr; | ||
| 263 | u32 addr; | 228 | u32 addr; |
| 264 | 229 | ||
| 265 | ret = cmd_db_get_header(id, &ent, &rsc_hdr); | 230 | ret = cmd_db_get_header(id, &ent, NULL); |
| 266 | if (ret < 0) | 231 | if (ret < 0) |
| 267 | return CMD_DB_HW_INVALID; | 232 | return CMD_DB_HW_INVALID; |
| 268 | 233 | ||
| 269 | addr = le32_to_cpu(ent.addr); | 234 | addr = le32_to_cpu(ent->addr); |
| 270 | return (addr >> SLAVE_ID_SHIFT) & SLAVE_ID_MASK; | 235 | return (addr >> SLAVE_ID_SHIFT) & SLAVE_ID_MASK; |
| 271 | } | 236 | } |
| 272 | EXPORT_SYMBOL(cmd_db_read_slave_id); | 237 | EXPORT_SYMBOL(cmd_db_read_slave_id); |
diff --git a/drivers/soc/qcom/llcc-slice.c b/drivers/soc/qcom/llcc-slice.c index 192ca761b2cb..80667f7be52c 100644 --- a/drivers/soc/qcom/llcc-slice.c +++ b/drivers/soc/qcom/llcc-slice.c | |||
| @@ -95,7 +95,8 @@ EXPORT_SYMBOL_GPL(llcc_slice_getd); | |||
| 95 | */ | 95 | */ |
| 96 | void llcc_slice_putd(struct llcc_slice_desc *desc) | 96 | void llcc_slice_putd(struct llcc_slice_desc *desc) |
| 97 | { | 97 | { |
| 98 | kfree(desc); | 98 | if (!IS_ERR_OR_NULL(desc)) |
| 99 | kfree(desc); | ||
| 99 | } | 100 | } |
| 100 | EXPORT_SYMBOL_GPL(llcc_slice_putd); | 101 | EXPORT_SYMBOL_GPL(llcc_slice_putd); |
| 101 | 102 | ||
| @@ -142,6 +143,9 @@ int llcc_slice_activate(struct llcc_slice_desc *desc) | |||
| 142 | int ret; | 143 | int ret; |
| 143 | u32 act_ctrl_val; | 144 | u32 act_ctrl_val; |
| 144 | 145 | ||
| 146 | if (IS_ERR_OR_NULL(desc)) | ||
| 147 | return -EINVAL; | ||
| 148 | |||
| 145 | mutex_lock(&drv_data->lock); | 149 | mutex_lock(&drv_data->lock); |
| 146 | if (test_bit(desc->slice_id, drv_data->bitmap)) { | 150 | if (test_bit(desc->slice_id, drv_data->bitmap)) { |
| 147 | mutex_unlock(&drv_data->lock); | 151 | mutex_unlock(&drv_data->lock); |
| @@ -176,6 +180,9 @@ int llcc_slice_deactivate(struct llcc_slice_desc *desc) | |||
| 176 | u32 act_ctrl_val; | 180 | u32 act_ctrl_val; |
| 177 | int ret; | 181 | int ret; |
| 178 | 182 | ||
| 183 | if (IS_ERR_OR_NULL(desc)) | ||
| 184 | return -EINVAL; | ||
| 185 | |||
| 179 | mutex_lock(&drv_data->lock); | 186 | mutex_lock(&drv_data->lock); |
| 180 | if (!test_bit(desc->slice_id, drv_data->bitmap)) { | 187 | if (!test_bit(desc->slice_id, drv_data->bitmap)) { |
| 181 | mutex_unlock(&drv_data->lock); | 188 | mutex_unlock(&drv_data->lock); |
| @@ -203,6 +210,9 @@ EXPORT_SYMBOL_GPL(llcc_slice_deactivate); | |||
| 203 | */ | 210 | */ |
| 204 | int llcc_get_slice_id(struct llcc_slice_desc *desc) | 211 | int llcc_get_slice_id(struct llcc_slice_desc *desc) |
| 205 | { | 212 | { |
| 213 | if (IS_ERR_OR_NULL(desc)) | ||
| 214 | return -EINVAL; | ||
| 215 | |||
| 206 | return desc->slice_id; | 216 | return desc->slice_id; |
| 207 | } | 217 | } |
| 208 | EXPORT_SYMBOL_GPL(llcc_get_slice_id); | 218 | EXPORT_SYMBOL_GPL(llcc_get_slice_id); |
| @@ -213,6 +223,9 @@ EXPORT_SYMBOL_GPL(llcc_get_slice_id); | |||
| 213 | */ | 223 | */ |
| 214 | size_t llcc_get_slice_size(struct llcc_slice_desc *desc) | 224 | size_t llcc_get_slice_size(struct llcc_slice_desc *desc) |
| 215 | { | 225 | { |
| 226 | if (IS_ERR_OR_NULL(desc)) | ||
| 227 | return 0; | ||
| 228 | |||
| 216 | return desc->slice_size; | 229 | return desc->slice_size; |
| 217 | } | 230 | } |
| 218 | EXPORT_SYMBOL_GPL(llcc_get_slice_size); | 231 | EXPORT_SYMBOL_GPL(llcc_get_slice_size); |
| @@ -360,5 +373,5 @@ int qcom_llcc_probe(struct platform_device *pdev, | |||
| 360 | return ret; | 373 | return ret; |
| 361 | } | 374 | } |
| 362 | EXPORT_SYMBOL_GPL(qcom_llcc_probe); | 375 | EXPORT_SYMBOL_GPL(qcom_llcc_probe); |
| 363 | |||
| 364 | MODULE_LICENSE("GPL v2"); | 376 | MODULE_LICENSE("GPL v2"); |
| 377 | MODULE_DESCRIPTION("Qualcomm Last Level Cache Controller"); | ||
diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index ee89ffb6dde8..6b8ef01472e9 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c | |||
| @@ -215,6 +215,16 @@ static void geni_se_io_init(void __iomem *base) | |||
| 215 | writel_relaxed(FORCE_DEFAULT, base + GENI_FORCE_DEFAULT_REG); | 215 | writel_relaxed(FORCE_DEFAULT, base + GENI_FORCE_DEFAULT_REG); |
| 216 | } | 216 | } |
| 217 | 217 | ||
| 218 | static void geni_se_irq_clear(struct geni_se *se) | ||
| 219 | { | ||
| 220 | writel_relaxed(0, se->base + SE_GSI_EVENT_EN); | ||
| 221 | writel_relaxed(0xffffffff, se->base + SE_GENI_M_IRQ_CLEAR); | ||
| 222 | writel_relaxed(0xffffffff, se->base + SE_GENI_S_IRQ_CLEAR); | ||
| 223 | writel_relaxed(0xffffffff, se->base + SE_DMA_TX_IRQ_CLR); | ||
| 224 | writel_relaxed(0xffffffff, se->base + SE_DMA_RX_IRQ_CLR); | ||
| 225 | writel_relaxed(0xffffffff, se->base + SE_IRQ_EN); | ||
| 226 | } | ||
| 227 | |||
| 218 | /** | 228 | /** |
| 219 | * geni_se_init() - Initialize the GENI serial engine | 229 | * geni_se_init() - Initialize the GENI serial engine |
| 220 | * @se: Pointer to the concerned serial engine. | 230 | * @se: Pointer to the concerned serial engine. |
| @@ -228,6 +238,7 @@ void geni_se_init(struct geni_se *se, u32 rx_wm, u32 rx_rfr) | |||
| 228 | { | 238 | { |
| 229 | u32 val; | 239 | u32 val; |
| 230 | 240 | ||
| 241 | geni_se_irq_clear(se); | ||
| 231 | geni_se_io_init(se->base); | 242 | geni_se_io_init(se->base); |
| 232 | geni_se_io_set_mode(se->base); | 243 | geni_se_io_set_mode(se->base); |
| 233 | 244 | ||
| @@ -249,12 +260,7 @@ static void geni_se_select_fifo_mode(struct geni_se *se) | |||
| 249 | u32 proto = geni_se_read_proto(se); | 260 | u32 proto = geni_se_read_proto(se); |
| 250 | u32 val; | 261 | u32 val; |
| 251 | 262 | ||
| 252 | writel_relaxed(0, se->base + SE_GSI_EVENT_EN); | 263 | geni_se_irq_clear(se); |
| 253 | writel_relaxed(0xffffffff, se->base + SE_GENI_M_IRQ_CLEAR); | ||
| 254 | writel_relaxed(0xffffffff, se->base + SE_GENI_S_IRQ_CLEAR); | ||
| 255 | writel_relaxed(0xffffffff, se->base + SE_DMA_TX_IRQ_CLR); | ||
| 256 | writel_relaxed(0xffffffff, se->base + SE_DMA_RX_IRQ_CLR); | ||
| 257 | writel_relaxed(0xffffffff, se->base + SE_IRQ_EN); | ||
| 258 | 264 | ||
| 259 | val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN); | 265 | val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN); |
| 260 | if (proto != GENI_SE_UART) { | 266 | if (proto != GENI_SE_UART) { |
| @@ -277,12 +283,7 @@ static void geni_se_select_dma_mode(struct geni_se *se) | |||
| 277 | { | 283 | { |
| 278 | u32 val; | 284 | u32 val; |
| 279 | 285 | ||
| 280 | writel_relaxed(0, se->base + SE_GSI_EVENT_EN); | 286 | geni_se_irq_clear(se); |
| 281 | writel_relaxed(0xffffffff, se->base + SE_GENI_M_IRQ_CLEAR); | ||
| 282 | writel_relaxed(0xffffffff, se->base + SE_GENI_S_IRQ_CLEAR); | ||
| 283 | writel_relaxed(0xffffffff, se->base + SE_DMA_TX_IRQ_CLR); | ||
| 284 | writel_relaxed(0xffffffff, se->base + SE_DMA_RX_IRQ_CLR); | ||
| 285 | writel_relaxed(0xffffffff, se->base + SE_IRQ_EN); | ||
| 286 | 287 | ||
| 287 | val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN); | 288 | val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN); |
| 288 | val |= GENI_DMA_MODE_EN; | 289 | val |= GENI_DMA_MODE_EN; |
diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c index 938ca41c56cd..c239a28e503f 100644 --- a/drivers/soc/qcom/qmi_interface.c +++ b/drivers/soc/qcom/qmi_interface.c | |||
| @@ -318,7 +318,7 @@ int qmi_txn_init(struct qmi_handle *qmi, struct qmi_txn *txn, | |||
| 318 | txn->dest = c_struct; | 318 | txn->dest = c_struct; |
| 319 | 319 | ||
| 320 | mutex_lock(&qmi->txn_lock); | 320 | mutex_lock(&qmi->txn_lock); |
| 321 | ret = idr_alloc_cyclic(&qmi->txns, txn, 0, INT_MAX, GFP_KERNEL); | 321 | ret = idr_alloc_cyclic(&qmi->txns, txn, 0, U16_MAX, GFP_KERNEL); |
| 322 | if (ret < 0) | 322 | if (ret < 0) |
| 323 | pr_err("failed to allocate transaction id\n"); | 323 | pr_err("failed to allocate transaction id\n"); |
| 324 | 324 | ||
diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c index 93517ed83355..b8e63724a49d 100644 --- a/drivers/soc/qcom/smd-rpm.c +++ b/drivers/soc/qcom/smd-rpm.c | |||
| @@ -227,6 +227,7 @@ static const struct of_device_id qcom_smd_rpm_of_match[] = { | |||
| 227 | { .compatible = "qcom,rpm-msm8974" }, | 227 | { .compatible = "qcom,rpm-msm8974" }, |
| 228 | { .compatible = "qcom,rpm-msm8996" }, | 228 | { .compatible = "qcom,rpm-msm8996" }, |
| 229 | { .compatible = "qcom,rpm-msm8998" }, | 229 | { .compatible = "qcom,rpm-msm8998" }, |
| 230 | { .compatible = "qcom,rpm-qcs404" }, | ||
| 230 | {} | 231 | {} |
| 231 | }; | 232 | }; |
| 232 | MODULE_DEVICE_TABLE(of, qcom_smd_rpm_of_match); | 233 | MODULE_DEVICE_TABLE(of, qcom_smd_rpm_of_match); |
diff --git a/drivers/soc/renesas/r8a77965-sysc.c b/drivers/soc/renesas/r8a77965-sysc.c index d7f7928e3c07..e0533beb50fd 100644 --- a/drivers/soc/renesas/r8a77965-sysc.c +++ b/drivers/soc/renesas/r8a77965-sysc.c | |||
| @@ -28,7 +28,6 @@ static const struct rcar_sysc_area r8a77965_areas[] __initconst = { | |||
| 28 | { "a2vc1", 0x3c0, 1, R8A77965_PD_A2VC1, R8A77965_PD_A3VC }, | 28 | { "a2vc1", 0x3c0, 1, R8A77965_PD_A2VC1, R8A77965_PD_A3VC }, |
| 29 | { "3dg-a", 0x100, 0, R8A77965_PD_3DG_A, R8A77965_PD_ALWAYS_ON }, | 29 | { "3dg-a", 0x100, 0, R8A77965_PD_3DG_A, R8A77965_PD_ALWAYS_ON }, |
| 30 | { "3dg-b", 0x100, 1, R8A77965_PD_3DG_B, R8A77965_PD_3DG_A }, | 30 | { "3dg-b", 0x100, 1, R8A77965_PD_3DG_B, R8A77965_PD_3DG_A }, |
| 31 | { "a3ir", 0x180, 0, R8A77965_PD_A3IR, R8A77965_PD_ALWAYS_ON }, | ||
| 32 | }; | 31 | }; |
| 33 | 32 | ||
| 34 | const struct rcar_sysc_info r8a77965_sysc_info __initconst = { | 33 | const struct rcar_sysc_info r8a77965_sysc_info __initconst = { |
diff --git a/drivers/soc/renesas/r8a77970-sysc.c b/drivers/soc/renesas/r8a77970-sysc.c index 35b30d6a8958..280c48b80f24 100644 --- a/drivers/soc/renesas/r8a77970-sysc.c +++ b/drivers/soc/renesas/r8a77970-sysc.c | |||
| @@ -20,12 +20,11 @@ static const struct rcar_sysc_area r8a77970_areas[] __initconst = { | |||
| 20 | PD_CPU_NOCR }, | 20 | PD_CPU_NOCR }, |
| 21 | { "ca53-cpu1", 0x200, 1, R8A77970_PD_CA53_CPU1, R8A77970_PD_CA53_SCU, | 21 | { "ca53-cpu1", 0x200, 1, R8A77970_PD_CA53_CPU1, R8A77970_PD_CA53_SCU, |
| 22 | PD_CPU_NOCR }, | 22 | PD_CPU_NOCR }, |
| 23 | { "cr7", 0x240, 0, R8A77970_PD_CR7, R8A77970_PD_ALWAYS_ON }, | ||
| 24 | { "a3ir", 0x180, 0, R8A77970_PD_A3IR, R8A77970_PD_ALWAYS_ON }, | 23 | { "a3ir", 0x180, 0, R8A77970_PD_A3IR, R8A77970_PD_ALWAYS_ON }, |
| 25 | { "a2ir0", 0x400, 0, R8A77970_PD_A2IR0, R8A77970_PD_A3IR }, | 24 | { "a2ir0", 0x400, 0, R8A77970_PD_A2IR0, R8A77970_PD_A3IR }, |
| 26 | { "a2ir1", 0x400, 1, R8A77970_PD_A2IR1, R8A77970_PD_A3IR }, | 25 | { "a2ir1", 0x400, 1, R8A77970_PD_A2IR1, R8A77970_PD_A3IR }, |
| 27 | { "a2ir2", 0x400, 2, R8A77970_PD_A2IR2, R8A77970_PD_A3IR }, | 26 | { "a2dp", 0x400, 2, R8A77970_PD_A2DP, R8A77970_PD_A3IR }, |
| 28 | { "a2ir3", 0x400, 3, R8A77970_PD_A2IR3, R8A77970_PD_A3IR }, | 27 | { "a2cn", 0x400, 3, R8A77970_PD_A2CN, R8A77970_PD_A3IR }, |
| 29 | { "a2sc0", 0x400, 4, R8A77970_PD_A2SC0, R8A77970_PD_A3IR }, | 28 | { "a2sc0", 0x400, 4, R8A77970_PD_A2SC0, R8A77970_PD_A3IR }, |
| 30 | { "a2sc1", 0x400, 5, R8A77970_PD_A2SC1, R8A77970_PD_A3IR }, | 29 | { "a2sc1", 0x400, 5, R8A77970_PD_A2SC1, R8A77970_PD_A3IR }, |
| 31 | }; | 30 | }; |
diff --git a/drivers/soc/renesas/r8a77980-sysc.c b/drivers/soc/renesas/r8a77980-sysc.c index 9265fb525ef3..a8dbe55e8ba8 100644 --- a/drivers/soc/renesas/r8a77980-sysc.c +++ b/drivers/soc/renesas/r8a77980-sysc.c | |||
| @@ -38,12 +38,12 @@ static const struct rcar_sysc_area r8a77980_areas[] __initconst = { | |||
| 38 | { "a2sc2", 0x400, 8, R8A77980_PD_A2SC2, R8A77980_PD_A3IR }, | 38 | { "a2sc2", 0x400, 8, R8A77980_PD_A2SC2, R8A77980_PD_A3IR }, |
| 39 | { "a2sc3", 0x400, 9, R8A77980_PD_A2SC3, R8A77980_PD_A3IR }, | 39 | { "a2sc3", 0x400, 9, R8A77980_PD_A2SC3, R8A77980_PD_A3IR }, |
| 40 | { "a2sc4", 0x400, 10, R8A77980_PD_A2SC4, R8A77980_PD_A3IR }, | 40 | { "a2sc4", 0x400, 10, R8A77980_PD_A2SC4, R8A77980_PD_A3IR }, |
| 41 | { "a2pd0", 0x400, 11, R8A77980_PD_A2PD0, R8A77980_PD_A3IR }, | 41 | { "a2dp0", 0x400, 11, R8A77980_PD_A2DP0, R8A77980_PD_A3IR }, |
| 42 | { "a2pd1", 0x400, 12, R8A77980_PD_A2PD1, R8A77980_PD_A3IR }, | 42 | { "a2dp1", 0x400, 12, R8A77980_PD_A2DP1, R8A77980_PD_A3IR }, |
| 43 | { "a2cn", 0x400, 13, R8A77980_PD_A2CN, R8A77980_PD_A3IR }, | 43 | { "a2cn", 0x400, 13, R8A77980_PD_A2CN, R8A77980_PD_A3IR }, |
| 44 | { "a3vip", 0x2c0, 0, R8A77980_PD_A3VIP, R8A77980_PD_ALWAYS_ON }, | 44 | { "a3vip0", 0x2c0, 0, R8A77980_PD_A3VIP0, R8A77980_PD_ALWAYS_ON }, |
| 45 | { "a3vip1", 0x300, 0, R8A77980_PD_A3VIP1, R8A77980_PD_A3VIP }, | 45 | { "a3vip1", 0x300, 0, R8A77980_PD_A3VIP1, R8A77980_PD_ALWAYS_ON }, |
| 46 | { "a3vip2", 0x280, 0, R8A77980_PD_A3VIP2, R8A77980_PD_A3VIP }, | 46 | { "a3vip2", 0x280, 0, R8A77980_PD_A3VIP2, R8A77980_PD_ALWAYS_ON }, |
| 47 | }; | 47 | }; |
| 48 | 48 | ||
| 49 | const struct rcar_sysc_info r8a77980_sysc_info __initconst = { | 49 | const struct rcar_sysc_info r8a77980_sysc_info __initconst = { |
diff --git a/drivers/soc/renesas/r8a77990-sysc.c b/drivers/soc/renesas/r8a77990-sysc.c index 15579ebc5ed2..664b244eb1dd 100644 --- a/drivers/soc/renesas/r8a77990-sysc.c +++ b/drivers/soc/renesas/r8a77990-sysc.c | |||
| @@ -28,19 +28,6 @@ static struct rcar_sysc_area r8a77990_areas[] __initdata = { | |||
| 28 | { "3dg-b", 0x100, 1, R8A77990_PD_3DG_B, R8A77990_PD_3DG_A }, | 28 | { "3dg-b", 0x100, 1, R8A77990_PD_3DG_B, R8A77990_PD_3DG_A }, |
| 29 | }; | 29 | }; |
| 30 | 30 | ||
| 31 | static void __init rcar_sysc_fix_parent(struct rcar_sysc_area *areas, | ||
| 32 | unsigned int num_areas, u8 id, | ||
| 33 | int new_parent) | ||
| 34 | { | ||
| 35 | unsigned int i; | ||
| 36 | |||
| 37 | for (i = 0; i < num_areas; i++) | ||
| 38 | if (areas[i].isr_bit == id) { | ||
| 39 | areas[i].parent = new_parent; | ||
| 40 | return; | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | /* Fixups for R-Car E3 ES1.0 revision */ | 31 | /* Fixups for R-Car E3 ES1.0 revision */ |
| 45 | static const struct soc_device_attribute r8a77990[] __initconst = { | 32 | static const struct soc_device_attribute r8a77990[] __initconst = { |
| 46 | { .soc_id = "r8a77990", .revision = "ES1.0" }, | 33 | { .soc_id = "r8a77990", .revision = "ES1.0" }, |
| @@ -50,12 +37,10 @@ static const struct soc_device_attribute r8a77990[] __initconst = { | |||
| 50 | static int __init r8a77990_sysc_init(void) | 37 | static int __init r8a77990_sysc_init(void) |
| 51 | { | 38 | { |
| 52 | if (soc_device_match(r8a77990)) { | 39 | if (soc_device_match(r8a77990)) { |
| 53 | rcar_sysc_fix_parent(r8a77990_areas, | 40 | /* Fix incorrect 3DG hierarchy */ |
| 54 | ARRAY_SIZE(r8a77990_areas), | 41 | swap(r8a77990_areas[7], r8a77990_areas[8]); |
| 55 | R8A77990_PD_3DG_A, R8A77990_PD_3DG_B); | 42 | r8a77990_areas[7].parent = R8A77990_PD_ALWAYS_ON; |
| 56 | rcar_sysc_fix_parent(r8a77990_areas, | 43 | r8a77990_areas[8].parent = R8A77990_PD_3DG_B; |
| 57 | ARRAY_SIZE(r8a77990_areas), | ||
| 58 | R8A77990_PD_3DG_B, R8A77990_PD_ALWAYS_ON); | ||
| 59 | } | 44 | } |
| 60 | 45 | ||
| 61 | return 0; | 46 | return 0; |
diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c index af53363eda03..0c80fab4f8de 100644 --- a/drivers/soc/renesas/rcar-sysc.c +++ b/drivers/soc/renesas/rcar-sysc.c | |||
| @@ -105,6 +105,15 @@ static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on) | |||
| 105 | 105 | ||
| 106 | spin_lock_irqsave(&rcar_sysc_lock, flags); | 106 | spin_lock_irqsave(&rcar_sysc_lock, flags); |
| 107 | 107 | ||
| 108 | /* | ||
| 109 | * The interrupt source needs to be enabled, but masked, to prevent the | ||
| 110 | * CPU from receiving it. | ||
| 111 | */ | ||
| 112 | iowrite32(ioread32(rcar_sysc_base + SYSCIMR) | isr_mask, | ||
| 113 | rcar_sysc_base + SYSCIMR); | ||
| 114 | iowrite32(ioread32(rcar_sysc_base + SYSCIER) | isr_mask, | ||
| 115 | rcar_sysc_base + SYSCIER); | ||
| 116 | |||
| 108 | iowrite32(isr_mask, rcar_sysc_base + SYSCISCR); | 117 | iowrite32(isr_mask, rcar_sysc_base + SYSCISCR); |
| 109 | 118 | ||
| 110 | /* Submit power shutoff or resume request until it was accepted */ | 119 | /* Submit power shutoff or resume request until it was accepted */ |
| @@ -146,16 +155,6 @@ static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on) | |||
| 146 | return ret; | 155 | return ret; |
| 147 | } | 156 | } |
| 148 | 157 | ||
| 149 | static int rcar_sysc_power_down(const struct rcar_sysc_ch *sysc_ch) | ||
| 150 | { | ||
| 151 | return rcar_sysc_power(sysc_ch, false); | ||
| 152 | } | ||
| 153 | |||
| 154 | static int rcar_sysc_power_up(const struct rcar_sysc_ch *sysc_ch) | ||
| 155 | { | ||
| 156 | return rcar_sysc_power(sysc_ch, true); | ||
| 157 | } | ||
| 158 | |||
| 159 | static bool rcar_sysc_power_is_off(const struct rcar_sysc_ch *sysc_ch) | 158 | static bool rcar_sysc_power_is_off(const struct rcar_sysc_ch *sysc_ch) |
| 160 | { | 159 | { |
| 161 | unsigned int st; | 160 | unsigned int st; |
| @@ -184,7 +183,7 @@ static int rcar_sysc_pd_power_off(struct generic_pm_domain *genpd) | |||
| 184 | struct rcar_sysc_pd *pd = to_rcar_pd(genpd); | 183 | struct rcar_sysc_pd *pd = to_rcar_pd(genpd); |
| 185 | 184 | ||
| 186 | pr_debug("%s: %s\n", __func__, genpd->name); | 185 | pr_debug("%s: %s\n", __func__, genpd->name); |
| 187 | return rcar_sysc_power_down(&pd->ch); | 186 | return rcar_sysc_power(&pd->ch, false); |
| 188 | } | 187 | } |
| 189 | 188 | ||
| 190 | static int rcar_sysc_pd_power_on(struct generic_pm_domain *genpd) | 189 | static int rcar_sysc_pd_power_on(struct generic_pm_domain *genpd) |
| @@ -192,7 +191,7 @@ static int rcar_sysc_pd_power_on(struct generic_pm_domain *genpd) | |||
| 192 | struct rcar_sysc_pd *pd = to_rcar_pd(genpd); | 191 | struct rcar_sysc_pd *pd = to_rcar_pd(genpd); |
| 193 | 192 | ||
| 194 | pr_debug("%s: %s\n", __func__, genpd->name); | 193 | pr_debug("%s: %s\n", __func__, genpd->name); |
| 195 | return rcar_sysc_power_up(&pd->ch); | 194 | return rcar_sysc_power(&pd->ch, true); |
| 196 | } | 195 | } |
| 197 | 196 | ||
| 198 | static bool has_cpg_mstp; | 197 | static bool has_cpg_mstp; |
| @@ -252,7 +251,7 @@ static int __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd) | |||
| 252 | goto finalize; | 251 | goto finalize; |
| 253 | } | 252 | } |
| 254 | 253 | ||
| 255 | rcar_sysc_power_up(&pd->ch); | 254 | rcar_sysc_power(&pd->ch, true); |
| 256 | 255 | ||
| 257 | finalize: | 256 | finalize: |
| 258 | error = pm_genpd_init(genpd, gov, false); | 257 | error = pm_genpd_init(genpd, gov, false); |
| @@ -334,7 +333,6 @@ static int __init rcar_sysc_pd_init(void) | |||
| 334 | const struct of_device_id *match; | 333 | const struct of_device_id *match; |
| 335 | struct rcar_pm_domains *domains; | 334 | struct rcar_pm_domains *domains; |
| 336 | struct device_node *np; | 335 | struct device_node *np; |
| 337 | u32 syscier, syscimr; | ||
| 338 | void __iomem *base; | 336 | void __iomem *base; |
| 339 | unsigned int i; | 337 | unsigned int i; |
| 340 | int error; | 338 | int error; |
| @@ -373,27 +371,6 @@ static int __init rcar_sysc_pd_init(void) | |||
| 373 | domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains); | 371 | domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains); |
| 374 | rcar_sysc_onecell_data = &domains->onecell_data; | 372 | rcar_sysc_onecell_data = &domains->onecell_data; |
| 375 | 373 | ||
| 376 | for (i = 0, syscier = 0; i < info->num_areas; i++) | ||
| 377 | syscier |= BIT(info->areas[i].isr_bit); | ||
| 378 | |||
| 379 | /* | ||
| 380 | * Mask all interrupt sources to prevent the CPU from receiving them. | ||
| 381 | * Make sure not to clear reserved bits that were set before. | ||
| 382 | */ | ||
| 383 | syscimr = ioread32(base + SYSCIMR); | ||
| 384 | syscimr |= syscier; | ||
| 385 | pr_debug("%pOF: syscimr = 0x%08x\n", np, syscimr); | ||
| 386 | iowrite32(syscimr, base + SYSCIMR); | ||
| 387 | |||
| 388 | /* | ||
| 389 | * SYSC needs all interrupt sources enabled to control power. | ||
| 390 | */ | ||
| 391 | pr_debug("%pOF: syscier = 0x%08x\n", np, syscier); | ||
| 392 | iowrite32(syscier, base + SYSCIER); | ||
| 393 | |||
| 394 | /* | ||
| 395 | * First, create all PM domains | ||
| 396 | */ | ||
| 397 | for (i = 0; i < info->num_areas; i++) { | 374 | for (i = 0; i < info->num_areas; i++) { |
| 398 | const struct rcar_sysc_area *area = &info->areas[i]; | 375 | const struct rcar_sysc_area *area = &info->areas[i]; |
| 399 | struct rcar_sysc_pd *pd; | 376 | struct rcar_sysc_pd *pd; |
| @@ -421,22 +398,17 @@ static int __init rcar_sysc_pd_init(void) | |||
| 421 | goto out_put; | 398 | goto out_put; |
| 422 | 399 | ||
| 423 | domains->domains[area->isr_bit] = &pd->genpd; | 400 | domains->domains[area->isr_bit] = &pd->genpd; |
| 424 | } | ||
| 425 | 401 | ||
| 426 | /* | 402 | if (area->parent < 0) |
| 427 | * Second, link all PM domains to their parents | ||
| 428 | */ | ||
| 429 | for (i = 0; i < info->num_areas; i++) { | ||
| 430 | const struct rcar_sysc_area *area = &info->areas[i]; | ||
| 431 | |||
| 432 | if (!area->name || area->parent < 0) | ||
| 433 | continue; | 403 | continue; |
| 434 | 404 | ||
| 435 | error = pm_genpd_add_subdomain(domains->domains[area->parent], | 405 | error = pm_genpd_add_subdomain(domains->domains[area->parent], |
| 436 | domains->domains[area->isr_bit]); | 406 | &pd->genpd); |
| 437 | if (error) | 407 | if (error) { |
| 438 | pr_warn("Failed to add PM subdomain %s to parent %u\n", | 408 | pr_warn("Failed to add PM subdomain %s to parent %u\n", |
| 439 | area->name, area->parent); | 409 | area->name, area->parent); |
| 410 | goto out_put; | ||
| 411 | } | ||
| 440 | } | 412 | } |
| 441 | 413 | ||
| 442 | error = of_genpd_add_provider_onecell(np, &domains->onecell_data); | 414 | error = of_genpd_add_provider_onecell(np, &domains->onecell_data); |
| @@ -478,8 +450,7 @@ static int rcar_sysc_power_cpu(unsigned int idx, bool on) | |||
| 478 | if (!(pd->flags & PD_CPU) || pd->ch.chan_bit != idx) | 450 | if (!(pd->flags & PD_CPU) || pd->ch.chan_bit != idx) |
| 479 | continue; | 451 | continue; |
| 480 | 452 | ||
| 481 | return on ? rcar_sysc_power_up(&pd->ch) | 453 | return rcar_sysc_power(&pd->ch, on); |
| 482 | : rcar_sysc_power_down(&pd->ch); | ||
| 483 | } | 454 | } |
| 484 | 455 | ||
| 485 | return -ENOENT; | 456 | return -ENOENT; |
diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index 6f86a726bb45..847c7c482b26 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c | |||
| @@ -21,7 +21,9 @@ | |||
| 21 | #include <linux/mfd/syscon.h> | 21 | #include <linux/mfd/syscon.h> |
| 22 | #include <dt-bindings/power/px30-power.h> | 22 | #include <dt-bindings/power/px30-power.h> |
| 23 | #include <dt-bindings/power/rk3036-power.h> | 23 | #include <dt-bindings/power/rk3036-power.h> |
| 24 | #include <dt-bindings/power/rk3066-power.h> | ||
| 24 | #include <dt-bindings/power/rk3128-power.h> | 25 | #include <dt-bindings/power/rk3128-power.h> |
| 26 | #include <dt-bindings/power/rk3188-power.h> | ||
| 25 | #include <dt-bindings/power/rk3228-power.h> | 27 | #include <dt-bindings/power/rk3228-power.h> |
| 26 | #include <dt-bindings/power/rk3288-power.h> | 28 | #include <dt-bindings/power/rk3288-power.h> |
| 27 | #include <dt-bindings/power/rk3328-power.h> | 29 | #include <dt-bindings/power/rk3328-power.h> |
| @@ -737,6 +739,14 @@ static const struct rockchip_domain_info rk3036_pm_domains[] = { | |||
| 737 | [RK3036_PD_SYS] = DOMAIN_RK3036(8, 22, 29, false), | 739 | [RK3036_PD_SYS] = DOMAIN_RK3036(8, 22, 29, false), |
| 738 | }; | 740 | }; |
| 739 | 741 | ||
| 742 | static const struct rockchip_domain_info rk3066_pm_domains[] = { | ||
| 743 | [RK3066_PD_GPU] = DOMAIN(9, 9, 3, 24, 29, false), | ||
| 744 | [RK3066_PD_VIDEO] = DOMAIN(8, 8, 4, 23, 28, false), | ||
| 745 | [RK3066_PD_VIO] = DOMAIN(7, 7, 5, 22, 27, false), | ||
| 746 | [RK3066_PD_PERI] = DOMAIN(6, 6, 2, 25, 30, false), | ||
| 747 | [RK3066_PD_CPU] = DOMAIN(-1, 5, 1, 26, 31, false), | ||
| 748 | }; | ||
| 749 | |||
| 740 | static const struct rockchip_domain_info rk3128_pm_domains[] = { | 750 | static const struct rockchip_domain_info rk3128_pm_domains[] = { |
| 741 | [RK3128_PD_CORE] = DOMAIN_RK3288(0, 0, 4, false), | 751 | [RK3128_PD_CORE] = DOMAIN_RK3288(0, 0, 4, false), |
| 742 | [RK3128_PD_MSCH] = DOMAIN_RK3288(-1, -1, 6, true), | 752 | [RK3128_PD_MSCH] = DOMAIN_RK3288(-1, -1, 6, true), |
| @@ -745,6 +755,14 @@ static const struct rockchip_domain_info rk3128_pm_domains[] = { | |||
| 745 | [RK3128_PD_GPU] = DOMAIN_RK3288(1, 1, 3, false), | 755 | [RK3128_PD_GPU] = DOMAIN_RK3288(1, 1, 3, false), |
| 746 | }; | 756 | }; |
| 747 | 757 | ||
| 758 | static const struct rockchip_domain_info rk3188_pm_domains[] = { | ||
| 759 | [RK3188_PD_GPU] = DOMAIN(9, 9, 3, 24, 29, false), | ||
| 760 | [RK3188_PD_VIDEO] = DOMAIN(8, 8, 4, 23, 28, false), | ||
| 761 | [RK3188_PD_VIO] = DOMAIN(7, 7, 5, 22, 27, false), | ||
| 762 | [RK3188_PD_PERI] = DOMAIN(6, 6, 2, 25, 30, false), | ||
| 763 | [RK3188_PD_CPU] = DOMAIN(5, 5, 1, 26, 31, false), | ||
| 764 | }; | ||
| 765 | |||
| 748 | static const struct rockchip_domain_info rk3228_pm_domains[] = { | 766 | static const struct rockchip_domain_info rk3228_pm_domains[] = { |
| 749 | [RK3228_PD_CORE] = DOMAIN_RK3036(0, 0, 16, true), | 767 | [RK3228_PD_CORE] = DOMAIN_RK3036(0, 0, 16, true), |
| 750 | [RK3228_PD_MSCH] = DOMAIN_RK3036(1, 1, 17, true), | 768 | [RK3228_PD_MSCH] = DOMAIN_RK3036(1, 1, 17, true), |
| @@ -846,6 +864,17 @@ static const struct rockchip_pmu_info rk3036_pmu = { | |||
| 846 | .domain_info = rk3036_pm_domains, | 864 | .domain_info = rk3036_pm_domains, |
| 847 | }; | 865 | }; |
| 848 | 866 | ||
| 867 | static const struct rockchip_pmu_info rk3066_pmu = { | ||
| 868 | .pwr_offset = 0x08, | ||
| 869 | .status_offset = 0x0c, | ||
| 870 | .req_offset = 0x38, /* PMU_MISC_CON1 */ | ||
| 871 | .idle_offset = 0x0c, | ||
| 872 | .ack_offset = 0x0c, | ||
| 873 | |||
| 874 | .num_domains = ARRAY_SIZE(rk3066_pm_domains), | ||
| 875 | .domain_info = rk3066_pm_domains, | ||
| 876 | }; | ||
| 877 | |||
| 849 | static const struct rockchip_pmu_info rk3128_pmu = { | 878 | static const struct rockchip_pmu_info rk3128_pmu = { |
| 850 | .pwr_offset = 0x04, | 879 | .pwr_offset = 0x04, |
| 851 | .status_offset = 0x08, | 880 | .status_offset = 0x08, |
| @@ -857,6 +886,17 @@ static const struct rockchip_pmu_info rk3128_pmu = { | |||
| 857 | .domain_info = rk3128_pm_domains, | 886 | .domain_info = rk3128_pm_domains, |
| 858 | }; | 887 | }; |
| 859 | 888 | ||
| 889 | static const struct rockchip_pmu_info rk3188_pmu = { | ||
| 890 | .pwr_offset = 0x08, | ||
| 891 | .status_offset = 0x0c, | ||
| 892 | .req_offset = 0x38, /* PMU_MISC_CON1 */ | ||
| 893 | .idle_offset = 0x0c, | ||
| 894 | .ack_offset = 0x0c, | ||
| 895 | |||
| 896 | .num_domains = ARRAY_SIZE(rk3188_pm_domains), | ||
| 897 | .domain_info = rk3188_pm_domains, | ||
| 898 | }; | ||
| 899 | |||
| 860 | static const struct rockchip_pmu_info rk3228_pmu = { | 900 | static const struct rockchip_pmu_info rk3228_pmu = { |
| 861 | .req_offset = 0x40c, | 901 | .req_offset = 0x40c, |
| 862 | .idle_offset = 0x488, | 902 | .idle_offset = 0x488, |
| @@ -949,10 +989,18 @@ static const struct of_device_id rockchip_pm_domain_dt_match[] = { | |||
| 949 | .data = (void *)&rk3036_pmu, | 989 | .data = (void *)&rk3036_pmu, |
| 950 | }, | 990 | }, |
| 951 | { | 991 | { |
| 992 | .compatible = "rockchip,rk3066-power-controller", | ||
| 993 | .data = (void *)&rk3066_pmu, | ||
| 994 | }, | ||
| 995 | { | ||
| 952 | .compatible = "rockchip,rk3128-power-controller", | 996 | .compatible = "rockchip,rk3128-power-controller", |
| 953 | .data = (void *)&rk3128_pmu, | 997 | .data = (void *)&rk3128_pmu, |
| 954 | }, | 998 | }, |
| 955 | { | 999 | { |
| 1000 | .compatible = "rockchip,rk3188-power-controller", | ||
| 1001 | .data = (void *)&rk3188_pmu, | ||
| 1002 | }, | ||
| 1003 | { | ||
| 956 | .compatible = "rockchip,rk3228-power-controller", | 1004 | .compatible = "rockchip,rk3228-power-controller", |
| 957 | .data = (void *)&rk3228_pmu, | 1005 | .data = (void *)&rk3228_pmu, |
| 958 | }, | 1006 | }, |
diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c index b4b0f3480bd3..1b0d50f36349 100644 --- a/drivers/soc/sunxi/sunxi_sram.c +++ b/drivers/soc/sunxi/sunxi_sram.c | |||
| @@ -155,17 +155,7 @@ static int sunxi_sram_show(struct seq_file *s, void *data) | |||
| 155 | return 0; | 155 | return 0; |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | static int sunxi_sram_open(struct inode *inode, struct file *file) | 158 | DEFINE_SHOW_ATTRIBUTE(sunxi_sram); |
| 159 | { | ||
| 160 | return single_open(file, sunxi_sram_show, inode->i_private); | ||
| 161 | } | ||
| 162 | |||
| 163 | static const struct file_operations sunxi_sram_fops = { | ||
| 164 | .open = sunxi_sram_open, | ||
| 165 | .read = seq_read, | ||
| 166 | .llseek = seq_lseek, | ||
| 167 | .release = single_release, | ||
| 168 | }; | ||
| 169 | 159 | ||
| 170 | static inline struct sunxi_sram_desc *to_sram_desc(const struct sunxi_sram_data *data) | 160 | static inline struct sunxi_sram_desc *to_sram_desc(const struct sunxi_sram_data *data) |
| 171 | { | 161 | { |
| @@ -300,6 +290,10 @@ static const struct sunxi_sramc_variant sun4i_a10_sramc_variant = { | |||
| 300 | /* Nothing special */ | 290 | /* Nothing special */ |
| 301 | }; | 291 | }; |
| 302 | 292 | ||
| 293 | static const struct sunxi_sramc_variant sun8i_h3_sramc_variant = { | ||
| 294 | .has_emac_clock = true, | ||
| 295 | }; | ||
| 296 | |||
| 303 | static const struct sunxi_sramc_variant sun50i_a64_sramc_variant = { | 297 | static const struct sunxi_sramc_variant sun50i_a64_sramc_variant = { |
| 304 | .has_emac_clock = true, | 298 | .has_emac_clock = true, |
| 305 | }; | 299 | }; |
| @@ -379,7 +373,7 @@ static const struct of_device_id sunxi_sram_dt_match[] = { | |||
| 379 | }, | 373 | }, |
| 380 | { | 374 | { |
| 381 | .compatible = "allwinner,sun8i-h3-system-control", | 375 | .compatible = "allwinner,sun8i-h3-system-control", |
| 382 | .data = &sun4i_a10_sramc_variant, | 376 | .data = &sun8i_h3_sramc_variant, |
| 383 | }, | 377 | }, |
| 384 | { | 378 | { |
| 385 | .compatible = "allwinner,sun50i-a64-sram-controller", | 379 | .compatible = "allwinner,sun50i-a64-sram-controller", |
| @@ -389,6 +383,10 @@ static const struct of_device_id sunxi_sram_dt_match[] = { | |||
| 389 | .compatible = "allwinner,sun50i-a64-system-control", | 383 | .compatible = "allwinner,sun50i-a64-system-control", |
| 390 | .data = &sun50i_a64_sramc_variant, | 384 | .data = &sun50i_a64_sramc_variant, |
| 391 | }, | 385 | }, |
| 386 | { | ||
| 387 | .compatible = "allwinner,sun50i-h5-system-control", | ||
| 388 | .data = &sun50i_a64_sramc_variant, | ||
| 389 | }, | ||
| 392 | { }, | 390 | { }, |
| 393 | }; | 391 | }; |
| 394 | MODULE_DEVICE_TABLE(of, sunxi_sram_dt_match); | 392 | MODULE_DEVICE_TABLE(of, sunxi_sram_dt_match); |
diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c index cd8f41351add..7bfb154d6fa5 100644 --- a/drivers/soc/tegra/common.c +++ b/drivers/soc/tegra/common.c | |||
| @@ -22,11 +22,15 @@ static const struct of_device_id tegra_machine_match[] = { | |||
| 22 | 22 | ||
| 23 | bool soc_is_tegra(void) | 23 | bool soc_is_tegra(void) |
| 24 | { | 24 | { |
| 25 | const struct of_device_id *match; | ||
| 25 | struct device_node *root; | 26 | struct device_node *root; |
| 26 | 27 | ||
| 27 | root = of_find_node_by_path("/"); | 28 | root = of_find_node_by_path("/"); |
| 28 | if (!root) | 29 | if (!root) |
| 29 | return false; | 30 | return false; |
| 30 | 31 | ||
| 31 | return of_match_node(tegra_machine_match, root) != NULL; | 32 | match = of_match_node(tegra_machine_match, root); |
| 33 | of_node_put(root); | ||
| 34 | |||
| 35 | return match != NULL; | ||
| 32 | } | 36 | } |
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index b30af18516d6..7ea3280279ff 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * drivers/soc/tegra/pmc.c | 2 | * drivers/soc/tegra/pmc.c |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2010 Google, Inc | 4 | * Copyright (c) 2010 Google, Inc |
| 5 | * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. | ||
| 5 | * | 6 | * |
| 6 | * Author: | 7 | * Author: |
| 7 | * Colin Cross <ccross@google.com> | 8 | * Colin Cross <ccross@google.com> |
| @@ -29,9 +30,12 @@ | |||
| 29 | #include <linux/init.h> | 30 | #include <linux/init.h> |
| 30 | #include <linux/io.h> | 31 | #include <linux/io.h> |
| 31 | #include <linux/iopoll.h> | 32 | #include <linux/iopoll.h> |
| 33 | #include <linux/irq.h> | ||
| 34 | #include <linux/irqdomain.h> | ||
| 32 | #include <linux/of.h> | 35 | #include <linux/of.h> |
| 33 | #include <linux/of_address.h> | 36 | #include <linux/of_address.h> |
| 34 | #include <linux/of_clk.h> | 37 | #include <linux/of_clk.h> |
| 38 | #include <linux/of_irq.h> | ||
| 35 | #include <linux/of_platform.h> | 39 | #include <linux/of_platform.h> |
| 36 | #include <linux/pinctrl/pinctrl.h> | 40 | #include <linux/pinctrl/pinctrl.h> |
| 37 | #include <linux/pinctrl/pinconf.h> | 41 | #include <linux/pinctrl/pinconf.h> |
| @@ -48,7 +52,10 @@ | |||
| 48 | #include <soc/tegra/fuse.h> | 52 | #include <soc/tegra/fuse.h> |
| 49 | #include <soc/tegra/pmc.h> | 53 | #include <soc/tegra/pmc.h> |
| 50 | 54 | ||
| 55 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 51 | #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h> | 56 | #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h> |
| 57 | #include <dt-bindings/gpio/tegra186-gpio.h> | ||
| 58 | #include <dt-bindings/gpio/tegra194-gpio.h> | ||
| 52 | 59 | ||
| 53 | #define PMC_CNTRL 0x0 | 60 | #define PMC_CNTRL 0x0 |
| 54 | #define PMC_CNTRL_INTR_POLARITY BIT(17) /* inverts INTR polarity */ | 61 | #define PMC_CNTRL_INTR_POLARITY BIT(17) /* inverts INTR polarity */ |
| @@ -92,7 +99,6 @@ | |||
| 92 | #define PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2) | 99 | #define PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2) |
| 93 | #define PMC_SENSOR_CTRL_ENABLE_RST BIT(1) | 100 | #define PMC_SENSOR_CTRL_ENABLE_RST BIT(1) |
| 94 | 101 | ||
| 95 | #define PMC_RST_STATUS 0x1b4 | ||
| 96 | #define PMC_RST_STATUS_POR 0 | 102 | #define PMC_RST_STATUS_POR 0 |
| 97 | #define PMC_RST_STATUS_WATCHDOG 1 | 103 | #define PMC_RST_STATUS_WATCHDOG 1 |
| 98 | #define PMC_RST_STATUS_SENSOR 2 | 104 | #define PMC_RST_STATUS_SENSOR 2 |
| @@ -126,6 +132,16 @@ | |||
| 126 | #define GPU_RG_CNTRL 0x2d4 | 132 | #define GPU_RG_CNTRL 0x2d4 |
| 127 | 133 | ||
| 128 | /* Tegra186 and later */ | 134 | /* Tegra186 and later */ |
| 135 | #define WAKE_AOWAKE_CNTRL(x) (0x000 + ((x) << 2)) | ||
| 136 | #define WAKE_AOWAKE_CNTRL_LEVEL (1 << 3) | ||
| 137 | #define WAKE_AOWAKE_MASK_W(x) (0x180 + ((x) << 2)) | ||
| 138 | #define WAKE_AOWAKE_MASK_R(x) (0x300 + ((x) << 2)) | ||
| 139 | #define WAKE_AOWAKE_STATUS_W(x) (0x30c + ((x) << 2)) | ||
| 140 | #define WAKE_AOWAKE_STATUS_R(x) (0x48c + ((x) << 2)) | ||
| 141 | #define WAKE_AOWAKE_TIER0_ROUTING(x) (0x4b4 + ((x) << 2)) | ||
| 142 | #define WAKE_AOWAKE_TIER1_ROUTING(x) (0x4c0 + ((x) << 2)) | ||
| 143 | #define WAKE_AOWAKE_TIER2_ROUTING(x) (0x4cc + ((x) << 2)) | ||
| 144 | |||
| 129 | #define WAKE_AOWAKE_CTRL 0x4f4 | 145 | #define WAKE_AOWAKE_CTRL 0x4f4 |
| 130 | #define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0) | 146 | #define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0) |
| 131 | 147 | ||
| @@ -151,8 +167,45 @@ struct tegra_pmc_regs { | |||
| 151 | unsigned int dpd_status; | 167 | unsigned int dpd_status; |
| 152 | unsigned int dpd2_req; | 168 | unsigned int dpd2_req; |
| 153 | unsigned int dpd2_status; | 169 | unsigned int dpd2_status; |
| 170 | unsigned int rst_status; | ||
| 171 | unsigned int rst_source_shift; | ||
| 172 | unsigned int rst_source_mask; | ||
| 173 | unsigned int rst_level_shift; | ||
| 174 | unsigned int rst_level_mask; | ||
| 175 | }; | ||
| 176 | |||
| 177 | struct tegra_wake_event { | ||
| 178 | const char *name; | ||
| 179 | unsigned int id; | ||
| 180 | unsigned int irq; | ||
| 181 | struct { | ||
| 182 | unsigned int instance; | ||
| 183 | unsigned int pin; | ||
| 184 | } gpio; | ||
| 154 | }; | 185 | }; |
| 155 | 186 | ||
| 187 | #define TEGRA_WAKE_IRQ(_name, _id, _irq) \ | ||
| 188 | { \ | ||
| 189 | .name = _name, \ | ||
| 190 | .id = _id, \ | ||
| 191 | .irq = _irq, \ | ||
| 192 | .gpio = { \ | ||
| 193 | .instance = UINT_MAX, \ | ||
| 194 | .pin = UINT_MAX, \ | ||
| 195 | }, \ | ||
| 196 | } | ||
| 197 | |||
| 198 | #define TEGRA_WAKE_GPIO(_name, _id, _instance, _pin) \ | ||
| 199 | { \ | ||
| 200 | .name = _name, \ | ||
| 201 | .id = _id, \ | ||
| 202 | .irq = 0, \ | ||
| 203 | .gpio = { \ | ||
| 204 | .instance = _instance, \ | ||
| 205 | .pin = _pin, \ | ||
| 206 | }, \ | ||
| 207 | } | ||
| 208 | |||
| 156 | struct tegra_pmc_soc { | 209 | struct tegra_pmc_soc { |
| 157 | unsigned int num_powergates; | 210 | unsigned int num_powergates; |
| 158 | const char *const *powergates; | 211 | const char *const *powergates; |
| @@ -175,6 +228,45 @@ struct tegra_pmc_soc { | |||
| 175 | void (*setup_irq_polarity)(struct tegra_pmc *pmc, | 228 | void (*setup_irq_polarity)(struct tegra_pmc *pmc, |
| 176 | struct device_node *np, | 229 | struct device_node *np, |
| 177 | bool invert); | 230 | bool invert); |
| 231 | |||
| 232 | const char * const *reset_sources; | ||
| 233 | unsigned int num_reset_sources; | ||
| 234 | const char * const *reset_levels; | ||
| 235 | unsigned int num_reset_levels; | ||
| 236 | |||
| 237 | const struct tegra_wake_event *wake_events; | ||
| 238 | unsigned int num_wake_events; | ||
| 239 | }; | ||
| 240 | |||
| 241 | static const char * const tegra186_reset_sources[] = { | ||
| 242 | "SYS_RESET", | ||
| 243 | "AOWDT", | ||
| 244 | "MCCPLEXWDT", | ||
| 245 | "BPMPWDT", | ||
| 246 | "SCEWDT", | ||
| 247 | "SPEWDT", | ||
| 248 | "APEWDT", | ||
| 249 | "BCCPLEXWDT", | ||
| 250 | "SENSOR", | ||
| 251 | "AOTAG", | ||
| 252 | "VFSENSOR", | ||
| 253 | "SWREST", | ||
| 254 | "SC7", | ||
| 255 | "HSM", | ||
| 256 | "CORESIGHT" | ||
| 257 | }; | ||
| 258 | |||
| 259 | static const char * const tegra186_reset_levels[] = { | ||
| 260 | "L0", "L1", "L2", "WARM" | ||
| 261 | }; | ||
| 262 | |||
| 263 | static const char * const tegra30_reset_sources[] = { | ||
| 264 | "POWER_ON_RESET", | ||
| 265 | "WATCHDOG", | ||
| 266 | "SENSOR", | ||
| 267 | "SW_MAIN", | ||
| 268 | "LP0", | ||
| 269 | "AOTAG" | ||
| 178 | }; | 270 | }; |
| 179 | 271 | ||
| 180 | /** | 272 | /** |
| @@ -230,6 +322,9 @@ struct tegra_pmc { | |||
| 230 | struct mutex powergates_lock; | 322 | struct mutex powergates_lock; |
| 231 | 323 | ||
| 232 | struct pinctrl_dev *pctl_dev; | 324 | struct pinctrl_dev *pctl_dev; |
| 325 | |||
| 326 | struct irq_domain *domain; | ||
| 327 | struct irq_chip irq; | ||
| 233 | }; | 328 | }; |
| 234 | 329 | ||
| 235 | static struct tegra_pmc *pmc = &(struct tegra_pmc) { | 330 | static struct tegra_pmc *pmc = &(struct tegra_pmc) { |
| @@ -538,16 +633,10 @@ EXPORT_SYMBOL(tegra_powergate_power_off); | |||
| 538 | */ | 633 | */ |
| 539 | int tegra_powergate_is_powered(unsigned int id) | 634 | int tegra_powergate_is_powered(unsigned int id) |
| 540 | { | 635 | { |
| 541 | int status; | ||
| 542 | |||
| 543 | if (!tegra_powergate_is_valid(id)) | 636 | if (!tegra_powergate_is_valid(id)) |
| 544 | return -EINVAL; | 637 | return -EINVAL; |
| 545 | 638 | ||
| 546 | mutex_lock(&pmc->powergates_lock); | 639 | return tegra_powergate_state(id); |
| 547 | status = tegra_powergate_state(id); | ||
| 548 | mutex_unlock(&pmc->powergates_lock); | ||
| 549 | |||
| 550 | return status; | ||
| 551 | } | 640 | } |
| 552 | 641 | ||
| 553 | /** | 642 | /** |
| @@ -715,17 +804,7 @@ static int powergate_show(struct seq_file *s, void *data) | |||
| 715 | return 0; | 804 | return 0; |
| 716 | } | 805 | } |
| 717 | 806 | ||
| 718 | static int powergate_open(struct inode *inode, struct file *file) | 807 | DEFINE_SHOW_ATTRIBUTE(powergate); |
| 719 | { | ||
| 720 | return single_open(file, powergate_show, inode->i_private); | ||
| 721 | } | ||
| 722 | |||
| 723 | static const struct file_operations powergate_fops = { | ||
| 724 | .open = powergate_open, | ||
| 725 | .read = seq_read, | ||
| 726 | .llseek = seq_lseek, | ||
| 727 | .release = single_release, | ||
| 728 | }; | ||
| 729 | 808 | ||
| 730 | static int tegra_powergate_debugfs_init(void) | 809 | static int tegra_powergate_debugfs_init(void) |
| 731 | { | 810 | { |
| @@ -845,22 +924,6 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) | |||
| 845 | goto remove_resets; | 924 | goto remove_resets; |
| 846 | } | 925 | } |
| 847 | 926 | ||
| 848 | /* | ||
| 849 | * FIXME: If XHCI is enabled for Tegra, then power-up the XUSB | ||
| 850 | * host and super-speed partitions. Once the XHCI driver | ||
| 851 | * manages the partitions itself this code can be removed. Note | ||
| 852 | * that we don't register these partitions with the genpd core | ||
| 853 | * to avoid it from powering down the partitions as they appear | ||
| 854 | * to be unused. | ||
| 855 | */ | ||
| 856 | if (IS_ENABLED(CONFIG_USB_XHCI_TEGRA) && | ||
| 857 | (id == TEGRA_POWERGATE_XUSBA || id == TEGRA_POWERGATE_XUSBC)) { | ||
| 858 | if (off) | ||
| 859 | WARN_ON(tegra_powergate_power_up(pg, true)); | ||
| 860 | |||
| 861 | goto remove_resets; | ||
| 862 | } | ||
| 863 | |||
| 864 | err = pm_genpd_init(&pg->genpd, NULL, off); | 927 | err = pm_genpd_init(&pg->genpd, NULL, off); |
| 865 | if (err < 0) { | 928 | if (err < 0) { |
| 866 | pr_err("failed to initialise PM domain %pOFn: %d\n", np, | 929 | pr_err("failed to initialise PM domain %pOFn: %d\n", np, |
| @@ -1541,6 +1604,225 @@ static int tegra_pmc_pinctrl_init(struct tegra_pmc *pmc) | |||
| 1541 | return err; | 1604 | return err; |
| 1542 | } | 1605 | } |
| 1543 | 1606 | ||
| 1607 | static ssize_t reset_reason_show(struct device *dev, | ||
| 1608 | struct device_attribute *attr, char *buf) | ||
| 1609 | { | ||
| 1610 | u32 value, rst_src; | ||
| 1611 | |||
| 1612 | value = tegra_pmc_readl(pmc->soc->regs->rst_status); | ||
| 1613 | rst_src = (value & pmc->soc->regs->rst_source_mask) >> | ||
| 1614 | pmc->soc->regs->rst_source_shift; | ||
| 1615 | |||
| 1616 | return sprintf(buf, "%s\n", pmc->soc->reset_sources[rst_src]); | ||
| 1617 | } | ||
| 1618 | |||
| 1619 | static DEVICE_ATTR_RO(reset_reason); | ||
| 1620 | |||
| 1621 | static ssize_t reset_level_show(struct device *dev, | ||
| 1622 | struct device_attribute *attr, char *buf) | ||
| 1623 | { | ||
| 1624 | u32 value, rst_lvl; | ||
| 1625 | |||
| 1626 | value = tegra_pmc_readl(pmc->soc->regs->rst_status); | ||
| 1627 | rst_lvl = (value & pmc->soc->regs->rst_level_mask) >> | ||
| 1628 | pmc->soc->regs->rst_level_shift; | ||
| 1629 | |||
| 1630 | return sprintf(buf, "%s\n", pmc->soc->reset_levels[rst_lvl]); | ||
| 1631 | } | ||
| 1632 | |||
| 1633 | static DEVICE_ATTR_RO(reset_level); | ||
| 1634 | |||
| 1635 | static void tegra_pmc_reset_sysfs_init(struct tegra_pmc *pmc) | ||
| 1636 | { | ||
| 1637 | struct device *dev = pmc->dev; | ||
| 1638 | int err = 0; | ||
| 1639 | |||
| 1640 | if (pmc->soc->reset_sources) { | ||
| 1641 | err = device_create_file(dev, &dev_attr_reset_reason); | ||
| 1642 | if (err < 0) | ||
| 1643 | dev_warn(dev, | ||
| 1644 | "failed to create attr \"reset_reason\": %d\n", | ||
| 1645 | err); | ||
| 1646 | } | ||
| 1647 | |||
| 1648 | if (pmc->soc->reset_levels) { | ||
| 1649 | err = device_create_file(dev, &dev_attr_reset_level); | ||
| 1650 | if (err < 0) | ||
| 1651 | dev_warn(dev, | ||
| 1652 | "failed to create attr \"reset_level\": %d\n", | ||
| 1653 | err); | ||
| 1654 | } | ||
| 1655 | } | ||
| 1656 | |||
| 1657 | static int tegra_pmc_irq_translate(struct irq_domain *domain, | ||
| 1658 | struct irq_fwspec *fwspec, | ||
| 1659 | unsigned long *hwirq, | ||
| 1660 | unsigned int *type) | ||
| 1661 | { | ||
| 1662 | if (WARN_ON(fwspec->param_count < 2)) | ||
| 1663 | return -EINVAL; | ||
| 1664 | |||
| 1665 | *hwirq = fwspec->param[0]; | ||
| 1666 | *type = fwspec->param[1]; | ||
| 1667 | |||
| 1668 | return 0; | ||
| 1669 | } | ||
| 1670 | |||
| 1671 | static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq, | ||
| 1672 | unsigned int num_irqs, void *data) | ||
| 1673 | { | ||
| 1674 | struct tegra_pmc *pmc = domain->host_data; | ||
| 1675 | const struct tegra_pmc_soc *soc = pmc->soc; | ||
| 1676 | struct irq_fwspec *fwspec = data; | ||
| 1677 | unsigned int i; | ||
| 1678 | int err = 0; | ||
| 1679 | |||
| 1680 | for (i = 0; i < soc->num_wake_events; i++) { | ||
| 1681 | const struct tegra_wake_event *event = &soc->wake_events[i]; | ||
| 1682 | |||
| 1683 | if (fwspec->param_count == 2) { | ||
| 1684 | struct irq_fwspec spec; | ||
| 1685 | |||
| 1686 | if (event->id != fwspec->param[0]) | ||
| 1687 | continue; | ||
| 1688 | |||
| 1689 | err = irq_domain_set_hwirq_and_chip(domain, virq, | ||
| 1690 | event->id, | ||
| 1691 | &pmc->irq, pmc); | ||
| 1692 | if (err < 0) | ||
| 1693 | break; | ||
| 1694 | |||
| 1695 | spec.fwnode = &pmc->dev->of_node->fwnode; | ||
| 1696 | spec.param_count = 3; | ||
| 1697 | spec.param[0] = GIC_SPI; | ||
| 1698 | spec.param[1] = event->irq; | ||
| 1699 | spec.param[2] = fwspec->param[1]; | ||
| 1700 | |||
| 1701 | err = irq_domain_alloc_irqs_parent(domain, virq, | ||
| 1702 | num_irqs, &spec); | ||
| 1703 | |||
| 1704 | break; | ||
| 1705 | } | ||
| 1706 | |||
| 1707 | if (fwspec->param_count == 3) { | ||
| 1708 | if (event->gpio.instance != fwspec->param[0] || | ||
| 1709 | event->gpio.pin != fwspec->param[1]) | ||
| 1710 | continue; | ||
| 1711 | |||
| 1712 | err = irq_domain_set_hwirq_and_chip(domain, virq, | ||
| 1713 | event->id, | ||
| 1714 | &pmc->irq, pmc); | ||
| 1715 | |||
| 1716 | break; | ||
| 1717 | } | ||
| 1718 | } | ||
| 1719 | |||
| 1720 | if (i == soc->num_wake_events) | ||
| 1721 | err = irq_domain_set_hwirq_and_chip(domain, virq, ULONG_MAX, | ||
| 1722 | &pmc->irq, pmc); | ||
| 1723 | |||
| 1724 | return err; | ||
| 1725 | } | ||
| 1726 | |||
| 1727 | static const struct irq_domain_ops tegra_pmc_irq_domain_ops = { | ||
| 1728 | .translate = tegra_pmc_irq_translate, | ||
| 1729 | .alloc = tegra_pmc_irq_alloc, | ||
| 1730 | }; | ||
| 1731 | |||
| 1732 | static int tegra_pmc_irq_set_wake(struct irq_data *data, unsigned int on) | ||
| 1733 | { | ||
| 1734 | struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data); | ||
| 1735 | unsigned int offset, bit; | ||
| 1736 | u32 value; | ||
| 1737 | |||
| 1738 | offset = data->hwirq / 32; | ||
| 1739 | bit = data->hwirq % 32; | ||
| 1740 | |||
| 1741 | /* clear wake status */ | ||
| 1742 | writel(0x1, pmc->wake + WAKE_AOWAKE_STATUS_W(data->hwirq)); | ||
| 1743 | |||
| 1744 | /* route wake to tier 2 */ | ||
| 1745 | value = readl(pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(offset)); | ||
| 1746 | |||
| 1747 | if (!on) | ||
| 1748 | value &= ~(1 << bit); | ||
| 1749 | else | ||
| 1750 | value |= 1 << bit; | ||
| 1751 | |||
| 1752 | writel(value, pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(offset)); | ||
| 1753 | |||
| 1754 | /* enable wakeup event */ | ||
| 1755 | writel(!!on, pmc->wake + WAKE_AOWAKE_MASK_W(data->hwirq)); | ||
| 1756 | |||
| 1757 | return 0; | ||
| 1758 | } | ||
| 1759 | |||
| 1760 | static int tegra_pmc_irq_set_type(struct irq_data *data, unsigned int type) | ||
| 1761 | { | ||
| 1762 | struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data); | ||
| 1763 | u32 value; | ||
| 1764 | |||
| 1765 | if (data->hwirq == ULONG_MAX) | ||
| 1766 | return 0; | ||
| 1767 | |||
| 1768 | value = readl(pmc->wake + WAKE_AOWAKE_CNTRL(data->hwirq)); | ||
| 1769 | |||
| 1770 | switch (type) { | ||
| 1771 | case IRQ_TYPE_EDGE_RISING: | ||
| 1772 | case IRQ_TYPE_LEVEL_HIGH: | ||
| 1773 | value |= WAKE_AOWAKE_CNTRL_LEVEL; | ||
| 1774 | break; | ||
| 1775 | |||
| 1776 | case IRQ_TYPE_EDGE_FALLING: | ||
| 1777 | case IRQ_TYPE_LEVEL_LOW: | ||
| 1778 | value &= ~WAKE_AOWAKE_CNTRL_LEVEL; | ||
| 1779 | break; | ||
| 1780 | |||
| 1781 | case IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING: | ||
| 1782 | value ^= WAKE_AOWAKE_CNTRL_LEVEL; | ||
| 1783 | break; | ||
| 1784 | |||
| 1785 | default: | ||
| 1786 | return -EINVAL; | ||
| 1787 | } | ||
| 1788 | |||
| 1789 | writel(value, pmc->wake + WAKE_AOWAKE_CNTRL(data->hwirq)); | ||
| 1790 | |||
| 1791 | return 0; | ||
| 1792 | } | ||
| 1793 | |||
| 1794 | static int tegra_pmc_irq_init(struct tegra_pmc *pmc) | ||
| 1795 | { | ||
| 1796 | struct irq_domain *parent = NULL; | ||
| 1797 | struct device_node *np; | ||
| 1798 | |||
| 1799 | np = of_irq_find_parent(pmc->dev->of_node); | ||
| 1800 | if (np) { | ||
| 1801 | parent = irq_find_host(np); | ||
| 1802 | of_node_put(np); | ||
| 1803 | } | ||
| 1804 | |||
| 1805 | if (!parent) | ||
| 1806 | return 0; | ||
| 1807 | |||
| 1808 | pmc->irq.name = dev_name(pmc->dev); | ||
| 1809 | pmc->irq.irq_mask = irq_chip_mask_parent; | ||
| 1810 | pmc->irq.irq_unmask = irq_chip_unmask_parent; | ||
| 1811 | pmc->irq.irq_eoi = irq_chip_eoi_parent; | ||
| 1812 | pmc->irq.irq_set_affinity = irq_chip_set_affinity_parent; | ||
| 1813 | pmc->irq.irq_set_type = tegra_pmc_irq_set_type; | ||
| 1814 | pmc->irq.irq_set_wake = tegra_pmc_irq_set_wake; | ||
| 1815 | |||
| 1816 | pmc->domain = irq_domain_add_hierarchy(parent, 0, 96, pmc->dev->of_node, | ||
| 1817 | &tegra_pmc_irq_domain_ops, pmc); | ||
| 1818 | if (!pmc->domain) { | ||
| 1819 | dev_err(pmc->dev, "failed to allocate domain\n"); | ||
| 1820 | return -ENOMEM; | ||
| 1821 | } | ||
| 1822 | |||
| 1823 | return 0; | ||
| 1824 | } | ||
| 1825 | |||
| 1544 | static int tegra_pmc_probe(struct platform_device *pdev) | 1826 | static int tegra_pmc_probe(struct platform_device *pdev) |
| 1545 | { | 1827 | { |
| 1546 | void __iomem *base; | 1828 | void __iomem *base; |
| @@ -1610,6 +1892,8 @@ static int tegra_pmc_probe(struct platform_device *pdev) | |||
| 1610 | 1892 | ||
| 1611 | tegra_pmc_init_tsense_reset(pmc); | 1893 | tegra_pmc_init_tsense_reset(pmc); |
| 1612 | 1894 | ||
| 1895 | tegra_pmc_reset_sysfs_init(pmc); | ||
| 1896 | |||
| 1613 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { | 1897 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { |
| 1614 | err = tegra_powergate_debugfs_init(); | 1898 | err = tegra_powergate_debugfs_init(); |
| 1615 | if (err < 0) | 1899 | if (err < 0) |
| @@ -1627,6 +1911,10 @@ static int tegra_pmc_probe(struct platform_device *pdev) | |||
| 1627 | if (err) | 1911 | if (err) |
| 1628 | goto cleanup_restart_handler; | 1912 | goto cleanup_restart_handler; |
| 1629 | 1913 | ||
| 1914 | err = tegra_pmc_irq_init(pmc); | ||
| 1915 | if (err < 0) | ||
| 1916 | goto cleanup_restart_handler; | ||
| 1917 | |||
| 1630 | mutex_lock(&pmc->powergates_lock); | 1918 | mutex_lock(&pmc->powergates_lock); |
| 1631 | iounmap(pmc->base); | 1919 | iounmap(pmc->base); |
| 1632 | pmc->base = base; | 1920 | pmc->base = base; |
| @@ -1676,6 +1964,11 @@ static const struct tegra_pmc_regs tegra20_pmc_regs = { | |||
| 1676 | .dpd_status = 0x1bc, | 1964 | .dpd_status = 0x1bc, |
| 1677 | .dpd2_req = 0x1c0, | 1965 | .dpd2_req = 0x1c0, |
| 1678 | .dpd2_status = 0x1c4, | 1966 | .dpd2_status = 0x1c4, |
| 1967 | .rst_status = 0x1b4, | ||
| 1968 | .rst_source_shift = 0x0, | ||
| 1969 | .rst_source_mask = 0x7, | ||
| 1970 | .rst_level_shift = 0x0, | ||
| 1971 | .rst_level_mask = 0x0, | ||
| 1679 | }; | 1972 | }; |
| 1680 | 1973 | ||
| 1681 | static void tegra20_pmc_init(struct tegra_pmc *pmc) | 1974 | static void tegra20_pmc_init(struct tegra_pmc *pmc) |
| @@ -1733,6 +2026,10 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = { | |||
| 1733 | .regs = &tegra20_pmc_regs, | 2026 | .regs = &tegra20_pmc_regs, |
| 1734 | .init = tegra20_pmc_init, | 2027 | .init = tegra20_pmc_init, |
| 1735 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, | 2028 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, |
| 2029 | .reset_sources = NULL, | ||
| 2030 | .num_reset_sources = 0, | ||
| 2031 | .reset_levels = NULL, | ||
| 2032 | .num_reset_levels = 0, | ||
| 1736 | }; | 2033 | }; |
| 1737 | 2034 | ||
| 1738 | static const char * const tegra30_powergates[] = { | 2035 | static const char * const tegra30_powergates[] = { |
| @@ -1774,6 +2071,10 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = { | |||
| 1774 | .regs = &tegra20_pmc_regs, | 2071 | .regs = &tegra20_pmc_regs, |
| 1775 | .init = tegra20_pmc_init, | 2072 | .init = tegra20_pmc_init, |
| 1776 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, | 2073 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, |
| 2074 | .reset_sources = tegra30_reset_sources, | ||
| 2075 | .num_reset_sources = 5, | ||
| 2076 | .reset_levels = NULL, | ||
| 2077 | .num_reset_levels = 0, | ||
| 1777 | }; | 2078 | }; |
| 1778 | 2079 | ||
| 1779 | static const char * const tegra114_powergates[] = { | 2080 | static const char * const tegra114_powergates[] = { |
| @@ -1819,6 +2120,10 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = { | |||
| 1819 | .regs = &tegra20_pmc_regs, | 2120 | .regs = &tegra20_pmc_regs, |
| 1820 | .init = tegra20_pmc_init, | 2121 | .init = tegra20_pmc_init, |
| 1821 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, | 2122 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, |
| 2123 | .reset_sources = tegra30_reset_sources, | ||
| 2124 | .num_reset_sources = 5, | ||
| 2125 | .reset_levels = NULL, | ||
| 2126 | .num_reset_levels = 0, | ||
| 1822 | }; | 2127 | }; |
| 1823 | 2128 | ||
| 1824 | static const char * const tegra124_powergates[] = { | 2129 | static const char * const tegra124_powergates[] = { |
| @@ -1924,6 +2229,10 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { | |||
| 1924 | .regs = &tegra20_pmc_regs, | 2229 | .regs = &tegra20_pmc_regs, |
| 1925 | .init = tegra20_pmc_init, | 2230 | .init = tegra20_pmc_init, |
| 1926 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, | 2231 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, |
| 2232 | .reset_sources = tegra30_reset_sources, | ||
| 2233 | .num_reset_sources = 5, | ||
| 2234 | .reset_levels = NULL, | ||
| 2235 | .num_reset_levels = 0, | ||
| 1927 | }; | 2236 | }; |
| 1928 | 2237 | ||
| 1929 | static const char * const tegra210_powergates[] = { | 2238 | static const char * const tegra210_powergates[] = { |
| @@ -2025,6 +2334,10 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = { | |||
| 2025 | .regs = &tegra20_pmc_regs, | 2334 | .regs = &tegra20_pmc_regs, |
| 2026 | .init = tegra20_pmc_init, | 2335 | .init = tegra20_pmc_init, |
| 2027 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, | 2336 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, |
| 2337 | .reset_sources = tegra30_reset_sources, | ||
| 2338 | .num_reset_sources = 5, | ||
| 2339 | .reset_levels = NULL, | ||
| 2340 | .num_reset_levels = 0, | ||
| 2028 | }; | 2341 | }; |
| 2029 | 2342 | ||
| 2030 | #define TEGRA186_IO_PAD_TABLE(_pad) \ | 2343 | #define TEGRA186_IO_PAD_TABLE(_pad) \ |
| @@ -2082,6 +2395,11 @@ static const struct tegra_pmc_regs tegra186_pmc_regs = { | |||
| 2082 | .dpd_status = 0x78, | 2395 | .dpd_status = 0x78, |
| 2083 | .dpd2_req = 0x7c, | 2396 | .dpd2_req = 0x7c, |
| 2084 | .dpd2_status = 0x80, | 2397 | .dpd2_status = 0x80, |
| 2398 | .rst_status = 0x70, | ||
| 2399 | .rst_source_shift = 0x2, | ||
| 2400 | .rst_source_mask = 0x3C, | ||
| 2401 | .rst_level_shift = 0x0, | ||
| 2402 | .rst_level_mask = 0x3, | ||
| 2085 | }; | 2403 | }; |
| 2086 | 2404 | ||
| 2087 | static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc, | 2405 | static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc, |
| @@ -2119,6 +2437,11 @@ static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc, | |||
| 2119 | iounmap(wake); | 2437 | iounmap(wake); |
| 2120 | } | 2438 | } |
| 2121 | 2439 | ||
| 2440 | static const struct tegra_wake_event tegra186_wake_events[] = { | ||
| 2441 | TEGRA_WAKE_GPIO("power", 29, 1, TEGRA_AON_GPIO(FF, 0)), | ||
| 2442 | TEGRA_WAKE_IRQ("rtc", 73, 10), | ||
| 2443 | }; | ||
| 2444 | |||
| 2122 | static const struct tegra_pmc_soc tegra186_pmc_soc = { | 2445 | static const struct tegra_pmc_soc tegra186_pmc_soc = { |
| 2123 | .num_powergates = 0, | 2446 | .num_powergates = 0, |
| 2124 | .powergates = NULL, | 2447 | .powergates = NULL, |
| @@ -2134,10 +2457,87 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = { | |||
| 2134 | .regs = &tegra186_pmc_regs, | 2457 | .regs = &tegra186_pmc_regs, |
| 2135 | .init = NULL, | 2458 | .init = NULL, |
| 2136 | .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, | 2459 | .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, |
| 2460 | .reset_sources = tegra186_reset_sources, | ||
| 2461 | .num_reset_sources = 14, | ||
| 2462 | .reset_levels = tegra186_reset_levels, | ||
| 2463 | .num_reset_levels = 3, | ||
| 2464 | .num_wake_events = ARRAY_SIZE(tegra186_wake_events), | ||
| 2465 | .wake_events = tegra186_wake_events, | ||
| 2466 | }; | ||
| 2467 | |||
| 2468 | static const struct tegra_io_pad_soc tegra194_io_pads[] = { | ||
| 2469 | { .id = TEGRA_IO_PAD_CSIA, .dpd = 0, .voltage = UINT_MAX }, | ||
| 2470 | { .id = TEGRA_IO_PAD_CSIB, .dpd = 1, .voltage = UINT_MAX }, | ||
| 2471 | { .id = TEGRA_IO_PAD_MIPI_BIAS, .dpd = 3, .voltage = UINT_MAX }, | ||
| 2472 | { .id = TEGRA_IO_PAD_PEX_CLK_BIAS, .dpd = 4, .voltage = UINT_MAX }, | ||
| 2473 | { .id = TEGRA_IO_PAD_PEX_CLK3, .dpd = 5, .voltage = UINT_MAX }, | ||
| 2474 | { .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 6, .voltage = UINT_MAX }, | ||
| 2475 | { .id = TEGRA_IO_PAD_PEX_CLK1, .dpd = 7, .voltage = UINT_MAX }, | ||
| 2476 | { .id = TEGRA_IO_PAD_EQOS, .dpd = 8, .voltage = UINT_MAX }, | ||
| 2477 | { .id = TEGRA_IO_PAD_PEX_CLK2_BIAS, .dpd = 9, .voltage = UINT_MAX }, | ||
| 2478 | { .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 10, .voltage = UINT_MAX }, | ||
| 2479 | { .id = TEGRA_IO_PAD_DAP3, .dpd = 11, .voltage = UINT_MAX }, | ||
| 2480 | { .id = TEGRA_IO_PAD_DAP5, .dpd = 12, .voltage = UINT_MAX }, | ||
| 2481 | { .id = TEGRA_IO_PAD_UART, .dpd = 14, .voltage = UINT_MAX }, | ||
| 2482 | { .id = TEGRA_IO_PAD_PWR_CTL, .dpd = 15, .voltage = UINT_MAX }, | ||
| 2483 | { .id = TEGRA_IO_PAD_SOC_GPIO53, .dpd = 16, .voltage = UINT_MAX }, | ||
| 2484 | { .id = TEGRA_IO_PAD_AUDIO, .dpd = 17, .voltage = UINT_MAX }, | ||
| 2485 | { .id = TEGRA_IO_PAD_GP_PWM2, .dpd = 18, .voltage = UINT_MAX }, | ||
| 2486 | { .id = TEGRA_IO_PAD_GP_PWM3, .dpd = 19, .voltage = UINT_MAX }, | ||
| 2487 | { .id = TEGRA_IO_PAD_SOC_GPIO12, .dpd = 20, .voltage = UINT_MAX }, | ||
| 2488 | { .id = TEGRA_IO_PAD_SOC_GPIO13, .dpd = 21, .voltage = UINT_MAX }, | ||
| 2489 | { .id = TEGRA_IO_PAD_SOC_GPIO10, .dpd = 22, .voltage = UINT_MAX }, | ||
| 2490 | { .id = TEGRA_IO_PAD_UART4, .dpd = 23, .voltage = UINT_MAX }, | ||
| 2491 | { .id = TEGRA_IO_PAD_UART5, .dpd = 24, .voltage = UINT_MAX }, | ||
| 2492 | { .id = TEGRA_IO_PAD_DBG, .dpd = 25, .voltage = UINT_MAX }, | ||
| 2493 | { .id = TEGRA_IO_PAD_HDMI_DP3, .dpd = 26, .voltage = UINT_MAX }, | ||
| 2494 | { .id = TEGRA_IO_PAD_HDMI_DP2, .dpd = 27, .voltage = UINT_MAX }, | ||
| 2495 | { .id = TEGRA_IO_PAD_HDMI_DP0, .dpd = 28, .voltage = UINT_MAX }, | ||
| 2496 | { .id = TEGRA_IO_PAD_HDMI_DP1, .dpd = 29, .voltage = UINT_MAX }, | ||
| 2497 | { .id = TEGRA_IO_PAD_PEX_CNTRL, .dpd = 32, .voltage = UINT_MAX }, | ||
| 2498 | { .id = TEGRA_IO_PAD_PEX_CTL2, .dpd = 33, .voltage = UINT_MAX }, | ||
| 2499 | { .id = TEGRA_IO_PAD_PEX_L0_RST_N, .dpd = 34, .voltage = UINT_MAX }, | ||
| 2500 | { .id = TEGRA_IO_PAD_PEX_L1_RST_N, .dpd = 35, .voltage = UINT_MAX }, | ||
| 2501 | { .id = TEGRA_IO_PAD_SDMMC4, .dpd = 36, .voltage = UINT_MAX }, | ||
| 2502 | { .id = TEGRA_IO_PAD_PEX_L5_RST_N, .dpd = 37, .voltage = UINT_MAX }, | ||
| 2503 | { .id = TEGRA_IO_PAD_CSIC, .dpd = 43, .voltage = UINT_MAX }, | ||
| 2504 | { .id = TEGRA_IO_PAD_CSID, .dpd = 44, .voltage = UINT_MAX }, | ||
| 2505 | { .id = TEGRA_IO_PAD_CSIE, .dpd = 45, .voltage = UINT_MAX }, | ||
| 2506 | { .id = TEGRA_IO_PAD_CSIF, .dpd = 46, .voltage = UINT_MAX }, | ||
| 2507 | { .id = TEGRA_IO_PAD_SPI, .dpd = 47, .voltage = UINT_MAX }, | ||
| 2508 | { .id = TEGRA_IO_PAD_UFS, .dpd = 49, .voltage = UINT_MAX }, | ||
| 2509 | { .id = TEGRA_IO_PAD_CSIG, .dpd = 50, .voltage = UINT_MAX }, | ||
| 2510 | { .id = TEGRA_IO_PAD_CSIH, .dpd = 51, .voltage = UINT_MAX }, | ||
| 2511 | { .id = TEGRA_IO_PAD_EDP, .dpd = 53, .voltage = UINT_MAX }, | ||
| 2512 | { .id = TEGRA_IO_PAD_SDMMC1_HV, .dpd = 55, .voltage = UINT_MAX }, | ||
| 2513 | { .id = TEGRA_IO_PAD_SDMMC3_HV, .dpd = 56, .voltage = UINT_MAX }, | ||
| 2514 | { .id = TEGRA_IO_PAD_CONN, .dpd = 60, .voltage = UINT_MAX }, | ||
| 2515 | { .id = TEGRA_IO_PAD_AUDIO_HV, .dpd = 61, .voltage = UINT_MAX }, | ||
| 2516 | }; | ||
| 2517 | |||
| 2518 | static const struct tegra_wake_event tegra194_wake_events[] = { | ||
| 2519 | TEGRA_WAKE_GPIO("power", 29, 1, TEGRA194_AON_GPIO(EE, 4)), | ||
| 2520 | TEGRA_WAKE_IRQ("rtc", 73, 10), | ||
| 2521 | }; | ||
| 2522 | |||
| 2523 | static const struct tegra_pmc_soc tegra194_pmc_soc = { | ||
| 2524 | .num_powergates = 0, | ||
| 2525 | .powergates = NULL, | ||
| 2526 | .num_cpu_powergates = 0, | ||
| 2527 | .cpu_powergates = NULL, | ||
| 2528 | .has_tsense_reset = false, | ||
| 2529 | .has_gpu_clamps = false, | ||
| 2530 | .num_io_pads = ARRAY_SIZE(tegra194_io_pads), | ||
| 2531 | .io_pads = tegra194_io_pads, | ||
| 2532 | .regs = &tegra186_pmc_regs, | ||
| 2533 | .init = NULL, | ||
| 2534 | .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, | ||
| 2535 | .num_wake_events = ARRAY_SIZE(tegra194_wake_events), | ||
| 2536 | .wake_events = tegra194_wake_events, | ||
| 2137 | }; | 2537 | }; |
| 2138 | 2538 | ||
| 2139 | static const struct of_device_id tegra_pmc_match[] = { | 2539 | static const struct of_device_id tegra_pmc_match[] = { |
| 2140 | { .compatible = "nvidia,tegra194-pmc", .data = &tegra186_pmc_soc }, | 2540 | { .compatible = "nvidia,tegra194-pmc", .data = &tegra194_pmc_soc }, |
| 2141 | { .compatible = "nvidia,tegra186-pmc", .data = &tegra186_pmc_soc }, | 2541 | { .compatible = "nvidia,tegra186-pmc", .data = &tegra186_pmc_soc }, |
| 2142 | { .compatible = "nvidia,tegra210-pmc", .data = &tegra210_pmc_soc }, | 2542 | { .compatible = "nvidia,tegra210-pmc", .data = &tegra210_pmc_soc }, |
| 2143 | { .compatible = "nvidia,tegra132-pmc", .data = &tegra124_pmc_soc }, | 2543 | { .compatible = "nvidia,tegra132-pmc", .data = &tegra124_pmc_soc }, |
diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c index f5cb8c0af09f..d65e361c5de1 100644 --- a/drivers/soc/ti/wkup_m3_ipc.c +++ b/drivers/soc/ti/wkup_m3_ipc.c | |||
| @@ -57,6 +57,7 @@ | |||
| 57 | static struct wkup_m3_ipc *m3_ipc_state; | 57 | static struct wkup_m3_ipc *m3_ipc_state; |
| 58 | 58 | ||
| 59 | static const struct wkup_m3_wakeup_src wakeups[] = { | 59 | static const struct wkup_m3_wakeup_src wakeups[] = { |
| 60 | {.irq_nr = 16, .src = "PRCM"}, | ||
| 60 | {.irq_nr = 35, .src = "USB0_PHY"}, | 61 | {.irq_nr = 35, .src = "USB0_PHY"}, |
| 61 | {.irq_nr = 36, .src = "USB1_PHY"}, | 62 | {.irq_nr = 36, .src = "USB1_PHY"}, |
| 62 | {.irq_nr = 40, .src = "I2C0"}, | 63 | {.irq_nr = 40, .src = "I2C0"}, |
