Skip to content

Commit

Permalink
Merge tag 'at91-soc-5.18' of git://git.kernel.org/pub/scm/linux/kerne…
Browse files Browse the repository at this point in the history
…l/git/at91/linux into arm/soc

AT91 & POLARFIRE SoC #1 for 5.18:

- sama7g5: CPU idle support with CPUFreq operating points defined in DT
- polarfire: addition of the soc system controller

* tag 'at91-soc-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/at91/linux:
  soc: add microchip polarfire soc system controller
  ARM: at91: Kconfig: select PM_OPP
  ARM: at91: PM: add cpu idle support for sama7g5
  ARM: at91: ddr: fix typo to align with datasheet naming
  ARM: at91: ddr: align macro definitions
  ARM: at91: ddr: remove CONFIG_SOC_SAMA7 dependency

Link: https://lore.kernel.org/r/20220225121943.71494-1-nicolas.ferre@microchip.com
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
  • Loading branch information
Arnd Bergmann committed Feb 25, 2022
2 parents 16018c0 + d0054a4 commit 022e522
Show file tree
Hide file tree
Showing 11 changed files with 248 additions and 14 deletions.
1 change: 1 addition & 0 deletions arch/arm/mach-at91/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ config SOC_SAMA7G5
select HAVE_AT91_GENERATED_CLK
select HAVE_AT91_SAM9X60_PLL
select HAVE_AT91_UTMI
select PM_OPP
select SOC_SAMA7
help
Select this if you are using one of Microchip's SAMA7G5 family SoC.
Expand Down
27 changes: 26 additions & 1 deletion arch/arm/mach-at91/pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,30 @@ static void at91sam9_sdram_standby(void)
at91_ramc_write(1, AT91_SDRAMC_LPR, saved_lpr1);
}

static void sama7g5_standby(void)
{
int pwrtmg, ratio;

pwrtmg = readl(soc_pm.data.ramc[0] + UDDRC_PWRCTL);
ratio = readl(soc_pm.data.pmc + AT91_PMC_RATIO);

/*
* Place RAM into self-refresh after a maximum idle clocks. The maximum
* idle clocks is configured by bootloader in
* UDDRC_PWRMGT.SELFREF_TO_X32.
*/
writel(pwrtmg | UDDRC_PWRCTL_SELFREF_EN,
soc_pm.data.ramc[0] + UDDRC_PWRCTL);
/* Divide CPU clock by 16. */
writel(ratio & ~AT91_PMC_RATIO_RATIO, soc_pm.data.pmc + AT91_PMC_RATIO);

cpu_do_idle();

/* Restore previous configuration. */
writel(ratio, soc_pm.data.pmc + AT91_PMC_RATIO);
writel(pwrtmg, soc_pm.data.ramc[0] + UDDRC_PWRCTL);
}

