diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-23 23:44:43 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-23 23:44:43 +0300 |
commit | 9e259f9352d52053058a234f7c062c4e4f56dc85 (patch) | |
tree | bfb1c442e27f95ddb9a04bae2a44ca9e3dd69a85 /drivers | |
parent | 5563ae9b39c5ba492be1b18f2d72fd43ba549915 (diff) | |
parent | f0fc40aff6fee100ffbed8328a0df88f8aa75fce (diff) | |
download | linux-9e259f9352d52053058a234f7c062c4e4f56dc85.tar.xz |
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.c | 3 | ||||
-rw-r--r-- | drivers/clk/davinci/psc-da850.c | 3 | ||||
-rw-r--r-- | drivers/clk/davinci/psc-dm365.c | 3 | ||||
-rw-r--r-- | drivers/clk/davinci/psc-dm644x.c | 3 | ||||
-rw-r--r-- | drivers/clk/davinci/psc-dm646x.c | 3 | ||||
-rw-r--r-- | drivers/input/serio/ams_delta_serio.c | 198 | ||||
-rw-r--r-- | drivers/net/ethernet/smsc/smc911x.c | 13 | ||||
-rw-r--r-- | drivers/net/ethernet/smsc/smc91x.c | 9 | ||||
-rw-r--r-- | drivers/net/ethernet/smsc/smc91x.h | 1 | ||||
-rw-r--r-- | drivers/soc/renesas/Makefile | 3 | ||||
-rw-r--r-- | drivers/soc/renesas/r9a06g032-smp.c | 96 | ||||
-rw-r--r-- | drivers/soc/renesas/rcar-sysc.c | 64 | ||||
-rw-r--r-- | drivers/soc/ti/pm33xx.c | 16 |
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, - ¶m, &dev->dev, "rx"); - lp->txdma = - dma_request_slave_channel_compat(mask, pxad_filter_fn, - ¶m, &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, - ¶m, &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"); |