summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-08-23 13:44:43 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2018-08-23 13:44:43 -0700
commit9e259f9352d52053058a234f7c062c4e4f56dc85 (patch)
treebfb1c442e27f95ddb9a04bae2a44ca9e3dd69a85 /drivers
parent5563ae9b39c5ba492be1b18f2d72fd43ba549915 (diff)
parentf0fc40aff6fee100ffbed8328a0df88f8aa75fce (diff)
downloadlinux-9e259f9352d52053058a234f7c062c4e4f56dc85.tar.bz2
Merge tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM 32-bit SoC platform updates from Olof Johansson: "Most of the SoC updates in this cycle are cleanups and moves to more modern infrastructure: - Davinci was moved to common clock framework - OMAP1-based Amstrad E3 "Superphone" saw a bunch of cleanups to the keyboard interface (bitbanged AT keyboard via GPIO). - Removal of some stale code for Renesas platforms - Power management improvements for i.MX6LL" * tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (112 commits) ARM: uniphier: select RESET_CONTROLLER arm64: uniphier: select RESET_CONTROLLER ARM: uniphier: remove empty Makefile ARM: exynos: Clear global variable on init error path ARM: exynos: Remove outdated maintainer information ARM: shmobile: Always enable ARCH_TIMER on SoCs with A7 and/or A15 ARM: shmobile: r8a7779: hide unused r8a7779_platform_cpu_kill soc: r9a06g032: don't build SMP files for non-SMP config ARM: shmobile: Add the R9A06G032 SMP enabler driver ARM: at91: pm: configure wakeup sources for ULP1 mode ARM: at91: pm: add PMC fast startup registers defines ARM: at91: pm: Add ULP1 mode support ARM: at91: pm: Use ULP0 naming instead of slow clock ARM: hisi: handle of_iomap and fix missing of_node_put ARM: hisi: check of_iomap and fix missing of_node_put ARM: hisi: fix error handling and missing of_node_put ARM: mx5: Set the DBGEN bit in ARM_GPC register ARM: imx51: Configure M4IF to avoid visual artifacts ARM: imx: call imx6sx_cpuidle_init() conditionally for 6sll ARM: imx: fix i.MX6SLL build ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/davinci/psc-da830.c3
-rw-r--r--drivers/clk/davinci/psc-da850.c3
-rw-r--r--drivers/clk/davinci/psc-dm365.c3
-rw-r--r--drivers/clk/davinci/psc-dm644x.c3
-rw-r--r--drivers/clk/davinci/psc-dm646x.c3
-rw-r--r--drivers/input/serio/ams_delta_serio.c198
-rw-r--r--drivers/net/ethernet/smsc/smc911x.c13
-rw-r--r--drivers/net/ethernet/smsc/smc91x.c9
-rw-r--r--drivers/net/ethernet/smsc/smc91x.h1
-rw-r--r--drivers/soc/renesas/Makefile3
-rw-r--r--drivers/soc/renesas/r9a06g032-smp.c96
-rw-r--r--drivers/soc/renesas/rcar-sysc.c64
-rw-r--r--drivers/soc/ti/pm33xx.c16
13 files changed, 268 insertions, 147 deletions
diff --git a/drivers/clk/davinci/psc-da830.c b/drivers/clk/davinci/psc-da830.c
index 081b039fcb02..6481337382a6 100644
--- a/drivers/clk/davinci/psc-da830.c
+++ b/drivers/clk/davinci/psc-da830.c
@@ -14,6 +14,7 @@
#include "psc.h"
+LPSC_CLKDEV1(aemif_clkdev, NULL, "ti-aemif");
LPSC_CLKDEV1(spi0_clkdev, NULL, "spi_davinci.0");
LPSC_CLKDEV1(mmcsd_clkdev, NULL, "da830-mmc.0");
LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0");
@@ -22,7 +23,7 @@ static const struct davinci_lpsc_clk_info da830_psc0_info[] = {
LPSC(0, 0, tpcc, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
LPSC(1, 0, tptc0, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
LPSC(2, 0, tptc1, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
- LPSC(3, 0, aemif, pll0_sysclk3, NULL, LPSC_ALWAYS_ENABLED),
+ LPSC(3, 0, aemif, pll0_sysclk3, aemif_clkdev, LPSC_ALWAYS_ENABLED),
LPSC(4, 0, spi0, pll0_sysclk2, spi0_clkdev, 0),
LPSC(5, 0, mmcsd, pll0_sysclk2, mmcsd_clkdev, 0),
LPSC(6, 0, aintc, pll0_sysclk4, NULL, LPSC_ALWAYS_ENABLED),
diff --git a/drivers/clk/davinci/psc-da850.c b/drivers/clk/davinci/psc-da850.c
index d196dcbed560..5a18bca464cd 100644
--- a/drivers/clk/davinci/psc-da850.c
+++ b/drivers/clk/davinci/psc-da850.c
@@ -16,8 +16,7 @@
#include "psc.h"
-LPSC_CLKDEV2(emifa_clkdev, NULL, "ti-aemif",
- "aemif", "davinci_nand.0");
+LPSC_CLKDEV1(emifa_clkdev, NULL, "ti-aemif");
LPSC_CLKDEV1(spi0_clkdev, NULL, "spi_davinci.0");
LPSC_CLKDEV1(mmcsd0_clkdev, NULL, "da830-mmc.0");
LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0");
diff --git a/drivers/clk/davinci/psc-dm365.c b/drivers/clk/davinci/psc-dm365.c
index 8c73086cc676..c75424f4ea3b 100644
--- a/drivers/clk/davinci/psc-dm365.c
+++ b/drivers/clk/davinci/psc-dm365.c
@@ -21,7 +21,8 @@ LPSC_CLKDEV1(mmcsd1_clkdev, NULL, "da830-mmc.1");
LPSC_CLKDEV1(asp0_clkdev, NULL, "davinci-mcbsp");
LPSC_CLKDEV1(usb_clkdev, "usb", NULL);
LPSC_CLKDEV1(spi2_clkdev, NULL, "spi_davinci.2");
-LPSC_CLKDEV1(aemif_clkdev, "aemif", NULL);
+LPSC_CLKDEV2(aemif_clkdev, "aemif", NULL,
+ NULL, "ti-aemif");
LPSC_CLKDEV1(mmcsd0_clkdev, NULL, "da830-mmc.0");
LPSC_CLKDEV1(i2c_clkdev, NULL, "i2c_davinci.1");
LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0");
diff --git a/drivers/clk/davinci/psc-dm644x.c b/drivers/clk/davinci/psc-dm644x.c
index fc0230e3a3d6..0cea6e0bd5f0 100644
--- a/drivers/clk/davinci/psc-dm644x.c
+++ b/drivers/clk/davinci/psc-dm644x.c
@@ -21,7 +21,8 @@ LPSC_CLKDEV2(emac_clkdev, NULL, "davinci_emac.1",
"fck", "davinci_mdio.0");
LPSC_CLKDEV1(usb_clkdev, "usb", NULL);
LPSC_CLKDEV1(ide_clkdev, NULL, "palm_bk3710");
-LPSC_CLKDEV1(aemif_clkdev, "aemif", NULL);
+LPSC_CLKDEV2(aemif_clkdev, "aemif", NULL,
+ NULL, "ti-aemif");
LPSC_CLKDEV1(mmcsd_clkdev, NULL, "dm6441-mmc.0");
LPSC_CLKDEV1(asp0_clkdev, NULL, "davinci-mcbsp");
LPSC_CLKDEV1(i2c_clkdev, NULL, "i2c_davinci.1");
diff --git a/drivers/clk/davinci/psc-dm646x.c b/drivers/clk/davinci/psc-dm646x.c
index c3f82ed70a80..20012dc7471a 100644
--- a/drivers/clk/davinci/psc-dm646x.c
+++ b/drivers/clk/davinci/psc-dm646x.c
@@ -18,7 +18,8 @@
LPSC_CLKDEV1(ide_clkdev, NULL, "palm_bk3710");
LPSC_CLKDEV2(emac_clkdev, NULL, "davinci_emac.1",
"fck", "davinci_mdio.0");
-LPSC_CLKDEV1(aemif_clkdev, "aemif", NULL);
+LPSC_CLKDEV2(aemif_clkdev, "aemif", NULL,
+ NULL, "ti-aemif");
LPSC_CLKDEV1(mcasp0_clkdev, NULL, "davinci-mcasp.0");
LPSC_CLKDEV1(mcasp1_clkdev, NULL, "davinci-mcasp.1");
LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0");
diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c
index 3df501c3421b..f8663d7891f2 100644
--- a/drivers/input/serio/ams_delta_serio.c
+++ b/drivers/input/serio/ams_delta_serio.c
@@ -20,32 +20,33 @@
* However, when used with the E3 mailboard that producecs non-standard
* scancodes, a custom key table must be prepared and loaded from userspace.
*/
-#include <linux/gpio.h>
#include <linux/irq.h>
+#include <linux/platform_data/ams-delta-fiq.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#include <linux/serio.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <asm/mach-types.h>
-#include <mach/board-ams-delta.h>
-
-#include <mach/ams-delta-fiq.h>
+#define DRIVER_NAME "ams-delta-serio"
MODULE_AUTHOR("Matt Callow");
MODULE_DESCRIPTION("AMS Delta (E3) keyboard port driver");
MODULE_LICENSE("GPL");
-static struct serio *ams_delta_serio;
+struct ams_delta_serio {
+ struct serio *serio;
+ struct regulator *vcc;
+ unsigned int *fiq_buffer;
+};
-static int check_data(int data)
+static int check_data(struct serio *serio, int data)
{
int i, parity = 0;
/* check valid stop bit */
if (!(data & 0x400)) {
- dev_warn(&ams_delta_serio->dev,
- "invalid stop bit, data=0x%X\n",
- data);
+ dev_warn(&serio->dev, "invalid stop bit, data=0x%X\n", data);
return SERIO_FRAME;
}
/* calculate the parity */
@@ -55,9 +56,9 @@ static int check_data(int data)
}
/* it should be odd */
if (!(parity & 0x01)) {
- dev_warn(&ams_delta_serio->dev,
- "parity check failed, data=0x%X parity=0x%X\n",
- data, parity);
+ dev_warn(&serio->dev,
+ "parity check failed, data=0x%X parity=0x%X\n", data,
+ parity);
return SERIO_PARITY;
}
return 0;
@@ -65,127 +66,130 @@ static int check_data(int data)
static irqreturn_t ams_delta_serio_interrupt(int irq, void *dev_id)
{
- int *circ_buff = &fiq_buffer[FIQ_CIRC_BUFF];
+ struct ams_delta_serio *priv = dev_id;
+ int *circ_buff = &priv->fiq_buffer[FIQ_CIRC_BUFF];
int data, dfl;
u8 scancode;
- fiq_buffer[FIQ_IRQ_PEND] = 0;
+ priv->fiq_buffer[FIQ_IRQ_PEND] = 0;
/*
* Read data from the circular buffer, check it
* and then pass it on the serio
*/
- while (fiq_buffer[FIQ_KEYS_CNT] > 0) {
+ while (priv->fiq_buffer[FIQ_KEYS_CNT] > 0) {
- data = circ_buff[fiq_buffer[FIQ_HEAD_OFFSET]++];
- fiq_buffer[FIQ_KEYS_CNT]--;
- if (fiq_buffer[FIQ_HEAD_OFFSET] == fiq_buffer[FIQ_BUF_LEN])
- fiq_buffer[FIQ_HEAD_OFFSET] = 0;
+ data = circ_buff[priv->fiq_buffer[FIQ_HEAD_OFFSET]++];
+ priv->fiq_buffer[FIQ_KEYS_CNT]--;
+ if (priv->fiq_buffer[FIQ_HEAD_OFFSET] ==
+ priv->fiq_buffer[FIQ_BUF_LEN])
+ priv->fiq_buffer[FIQ_HEAD_OFFSET] = 0;
- dfl = check_data(data);
+ dfl = check_data(priv->serio, data);
scancode = (u8) (data >> 1) & 0xFF;
- serio_interrupt(ams_delta_serio, scancode, dfl);
+ serio_interrupt(priv->serio, scancode, dfl);
}
return IRQ_HANDLED;
}
static int ams_delta_serio_open(struct serio *serio)
{
- /* enable keyboard */
- gpio_set_value(AMS_DELTA_GPIO_PIN_KEYBRD_PWR, 1);
+ struct ams_delta_serio *priv = serio->port_data;
- return 0;
+ /* enable keyboard */
+ return regulator_enable(priv->vcc);
}
static void ams_delta_serio_close(struct serio *serio)
{
+ struct ams_delta_serio *priv = serio->port_data;
+
/* disable keyboard */
- gpio_set_value(AMS_DELTA_GPIO_PIN_KEYBRD_PWR, 0);
+ regulator_disable(priv->vcc);
}
-static const struct gpio ams_delta_gpios[] __initconst_or_module = {
- {
- .gpio = AMS_DELTA_GPIO_PIN_KEYBRD_DATA,
- .flags = GPIOF_DIR_IN,
- .label = "serio-data",
- },
- {
- .gpio = AMS_DELTA_GPIO_PIN_KEYBRD_CLK,
- .flags = GPIOF_DIR_IN,
- .label = "serio-clock",
- },
- {
- .gpio = AMS_DELTA_GPIO_PIN_KEYBRD_PWR,
- .flags = GPIOF_OUT_INIT_LOW,
- .label = "serio-power",
- },
- {
- .gpio = AMS_DELTA_GPIO_PIN_KEYBRD_DATAOUT,
- .flags = GPIOF_OUT_INIT_LOW,
- .label = "serio-dataout",
- },
-};
-
-static int __init ams_delta_serio_init(void)
+static int ams_delta_serio_init(struct platform_device *pdev)
{
- int err;
-
- if (!machine_is_ams_delta())
- return -ENODEV;
+ struct ams_delta_serio *priv;
+ struct serio *serio;
+ int irq, err;
- ams_delta_serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
- if (!ams_delta_serio)
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
return -ENOMEM;
- ams_delta_serio->id.type = SERIO_8042;
- ams_delta_serio->open = ams_delta_serio_open;
- ams_delta_serio->close = ams_delta_serio_close;
- strlcpy(ams_delta_serio->name, "AMS DELTA keyboard adapter",
- sizeof(ams_delta_serio->name));
- strlcpy(ams_delta_serio->phys, "GPIO/serio0",
- sizeof(ams_delta_serio->phys));
-
- err = gpio_request_array(ams_delta_gpios,
- ARRAY_SIZE(ams_delta_gpios));
- if (err) {
- pr_err("ams_delta_serio: Couldn't request gpio pins\n");
- goto serio;
+ priv->fiq_buffer = pdev->dev.platform_data;
+ if (!priv->fiq_buffer)
+ return -EINVAL;
+
+ priv->vcc = devm_regulator_get(&pdev->dev, "vcc");
+ if (IS_ERR(priv->vcc)) {
+ err = PTR_ERR(priv->vcc);
+ dev_err(&pdev->dev, "regulator request failed (%d)\n", err);
+ /*
+ * When running on a non-dt platform and requested regulator
+ * is not available, devm_regulator_get() never returns
+ * -EPROBE_DEFER as it is not able to justify if the regulator
+ * may still appear later. On the other hand, the board can
+ * still set full constriants flag at late_initcall in order
+ * to instruct devm_regulator_get() to returnn a dummy one
+ * if sufficient. Hence, if we get -ENODEV here, let's convert
+ * it to -EPROBE_DEFER and wait for the board to decide or
+ * let Deferred Probe infrastructure handle this error.
+ */
+ if (err == -ENODEV)
+ err = -EPROBE_DEFER;
+ return err;
}
- err = request_irq(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK),
- ams_delta_serio_interrupt, IRQ_TYPE_EDGE_RISING,
- "ams-delta-serio", 0);
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return -ENXIO;
+
+ err = devm_request_irq(&pdev->dev, irq, ams_delta_serio_interrupt,
+ IRQ_TYPE_EDGE_RISING, DRIVER_NAME, priv);
if (err < 0) {
- pr_err("ams_delta_serio: couldn't request gpio interrupt %d\n",
- gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK));
- goto gpio;
+ dev_err(&pdev->dev, "IRQ request failed (%d)\n", err);
+ return err;
}
- /*
- * Since GPIO register handling for keyboard clock pin is performed
- * at FIQ level, switch back from edge to simple interrupt handler
- * to avoid bad interaction.
- */
- irq_set_handler(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK),
- handle_simple_irq);
- serio_register_port(ams_delta_serio);
- dev_info(&ams_delta_serio->dev, "%s\n", ams_delta_serio->name);
+ serio = kzalloc(sizeof(*serio), GFP_KERNEL);
+ if (!serio)
+ return -ENOMEM;
+
+ priv->serio = serio;
+
+ serio->id.type = SERIO_8042;
+ serio->open = ams_delta_serio_open;
+ serio->close = ams_delta_serio_close;
+ strlcpy(serio->name, "AMS DELTA keyboard adapter", sizeof(serio->name));
+ strlcpy(serio->phys, dev_name(&pdev->dev), sizeof(serio->phys));
+ serio->dev.parent = &pdev->dev;
+ serio->port_data = priv;
+
+ serio_register_port(serio);
+
+ platform_set_drvdata(pdev, priv);
+
+ dev_info(&serio->dev, "%s\n", serio->name);
return 0;
-gpio:
- gpio_free_array(ams_delta_gpios,
- ARRAY_SIZE(ams_delta_gpios));
-serio:
- kfree(ams_delta_serio);
- return err;
}
-module_init(ams_delta_serio_init);
-static void __exit ams_delta_serio_exit(void)
+static int ams_delta_serio_exit(struct platform_device *pdev)
{
- serio_unregister_port(ams_delta_serio);
- free_irq(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), 0);
- gpio_free_array(ams_delta_gpios,
- ARRAY_SIZE(ams_delta_gpios));
+ struct ams_delta_serio *priv = platform_get_drvdata(pdev);
+
+ serio_unregister_port(priv->serio);
+
+ return 0;
}
-module_exit(ams_delta_serio_exit);
+
+static struct platform_driver ams_delta_serio_driver = {
+ .probe = ams_delta_serio_init,
+ .remove = ams_delta_serio_exit,
+ .driver = {
+ .name = DRIVER_NAME
+ },
+};
+module_platform_driver(ams_delta_serio_driver);
diff --git a/drivers/net/ethernet/smsc/smc911x.c b/drivers/net/ethernet/smsc/smc911x.c
index 05157442a980..b1b53f6c452f 100644
--- a/drivers/net/ethernet/smsc/smc911x.c
+++ b/drivers/net/ethernet/smsc/smc911x.c
@@ -74,7 +74,6 @@ static const char version[] =
#include <linux/skbuff.h>
#include <linux/dmaengine.h>
-#include <linux/dma/pxa-dma.h>
#include <asm/io.h>
@@ -1795,7 +1794,6 @@ static int smc911x_probe(struct net_device *dev)
#ifdef SMC_USE_DMA
struct dma_slave_config config;
dma_cap_mask_t mask;
- struct pxad_param param;
#endif
DBG(SMC_DEBUG_FUNC, dev, "--> %s\n", __func__);
@@ -1971,15 +1969,8 @@ static int smc911x_probe(struct net_device *dev)
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
- param.prio = PXAD_PRIO_LOWEST;
- param.drcmr = -1UL;
-
- lp->rxdma =
- dma_request_slave_channel_compat(mask, pxad_filter_fn,
- &param, &dev->dev, "rx");
- lp->txdma =
- dma_request_slave_channel_compat(mask, pxad_filter_fn,
- &param, &dev->dev, "tx");
+ lp->rxdma = dma_request_channel(mask, NULL, NULL);
+ lp->txdma = dma_request_channel(mask, NULL, NULL);
lp->rxdma_active = 0;
lp->txdma_active = 0;
diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
index 080428762858..b944828f9ea3 100644
--- a/drivers/net/ethernet/smsc/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -2019,17 +2019,10 @@ static int smc_probe(struct net_device *dev, void __iomem *ioaddr,
# endif
if (lp->cfg.flags & SMC91X_USE_DMA) {
dma_cap_mask_t mask;
- struct pxad_param param;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
- param.prio = PXAD_PRIO_LOWEST;
- param.drcmr = -1UL;
-
- lp->dma_chan =
- dma_request_slave_channel_compat(mask, pxad_filter_fn,
- &param, &dev->dev,
- "data");
+ lp->dma_chan = dma_request_channel(mask, NULL, NULL);
}
#endif
diff --git a/drivers/net/ethernet/smsc/smc91x.h b/drivers/net/ethernet/smsc/smc91x.h
index b337ee97e0c0..a27352229fc2 100644
--- a/drivers/net/ethernet/smsc/smc91x.h
+++ b/drivers/net/ethernet/smsc/smc91x.h
@@ -301,7 +301,6 @@ struct smc_local {
* as RX which can overrun memory and lose packets.
*/
#include <linux/dma-mapping.h>
-#include <linux/dma/pxa-dma.h>
#ifdef SMC_insl
#undef SMC_insl
diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile
index 7dc0f20d7907..c37b0803c1b6 100644
--- a/drivers/soc/renesas/Makefile
+++ b/drivers/soc/renesas/Makefile
@@ -18,6 +18,9 @@ obj-$(CONFIG_SYSC_R8A77970) += r8a77970-sysc.o
obj-$(CONFIG_SYSC_R8A77980) += r8a77980-sysc.o
obj-$(CONFIG_SYSC_R8A77990) += r8a77990-sysc.o
obj-$(CONFIG_SYSC_R8A77995) += r8a77995-sysc.o
+ifdef CONFIG_SMP
+obj-$(CONFIG_ARCH_R9A06G032) += r9a06g032-smp.o
+endif
# Family
obj-$(CONFIG_RST_RCAR) += rcar-rst.o
diff --git a/drivers/soc/renesas/r9a06g032-smp.c b/drivers/soc/renesas/r9a06g032-smp.c
new file mode 100644
index 000000000000..a1926e8d73f2
--- /dev/null
+++ b/drivers/soc/renesas/r9a06g032-smp.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * R9A06G032 Second CA7 enabler.
+ *
+ * Copyright (C) 2018 Renesas Electronics Europe Limited
+ *
+ * Michel Pollet <michel.pollet@bp.renesas.com>, <buserror@gmail.com>
+ * Derived from actions,s500-smp
+ */
+
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/smp.h>
+
+/*
+ * The second CPU is parked in ROM at boot time. It requires waking it after
+ * writing an address into the BOOTADDR register of sysctrl.
+ *
+ * So the default value of the "cpu-release-addr" corresponds to BOOTADDR...
+ *
+ * *However* the BOOTADDR register is not available when the kernel
+ * starts in NONSEC mode.
+ *
+ * So for NONSEC mode, the bootloader re-parks the second CPU into a pen
+ * in SRAM, and changes the "cpu-release-addr" of linux's DT to a SRAM address,
+ * which is not restricted.
+ */
+
+static void __iomem *cpu_bootaddr;
+
+static DEFINE_SPINLOCK(cpu_lock);
+
+static int
+r9a06g032_smp_boot_secondary(unsigned int cpu,
+ struct task_struct *idle)
+{
+ if (!cpu_bootaddr)
+ return -ENODEV;
+
+ spin_lock(&cpu_lock);
+
+ writel(__pa_symbol(secondary_startup), cpu_bootaddr);
+ arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+
+ spin_unlock(&cpu_lock);
+
+ return 0;
+}
+
+static void __init r9a06g032_smp_prepare_cpus(unsigned int max_cpus)
+{
+ struct device_node *dn;
+ int ret = -EINVAL, dns;
+ u32 bootaddr;
+
+ dn = of_get_cpu_node(1, NULL);
+ if (!dn) {
+ pr_err("CPU#1: missing device tree node\n");
+ return;
+ }
+ /*
+ * Determine the address from which the CPU is polling.
+ * The bootloader *does* change this property.
+ * Note: The property can be either 64 or 32 bits, so handle both cases
+ */
+ if (of_find_property(dn, "cpu-release-addr", &dns)) {
+ if (dns == sizeof(u64)) {
+ u64 temp;
+
+ ret = of_property_read_u64(dn,
+ "cpu-release-addr", &temp);
+ bootaddr = temp;
+ } else {
+ ret = of_property_read_u32(dn,
+ "cpu-release-addr",
+ &bootaddr);
+ }
+ }
+ of_node_put(dn);
+ if (ret) {
+ pr_err("CPU#1: invalid cpu-release-addr property\n");
+ return;
+ }
+ pr_info("CPU#1: cpu-release-addr %08x\n", bootaddr);
+
+ cpu_bootaddr = ioremap(bootaddr, sizeof(bootaddr));
+}
+
+static const struct smp_operations r9a06g032_smp_ops __initconst = {
+ .smp_prepare_cpus = r9a06g032_smp_prepare_cpus,
+ .smp_boot_secondary = r9a06g032_smp_boot_secondary,
+};
+
+CPU_METHOD_OF_DECLARE(r9a06g032_smp,
+ "renesas,r9a06g032-smp", &r9a06g032_smp_ops);
diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c
index 50d03d8b4f9a..029188e8be6e 100644
--- a/drivers/soc/renesas/rcar-sysc.c
+++ b/drivers/soc/renesas/rcar-sysc.c
@@ -58,6 +58,12 @@
#define RCAR_PD_ALWAYS_ON 32 /* Always-on power area */
+struct rcar_sysc_ch {
+ u16 chan_offs;
+ u8 chan_bit;
+ u8 isr_bit;
+};
+
static void __iomem *rcar_sysc_base;
static DEFINE_SPINLOCK(rcar_sysc_lock); /* SMP CPUs + I/O devices */
@@ -143,12 +149,12 @@ static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on)
return ret;
}
-int rcar_sysc_power_down(const struct rcar_sysc_ch *sysc_ch)
+static int rcar_sysc_power_down(const struct rcar_sysc_ch *sysc_ch)
{
return rcar_sysc_power(sysc_ch, false);
}
-int rcar_sysc_power_up(const struct rcar_sysc_ch *sysc_ch)
+static int rcar_sysc_power_up(const struct rcar_sysc_ch *sysc_ch)
{
return rcar_sysc_power(sysc_ch, true);
}
@@ -315,6 +321,8 @@ struct rcar_pm_domains {
struct generic_pm_domain *domains[RCAR_PD_ALWAYS_ON + 1];
};
+static struct genpd_onecell_data *rcar_sysc_onecell_data;
+
static int __init rcar_sysc_pd_init(void)
{
const struct rcar_sysc_info *info;
@@ -326,9 +334,6 @@ static int __init rcar_sysc_pd_init(void)
unsigned int i;
int error;
- if (rcar_sysc_base)
- return 0;
-
np = of_find_matching_node_and_match(NULL, rcar_sysc_matches, &match);
if (!np)
return -ENODEV;
@@ -361,6 +366,7 @@ static int __init rcar_sysc_pd_init(void)
domains->onecell_data.domains = domains->domains;
domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains);
+ rcar_sysc_onecell_data = &domains->onecell_data;
for (i = 0, syscier = 0; i < info->num_areas; i++)
syscier |= BIT(info->areas[i].isr_bit);
@@ -448,27 +454,39 @@ void __init rcar_sysc_nullify(struct rcar_sysc_area *areas,
}
}
-void __init rcar_sysc_init(phys_addr_t base, u32 syscier)
+#ifdef CONFIG_ARCH_R8A7779
+static int rcar_sysc_power_cpu(unsigned int idx, bool on)
{
- u32 syscimr;
+ struct generic_pm_domain *genpd;
+ struct rcar_sysc_pd *pd;
+ unsigned int i;
- if (!rcar_sysc_pd_init())
- return;
+ if (!rcar_sysc_onecell_data)
+ return -ENODEV;
- rcar_sysc_base = ioremap_nocache(base, PAGE_SIZE);
+ for (i = 0; i < rcar_sysc_onecell_data->num_domains; i++) {
+ genpd = rcar_sysc_onecell_data->domains[i];
+ if (!genpd)
+ continue;
- /*
- * Mask all interrupt sources to prevent the CPU from receiving them.
- * Make sure not to clear reserved bits that were set before.
- */
- syscimr = ioread32(rcar_sysc_base + SYSCIMR);
- syscimr |= syscier;
- pr_debug("%s: syscimr = 0x%08x\n", __func__, syscimr);
- iowrite32(syscimr, rcar_sysc_base + SYSCIMR);
+ pd = to_rcar_pd(genpd);
+ if (!(pd->flags & PD_CPU) || pd->ch.chan_bit != idx)
+ continue;
- /*
- * SYSC needs all interrupt sources enabled to control power.
- */
- pr_debug("%s: syscier = 0x%08x\n", __func__, syscier);
- iowrite32(syscier, rcar_sysc_base + SYSCIER);
+ return on ? rcar_sysc_power_up(&pd->ch)
+ : rcar_sysc_power_down(&pd->ch);
+ }
+
+ return -ENOENT;
+}
+
+int rcar_sysc_power_down_cpu(unsigned int cpu)
+{
+ return rcar_sysc_power_cpu(cpu, false);
+}
+
+int rcar_sysc_power_up_cpu(unsigned int cpu)
+{
+ return rcar_sysc_power_cpu(cpu, true);
}
+#endif /* CONFIG_ARCH_R8A7779 */
diff --git a/drivers/soc/ti/pm33xx.c b/drivers/soc/ti/pm33xx.c
index 652739c7f718..d0dab323651f 100644
--- a/drivers/soc/ti/pm33xx.c
+++ b/drivers/soc/ti/pm33xx.c
@@ -41,6 +41,8 @@ static struct am33xx_pm_sram_addr *pm_sram;
static struct device *pm33xx_dev;
static struct wkup_m3_ipc *m3_ipc;
+static unsigned long suspend_wfi_flags;
+
static u32 sram_suspend_address(unsigned long addr)
{
return ((unsigned long)am33xx_do_wfi_sram +
@@ -53,7 +55,7 @@ static int am33xx_pm_suspend(suspend_state_t suspend_state)
int i, ret = 0;
ret = pm_ops->soc_suspend((unsigned long)suspend_state,
- am33xx_do_wfi_sram);
+ am33xx_do_wfi_sram, suspend_wfi_flags);
if (ret) {
dev_err(pm33xx_dev, "PM: Kernel suspend failure\n");
@@ -227,6 +229,7 @@ static int am33xx_push_sram_idle(void)
ro_sram_data.amx3_pm_sram_data_virt = ocmcram_location_data;
ro_sram_data.amx3_pm_sram_data_phys =
gen_pool_virt_to_phys(sram_pool_data, ocmcram_location_data);
+ ro_sram_data.rtc_base_virt = pm_ops->get_rtc_base_addr();
/* Save physical address to calculate resume offset during pm init */
am33xx_do_wfi_sram_phys = gen_pool_virt_to_phys(sram_pool,
@@ -310,6 +313,17 @@ static int am33xx_pm_probe(struct platform_device *pdev)
suspend_set_ops(&am33xx_pm_ops);
#endif /* CONFIG_SUSPEND */
+ /*
+ * For a system suspend we must flush the caches, we want
+ * the DDR in self-refresh, we want to save the context
+ * of the EMIF, and we want the wkup_m3 to handle low-power
+ * transition.
+ */
+ suspend_wfi_flags |= WFI_FLAG_FLUSH_CACHE;
+ suspend_wfi_flags |= WFI_FLAG_SELF_REFRESH;
+ suspend_wfi_flags |= WFI_FLAG_SAVE_EMIF;
+ suspend_wfi_flags |= WFI_FLAG_WAKE_M3;
+
ret = pm_ops->init();
if (ret) {
dev_err(dev, "Unable to call core pm init!\n");