struct ramc_info {
void (*idle)(void);
unsigned int memctrl;
Expand All @@ -615,14 +639,15 @@ static const struct ramc_info ramc_infos[] __initconst = {
{ .idle = at91sam9_sdram_standby, .memctrl = AT91_MEMCTRL_SDRAMC},
{ .idle = at91_ddr_standby, .memctrl = AT91_MEMCTRL_DDRSDR},
{ .idle = sama5d3_ddr_standby, .memctrl = AT91_MEMCTRL_DDRSDR},
{ .idle = sama7g5_standby, },
};

static const struct of_device_id ramc_ids[] __initconst = {
{ .compatible = "atmel,at91rm9200-sdramc", .data = &ramc_infos[0] },
{ .compatible = "atmel,at91sam9260-sdramc", .data = &ramc_infos[1] },
{ .compatible = "atmel,at91sam9g45-ddramc", .data = &ramc_infos[2] },
{ .compatible = "atmel,sama5d3-ddramc", .data = &ramc_infos[3] },
{ .compatible = "microchip,sama7g5-uddrc", },
{ .compatible = "microchip,sama7g5-uddrc", .data = &ramc_infos[4], },
{ /*sentinel*/ }
};

Expand Down
4 changes: 2 additions & 2 deletions arch/arm/mach-at91/pm_suspend.S
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ sr_ena_1:

/* Switch to self-refresh. */
ldr tmp1, [r2, #UDDRC_PWRCTL]
orr tmp1, tmp1, #UDDRC_PWRCTRL_SELFREF_SW
orr tmp1, tmp1, #UDDRC_PWRCTL_SELFREF_SW
str tmp1, [r2, #UDDRC_PWRCTL]

sr_ena_2:
Expand Down Expand Up @@ -276,7 +276,7 @@ sr_dis_5:

/* Trigger self-refresh exit. */
ldr tmp1, [r2, #UDDRC_PWRCTL]
bic tmp1, tmp1, #UDDRC_PWRCTRL_SELFREF_SW
bic tmp1, tmp1, #UDDRC_PWRCTL_SELFREF_SW
str tmp1, [r2, #UDDRC_PWRCTL]

sr_dis_6:
Expand Down
1 change: 1 addition & 0 deletions drivers/soc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ source "drivers/soc/imx/Kconfig"
source "drivers/soc/ixp4xx/Kconfig"
source "drivers/soc/litex/Kconfig"
source "drivers/soc/mediatek/Kconfig"
source "drivers/soc/microchip/Kconfig"
source "drivers/soc/qcom/Kconfig"
source "drivers/soc/renesas/Kconfig"
source "drivers/soc/rockchip/Kconfig"
Expand Down
1 change: 1 addition & 0 deletions drivers/soc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ obj-y += ixp4xx/
obj-$(CONFIG_SOC_XWAY) += lantiq/
obj-$(CONFIG_LITEX_SOC_CONTROLLER) += litex/
obj-y += mediatek/
obj-y += microchip/
obj-y += amlogic/
obj-y += qcom/
obj-y += renesas/
Expand Down
10 changes: 10 additions & 0 deletions drivers/soc/microchip/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
config POLARFIRE_SOC_SYS_CTRL
tristate "POLARFIRE_SOC_SYS_CTRL"
depends on POLARFIRE_SOC_MAILBOX
help
This driver adds support for the PolarFire SoC (MPFS) system controller.

To compile this driver as a module, choose M here. the
module will be called mpfs_system_controller.

If unsure, say N.
1 change: 1 addition & 0 deletions drivers/soc/microchip/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
obj-$(CONFIG_POLARFIRE_SOC_SYS_CTRL) += mpfs-sys-controller.o
194 changes: 194 additions & 0 deletions drivers/soc/microchip/mpfs-sys-controller.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Microchip PolarFire SoC (MPFS) system controller driver
*
* Copyright (c) 2020-2021 Microchip Corporation. All rights reserved.
*
* Author: Conor Dooley <conor.dooley@microchip.com>
*
*/

#include <linux/slab.h>
#include <linux/kref.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/of_platform.h>
#include <linux/mailbox_client.h>
#include <linux/platform_device.h>
#include <soc/microchip/mpfs.h>

static DEFINE_MUTEX(transaction_lock);

struct mpfs_sys_controller {
struct mbox_client client;
struct mbox_chan *chan;
struct completion c;
struct kref consumers;
};

int mpfs_blocking_transaction(struct mpfs_sys_controller *sys_controller, struct mpfs_mss_msg *msg)
{
int ret, err;

err = mutex_lock_interruptible(&transaction_lock);
if (err)
return err;

reinit_completion(&sys_controller->c);

ret = mbox_send_message(sys_controller->chan, msg);
if (ret >= 0) {
if (wait_for_completion_timeout(&sys_controller->c, HZ)) {
ret = 0;
} else {
ret = -ETIMEDOUT;
dev_warn(sys_controller->client.dev,
"MPFS sys controller transaction timeout\n");
}
} else {
dev_err(sys_controller->client.dev,
"mpfs sys controller transaction returned %d\n", ret);
}

mutex_unlock(&transaction_lock);

return ret;
}
EXPORT_SYMBOL(mpfs_blocking_transaction);

static void rx_callback(struct mbox_client *client, void *msg)
{
struct mpfs_sys_controller *sys_controller =
container_of(client, struct mpfs_sys_controller, client);

complete(&sys_controller->c);
}

static void mpfs_sys_controller_delete(struct kref *kref)
{
struct mpfs_sys_controller *sys_controller = container_of(kref, struct mpfs_sys_controller,
consumers);

mbox_free_channel(sys_controller->chan);
kfree(sys_controller);
}

void mpfs_sys_controller_put(void *data)
{
struct mpfs_sys_controller *sys_controller = data;

kref_put(&sys_controller->consumers, mpfs_sys_controller_delete);
}
EXPORT_SYMBOL(mpfs_sys_controller_put);

static struct platform_device subdevs[] = {
{
.name = "mpfs-rng",
.id = -1,
},
{
.name = "mpfs-generic-service",
.id = -1,
}
};

static int mpfs_sys_controller_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mpfs_sys_controller *sys_controller;
int i;

sys_controller = devm_kzalloc(dev, sizeof(*sys_controller), GFP_KERNEL);
if (!sys_controller)
return -ENOMEM;

sys_controller->client.dev = dev;
sys_controller->client.rx_callback = rx_callback;
sys_controller->client.tx_block = 1U;

sys_controller->chan = mbox_request_channel(&sys_controller->client, 0);
if (IS_ERR(sys_controller->chan))
return dev_err_probe(dev, PTR_ERR(sys_controller->chan),
"Failed to get mbox channel\n");

init_completion(&sys_controller->c);
kref_init(&sys_controller->consumers);

platform_set_drvdata(pdev, sys_controller);

dev_info(&pdev->dev, "Registered MPFS system controller\n");

for (i = 0; i < ARRAY_SIZE(subdevs); i++) {
subdevs[i].dev.parent = dev;
if (platform_device_register(&subdevs[i]))
dev_warn(dev, "Error registering sub device %s\n", subdevs[i].name);
}

return 0;
}

static int mpfs_sys_controller_remove(struct platform_device *pdev)
{
struct mpfs_sys_controller *sys_controller = platform_get_drvdata(pdev);

mpfs_sys_controller_put(sys_controller);

return 0;
}

static const struct of_device_id mpfs_sys_controller_of_match[] = {
{.compatible = "microchip,mpfs-sys-controller", },
{},
};
MODULE_DEVICE_TABLE(of, mpfs_sys_controller_of_match);

struct mpfs_sys_controller *mpfs_sys_controller_get(struct device *dev)
{
const struct of_device_id *match;
struct mpfs_sys_controller *sys_controller;
int ret;

if (!dev->parent)
goto err_no_device;

match = of_match_node(mpfs_sys_controller_of_match, dev->parent->of_node);
of_node_put(dev->parent->of_node);
if (!match)
goto err_no_device;

sys_controller = dev_get_drvdata(dev->parent);
if (!sys_controller)
goto err_bad_device;

if (!kref_get_unless_zero(&sys_controller->consumers))
goto err_bad_device;

ret = devm_add_action_or_reset(dev, mpfs_sys_controller_put, sys_controller);
if (ret)
return ERR_PTR(ret);

return sys_controller;

err_no_device:
dev_dbg(dev, "Parent device was not an MPFS system controller\n");
return ERR_PTR(-ENODEV);

err_bad_device:
dev_dbg(dev, "MPFS system controller found but could not register as a sub device\n");
return ERR_PTR(-EPROBE_DEFER);
}
EXPORT_SYMBOL(mpfs_sys_controller_get);

static struct platform_driver mpfs_sys_controller_driver = {
.driver = {
.name = "mpfs-sys-controller",
.of_match_table = mpfs_sys_controller_of_match,
},
.probe = mpfs_sys_controller_probe,
.remove = mpfs_sys_controller_remove,
};
module_platform_driver(mpfs_sys_controller_driver);

MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");
MODULE_DESCRIPTION("MPFS system controller driver");
4 changes: 4 additions & 0 deletions include/linux/clk/at91_pmc.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@
#define AT91_PMC_MAINRDY (1 << 16) /* Main Clock Ready */

#define AT91_CKGR_PLLAR 0x28 /* PLL A Register */

#define AT91_PMC_RATIO 0x2c /* Processor clock ratio register [SAMA7G5 only] */
#define AT91_PMC_RATIO_RATIO (0xf) /* CPU clock ratio. */

#define AT91_CKGR_PLLBR 0x2c /* PLL B Register */
#define AT91_PMC_DIV (0xff << 0) /* Divider */
#define AT91_PMC_PLLCOUNT (0x3f << 8) /* PLL Counter */
Expand Down
15 changes: 6 additions & 9 deletions include/soc/at91/sama7-ddr.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@
#ifndef __SAMA7_DDR_H__
#define __SAMA7_DDR_H__

#ifdef CONFIG_SOC_SAMA7

/* DDR3PHY */
#define DDR3PHY_PIR (0x04) /* DDR3PHY PHY Initialization Register */
#define DDR3PHY_PIR_DLLBYP (1 << 17) /* DLL Bypass */
#define DDR3PHY_PIR_DLLBYP (1 << 17) /* DLL Bypass */
#define DDR3PHY_PIR_ITMSRST (1 << 4) /* Interface Timing Module Soft Reset */
#define DDR3PHY_PIR_DLLLOCK (1 << 2) /* DLL Lock */
#define DDR3PHY_PIR_DLLLOCK (1 << 2) /* DLL Lock */
#define DDR3PHY_PIR_DLLSRST (1 << 1) /* DLL Soft Rest */
#define DDR3PHY_PIR_INIT (1 << 0) /* Initialization Trigger */
#define DDR3PHY_PIR_INIT (1 << 0) /* Initialization Trigger */

#define DDR3PHY_PGCR (0x08) /* DDR3PHY PHY General Configuration Register */
#define DDR3PHY_PGCR_CKDV1 (1 << 13) /* CK# Disable Value */
Expand Down Expand Up @@ -55,7 +53,8 @@
#define UDDRC_STAT_OPMODE_MSK (0x7 << 0) /* Operating mode mask */

#define UDDRC_PWRCTL (0x30) /* UDDRC Low Power Control Register */
#define UDDRC_PWRCTRL_SELFREF_SW (1 << 5) /* Software self-refresh */
#define UDDRC_PWRCTL_SELFREF_EN (1 << 0) /* Automatic self-refresh */
#define UDDRC_PWRCTL_SELFREF_SW (1 << 5) /* Software self-refresh */

#define UDDRC_DFIMISC (0x1B0) /* UDDRC DFI Miscellaneous Control Register */
#define UDDRC_DFIMISC_DFI_INIT_COMPLETE_EN (1 << 0) /* PHY initialization complete enable signal */
Expand All @@ -67,14 +66,12 @@
#define UDDRC_SWSTAT_SW_DONE_ACK (1 << 0) /* Register programming done */

#define UDDRC_PSTAT (0x3FC) /* UDDRC Port Status Register */
#define UDDRC_PSTAT_ALL_PORTS (0x1F001F) /* Read + writes outstanding transactions on all ports */
#define UDDRC_PSTAT_ALL_PORTS (0x1F001F) /* Read + writes outstanding transactions on all ports */

#define UDDRC_PCTRL_0 (0x490) /* UDDRC Port 0 Control Register */
#define UDDRC_PCTRL_1 (0x540) /* UDDRC Port 1 Control Register */
#define UDDRC_PCTRL_2 (0x5F0) /* UDDRC Port 2 Control Register */
#define UDDRC_PCTRL_3 (0x6A0) /* UDDRC Port 3 Control Register */
#define UDDRC_PCTRL_4 (0x750) /* UDDRC Port 4 Control Register */

#endif /* CONFIG_SOC_SAMA7 */

#endif /* __SAMA7_DDR_H__ */
4 changes: 2 additions & 2 deletions include/soc/microchip/mpfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ struct mpfs_mss_response {

#if IS_ENABLED(CONFIG_POLARFIRE_SOC_SYS_CTRL)

int mpfs_blocking_transaction(struct mpfs_sys_controller *mpfs_client, void *msg);
int mpfs_blocking_transaction(struct mpfs_sys_controller *mpfs_client, struct mpfs_mss_msg *msg);

struct mpfs_sys_controller *mpfs_sys_controller_get(struct device_node *mailbox_node);
struct mpfs_sys_controller *mpfs_sys_controller_get(struct device *dev);

#endif /* if IS_ENABLED(CONFIG_POLARFIRE_SOC_SYS_CTRL) */

Expand Down

0 comments on commit 022e522

Please sign in to comment.