summaryrefslogtreecommitdiff
path: root/drivers/soc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/soc')
-rw-r--r--drivers/soc/aspeed/Kconfig1
-rw-r--r--drivers/soc/aspeed/Makefile1
-rw-r--r--drivers/soc/aspeed/aspeed-lpc-ctrl.c2
-rw-r--r--drivers/soc/aspeed/aspeed-lpc-snoop.c40
-rw-r--r--drivers/soc/aspeed/aspeed-p2a-ctrl.c2
-rw-r--r--drivers/soc/bcm/brcmstb/common.c88
-rw-r--r--drivers/soc/fsl/qe/qe.c4
-rw-r--r--drivers/soc/fsl/qe/qe_ports_ic.c23
-rw-r--r--drivers/soc/imx/soc-imx8m.c2
-rw-r--r--drivers/soc/mediatek/mt8167-mmsys.h11
-rw-r--r--drivers/soc/mediatek/mtk-mmsys.c8
-rw-r--r--drivers/soc/mediatek/mtk-mutex.c5
-rw-r--r--drivers/soc/microchip/mpfs-sys-controller.c6
-rw-r--r--drivers/soc/qcom/ice.c66
-rw-r--r--drivers/soc/qcom/llcc-qcom.c481
-rw-r--r--drivers/soc/qcom/qcom-geni-se.c270
-rw-r--r--drivers/soc/qcom/qcom_aoss.c2
-rw-r--r--drivers/soc/qcom/qcom_pd_mapper.c9
-rw-r--r--drivers/soc/qcom/smem.c56
-rw-r--r--drivers/soc/qcom/socinfo.c23
-rw-r--r--drivers/soc/qcom/wcnss_ctrl.c11
-rw-r--r--drivers/soc/renesas/Kconfig9
-rw-r--r--drivers/soc/renesas/Makefile1
-rw-r--r--drivers/soc/renesas/r9a08g045-sysc.c33
-rw-r--r--drivers/soc/renesas/r9a08g046-sysc.c31
-rw-r--r--drivers/soc/renesas/r9a09g047-sys.c34
-rw-r--r--drivers/soc/renesas/r9a09g056-sys.c33
-rw-r--r--drivers/soc/renesas/r9a09g057-sys.c44
-rw-r--r--drivers/soc/renesas/rcar-mfis.c384
-rw-r--r--drivers/soc/renesas/renesas-soc.c11
-rw-r--r--drivers/soc/renesas/rzn1_irqmux.c1
-rw-r--r--drivers/soc/sophgo/sg2044-topsys.c1
-rw-r--r--drivers/soc/sunxi/sunxi_sram.c196
-rw-r--r--drivers/soc/tegra/cbb/tegra194-cbb.c2
-rw-r--r--drivers/soc/tegra/cbb/tegra234-cbb.c2
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra.c15
-rw-r--r--drivers/soc/tegra/fuse/tegra-apbmisc.c43
-rw-r--r--drivers/soc/tegra/pmc.c648
-rw-r--r--drivers/soc/ti/k3-ringacc.c7
-rw-r--r--drivers/soc/ti/k3-socinfo.c41
-rw-r--r--drivers/soc/ti/knav_dma.c8
-rw-r--r--drivers/soc/ti/knav_qmss.h2
-rw-r--r--drivers/soc/ti/knav_qmss_acc.c2
-rw-r--r--drivers/soc/ti/knav_qmss_queue.c155
-rw-r--r--drivers/soc/ti/smartreflex.c1
-rw-r--r--drivers/soc/xilinx/zynqmp_power.c47
46 files changed, 2077 insertions, 785 deletions
diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig
index f579ee0b5afa..63a656449a1a 100644
--- a/drivers/soc/aspeed/Kconfig
+++ b/drivers/soc/aspeed/Kconfig
@@ -46,7 +46,6 @@ config ASPEED_P2A_CTRL
config ASPEED_SOCINFO
bool "ASPEED SoC Information driver"
- default ARCH_ASPEED
select SOC_BUS
default ARCH_ASPEED
help
diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile
index b35d74592964..b5188dcde37a 100644
--- a/drivers/soc/aspeed/Makefile
+++ b/drivers/soc/aspeed/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
obj-$(CONFIG_ASPEED_UART_ROUTING) += aspeed-uart-routing.o
obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o
obj-$(CONFIG_ASPEED_SOCINFO) += aspeed-socinfo.o
+CONTEXT_ANALYSIS_aspeed-lpc-snoop.o := y
diff --git a/drivers/soc/aspeed/aspeed-lpc-ctrl.c b/drivers/soc/aspeed/aspeed-lpc-ctrl.c
index b7dbb12bd095..4d8574cac703 100644
--- a/drivers/soc/aspeed/aspeed-lpc-ctrl.c
+++ b/drivers/soc/aspeed/aspeed-lpc-ctrl.c
@@ -338,6 +338,7 @@ static const struct of_device_id aspeed_lpc_ctrl_match[] = {
{ .compatible = "aspeed,ast2600-lpc-ctrl" },
{ },
};
+MODULE_DEVICE_TABLE(of, aspeed_lpc_ctrl_match);
static struct platform_driver aspeed_lpc_ctrl_driver = {
.driver = {
@@ -350,7 +351,6 @@ static struct platform_driver aspeed_lpc_ctrl_driver = {
module_platform_driver(aspeed_lpc_ctrl_driver);
-MODULE_DEVICE_TABLE(of, aspeed_lpc_ctrl_match);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Cyril Bur <cyrilbur@gmail.com>");
MODULE_DESCRIPTION("Control for ASPEED LPC HOST to BMC mappings");
diff --git a/drivers/soc/aspeed/aspeed-lpc-snoop.c b/drivers/soc/aspeed/aspeed-lpc-snoop.c
index b03310c0830d..b09dca34099f 100644
--- a/drivers/soc/aspeed/aspeed-lpc-snoop.c
+++ b/drivers/soc/aspeed/aspeed-lpc-snoop.c
@@ -11,6 +11,7 @@
*/
#include <linux/bitops.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/dev_printk.h>
#include <linux/interrupt.h>
@@ -74,7 +75,8 @@ struct aspeed_lpc_snoop_channel_cfg {
struct aspeed_lpc_snoop_channel {
const struct aspeed_lpc_snoop_channel_cfg *cfg;
bool enabled;
- struct kfifo fifo;
+ spinlock_t lock;
+ struct kfifo fifo __guarded_by(&lock);
wait_queue_head_t wq;
struct miscdevice miscdev;
};
@@ -114,6 +116,7 @@ static ssize_t snoop_file_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
struct aspeed_lpc_snoop_channel *chan = snoop_file_to_chan(file);
+ u8 *buf __free(kfree) = NULL;
unsigned int copied;
int ret = 0;
@@ -125,9 +128,16 @@ static ssize_t snoop_file_read(struct file *file, char __user *buffer,
if (ret == -ERESTARTSYS)
return -EINTR;
}
- ret = kfifo_to_user(&chan->fifo, buffer, count, &copied);
- if (ret)
- return ret;
+
+ count = min_t(size_t, count, SNOOP_FIFO_SIZE);
+
+ buf = kmalloc(count, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ copied = kfifo_out_spinlocked(&chan->fifo, buf, count, &chan->lock);
+ if (copied && copy_to_user(buffer, buf, copied))
+ return -EFAULT;
return copied;
}
@@ -151,11 +161,13 @@ static const struct file_operations snoop_fops = {
/* Save a byte to a FIFO and discard the oldest byte if FIFO is full */
static void put_fifo_with_discard(struct aspeed_lpc_snoop_channel *chan, u8 val)
{
- if (!kfifo_initialized(&chan->fifo))
- return;
- if (kfifo_is_full(&chan->fifo))
- kfifo_skip(&chan->fifo);
- kfifo_put(&chan->fifo, val);
+ scoped_guard(spinlock, &chan->lock) {
+ if (!kfifo_initialized(&chan->fifo))
+ return;
+ if (kfifo_is_full(&chan->fifo))
+ kfifo_skip(&chan->fifo);
+ kfifo_put(&chan->fifo, val);
+ }
wake_up_interruptible(&chan->wq);
}
@@ -239,9 +251,11 @@ static int aspeed_lpc_enable_snoop(struct device *dev,
if (!channel->miscdev.name)
return -ENOMEM;
- rc = kfifo_alloc(&channel->fifo, SNOOP_FIFO_SIZE, GFP_KERNEL);
- if (rc)
- return rc;
+ scoped_guard(spinlock_init, &channel->lock) {
+ rc = kfifo_alloc(&channel->fifo, SNOOP_FIFO_SIZE, GFP_KERNEL);
+ if (rc)
+ return rc;
+ }
rc = misc_register(&channel->miscdev);
if (rc)
@@ -366,6 +380,7 @@ static const struct of_device_id aspeed_lpc_snoop_match[] = {
.data = &ast2500_model_data },
{ },
};
+MODULE_DEVICE_TABLE(of, aspeed_lpc_snoop_match);
static struct platform_driver aspeed_lpc_snoop_driver = {
.driver = {
@@ -378,7 +393,6 @@ static struct platform_driver aspeed_lpc_snoop_driver = {
module_platform_driver(aspeed_lpc_snoop_driver);
-MODULE_DEVICE_TABLE(of, aspeed_lpc_snoop_match);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Robert Lippert <rlippert@google.com>");
MODULE_DESCRIPTION("Linux driver to control Aspeed LPC snoop functionality");
diff --git a/drivers/soc/aspeed/aspeed-p2a-ctrl.c b/drivers/soc/aspeed/aspeed-p2a-ctrl.c
index d88abc5f195b..b6b7b80f842a 100644
--- a/drivers/soc/aspeed/aspeed-p2a-ctrl.c
+++ b/drivers/soc/aspeed/aspeed-p2a-ctrl.c
@@ -416,6 +416,7 @@ static const struct of_device_id aspeed_p2a_ctrl_match[] = {
.data = &ast2500_model_data },
{ },
};
+MODULE_DEVICE_TABLE(of, aspeed_p2a_ctrl_match);
static struct platform_driver aspeed_p2a_ctrl_driver = {
.driver = {
@@ -428,7 +429,6 @@ static struct platform_driver aspeed_p2a_ctrl_driver = {
module_platform_driver(aspeed_p2a_ctrl_driver);
-MODULE_DEVICE_TABLE(of, aspeed_p2a_ctrl_match);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Patrick Venture <venture@google.com>");
MODULE_DESCRIPTION("Control for aspeed 2400/2500 P2A VGA HOST to BMC mappings");
diff --git a/drivers/soc/bcm/brcmstb/common.c b/drivers/soc/bcm/brcmstb/common.c
index 2da79bd42930..7be0374f5943 100644
--- a/drivers/soc/bcm/brcmstb/common.c
+++ b/drivers/soc/bcm/brcmstb/common.c
@@ -11,18 +11,22 @@
#include <linux/soc/brcmstb/brcmstb.h>
#include <linux/sys_soc.h>
-static u32 family_id;
-static u32 product_id;
+struct brcmstb_soc_info {
+ u32 family_id;
+ u32 product_id;
+};
+
+static struct brcmstb_soc_info *soc_info;
u32 brcmstb_get_family_id(void)
{
- return family_id;
+ return soc_info ? soc_info->family_id : 0;
}
EXPORT_SYMBOL(brcmstb_get_family_id);
u32 brcmstb_get_product_id(void)
{
- return product_id;
+ return soc_info ? soc_info->product_id : 0;
}
EXPORT_SYMBOL(brcmstb_get_product_id);
@@ -40,10 +44,12 @@ static const struct of_device_id sun_top_ctrl_match[] = {
{ }
};
-static int __init brcmstb_soc_device_early_init(void)
+static int __init brcmstb_soc_device_init(void)
{
+ struct soc_device_attribute *soc_dev_attr;
struct device_node *sun_top_ctrl;
void __iomem *sun_top_ctrl_base;
+ struct soc_device *soc_dev;
int ret = 0;
/* We could be on a multi-platform kernel, don't make this fatal but
@@ -51,63 +57,61 @@ static int __init brcmstb_soc_device_early_init(void)
*/
sun_top_ctrl = of_find_matching_node(NULL, sun_top_ctrl_match);
if (!sun_top_ctrl)
- return ret;
+ return 0;
sun_top_ctrl_base = of_iomap(sun_top_ctrl, 0);
if (!sun_top_ctrl_base) {
ret = -ENODEV;
- goto out;
+ goto out_put_node;
}
- family_id = readl(sun_top_ctrl_base);
- product_id = readl(sun_top_ctrl_base + 0x4);
- iounmap(sun_top_ctrl_base);
-out:
- of_node_put(sun_top_ctrl);
- return ret;
-}
-early_initcall(brcmstb_soc_device_early_init);
-
-static int __init brcmstb_soc_device_init(void)
-{
- struct soc_device_attribute *soc_dev_attr;
- struct device_node *sun_top_ctrl;
- struct soc_device *soc_dev;
- int ret = 0;
+ soc_info = kzalloc(sizeof(*soc_info), GFP_KERNEL);
+ if (!soc_info) {
+ ret = -ENOMEM;
+ goto out_unmap;
+ }
- /* We could be on a multi-platform kernel, don't make this fatal but
- * bail out early
- */
- sun_top_ctrl = of_find_matching_node(NULL, sun_top_ctrl_match);
- if (!sun_top_ctrl)
- return ret;
+ soc_info->family_id = readl(sun_top_ctrl_base);
+ soc_info->product_id = readl(sun_top_ctrl_base + 0x4);
soc_dev_attr = kzalloc_obj(*soc_dev_attr);
if (!soc_dev_attr) {
ret = -ENOMEM;
- goto out;
+ goto out_free_info;
}
soc_dev_attr->family = kasprintf(GFP_KERNEL, "%x",
- family_id >> 28 ?
- family_id >> 16 : family_id >> 8);
+ soc_info->family_id >> 28 ?
+ soc_info->family_id >> 16 : soc_info->family_id >> 8);
soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%x",
- product_id >> 28 ?
- product_id >> 16 : product_id >> 8);
+ soc_info->product_id >> 28 ?
+ soc_info->product_id >> 16 : soc_info->product_id >> 8);
soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c%d",
- ((product_id & 0xf0) >> 4) + 'A',
- product_id & 0xf);
+ ((soc_info->product_id & 0xf0) >> 4) + 'A',
+ soc_info->product_id & 0xf);
soc_dev = soc_device_register(soc_dev_attr);
if (IS_ERR(soc_dev)) {
- kfree(soc_dev_attr->family);
- kfree(soc_dev_attr->soc_id);
- kfree(soc_dev_attr->revision);
- kfree(soc_dev_attr);
- ret = -ENOMEM;
+ ret = PTR_ERR(soc_dev);
+ goto out_free_attr;
}
-out:
+
+ iounmap(sun_top_ctrl_base);
+ of_node_put(sun_top_ctrl);
+ return 0;
+
+out_free_attr:
+ kfree(soc_dev_attr->revision);
+ kfree(soc_dev_attr->soc_id);
+ kfree(soc_dev_attr->family);
+ kfree(soc_dev_attr);
+out_free_info:
+ kfree(soc_info);
+ soc_info = NULL;
+out_unmap:
+ iounmap(sun_top_ctrl_base);
+out_put_node:
of_node_put(sun_top_ctrl);
return ret;
}
-arch_initcall(brcmstb_soc_device_init);
+early_initcall(brcmstb_soc_device_init);
diff --git a/drivers/soc/fsl/qe/qe.c b/drivers/soc/fsl/qe/qe.c
index 70b6eddb867b..5fdf1fe4edaf 100644
--- a/drivers/soc/fsl/qe/qe.c
+++ b/drivers/soc/fsl/qe/qe.c
@@ -24,7 +24,6 @@
#include <linux/ioport.h>
#include <linux/iopoll.h>
#include <linux/crc32.h>
-#include <linux/mod_devicetable.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <soc/fsl/qe/immap_qe.h>
@@ -89,6 +88,9 @@ void qe_reset(void)
if (qe_immr == NULL)
qe_immr = ioremap(get_qe_base(), QE_IMMAP_SIZE);
+ if (!qe_immr)
+ panic("QE:ioremap failed!");
+
qe_snums_init();
qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
diff --git a/drivers/soc/fsl/qe/qe_ports_ic.c b/drivers/soc/fsl/qe/qe_ports_ic.c
index 8e2107e2cde5..9b0bba64e91e 100644
--- a/drivers/soc/fsl/qe/qe_ports_ic.c
+++ b/drivers/soc/fsl/qe/qe_ports_ic.c
@@ -17,6 +17,7 @@
struct qepic_data {
void __iomem *reg;
struct irq_domain *host;
+ int irq;
};
static void qepic_mask(struct irq_data *d)
@@ -92,11 +93,18 @@ static const struct irq_domain_ops qepic_host_ops = {
.map = qepic_host_map,
};
+static void qepic_remove(void *res)
+{
+ struct qepic_data *data = res;
+
+ irq_set_chained_handler_and_data(data->irq, NULL, NULL);
+ irq_domain_remove(data->host);
+}
+
static int qepic_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct qepic_data *data;
- int irq;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
@@ -106,17 +114,18 @@ static int qepic_probe(struct platform_device *pdev)
if (IS_ERR(data->reg))
return PTR_ERR(data->reg);
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
+ data->irq = platform_get_irq(pdev, 0);
+ if (data->irq < 0)
+ return data->irq;
- data->host = irq_domain_add_linear(dev->of_node, 32, &qepic_host_ops, data);
+ data->host = irq_domain_create_linear(dev_fwnode(dev), 32, &qepic_host_ops, data);
if (!data->host)
return -ENODEV;
- irq_set_chained_handler_and_data(irq, qepic_cascade, data);
+ irq_set_chained_handler_and_data(data->irq, qepic_cascade, data);
+
+ return devm_add_action_or_reset(dev, qepic_remove, data);
- return 0;
}
static const struct of_device_id qepic_match[] = {
diff --git a/drivers/soc/imx/soc-imx8m.c b/drivers/soc/imx/soc-imx8m.c
index 77763a107edb..fc080e56f50d 100644
--- a/drivers/soc/imx/soc-imx8m.c
+++ b/drivers/soc/imx/soc-imx8m.c
@@ -247,7 +247,7 @@ static int imx8m_soc_probe(struct platform_device *pdev)
if (ret)
return ret;
- data = device_get_match_data(dev);
+ data = of_machine_get_match_data(imx8_soc_match);
if (data) {
soc_dev_attr->soc_id = data->name;
ret = imx8m_soc_prepare(pdev, data->ocotp_compatible);
diff --git a/drivers/soc/mediatek/mt8167-mmsys.h b/drivers/soc/mediatek/mt8167-mmsys.h
index c468926561b4..eef14083c47b 100644
--- a/drivers/soc/mediatek/mt8167-mmsys.h
+++ b/drivers/soc/mediatek/mt8167-mmsys.h
@@ -10,24 +10,29 @@
#define MT8167_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN 0x06c
#define MT8167_DITHER_MOUT_EN_RDMA0 0x1
+#define MT8167_DITHER_MOUT_EN_MASK 0x7
+
#define MT8167_RDMA0_SOUT_DSI0 0x2
+#define MT8167_RDMA0_SOUT_MASK 0x3
+
#define MT8167_DSI0_SEL_IN_RDMA0 0x1
+#define MT8167_DSI0_SEL_IN_MASK 0x3
static const struct mtk_mmsys_routes mt8167_mmsys_routing_table[] = {
MMSYS_ROUTE(OVL0, COLOR0,
MT8167_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN, OVL0_MOUT_EN_COLOR0,
OVL0_MOUT_EN_COLOR0),
MMSYS_ROUTE(DITHER0, RDMA0,
- MT8167_DISP_REG_CONFIG_DISP_DITHER_MOUT_EN, MT8167_DITHER_MOUT_EN_RDMA0,
+ MT8167_DISP_REG_CONFIG_DISP_DITHER_MOUT_EN, MT8167_DITHER_MOUT_EN_MASK,
MT8167_DITHER_MOUT_EN_RDMA0),
MMSYS_ROUTE(OVL0, COLOR0,
MT8167_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN, COLOR0_SEL_IN_OVL0,
COLOR0_SEL_IN_OVL0),
MMSYS_ROUTE(RDMA0, DSI0,
- MT8167_DISP_REG_CONFIG_DISP_DSI0_SEL_IN, MT8167_DSI0_SEL_IN_RDMA0,
+ MT8167_DISP_REG_CONFIG_DISP_DSI0_SEL_IN, MT8167_DSI0_SEL_IN_MASK,
MT8167_DSI0_SEL_IN_RDMA0),
MMSYS_ROUTE(RDMA0, DSI0,
- MT8167_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN, MT8167_RDMA0_SOUT_DSI0,
+ MT8167_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN, MT8167_RDMA0_SOUT_MASK,
MT8167_RDMA0_SOUT_DSI0),
};
diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c
index bb4639ca0b8c..2f3e0778bb17 100644
--- a/drivers/soc/mediatek/mtk-mmsys.c
+++ b/drivers/soc/mediatek/mtk-mmsys.c
@@ -167,9 +167,11 @@ static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32 offset, u32 mask,
u32 tmp;
if (mmsys->cmdq_base.size && cmdq_pkt) {
- ret = cmdq_pkt_write_mask(cmdq_pkt, mmsys->cmdq_base.subsys,
- mmsys->cmdq_base.offset + offset, val,
- mask);
+ ret = mmsys->cmdq_base.pkt_write_mask(cmdq_pkt,
+ mmsys->cmdq_base.subsys,
+ mmsys->cmdq_base.pa_base,
+ mmsys->cmdq_base.offset + offset,
+ val, mask);
if (ret)
pr_debug("CMDQ unavailable: using CPU write\n");
else
diff --git a/drivers/soc/mediatek/mtk-mutex.c b/drivers/soc/mediatek/mtk-mutex.c
index 38179e8cd98f..eb5d381ff5af 100644
--- a/drivers/soc/mediatek/mtk-mutex.c
+++ b/drivers/soc/mediatek/mtk-mutex.c
@@ -990,6 +990,7 @@ int mtk_mutex_enable_by_cmdq(struct mtk_mutex *mutex, void *pkt)
struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]);
struct cmdq_pkt *cmdq_pkt = (struct cmdq_pkt *)pkt;
+ dma_addr_t en_addr = mtx->addr + DISP_REG_MUTEX_EN(mutex->id);
WARN_ON(&mtx->mutex[mutex->id] != mutex);
@@ -998,8 +999,8 @@ int mtk_mutex_enable_by_cmdq(struct mtk_mutex *mutex, void *pkt)
return -ENODEV;
}
- cmdq_pkt_write(cmdq_pkt, mtx->cmdq_reg.subsys,
- mtx->addr + DISP_REG_MUTEX_EN(mutex->id), 1);
+ mtx->cmdq_reg.pkt_write(cmdq_pkt, mtx->cmdq_reg.subsys, en_addr, en_addr, 1);
+
return 0;
}
EXPORT_SYMBOL_GPL(mtk_mutex_enable_by_cmdq);
diff --git a/drivers/soc/microchip/mpfs-sys-controller.c b/drivers/soc/microchip/mpfs-sys-controller.c
index 92d1142a59e6..0400a01b2338 100644
--- a/drivers/soc/microchip/mpfs-sys-controller.c
+++ b/drivers/soc/microchip/mpfs-sys-controller.c
@@ -158,8 +158,8 @@ no_flash:
of_data = (struct mpfs_syscon_config *) device_get_match_data(dev);
if (!of_data) {
- dev_err(dev, "Error getting match data\n");
- return -EINVAL;
+ ret = dev_err_probe(dev, -EINVAL, "Error getting match data\n");
+ goto out_free_channel;
}
for (i = 0; i < of_data->nb_subdevs; i++) {
@@ -173,6 +173,8 @@ no_flash:
return 0;
+out_free_channel:
+ mbox_free_channel(sys_controller->chan);
out_free:
kfree(sys_controller);
return ret;
diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c
index b203bc685cad..5f20108aa03e 100644
--- a/drivers/soc/qcom/ice.c
+++ b/drivers/soc/qcom/ice.c
@@ -16,6 +16,7 @@
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/xarray.h>
#include <linux/firmware/qcom/qcom_scm.h>
@@ -108,11 +109,15 @@ struct qcom_ice {
void __iomem *base;
struct clk *core_clk;
+ struct clk *iface_clk;
bool use_hwkm;
bool hwkm_init_complete;
u8 hwkm_version;
};
+static DEFINE_XARRAY(ice_handles);
+static DEFINE_MUTEX(ice_mutex);
+
static bool qcom_ice_check_supported(struct qcom_ice *ice)
{
u32 regval = qcom_ice_readl(ice, QCOM_ICE_REG_VERSION);
@@ -312,8 +317,13 @@ int qcom_ice_resume(struct qcom_ice *ice)
err = clk_prepare_enable(ice->core_clk);
if (err) {
- dev_err(dev, "failed to enable core clock (%d)\n",
- err);
+ dev_err(dev, "Failed to enable core clock: %d\n", err);
+ return err;
+ }
+
+ err = clk_prepare_enable(ice->iface_clk);
+ if (err) {
+ dev_err(dev, "Failed to enable iface clock: %d\n", err);
return err;
}
qcom_ice_hwkm_init(ice);
@@ -323,6 +333,7 @@ EXPORT_SYMBOL_GPL(qcom_ice_resume);
int qcom_ice_suspend(struct qcom_ice *ice)
{
+ clk_disable_unprepare(ice->iface_clk);
clk_disable_unprepare(ice->core_clk);
ice->hwkm_init_complete = false;
@@ -559,7 +570,7 @@ static struct qcom_ice *qcom_ice_create(struct device *dev,
if (!qcom_scm_ice_available()) {
dev_warn(dev, "ICE SCM interface not found\n");
- return NULL;
+ return ERR_PTR(-EOPNOTSUPP);
}
engine = devm_kzalloc(dev, sizeof(*engine), GFP_KERNEL);
@@ -580,10 +591,16 @@ static struct qcom_ice *qcom_ice_create(struct device *dev,
if (!engine->core_clk)
engine->core_clk = devm_clk_get_optional_enabled(dev, "ice");
if (!engine->core_clk)
+ engine->core_clk = devm_clk_get_optional_enabled(dev, "core");
+ if (!engine->core_clk)
engine->core_clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(engine->core_clk))
return ERR_CAST(engine->core_clk);
+ engine->iface_clk = devm_clk_get_optional_enabled(dev, "iface");
+ if (IS_ERR(engine->iface_clk))
+ return ERR_CAST(engine->iface_clk);
+
if (!qcom_ice_check_supported(engine))
return ERR_PTR(-EOPNOTSUPP);
@@ -631,6 +648,8 @@ static struct qcom_ice *of_qcom_ice_get(struct device *dev)
return qcom_ice_create(&pdev->dev, base);
}
+ guard(mutex)(&ice_mutex);
+
/*
* If the consumer node does not provider an 'ice' reg range
* (legacy DT binding), then it must at least provide a phandle
@@ -639,20 +658,21 @@ static struct qcom_ice *of_qcom_ice_get(struct device *dev)
struct device_node *node __free(device_node) = of_parse_phandle(dev->of_node,
"qcom,ice", 0);
if (!node)
- return NULL;
+ return ERR_PTR(-EOPNOTSUPP);
pdev = of_find_device_by_node(node);
if (!pdev) {
dev_err(dev, "Cannot find device node %s\n", node->name);
- return ERR_PTR(-EPROBE_DEFER);
+ return ERR_PTR(-ENODEV);
}
- ice = platform_get_drvdata(pdev);
- if (!ice) {
- dev_err(dev, "Cannot get ice instance from %s\n",
- dev_name(&pdev->dev));
+ ice = xa_load(&ice_handles, pdev->dev.of_node->phandle);
+ if (IS_ERR_OR_NULL(ice)) {
platform_device_put(pdev);
- return ERR_PTR(-EPROBE_DEFER);
+ if (!ice)
+ return ERR_PTR(-EPROBE_DEFER);
+ else
+ return ice;
}
link = device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER);
@@ -691,8 +711,7 @@ static void devm_of_qcom_ice_put(struct device *dev, void *res)
* phandle via 'qcom,ice' property to an ICE DT, the ICE instance will already
* be created and so this function will return that instead.
*
- * Return: ICE pointer on success, NULL if there is no ICE data provided by the
- * consumer or ERR_PTR() on error.
+ * Return: ICE pointer on success, ERR_PTR() on error.
*/
struct qcom_ice *devm_of_qcom_ice_get(struct device *dev)
{
@@ -703,7 +722,7 @@ struct qcom_ice *devm_of_qcom_ice_get(struct device *dev)
return ERR_PTR(-ENOMEM);
ice = of_qcom_ice_get(dev);
- if (!IS_ERR_OR_NULL(ice)) {
+ if (!IS_ERR(ice)) {
*dr = ice;
devres_add(dev, dr);
} else {
@@ -716,24 +735,40 @@ EXPORT_SYMBOL_GPL(devm_of_qcom_ice_get);
static int qcom_ice_probe(struct platform_device *pdev)
{
+ unsigned long phandle = pdev->dev.of_node->phandle;
struct qcom_ice *engine;
void __iomem *base;
+ guard(mutex)(&ice_mutex);
+
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base)) {
dev_warn(&pdev->dev, "ICE registers not found\n");
+ /* Store the error pointer for devm_of_qcom_ice_get() */
+ xa_store(&ice_handles, phandle, (__force void *)base, GFP_KERNEL);
return PTR_ERR(base);
}
engine = qcom_ice_create(&pdev->dev, base);
- if (IS_ERR(engine))
+ if (IS_ERR(engine)) {
+ /* Store the error pointer for devm_of_qcom_ice_get() */
+ xa_store(&ice_handles, phandle, engine, GFP_KERNEL);
return PTR_ERR(engine);
+ }
- platform_set_drvdata(pdev, engine);
+ xa_store(&ice_handles, phandle, engine, GFP_KERNEL);
return 0;
}
+static void qcom_ice_remove(struct platform_device *pdev)
+{
+ unsigned long phandle = pdev->dev.of_node->phandle;
+
+ guard(mutex)(&ice_mutex);
+ xa_store(&ice_handles, phandle, NULL, GFP_KERNEL);
+}
+
static const struct of_device_id qcom_ice_of_match_table[] = {
{ .compatible = "qcom,inline-crypto-engine" },
{ },
@@ -742,6 +777,7 @@ MODULE_DEVICE_TABLE(of, qcom_ice_of_match_table);
static struct platform_driver qcom_ice_driver = {
.probe = qcom_ice_probe,
+ .remove = qcom_ice_remove,
.driver = {
.name = "qcom-ice",
.of_match_table = qcom_ice_of_match_table,
diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c
index 0161ceec8842..8948b5fd42d2 100644
--- a/drivers/soc/qcom/llcc-qcom.c
+++ b/drivers/soc/qcom/llcc-qcom.c
@@ -5,7 +5,6 @@
*/
#include <linux/bitfield.h>
-#include <linux/bitops.h>
#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/io.h>
@@ -14,6 +13,7 @@
#include <linux/mutex.h>
#include <linux/nvmem-consumer.h>
#include <linux/of.h>
+#include <linux/of_reserved_mem.h>
#include <linux/regmap.h>
#include <linux/sizes.h>
#include <linux/slab.h>
@@ -76,10 +76,16 @@
#define LLCC_VERSION_4_1_0_0 0x04010000
#define LLCC_VERSION_6_0_0_0 0X06000000
+#define SLC_SCT_MEM_LAYOUT_VERSION1 1 /* SCT Memory layout version */
+#define SLC_SCT_DONE 0x00534354444f4e45 /* SCT programming OK */
+#define SLC_SCT_FAIL 0x005343544641494c /* SCT programming failed */
+#define SLC_SCT_NAME_LEN 15
+#define SLC_SCT_SLICE_ACT_ON_BOOT BIT(25)
+
/**
- * struct llcc_slice_config - Data associated with the llcc slice
+ * struct llcc_slice_config - Data associated with the LLCC slice
* @usecase_id: Unique id for the client's use case
- * @slice_id: llcc slice id for each client
+ * @slice_id: LLCC slice id for each client
* @max_cap: The maximum capacity of the cache slice provided in KB
* @priority: Priority of the client used to select victim line for replacement
* @fixed_size: Boolean indicating if the slice has a fixed capacity
@@ -93,7 +99,7 @@
* slice: normal or TCM(Tightly Coupled Memory)
* @probe_target_ways: Determines what ways to probe for access hit. When
* configured to 1 only bonus and reserved ways are probed.
- * When configured to 0 all ways in llcc are probed.
+ * When configured to 0 all ways in LLCC are probed.
* @dis_cap_alloc: Disable capacity based allocation for a client
* @retain_on_pc: If this bit is set and client has maintained active vote
* then the ways assigned to this client are not flushed on power
@@ -143,6 +149,87 @@ struct llcc_slice_config {
u32 parent_slice_id;
};
+/*
+ * struct slc_sct_error - Represents SCT error
+ * @code: FW code status
+ * @param: Holds the SCT programming error
+ */
+struct slc_sct_error {
+ __le64 code;
+ __le64 param;
+} __packed;
+
+/*
+ * struct slc_sct_status - SCT programming status
+ * @program_status: Indicates programming success or failure
+ * @version: SCT mem layout version
+ * @error: Error enum and its param
+ */
+struct slc_sct_status {
+ __le64 program_status;
+ /* Use the lower 8 bits */
+ __le64 version;
+ struct slc_sct_error error;
+} __packed;
+
+/*
+ * struct slc_sct_details - SCT details
+ * @revision: revision of the SCT table
+ * @name: name of the SCT table
+ */
+struct slc_sct_details {
+ u8 revision;
+ char name[SLC_SCT_NAME_LEN];
+} __packed;
+
+/*
+ * struct tcm_mem_info - SC TCM Shared memory details
+ * @is_present: is TCM region present
+ * @offset: offset of TCM shared memory details
+ */
+struct slc_tcm_mem_info {
+ __le32 is_present;
+ __le32 offset;
+} __packed;
+
+/*
+ * struct slc_sct_slice_desc - Slice descriptor definition used in shmem
+ * @slice_id: SCID of the slice
+ * @usecase_id: Usecase ID of the slice
+ * @slice_properties:
+ * slice_size: Contains the slice descriptor size - 20 bit wide
+ * rsvd: Reserved space - 4 bit wide
+ * flags: Flags for descriptors - 3 bit wide
+ * MPAM SCID: Bit 24
+ * Activate on boot: Bit 25
+ * Non-HLOS SCID: Bit 26
+ * HWMutex: Ensures only one processor (CPU or MCU) at a time can
+ * access the LLCC hardware resources - 5 bit wide
+ */
+struct slc_sct_slice_desc {
+ __le16 slice_id;
+ __le16 usecase_id;
+ __le32 slice_properties;
+} __packed;
+
+/*
+ * struct slc_sct_mem - Shared memory structure
+ * @sct_status: Status of SCT programming
+ * @sct_details: Sct revision and name details
+ * @tcm_mem_info: TCM shared memory presence & offset info
+ * @slice_descs_count: Number of slice desc present in SCT
+ * @scid_max: Maximum no. of SCIDs supported
+ * @slice_descs: Array of SCT slice desc
+ */
+struct slc_sct_mem {
+ struct slc_sct_status sct_status;
+ struct slc_sct_details sct_details;
+ struct slc_tcm_mem_info tcm_mem_info;
+ __le32 slice_descs_count;
+ __le32 scid_max;
+ struct slc_sct_slice_desc slice_descs[] __counted_by_le(slice_descs_count);
+} __packed;
+
struct qcom_llcc_config {
const struct llcc_slice_config *sct_data;
const u32 *reg_offset;
@@ -181,6 +268,171 @@ enum llcc_reg_offset {
LLCC_TRP_WRS_CACHEABLE_EN,
};
+static const struct llcc_slice_config eliza_data[] = {
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 896,
+ .bonus_ways = 0xfff,
+ .activate_on_init = true,
+ .write_scid_en = true,
+ .stale_en = true,
+ },
+ {
+ .usecase_id = LLCC_MDMHPFX,
+ .slice_id = 24,
+ .max_cap = 1024,
+ .priority = 5,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ },
+ {
+ .usecase_id = LLCC_VIDSC0,
+ .slice_id = 2,
+ .max_cap = 128,
+ .priority = 5,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ },
+ {
+ .usecase_id = LLCC_MDMHPGRW,
+ .slice_id = 25,
+ .max_cap = 1024,
+ .priority = 5,
+ .bonus_ways = 0xfff,
+ },
+ {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ },
+ {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 9,
+ .max_cap = 896,
+ .priority = 1,
+ .bonus_ways = 0xfff,
+ .write_scid_cacheable_en = true,
+ },
+ {
+ .usecase_id = LLCC_MMUHWT,
+ .slice_id = 18,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .activate_on_init = true,
+ },
+ {
+ .usecase_id = LLCC_MDMPNG,
+ .slice_id = 27,
+ .max_cap = 256,
+ .priority = 5,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ },
+ {
+ .usecase_id = LLCC_MODPE,
+ .slice_id = 29,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xf00,
+ .alloc_oneway_en = true,
+ },
+ {
+ .usecase_id = LLCC_WRCACHE,
+ .slice_id = 31,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .activate_on_init = true,
+ },
+ {
+ .usecase_id = LLCC_LCPDARE,
+ .slice_id = 30,
+ .max_cap = 128,
+ .priority = 5,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .activate_on_init = true,
+ .alloc_oneway_en = true,
+ },
+ {
+ .usecase_id = LLCC_ISLAND1,
+ .slice_id = 12,
+ .max_cap = 1280,
+ .priority = 7,
+ .fixed_size = true,
+ .res_ways = 0x3ff,
+ },
+ {
+ .usecase_id = LLCC_CAMOFE,
+ .slice_id = 33,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .stale_en = true,
+ .parent_slice_id = 13,
+ },
+ {
+ .usecase_id = LLCC_CAMRTIP,
+ .slice_id = 13,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .stale_en = true,
+ .parent_slice_id = 13,
+ },
+ {
+ .usecase_id = LLCC_CAMSRTIP,
+ .slice_id = 14,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .stale_en = true,
+ .parent_slice_id = 13,
+ },
+ {
+ .usecase_id = LLCC_CAMRTRF,
+ .slice_id = 7,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .stale_en = true,
+ .parent_slice_id = 13,
+ },
+ {
+ .usecase_id = LLCC_CAMSRTRF,
+ .slice_id = 21,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .stale_en = true,
+ .parent_slice_id = 13,
+ },
+ {
+ .usecase_id = LLCC_CPUSSMPAM,
+ .slice_id = 6,
+ .max_cap = 512,
+ .priority = 0,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .activate_on_init = true,
+ .write_scid_en = true,
+ .stale_en = true,
+ },
+};
+
static const struct llcc_slice_config glymur_data[] = {
{
.usecase_id = LLCC_CPUSS,
@@ -4141,6 +4393,24 @@ static const u32 llcc_v6_reg_offset[] = {
[LLCC_TRP_WRS_CACHEABLE_EN] = 0x00042088,
};
+static const struct qcom_llcc_config hawi_sct_cfg[] = {
+ {
+ .sct_data = NULL,
+ .size = 0,
+ .reg_offset = llcc_v6_reg_offset,
+ .edac_reg_offset = &llcc_v6_edac_reg_offset,
+ },
+};
+
+static const struct qcom_llcc_config eliza_cfg[] = {
+ {
+ .sct_data = eliza_data,
+ .size = ARRAY_SIZE(eliza_data),
+ .reg_offset = llcc_v6_reg_offset,
+ .edac_reg_offset = &llcc_v6_edac_reg_offset,
+ },
+};
+
static const struct qcom_llcc_config kaanapali_cfg[] = {
{
.sct_data = kaanapali_data,
@@ -4397,6 +4667,16 @@ static const struct qcom_llcc_config x1e80100_cfg[] = {
},
};
+static const struct qcom_sct_config hawi_sct_cfgs = {
+ .llcc_config = hawi_sct_cfg,
+ .num_config = ARRAY_SIZE(hawi_sct_cfg),
+};
+
+static const struct qcom_sct_config eliza_cfgs = {
+ .llcc_config = eliza_cfg,
+ .num_config = ARRAY_SIZE(eliza_cfg),
+};
+
static const struct qcom_sct_config kaanapali_cfgs = {
.llcc_config = kaanapali_cfg,
.num_config = ARRAY_SIZE(kaanapali_cfg),
@@ -4525,37 +4805,34 @@ static const struct qcom_sct_config x1e80100_cfgs = {
static struct llcc_drv_data *drv_data = (void *) -EPROBE_DEFER;
/**
- * llcc_slice_getd - get llcc slice descriptor
+ * llcc_slice_getd - get LLCC slice descriptor
* @uid: usecase_id for the client
*
- * A pointer to llcc slice descriptor will be returned on success
+ * A pointer to LLCC slice descriptor will be returned on success
* and error pointer is returned on failure
*/
struct llcc_slice_desc *llcc_slice_getd(u32 uid)
{
- const struct llcc_slice_config *cfg;
- u32 sz, i;
-
if (IS_ERR(drv_data))
return ERR_CAST(drv_data);
- cfg = drv_data->cfg;
- sz = drv_data->cfg_size;
+ if (IS_ERR_OR_NULL(drv_data->desc))
+ return ERR_PTR(-ENODEV);
- for (i = 0; cfg && i < sz; i++, cfg++)
- if (cfg->usecase_id == uid)
- break;
+ for (u32 i = 0; i < drv_data->cfg_size; i++) {
+ if (uid == drv_data->desc[i].uid)
+ return &drv_data->desc[i];
+ }
- if (i == sz)
- return ERR_PTR(-ENODEV);
+ dev_err(drv_data->dev, "Failed to get slice desc for uid: %u\n", uid);
- return &drv_data->desc[i];
+ return ERR_PTR(-EINVAL);
}
EXPORT_SYMBOL_GPL(llcc_slice_getd);
/**
- * llcc_slice_putd - llcc slice descriptor
- * @desc: Pointer to llcc slice descriptor
+ * llcc_slice_putd - LLCC slice descriptor
+ * @desc: Pointer to LLCC slice descriptor
*/
void llcc_slice_putd(struct llcc_slice_desc *desc)
{
@@ -4618,8 +4895,8 @@ static int llcc_update_act_ctrl(u32 sid,
}
/**
- * llcc_slice_activate - Activate the llcc slice
- * @desc: Pointer to llcc slice descriptor
+ * llcc_slice_activate - Activate the LLCC slice
+ * @desc: Pointer to LLCC slice descriptor
*
* A value of zero will be returned on success and a negative errno will
* be returned in error cases
@@ -4654,8 +4931,8 @@ int llcc_slice_activate(struct llcc_slice_desc *desc)
EXPORT_SYMBOL_GPL(llcc_slice_activate);
/**
- * llcc_slice_deactivate - Deactivate the llcc slice
- * @desc: Pointer to llcc slice descriptor
+ * llcc_slice_deactivate - Deactivate the LLCC slice
+ * @desc: Pointer to LLCC slice descriptor
*
* A value of zero will be returned on success and a negative errno will
* be returned in error cases
@@ -4691,7 +4968,7 @@ EXPORT_SYMBOL_GPL(llcc_slice_deactivate);
/**
* llcc_get_slice_id - return the slice id
- * @desc: Pointer to llcc slice descriptor
+ * @desc: Pointer to LLCC slice descriptor
*/
int llcc_get_slice_id(struct llcc_slice_desc *desc)
{
@@ -4704,7 +4981,7 @@ EXPORT_SYMBOL_GPL(llcc_get_slice_id);
/**
* llcc_get_slice_size - return the slice id
- * @desc: Pointer to llcc slice descriptor
+ * @desc: Pointer to LLCC slice descriptor
*/
size_t llcc_get_slice_size(struct llcc_slice_desc *desc)
{
@@ -4738,9 +5015,9 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
/*
* LLCC instances can vary for each target.
* The SW writes to broadcast register which gets propagated
- * to each llcc instance (llcc0,.. llccN).
+ * to each LLCC instance (llcc0,.. llccN).
* Since the size of the memory is divided equally amongst the
- * llcc instances, we need to configure the max cap accordingly.
+ * LLCC instances, we need to configure the max cap accordingly.
*/
max_cap_cacheline = max_cap_cacheline / drv_data->num_banks;
max_cap_cacheline >>= CACHE_LINE_SIZE_SHIFT;
@@ -5029,6 +5306,12 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev,
sz = drv_data->cfg_size;
llcc_table = drv_data->cfg;
+ for (i = 0; i < sz; i++) {
+ drv_data->desc[i].uid = llcc_table[i].usecase_id;
+ drv_data->desc[i].slice_id = llcc_table[i].slice_id;
+ drv_data->desc[i].slice_size = llcc_table[i].max_cap;
+ }
+
if (drv_data->version >= LLCC_VERSION_6_0_0_0) {
for (i = 0; i < sz; i++) {
ret = _qcom_llcc_cfg_program_v6(&llcc_table[i], cfg);
@@ -5064,6 +5347,101 @@ static int qcom_llcc_get_cfg_index(struct platform_device *pdev, u8 *cfg_index,
return ret;
}
+static int qcom_llcc_verify_fw_config(struct device *dev,
+ const struct slc_sct_mem *slc_mem)
+{
+ u64 program_status;
+
+ program_status = le64_to_cpu(slc_mem->sct_status.program_status);
+
+ if (program_status == SLC_SCT_DONE) {
+ u32 desc_count = le32_to_cpu(slc_mem->slice_descs_count);
+ u32 scid_max = le32_to_cpu(slc_mem->scid_max);
+
+ if (desc_count > scid_max) {
+ dev_err(dev, "Descriptor count above max limit (%u > %u)\n",
+ desc_count, scid_max);
+ return -EINVAL;
+ }
+
+ u8 revision = slc_mem->sct_details.revision;
+ char name_buf[SLC_SCT_NAME_LEN];
+
+ memcpy(name_buf, slc_mem->sct_details.name,
+ SLC_SCT_NAME_LEN - 1);
+ name_buf[SLC_SCT_NAME_LEN - 1] = '\0';
+
+ dev_dbg(dev, "SCT init: desc_count=%u, rev=%u, name=%s\n",
+ desc_count, revision, name_buf);
+
+ return 0;
+ } else if (program_status == SLC_SCT_FAIL) {
+ u8 version = (u8)(le64_to_cpu(slc_mem->sct_status.version));
+ u64 code = le64_to_cpu(slc_mem->sct_status.error.code);
+ u64 param = le64_to_cpu(slc_mem->sct_status.error.param);
+
+ if (version == SLC_SCT_MEM_LAYOUT_VERSION1) {
+ dev_err(dev, "SCT init failed: code = %llu, param = %llu, version = 0x%x\n",
+ code, param, version);
+ } else {
+ dev_err(dev, "Found unsupported version %u\n", version);
+ }
+ } else {
+ dev_err(dev, "Unknown SCT Initialization error\n");
+ }
+
+ return -EINVAL;
+}
+
+static int qcom_llcc_get_fw_config(struct platform_device *pdev)
+{
+ const struct slc_sct_mem *slc_mem = NULL;
+ const struct slc_sct_slice_desc *memslice;
+ struct device *dev = &pdev->dev;
+ u32 slice_properties;
+ struct resource res;
+ u32 i, sz;
+ int ret;
+
+ ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res);
+ if (ret) {
+ dev_err(dev, "Unable to locate DT /reserved-memory resource\n");
+ return ret;
+ }
+
+ slc_mem = devm_memremap(dev, res.start, resource_size(&res), MEMREMAP_WB);
+ if (IS_ERR(slc_mem)) {
+ dev_err(dev, "Failed to memremap SLC shared memory\n");
+ return PTR_ERR(slc_mem);
+ }
+
+ ret = qcom_llcc_verify_fw_config(dev, slc_mem);
+ if (ret)
+ return ret;
+
+ sz = le32_to_cpu(slc_mem->slice_descs_count);
+
+ drv_data->desc = devm_kcalloc(dev, sz, sizeof(struct llcc_slice_desc),
+ GFP_KERNEL);
+ if (!drv_data->desc)
+ return -ENOMEM;
+
+ for (i = 0; i < sz; i++) {
+ memslice = &slc_mem->slice_descs[i];
+ drv_data->desc[i].slice_id = le16_to_cpu(memslice->slice_id);
+ drv_data->desc[i].uid = le16_to_cpu(memslice->usecase_id);
+ slice_properties = le32_to_cpu(memslice->slice_properties);
+ /* Set refcount to 1 if FW already activated this descriptor */
+ if (FIELD_GET(SLC_SCT_SLICE_ACT_ON_BOOT, slice_properties))
+ refcount_set(&drv_data->desc[i].refcount, 1);
+ }
+
+ drv_data->cfg = NULL;
+ drv_data->cfg_size = sz;
+
+ return 0;
+}
+
static void qcom_llcc_remove(struct platform_device *pdev)
{
/* Set the global pointer to a error code to avoid referencing it */
@@ -5096,8 +5474,6 @@ static int qcom_llcc_probe(struct platform_device *pdev)
struct platform_device *llcc_edac;
const struct qcom_sct_config *cfgs;
const struct qcom_llcc_config *cfg;
- const struct llcc_slice_config *llcc_cfg;
- u32 sz;
u8 cfg_index;
u32 version;
struct regmap *regmap;
@@ -5190,32 +5566,31 @@ static int qcom_llcc_probe(struct platform_device *pdev)
}
}
- llcc_cfg = cfg->sct_data;
- sz = cfg->size;
- drv_data->desc = devm_kcalloc(dev, sz, sizeof(struct llcc_slice_desc), GFP_KERNEL);
- if (!drv_data->desc) {
- ret = -ENOMEM;
- goto err;
- }
+ mutex_init(&drv_data->lock);
+ if (!cfg->size) {
+ ret = qcom_llcc_get_fw_config(pdev);
+ if (ret)
+ goto err;
+ } else {
+ drv_data->cfg = cfg->sct_data;
+ drv_data->cfg_size = cfg->size;
+ drv_data->desc = devm_kcalloc(dev, cfg->size,
+ sizeof(struct llcc_slice_desc), GFP_KERNEL);
- for (i = 0; i < sz; i++) {
- drv_data->desc[i].slice_id = llcc_cfg[i].slice_id;
- drv_data->desc[i].slice_size = llcc_cfg[i].max_cap;
- refcount_set(&drv_data->desc[i].refcount, 0);
+ if (!drv_data->desc) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = qcom_llcc_cfg_program(pdev, cfg);
+ if (ret)
+ goto err;
}
- drv_data->cfg = llcc_cfg;
- drv_data->cfg_size = sz;
+ drv_data->ecc_irq = platform_get_irq_optional(pdev, 0);
drv_data->edac_reg_offset = cfg->edac_reg_offset;
drv_data->ecc_irq_configured = cfg->irq_configured;
- mutex_init(&drv_data->lock);
- platform_set_drvdata(pdev, drv_data);
-
- ret = qcom_llcc_cfg_program(pdev, cfg);
- if (ret)
- goto err;
-
- drv_data->ecc_irq = platform_get_irq_optional(pdev, 0);
+ drv_data->dev = dev;
/*
* On some platforms, the access to EDAC registers will be locked by
@@ -5228,9 +5603,11 @@ static int qcom_llcc_probe(struct platform_device *pdev)
"qcom_llcc_edac", -1, drv_data,
sizeof(*drv_data));
if (IS_ERR(llcc_edac))
- dev_err(dev, "Failed to register llcc edac driver\n");
+ dev_err(dev, "Failed to register LLCC EDAC driver\n");
}
+ platform_set_drvdata(pdev, drv_data);
+
return 0;
err:
drv_data = ERR_PTR(-ENODEV);
@@ -5238,7 +5615,9 @@ err:
}
static const struct of_device_id qcom_llcc_of_match[] = {
+ { .compatible = "qcom,eliza-llcc", .data = &eliza_cfgs },
{ .compatible = "qcom,glymur-llcc", .data = &glymur_cfgs },
+ { .compatible = "qcom,hawi-llcc", .data = &hawi_sct_cfgs },
{ .compatible = "qcom,ipq5424-llcc", .data = &ipq5424_cfgs},
{ .compatible = "qcom,kaanapali-llcc", .data = &kaanapali_cfgs},
{ .compatible = "qcom,qcs615-llcc", .data = &qcs615_cfgs},
diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c
index cd1779b6a91a..15636a8dc907 100644
--- a/drivers/soc/qcom/qcom-geni-se.c
+++ b/drivers/soc/qcom/qcom-geni-se.c
@@ -19,6 +19,8 @@
#include <linux/of_platform.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_opp.h>
#include <linux/soc/qcom/geni-se.h>
/**
@@ -280,6 +282,12 @@ struct se_fw_hdr {
#define geni_setbits32(_addr, _v) writel(readl(_addr) | (_v), _addr)
#define geni_clrbits32(_addr, _v) writel(readl(_addr) & ~(_v), _addr)
+enum domain_idx {
+ DOMAIN_IDX_POWER,
+ DOMAIN_IDX_PERF,
+ DOMAIN_IDX_MAX
+};
+
/**
* geni_se_get_qup_hw_version() - Read the QUP wrapper Hardware version
* @se: Pointer to the corresponding serial engine.
@@ -582,6 +590,7 @@ static void geni_se_clks_off(struct geni_se *se)
clk_disable_unprepare(se->clk);
clk_bulk_disable_unprepare(wrapper->num_clks, wrapper->clks);
+ clk_disable_unprepare(se->core_clk);
}
/**
@@ -618,7 +627,18 @@ static int geni_se_clks_on(struct geni_se *se)
ret = clk_prepare_enable(se->clk);
if (ret)
- clk_bulk_disable_unprepare(wrapper->num_clks, wrapper->clks);
+ goto err_bulk_clks;
+
+ ret = clk_prepare_enable(se->core_clk);
+ if (ret)
+ goto err_se_clk;
+
+ return 0;
+
+err_se_clk:
+ clk_disable_unprepare(se->clk);
+err_bulk_clks:
+ clk_bulk_disable_unprepare(wrapper->num_clks, wrapper->clks);
return ret;
}
@@ -899,30 +919,32 @@ EXPORT_SYMBOL_GPL(geni_se_rx_dma_unprep);
int geni_icc_get(struct geni_se *se, const char *icc_ddr)
{
- int i, err;
- const char *icc_names[] = {"qup-core", "qup-config", icc_ddr};
+ struct geni_icc_path *icc_paths = se->icc_paths;
if (has_acpi_companion(se->dev))
return 0;
- for (i = 0; i < ARRAY_SIZE(se->icc_paths); i++) {
- if (!icc_names[i])
- continue;
-
- se->icc_paths[i].path = devm_of_icc_get(se->dev, icc_names[i]);
- if (IS_ERR(se->icc_paths[i].path))
- goto err;
+ icc_paths[GENI_TO_CORE].path = devm_of_icc_get(se->dev, "qup-core");
+ if (IS_ERR(icc_paths[GENI_TO_CORE].path))
+ return dev_err_probe(se->dev, PTR_ERR(icc_paths[GENI_TO_CORE].path),
+ "Failed to get 'qup-core' ICC path\n");
+
+ icc_paths[CPU_TO_GENI].path = devm_of_icc_get(se->dev, "qup-config");
+ if (IS_ERR(icc_paths[CPU_TO_GENI].path))
+ return dev_err_probe(se->dev, PTR_ERR(icc_paths[CPU_TO_GENI].path),
+ "Failed to get 'qup-config' ICC path\n");
+
+ /* The DDR path is optional, depending on protocol and hw capabilities */
+ icc_paths[GENI_TO_DDR].path = devm_of_icc_get(se->dev, "qup-memory");
+ if (IS_ERR(icc_paths[GENI_TO_DDR].path)) {
+ if (PTR_ERR(icc_paths[GENI_TO_DDR].path) == -ENODATA)
+ icc_paths[GENI_TO_DDR].path = NULL;
+ else
+ return dev_err_probe(se->dev, PTR_ERR(icc_paths[GENI_TO_DDR].path),
+ "Failed to get 'qup-memory' ICC path\n");
}
return 0;
-
-err:
- err = PTR_ERR(se->icc_paths[i].path);
- if (err != -EPROBE_DEFER)
- dev_err_ratelimited(se->dev, "Failed to get ICC path '%s': %d\n",
- icc_names[i], err);
- return err;
-
}
EXPORT_SYMBOL_GPL(geni_icc_get);
@@ -944,6 +966,28 @@ int geni_icc_set_bw(struct geni_se *se)
}
EXPORT_SYMBOL_GPL(geni_icc_set_bw);
+/**
+ * geni_icc_set_bw_ab() - Set average bandwidth for all ICC paths and apply
+ * @se: Pointer to the concerned serial engine.
+ * @core_ab: Average bandwidth in kBps for GENI_TO_CORE path.
+ * @cfg_ab: Average bandwidth in kBps for CPU_TO_GENI path.
+ * @ddr_ab: Average bandwidth in kBps for GENI_TO_DDR path.
+ *
+ * Sets bandwidth values for all ICC paths and applies them. DDR path is
+ * optional and only set if it exists.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int geni_icc_set_bw_ab(struct geni_se *se, u32 core_ab, u32 cfg_ab, u32 ddr_ab)
+{
+ se->icc_paths[GENI_TO_CORE].avg_bw = core_ab;
+ se->icc_paths[CPU_TO_GENI].avg_bw = cfg_ab;
+ se->icc_paths[GENI_TO_DDR].avg_bw = ddr_ab;
+
+ return geni_icc_set_bw(se);
+}
+EXPORT_SYMBOL_GPL(geni_icc_set_bw_ab);
+
void geni_icc_set_tag(struct geni_se *se, u32 tag)
{
int i;
@@ -989,6 +1033,196 @@ int geni_icc_disable(struct geni_se *se)
EXPORT_SYMBOL_GPL(geni_icc_disable);
/**
+ * geni_se_resources_deactivate() - Deactivate GENI SE device resources
+ * @se: Pointer to the geni_se structure
+ *
+ * Deactivates device resources for power saving: OPP rate to 0, pin control
+ * to sleep state, turns off clocks, and disables interconnect. Skips ACPI devices.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+int geni_se_resources_deactivate(struct geni_se *se)
+{
+ int ret;
+
+ if (has_acpi_companion(se->dev))
+ return 0;
+
+ if (se->has_opp)
+ dev_pm_opp_set_rate(se->dev, 0);
+
+ ret = pinctrl_pm_select_sleep_state(se->dev);
+ if (ret)
+ return ret;
+
+ geni_se_clks_off(se);
+
+ return geni_icc_disable(se);
+}
+EXPORT_SYMBOL_GPL(geni_se_resources_deactivate);
+
+/**
+ * geni_se_resources_activate() - Activate GENI SE device resources
+ * @se: Pointer to the geni_se structure
+ *
+ * Activates device resources for operation: enables interconnect, prepares clocks,
+ * and sets pin control to default state. Includes error cleanup. Skips ACPI devices.
+ *
+ * Unlike geni_se_resources_deactivate(), this function doesn't alter the
+ * connected genpds' performance states, which must be additionally handled.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+int geni_se_resources_activate(struct geni_se *se)
+{
+ int ret;
+
+ if (has_acpi_companion(se->dev))
+ return 0;
+
+ ret = geni_icc_enable(se);
+ if (ret)
+ return ret;
+
+ ret = geni_se_clks_on(se);
+ if (ret)
+ goto out_icc_disable;
+
+ ret = pinctrl_pm_select_default_state(se->dev);
+ if (ret) {
+ geni_se_clks_off(se);
+ goto out_icc_disable;
+ }
+
+ return 0;
+
+out_icc_disable:
+ geni_icc_disable(se);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(geni_se_resources_activate);
+
+/**
+ * geni_se_set_perf_level() - Set performance level for GENI SE.
+ * @se: Pointer to the struct geni_se instance.
+ * @level: The desired performance level.
+ *
+ * Sets the performance level by directly calling dev_pm_opp_set_level
+ * on the performance device associated with the SE.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int geni_se_set_perf_level(struct geni_se *se, unsigned long level)
+{
+ return dev_pm_opp_set_level(se->pd_list->pd_devs[DOMAIN_IDX_PERF], level);
+}
+EXPORT_SYMBOL_GPL(geni_se_set_perf_level);
+
+/**
+ * geni_se_set_perf_opp() - Set performance OPP for GENI SE by frequency.
+ * @se: Pointer to the struct geni_se instance.
+ * @clk_freq: The requested clock frequency.
+ *
+ * Finds the nearest operating performance point (OPP) for the given
+ * clock frequency and applies it to the SE's performance device.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int geni_se_set_perf_opp(struct geni_se *se, unsigned long clk_freq)
+{
+ struct device *perf_dev = se->pd_list->pd_devs[DOMAIN_IDX_PERF];
+ struct dev_pm_opp *opp;
+ int ret;
+
+ opp = dev_pm_opp_find_freq_floor(perf_dev, &clk_freq);
+ if (IS_ERR(opp)) {
+ dev_err(se->dev, "failed to find opp for freq %lu\n", clk_freq);
+ return PTR_ERR(opp);
+ }
+
+ ret = dev_pm_opp_set_opp(perf_dev, opp);
+ dev_pm_opp_put(opp);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(geni_se_set_perf_opp);
+
+/**
+ * geni_se_domain_attach() - Attach power domains to a GENI SE device.
+ * @se: Pointer to the geni_se structure representing the GENI SE device.
+ *
+ * This function attaches the power domains ("power" and "perf") required
+ * in the SCMI auto-VM environment to the GENI Serial Engine device. It
+ * initializes se->pd_list with the attached domains.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int geni_se_domain_attach(struct geni_se *se)
+{
+ struct dev_pm_domain_attach_data pd_data = {
+ .pd_flags = PD_FLAG_DEV_LINK_ON,
+ .pd_names = (const char*[]) { "power", "perf" },
+ .num_pd_names = 2,
+ };
+ int ret;
+
+ ret = devm_pm_domain_attach_list(se->dev,
+ &pd_data, &se->pd_list);
+ if (ret == 0)
+ return -ENODEV;
+ else if (ret < 0)
+ return ret;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(geni_se_domain_attach);
+
+/**
+ * geni_se_resources_init() - Initialize resources for a GENI SE device.
+ * @se: Pointer to the geni_se structure representing the GENI SE device.
+ *
+ * This function initializes various resources required by the GENI Serial Engine
+ * (SE) device, including clock resources (core and SE clocks), interconnect
+ * paths for communication.
+ * It retrieves optional and mandatory clock resources, adds an OF-based
+ * operating performance point (OPP) table, and sets up interconnect paths
+ * with default bandwidths. The function also sets a flag (`has_opp`) to
+ * indicate whether OPP support is available for the device.
+ *
+ * Return: 0 on success, or a negative errno on failure.
+ */
+int geni_se_resources_init(struct geni_se *se)
+{
+ int ret;
+
+ se->core_clk = devm_clk_get_optional(se->dev, "core");
+ if (IS_ERR(se->core_clk))
+ return dev_err_probe(se->dev, PTR_ERR(se->core_clk),
+ "Failed to get optional core clk\n");
+
+ se->clk = devm_clk_get(se->dev, "se");
+ if (IS_ERR(se->clk) && !has_acpi_companion(se->dev))
+ return dev_err_probe(se->dev, PTR_ERR(se->clk),
+ "Failed to get SE clk\n");
+
+ ret = devm_pm_opp_set_clkname(se->dev, "se");
+ if (ret)
+ return ret;
+
+ ret = devm_pm_opp_of_add_table(se->dev);
+ if (ret && ret != -ENODEV)
+ return dev_err_probe(se->dev, ret, "Failed to add OPP table\n");
+
+ se->has_opp = (ret == 0);
+
+ ret = geni_icc_get(se, "qup-memory");
+ if (ret)
+ return ret;
+
+ return geni_icc_set_bw_ab(se, GENI_DEFAULT_BW, GENI_DEFAULT_BW, GENI_DEFAULT_BW);
+}
+EXPORT_SYMBOL_GPL(geni_se_resources_init);
+
+/**
* geni_find_protocol_fw() - Locate and validate SE firmware for a protocol.
* @dev: Pointer to the device structure.
* @fw: Pointer to the firmware image.
diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c
index c255662b8fc3..259c41f0c34e 100644
--- a/drivers/soc/qcom/qcom_aoss.c
+++ b/drivers/soc/qcom/qcom_aoss.c
@@ -381,7 +381,7 @@ static int qmp_cooling_device_add(struct qmp *qmp,
qmp_cdev->qmp = qmp;
qmp_cdev->state = !qmp_cdev_max_state;
qmp_cdev->name = cdev_name;
- qmp_cdev->cdev = devm_thermal_of_cooling_device_register
+ qmp_cdev->cdev = devm_thermal_of_child_cooling_device_register
(qmp->dev, node,
cdev_name,
qmp_cdev, &qmp_cooling_device_ops);
diff --git a/drivers/soc/qcom/qcom_pd_mapper.c b/drivers/soc/qcom/qcom_pd_mapper.c
index 7bb14c20ab5d..0dc1a7946050 100644
--- a/drivers/soc/qcom/qcom_pd_mapper.c
+++ b/drivers/soc/qcom/qcom_pd_mapper.c
@@ -7,7 +7,6 @@
#include <linux/auxiliary_bus.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/refcount.h>
@@ -266,6 +265,12 @@ static const struct qcom_pdm_domain_data adsp_charger_pd = {
.services = { NULL },
};
+static const struct qcom_pdm_domain_data adsp_ois_pd = {
+ .domain = "msm/adsp/ois_pd",
+ .instance_id = 74,
+ .services = { NULL, },
+};
+
static const struct qcom_pdm_domain_data adsp_root_pd = {
.domain = "msm/adsp/root_pd",
.instance_id = 74,
@@ -370,6 +375,7 @@ static const struct qcom_pdm_domain_data *glymur_domains[] = {
static const struct qcom_pdm_domain_data *kaanapali_domains[] = {
&adsp_audio_pd,
+ &adsp_ois_pd,
&adsp_root_pd,
&adsp_sensor_pd,
&cdsp_root_pd,
@@ -581,6 +587,7 @@ static const struct of_device_id qcom_pdm_domains[] __maybe_unused = {
{ .compatible = "qcom,eliza", .data = sm8550_domains, },
{ .compatible = "qcom,apq8096", .data = msm8996_domains, },
{ .compatible = "qcom,glymur", .data = glymur_domains, },
+ { .compatible = "qcom,hawi", .data = kaanapali_domains, },
{ .compatible = "qcom,kaanapali", .data = kaanapali_domains, },
{ .compatible = "qcom,mahua", .data = glymur_domains, },
{ .compatible = "qcom,milos", .data = sm8550_domains, },
diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c
index d5c94b47f431..afb21a778fe7 100644
--- a/drivers/soc/qcom/smem.c
+++ b/drivers/soc/qcom/smem.c
@@ -85,9 +85,6 @@
/* Processor/host identifier for the global partition */
#define SMEM_GLOBAL_HOST 0xfffe
-/* Max number of processors/hosts in a system */
-#define SMEM_HOST_COUNT 25
-
/**
* struct smem_proc_comm - proc_comm communication struct (legacy)
* @command: current command to be executed
@@ -282,7 +279,7 @@ struct qcom_smem {
struct platform_device *socinfo;
struct smem_ptable *ptable;
struct smem_partition global_partition;
- struct smem_partition partitions[SMEM_HOST_COUNT];
+ struct xarray partitions;
unsigned num_regions;
struct smem_region regions[] __counted_by(num_regions);
@@ -382,7 +379,7 @@ static struct qcom_smem *__smem = INIT_ERR_PTR(-EPROBE_DEFER);
int qcom_smem_bust_hwspin_lock_by_host(unsigned int host)
{
/* This function is for remote procs, so ignore SMEM_HOST_APPS */
- if (host == SMEM_HOST_APPS || host >= SMEM_HOST_COUNT)
+ if (host == SMEM_HOST_APPS || !xa_load(&__smem->partitions, host))
return -EINVAL;
return hwspin_lock_bust(__smem->hwlock, SMEM_HOST_ID_TO_HWSPINLOCK_ID(host));
@@ -530,8 +527,8 @@ int qcom_smem_alloc(unsigned host, unsigned item, size_t size)
if (ret)
return ret;
- if (host < SMEM_HOST_COUNT && __smem->partitions[host].virt_base) {
- part = &__smem->partitions[host];
+ part = xa_load(&__smem->partitions, host);
+ if (part) {
ret = qcom_smem_alloc_private(__smem, part, item, size);
} else if (__smem->global_partition.virt_base) {
part = &__smem->global_partition;
@@ -697,8 +694,8 @@ void *qcom_smem_get(unsigned host, unsigned item, size_t *size)
if (item >= __smem->item_count)
return ERR_PTR(-EINVAL);
- if (host < SMEM_HOST_COUNT && __smem->partitions[host].virt_base) {
- part = &__smem->partitions[host];
+ part = xa_load(&__smem->partitions, host);
+ if (part) {
ptr = qcom_smem_get_private(__smem, part, item, size);
} else if (__smem->global_partition.virt_base) {
part = &__smem->global_partition;
@@ -730,8 +727,8 @@ int qcom_smem_get_free_space(unsigned host)
if (IS_ERR(__smem))
return PTR_ERR(__smem);
- if (host < SMEM_HOST_COUNT && __smem->partitions[host].virt_base) {
- part = &__smem->partitions[host];
+ part = xa_load(&__smem->partitions, host);
+ if (part) {
phdr = part->virt_base;
ret = le32_to_cpu(phdr->offset_free_cached) -
le32_to_cpu(phdr->offset_free_uncached);
@@ -774,12 +771,11 @@ phys_addr_t qcom_smem_virt_to_phys(void *p)
{
struct smem_partition *part;
struct smem_region *area;
+ unsigned long index;
u64 offset;
u32 i;
- for (i = 0; i < SMEM_HOST_COUNT; i++) {
- part = &__smem->partitions[i];
-
+ xa_for_each(&__smem->partitions, index, part) {
if (addr_in_range(part->virt_base, part->size, p)) {
offset = p - part->virt_base;
@@ -1016,16 +1012,20 @@ static int
qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host)
{
struct smem_partition_header *header;
+ struct smem_partition *part;
struct smem_ptable_entry *entry;
struct smem_ptable *ptable;
u16 remote_host;
u16 host0, host1;
+ int ret;
int i;
ptable = qcom_smem_get_ptable(smem);
if (IS_ERR(ptable))
return PTR_ERR(ptable);
+ xa_init(&smem->partitions);
+
for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) {
entry = &ptable->entry[i];
if (!le32_to_cpu(entry->offset))
@@ -1042,12 +1042,7 @@ qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host)
else
continue;
- if (remote_host >= SMEM_HOST_COUNT) {
- dev_err(smem->dev, "bad host %u\n", remote_host);
- return -EINVAL;
- }
-
- if (smem->partitions[remote_host].virt_base) {
+ if (xa_load(&smem->partitions, remote_host)) {
dev_err(smem->dev, "duplicate host %u\n", remote_host);
return -EINVAL;
}
@@ -1056,11 +1051,20 @@ qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host)
if (!header)
return -EINVAL;
- smem->partitions[remote_host].virt_base = (void __iomem *)header;
- smem->partitions[remote_host].phys_base = smem->regions[0].aux_base +
- le32_to_cpu(entry->offset);
- smem->partitions[remote_host].size = le32_to_cpu(entry->size);
- smem->partitions[remote_host].cacheline = le32_to_cpu(entry->cacheline);
+ part = devm_kzalloc(smem->dev, sizeof(struct smem_partition), GFP_KERNEL);
+ if (!part)
+ return -ENOMEM;
+
+ part->virt_base = (void __iomem *)header;
+ part->phys_base = smem->regions[0].aux_base + le32_to_cpu(entry->offset);
+ part->size = le32_to_cpu(entry->size);
+ part->cacheline = le32_to_cpu(entry->cacheline);
+
+ ret = xa_insert(&smem->partitions, remote_host, part, GFP_KERNEL);
+ if (ret) {
+ dev_err(smem->dev, "fail to insert host %u\n", remote_host);
+ return ret;
+ }
}
return 0;
@@ -1229,7 +1233,6 @@ static int qcom_smem_probe(struct platform_device *pdev)
return -EINVAL;
}
- BUILD_BUG_ON(SMEM_HOST_APPS >= SMEM_HOST_COUNT);
ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS);
if (ret < 0 && ret != -ENOENT)
return ret;
@@ -1249,6 +1252,7 @@ static void qcom_smem_remove(struct platform_device *pdev)
{
platform_device_unregister(__smem->socinfo);
+ xa_destroy(&__smem->partitions);
/* Set to -EPROBE_DEFER to signal unprobed state */
__smem = ERR_PTR(-EPROBE_DEFER);
}
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 8ffd903ebddb..af418adad7aa 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -188,7 +188,19 @@ static const char *const pmic_models[] = {
[80] = "PM7550",
[82] = "PMC8380",
[83] = "SMB2360",
+ [86] = "PM8750B",
+ [87] = "PMD8028",
+ [88] = "PMC1020H",
+ [89] = "PMIV0104",
+ [90] = "PMIV0102",
[91] = "PMIV0108",
+ [92] = "PMK8850",
+ [93] = "PMH0101",
+ [94] = "PMAU0102",
+ [95] = "SMB2370",
+ [96] = "PMH0104",
+ [97] = "PMH0110",
+ [98] = "PMCX0102",
};
struct socinfo_params {
@@ -519,6 +531,7 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(IPQ5424) },
{ qcom_board_id(QCM6690) },
{ qcom_board_id(QCS6690) },
+ { qcom_board_id(SM7750) },
{ qcom_board_id(SM8850) },
{ qcom_board_id(IPQ5404) },
{ qcom_board_id(QCS9100) },
@@ -526,13 +539,23 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(QCS8275) },
{ qcom_board_id(QCS9075) },
{ qcom_board_id(QCS615) },
+ { qcom_board_id(SA8797P) },
{ qcom_board_id(CQ7790M) },
{ qcom_board_id(CQ7790S) },
+ { qcom_board_id(CQ2390M) },
+ { qcom_board_id(CQ2390S) },
+ { qcom_board_id(IQ2390S) },
{ qcom_board_id(IPQ5200) },
{ qcom_board_id(IPQ5210) },
{ qcom_board_id(QCF2200) },
{ qcom_board_id(QCF3200) },
{ qcom_board_id(QCF3210) },
+ { qcom_board_id(IPQ9620) },
+ { qcom_board_id(IPQ9650) },
+ { qcom_board_id(IPQ9610) },
+ { qcom_board_id(IPQ9630) },
+ { qcom_board_id(IPQ9640) },
+ { qcom_board_id(IPQ9670) },
};
static const char *socinfo_machine(struct device *dev, unsigned int id)
diff --git a/drivers/soc/qcom/wcnss_ctrl.c b/drivers/soc/qcom/wcnss_ctrl.c
index ffb31a049d4a..942e11feba65 100644
--- a/drivers/soc/qcom/wcnss_ctrl.c
+++ b/drivers/soc/qcom/wcnss_ctrl.c
@@ -221,8 +221,10 @@ static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc)
left = fw->size;
req = kzalloc_flex(*req, fragment, NV_FRAGMENT_SIZE);
- if (!req)
- return -ENOMEM;
+ if (!req) {
+ ret = -ENOMEM;
+ goto release_fw;
+ }
req->frag_size = NV_FRAGMENT_SIZE;
req->hdr.type = WCNSS_DOWNLOAD_NV_REQ;
@@ -243,7 +245,7 @@ static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc)
ret = rpmsg_send(wcnss->channel, req, req->hdr.len);
if (ret < 0) {
dev_err(dev, "failed to send smd packet\n");
- goto release_fw;
+ goto release_req;
}
/* Increment for next fragment */
@@ -262,9 +264,10 @@ static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc)
ret = 0;
}
+release_req:
+ kfree(req);
release_fw:
release_firmware(fw);
- kfree(req);
return ret;
}
diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig
index 26bed0fdceb0..2ab150d04bb1 100644
--- a/drivers/soc/renesas/Kconfig
+++ b/drivers/soc/renesas/Kconfig
@@ -465,6 +465,15 @@ config ARCH_R9A07G043
endif # RISCV
+config RCAR_MFIS
+ tristate "Renesas R-Car MFIS driver"
+ depends on ARCH_RENESAS || COMPILE_TEST
+ depends on MAILBOX
+ help
+ Select this option to enable the Renesas R-Car MFIS core driver for
+ the MFIS device found on SoCs like R-Car. On families like Gen5, this
+ is needed to communicate with the SCP.
+
config PWC_RZV2M
bool "Renesas RZ/V2M PWC support" if COMPILE_TEST
diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile
index 655dbcb08747..81bde85c2178 100644
--- a/drivers/soc/renesas/Makefile
+++ b/drivers/soc/renesas/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_SYS_R9A09G057) += r9a09g057-sys.o
# Family
obj-$(CONFIG_PWC_RZV2M) += pwc-rzv2m.o
+obj-$(CONFIG_RCAR_MFIS) += rcar-mfis.o
obj-$(CONFIG_RST_RCAR) += rcar-rst.o
obj-$(CONFIG_RZN1_IRQMUX) += rzn1_irqmux.o
obj-$(CONFIG_SYSC_RZ) += rz-sysc.o
diff --git a/drivers/soc/renesas/r9a08g045-sysc.c b/drivers/soc/renesas/r9a08g045-sysc.c
index 03d653d5cde5..63e4aa6a7cd0 100644
--- a/drivers/soc/renesas/r9a08g045-sysc.c
+++ b/drivers/soc/renesas/r9a08g045-sysc.c
@@ -37,18 +37,14 @@ static const struct rz_sysc_soc_id_init_data rzg3s_sysc_soc_id_init_data __initc
.specific_id_mask = GENMASK(27, 0),
};
-static bool rzg3s_regmap_readable_reg(struct device *dev, unsigned int reg)
+static bool rzg3s_regmap_readable_writeable_reg(unsigned int reg)
{
switch (reg) {
case SYS_XSPI_MAP_STAADD_CS0:
case SYS_XSPI_MAP_ENDADD_CS0:
case SYS_XSPI_MAP_STAADD_CS1:
case SYS_XSPI_MAP_ENDADD_CS1:
- case SYS_GETH0_CFG:
- case SYS_GETH1_CFG:
case SYS_PCIE_CFG:
- case SYS_PCIE_MON:
- case SYS_PCIE_ERR_MON:
case SYS_PCIE_PHY:
case SYS_I2C0_CFG:
case SYS_I2C1_CFG:
@@ -63,28 +59,27 @@ static bool rzg3s_regmap_readable_reg(struct device *dev, unsigned int reg)
}
}
-static bool rzg3s_regmap_writeable_reg(struct device *dev, unsigned int reg)
+static bool rzg3s_regmap_readable_reg(struct device *dev, unsigned int reg)
{
+ if (rzg3s_regmap_readable_writeable_reg(reg))
+ return true;
+
switch (reg) {
- case SYS_XSPI_MAP_STAADD_CS0:
- case SYS_XSPI_MAP_ENDADD_CS0:
- case SYS_XSPI_MAP_STAADD_CS1:
- case SYS_XSPI_MAP_ENDADD_CS1:
- case SYS_PCIE_CFG:
- case SYS_PCIE_PHY:
- case SYS_I2C0_CFG:
- case SYS_I2C1_CFG:
- case SYS_I2C2_CFG:
- case SYS_I2C3_CFG:
- case SYS_I3C_CFG:
- case SYS_USB_PWRRDY:
- case SYS_PCIE_RST_RSM_B:
+ case SYS_GETH0_CFG:
+ case SYS_GETH1_CFG:
+ case SYS_PCIE_MON:
+ case SYS_PCIE_ERR_MON:
return true;
default:
return false;
}
}
+static bool rzg3s_regmap_writeable_reg(struct device *dev, unsigned int reg)
+{
+ return rzg3s_regmap_readable_writeable_reg(reg);
+}
+
const struct rz_sysc_init_data rzg3s_sysc_init_data __initconst = {
.soc_id_init_data = &rzg3s_sysc_soc_id_init_data,
.readable_reg = rzg3s_regmap_readable_reg,
diff --git a/drivers/soc/renesas/r9a08g046-sysc.c b/drivers/soc/renesas/r9a08g046-sysc.c
index fd98df196d0a..90db9d383539 100644
--- a/drivers/soc/renesas/r9a08g046-sysc.c
+++ b/drivers/soc/renesas/r9a08g046-sysc.c
@@ -28,17 +28,14 @@
#define SYS_PWRRDY_N 0xd70
#define SYS_IPCONT_SEL_CLONECH 0xe2c
-static bool rzg3l_regmap_readable_reg(struct device *dev, unsigned int reg)
+static bool rzg3l_regmap_readable_writeable_reg(unsigned int reg)
{
switch (reg) {
case SYS_XSPI_MAP_STAADD_CS0:
case SYS_XSPI_MAP_ENDADD_CS0:
case SYS_XSPI_MAP_STAADD_CS1:
case SYS_XSPI_MAP_ENDADD_CS1:
- case SYS_GETH0_CFG:
- case SYS_GETH1_CFG:
case SYS_PCIE_CFG:
- case SYS_PCIE_MON:
case SYS_PCIE_PHY:
case SYS_I2C0_CFG:
case SYS_I2C1_CFG:
@@ -53,28 +50,26 @@ static bool rzg3l_regmap_readable_reg(struct device *dev, unsigned int reg)
}
}
-static bool rzg3l_regmap_writeable_reg(struct device *dev, unsigned int reg)
+static bool rzg3l_regmap_readable_reg(struct device *dev, unsigned int reg)
{
+ if (rzg3l_regmap_readable_writeable_reg(reg))
+ return true;
+
switch (reg) {
- case SYS_XSPI_MAP_STAADD_CS0:
- case SYS_XSPI_MAP_ENDADD_CS0:
- case SYS_XSPI_MAP_STAADD_CS1:
- case SYS_XSPI_MAP_ENDADD_CS1:
- case SYS_PCIE_CFG:
- case SYS_PCIE_PHY:
- case SYS_I2C0_CFG:
- case SYS_I2C1_CFG:
- case SYS_I2C2_CFG:
- case SYS_I2C3_CFG:
- case SYS_I3C_CFG:
- case SYS_PWRRDY_N:
- case SYS_IPCONT_SEL_CLONECH:
+ case SYS_GETH0_CFG:
+ case SYS_GETH1_CFG:
+ case SYS_PCIE_MON:
return true;
default:
return false;
}
}
+static bool rzg3l_regmap_writeable_reg(struct device *dev, unsigned int reg)
+{
+ return rzg3l_regmap_readable_writeable_reg(reg);
+}
+
static const struct rz_sysc_soc_id_init_data rzg3l_sysc_soc_id_init_data __initconst = {
.family = "RZ/G3L",
.id = 0x87d9447,
diff --git a/drivers/soc/renesas/r9a09g047-sys.c b/drivers/soc/renesas/r9a09g047-sys.c
index ea3ca10fcc33..b617fb0bde7b 100644
--- a/drivers/soc/renesas/r9a09g047-sys.c
+++ b/drivers/soc/renesas/r9a09g047-sys.c
@@ -83,11 +83,9 @@ static const struct rz_sysc_soc_id_init_data rzg3e_sys_soc_id_init_data __initco
.print_id = rzg3e_sys_print_id,
};
-static bool rzg3e_regmap_readable_reg(struct device *dev, unsigned int reg)
+static bool rzg3e_regmap_readable_writeable_reg(unsigned int reg)
{
switch (reg) {
- case SYS_LSI_OTPTSU1TRMVAL0:
- case SYS_LSI_OTPTSU1TRMVAL1:
case SYS_SPI_STAADDCS0:
case SYS_SPI_ENDADDCS0:
case SYS_SPI_STAADDCS1:
@@ -112,33 +110,25 @@ static bool rzg3e_regmap_readable_reg(struct device *dev, unsigned int reg)
}
}
-static bool rzg3e_regmap_writeable_reg(struct device *dev, unsigned int reg)
+static bool rzg3e_regmap_readable_reg(struct device *dev, unsigned int reg)
{
+ if (rzg3e_regmap_readable_writeable_reg(reg))
+ return true;
+
switch (reg) {
- case SYS_SPI_STAADDCS0:
- case SYS_SPI_ENDADDCS0:
- case SYS_SPI_STAADDCS1:
- case SYS_SPI_ENDADDCS1:
- case SYS_VSP_CLK:
- case SYS_GBETH0_CFG:
- case SYS_GBETH1_CFG:
- case SYS_PCIE_INTX_CH0:
- case SYS_PCIE_MSI1_CH0:
- case SYS_PCIE_MSI2_CH0:
- case SYS_PCIE_MSI3_CH0:
- case SYS_PCIE_MSI4_CH0:
- case SYS_PCIE_MSI5_CH0:
- case SYS_PCIE_PME_CH0:
- case SYS_PCIE_ACK_CH0:
- case SYS_PCIE_MISC_CH0:
- case SYS_PCIE_MODE_CH0:
- case SYS_ADC_CFG:
+ case SYS_LSI_OTPTSU1TRMVAL0:
+ case SYS_LSI_OTPTSU1TRMVAL1:
return true;
default:
return false;
}
}
+static bool rzg3e_regmap_writeable_reg(struct device *dev, unsigned int reg)
+{
+ return rzg3e_regmap_readable_writeable_reg(reg);
+}
+
const struct rz_sysc_init_data rzg3e_sys_init_data __initconst = {
.soc_id_init_data = &rzg3e_sys_soc_id_init_data,
.readable_reg = rzg3e_regmap_readable_reg,
diff --git a/drivers/soc/renesas/r9a09g056-sys.c b/drivers/soc/renesas/r9a09g056-sys.c
index 2a8ebc209961..e6a66688423f 100644
--- a/drivers/soc/renesas/r9a09g056-sys.c
+++ b/drivers/soc/renesas/r9a09g056-sys.c
@@ -88,13 +88,9 @@ static const struct rz_sysc_soc_id_init_data rzv2n_sys_soc_id_init_data __initco
.print_id = rzv2n_sys_print_id,
};
-static bool rzv2n_regmap_readable_reg(struct device *dev, unsigned int reg)
+static bool rzv2n_regmap_readable_writeable_reg(unsigned int reg)
{
switch (reg) {
- case SYS_LSI_OTPTSU0TRMVAL0:
- case SYS_LSI_OTPTSU0TRMVAL1:
- case SYS_LSI_OTPTSU1TRMVAL0:
- case SYS_LSI_OTPTSU1TRMVAL1:
case SYS_GBETH0_CFG:
case SYS_GBETH1_CFG:
case SYS_PCIE_INTX_CH0:
@@ -114,28 +110,27 @@ static bool rzv2n_regmap_readable_reg(struct device *dev, unsigned int reg)
}
}
-static bool rzv2n_regmap_writeable_reg(struct device *dev, unsigned int reg)
+static bool rzv2n_regmap_readable_reg(struct device *dev, unsigned int reg)
{
+ if (rzv2n_regmap_readable_writeable_reg(reg))
+ return true;
+
switch (reg) {
- case SYS_GBETH0_CFG:
- case SYS_GBETH1_CFG:
- case SYS_PCIE_INTX_CH0:
- case SYS_PCIE_MSI1_CH0:
- case SYS_PCIE_MSI2_CH0:
- case SYS_PCIE_MSI3_CH0:
- case SYS_PCIE_MSI4_CH0:
- case SYS_PCIE_MSI5_CH0:
- case SYS_PCIE_PME_CH0:
- case SYS_PCIE_ACK_CH0:
- case SYS_PCIE_MISC_CH0:
- case SYS_PCIE_MODE_CH0:
- case SYS_ADC_CFG:
+ case SYS_LSI_OTPTSU0TRMVAL0:
+ case SYS_LSI_OTPTSU0TRMVAL1:
+ case SYS_LSI_OTPTSU1TRMVAL0:
+ case SYS_LSI_OTPTSU1TRMVAL1:
return true;
default:
return false;
}
}
+static bool rzv2n_regmap_writeable_reg(struct device *dev, unsigned int reg)
+{
+ return rzv2n_regmap_readable_writeable_reg(reg);
+}
+
const struct rz_sysc_init_data rzv2n_sys_init_data __initconst = {
.soc_id_init_data = &rzv2n_sys_soc_id_init_data,
.readable_reg = rzv2n_regmap_readable_reg,
diff --git a/drivers/soc/renesas/r9a09g057-sys.c b/drivers/soc/renesas/r9a09g057-sys.c
index f3e054206acb..308492c31acb 100644
--- a/drivers/soc/renesas/r9a09g057-sys.c
+++ b/drivers/soc/renesas/r9a09g057-sys.c
@@ -91,13 +91,9 @@ static const struct rz_sysc_soc_id_init_data rzv2h_sys_soc_id_init_data __initco
.print_id = rzv2h_sys_print_id,
};
-static bool rzv2h_regmap_readable_reg(struct device *dev, unsigned int reg)
+static bool rzv2h_regmap_readable_writeable_reg(unsigned int reg)
{
switch (reg) {
- case SYS_LSI_OTPTSU0TRMVAL0:
- case SYS_LSI_OTPTSU0TRMVAL1:
- case SYS_LSI_OTPTSU1TRMVAL0:
- case SYS_LSI_OTPTSU1TRMVAL1:
case SYS_GBETH0_CFG:
case SYS_GBETH1_CFG:
case SYS_PCIE_INTX_CH0:
@@ -128,39 +124,27 @@ static bool rzv2h_regmap_readable_reg(struct device *dev, unsigned int reg)
}
}
-static bool rzv2h_regmap_writeable_reg(struct device *dev, unsigned int reg)
+static bool rzv2h_regmap_readable_reg(struct device *dev, unsigned int reg)
{
+ if (rzv2h_regmap_readable_writeable_reg(reg))
+ return true;
+
switch (reg) {
- case SYS_GBETH0_CFG:
- case SYS_GBETH1_CFG:
- case SYS_PCIE_INTX_CH0:
- case SYS_PCIE_MSI1_CH0:
- case SYS_PCIE_MSI2_CH0:
- case SYS_PCIE_MSI3_CH0:
- case SYS_PCIE_MSI4_CH0:
- case SYS_PCIE_MSI5_CH0:
- case SYS_PCIE_PME_CH0:
- case SYS_PCIE_ACK_CH0:
- case SYS_PCIE_MISC_CH0:
- case SYS_PCIE_MODE_CH0:
- case SYS_PCIE_INTX_CH1:
- case SYS_PCIE_MSI1_CH1:
- case SYS_PCIE_MSI2_CH1:
- case SYS_PCIE_MSI3_CH1:
- case SYS_PCIE_MSI4_CH1:
- case SYS_PCIE_MSI5_CH1:
- case SYS_PCIE_PME_CH1:
- case SYS_PCIE_ACK_CH1:
- case SYS_PCIE_MISC_CH1:
- case SYS_PCIE_MODE_CH1:
- case SYS_PCIE_MODE:
- case SYS_ADC_CFG:
+ case SYS_LSI_OTPTSU0TRMVAL0:
+ case SYS_LSI_OTPTSU0TRMVAL1:
+ case SYS_LSI_OTPTSU1TRMVAL0:
+ case SYS_LSI_OTPTSU1TRMVAL1:
return true;
default:
return false;
}
}
+static bool rzv2h_regmap_writeable_reg(struct device *dev, unsigned int reg)
+{
+ return rzv2h_regmap_readable_writeable_reg(reg);
+}
+
const struct rz_sysc_init_data rzv2h_sys_init_data __initconst = {
.soc_id_init_data = &rzv2h_sys_soc_id_init_data,
.readable_reg = rzv2h_regmap_readable_reg,
diff --git a/drivers/soc/renesas/rcar-mfis.c b/drivers/soc/renesas/rcar-mfis.c
new file mode 100644
index 000000000000..3435c3e16198
--- /dev/null
+++ b/drivers/soc/renesas/rcar-mfis.c
@@ -0,0 +1,384 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Renesas R-Car MFIS (Multifunctional Interface) driver
+ *
+ * Copyright (C) Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ * Wolfram Sang <wsa+renesas@sang-engineering.com>
+ */
+#include <dt-bindings/soc/renesas,r8a78000-mfis.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mailbox_controller.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#define MFISWPCNTR 0x0900
+#define MFISWACNTR 0x0904
+
+#define MFIS_X5H_IICR(i) ((i) * 0x1000 + 0x00)
+#define MFIS_X5H_EICR(i) ((i) * 0x1000 + 0x04)
+
+#define MFIS_UNPROTECT_KEY 0xACCE0000
+
+struct mfis_priv;
+
+struct mfis_reg {
+ void __iomem *base;
+ resource_size_t start;
+ struct mfis_priv *priv;
+};
+
+struct mfis_info {
+ u32 unprotect_mask;
+ unsigned int mb_num_channels;
+ unsigned int mb_reg_comes_from_dt:1;
+ unsigned int mb_tx_uses_eicr:1;
+ unsigned int mb_channels_are_unidir:1;
+ u32 (*mb_calc_reg)(u32 chan_num, bool tx_uses_eicr, bool is_only_rx);
+};
+
+struct mfis_chan_priv {
+ u32 reg;
+ int irq;
+};
+
+struct mfis_priv {
+ spinlock_t unprotect_lock; /* guards access to the unprotection reg */
+ struct device *dev;
+ struct mfis_reg common_reg;
+ struct mfis_reg mbox_reg;
+ const struct mfis_info *info;
+
+ /* mailbox private data */
+ struct mbox_controller mbox;
+ struct mfis_chan_priv *chan_privs;
+};
+
+static u32 mfis_read(struct mfis_reg *mreg, unsigned int reg)
+{
+ return ioread32(mreg->base + reg);
+}
+
+static void mfis_write(struct mfis_reg *mreg, u32 reg, u32 val)
+{
+ struct mfis_priv *priv = mreg->priv;
+ u32 unprotect_mask = priv->info->unprotect_mask;
+ unsigned long flags;
+ u32 unprotect_code;
+
+ /*
+ * [Gen4] key: 0xACCE0000, mask: 0x0000FFFF
+ * [Gen5] key: 0xACC00000, mask: 0x000FFFFF
+ */
+ unprotect_code = (MFIS_UNPROTECT_KEY & ~unprotect_mask) |
+ ((mreg->start + reg) & unprotect_mask);
+
+ spin_lock_irqsave(&priv->unprotect_lock, flags);
+ iowrite32(unprotect_code, priv->common_reg.base + MFISWACNTR);
+ iowrite32(val, mreg->base + reg);
+ spin_unlock_irqrestore(&priv->unprotect_lock, flags);
+}
+
+/********************************************************
+ * Mailbox *
+ ********************************************************/
+
+#define mfis_mb_mbox_to_priv(_m) container_of((_m), struct mfis_priv, mbox)
+
+static irqreturn_t mfis_mb_iicr_interrupt(int irq, void *data)
+{
+ struct mbox_chan *chan = data;
+ struct mfis_priv *priv = mfis_mb_mbox_to_priv(chan->mbox);
+ struct mfis_chan_priv *chan_priv = chan->con_priv;
+
+ mbox_chan_received_data(chan, NULL);
+ /* Stop remote(!) doorbell */
+ mfis_write(&priv->mbox_reg, chan_priv->reg, 0);
+
+ return IRQ_HANDLED;
+}
+
+static int mfis_mb_startup(struct mbox_chan *chan)
+{
+ struct mfis_chan_priv *chan_priv = chan->con_priv;
+
+ if (!chan_priv->irq)
+ return 0;
+
+ return request_irq(chan_priv->irq, mfis_mb_iicr_interrupt, 0,
+ dev_name(chan->mbox->dev), chan);
+}
+
+static void mfis_mb_shutdown(struct mbox_chan *chan)
+{
+ struct mfis_chan_priv *chan_priv = chan->con_priv;
+
+ if (chan_priv->irq)
+ free_irq(chan_priv->irq, chan);
+}
+
+static int mfis_mb_iicr_send_data(struct mbox_chan *chan, void *data)
+{
+ struct mfis_priv *priv = mfis_mb_mbox_to_priv(chan->mbox);
+ struct mfis_chan_priv *chan_priv = chan->con_priv;
+
+ /* Our doorbell still active? */
+ if (mfis_read(&priv->mbox_reg, chan_priv->reg) & BIT(0))
+ return -EBUSY;
+
+ /* Start our doorbell */
+ mfis_write(&priv->mbox_reg, chan_priv->reg, BIT(0));
+
+ return 0;
+}
+
+static bool mfis_mb_iicr_last_tx_done(struct mbox_chan *chan)
+{
+ struct mfis_priv *priv = mfis_mb_mbox_to_priv(chan->mbox);
+ struct mfis_chan_priv *chan_priv = chan->con_priv;
+
+ /* Our doorbell still active? */
+ return !(mfis_read(&priv->mbox_reg, chan_priv->reg) & BIT(0));
+}
+
+/* For MFIS variants using the IICR/EICR register pair */
+static const struct mbox_chan_ops mfis_iicr_ops = {
+ .startup = mfis_mb_startup,
+ .shutdown = mfis_mb_shutdown,
+ .send_data = mfis_mb_iicr_send_data,
+ .last_tx_done = mfis_mb_iicr_last_tx_done,
+};
+
+static u32 mfis_mb_r8a779g0_calc_reg(u32 chan_num, bool tx_uses_eicr, bool is_only_rx)
+{
+ unsigned int i, k;
+ u32 reg;
+
+ i = chan_num & 3;
+ k = chan_num >> 2;
+
+ if (is_only_rx) {
+ if (k < 2)
+ reg = 0x9404 + 0x1020 * k + 0x08 * i;
+ else
+ reg = 0xb504 + 0x08 * i;
+ } else {
+ if (k < 2)
+ reg = 0x1400 + 0x1008 * i + 0x20 * k;
+ else
+ reg = 0x1500 + 0x1008 * i;
+ }
+
+ return reg;
+}
+
+static u32 mfis_mb_r8a78000_calc_reg(u32 chan_num, bool tx_uses_eicr, bool is_only_rx)
+{
+ return (tx_uses_eicr ^ is_only_rx) ? MFIS_X5H_EICR(chan_num) :
+ MFIS_X5H_IICR(chan_num);
+}
+
+static struct mbox_chan *mfis_mb_of_xlate(struct mbox_controller *mbox,
+ const struct of_phandle_args *sp)
+{
+ struct mfis_priv *priv = mfis_mb_mbox_to_priv(mbox);
+ struct mfis_chan_priv *chan_priv;
+ bool tx_uses_eicr, is_only_rx;
+ u32 chan_num, chan_flags;
+ struct mbox_chan *chan;
+
+ if (sp->args_count != 2)
+ return ERR_PTR(-EINVAL);
+
+ chan_num = sp->args[0];
+ chan_flags = sp->args[1];
+
+ if (chan_num >= priv->info->mb_num_channels)
+ return ERR_PTR(-EINVAL);
+
+ /* Channel layout is described in mfis_mb_probe() */
+ if (priv->info->mb_channels_are_unidir) {
+ is_only_rx = chan_flags & MFIS_CHANNEL_RX;
+ chan = mbox->chans + 2 * chan_num + is_only_rx;
+ } else {
+ is_only_rx = false;
+ chan = mbox->chans + chan_num;
+ }
+
+ if (priv->info->mb_reg_comes_from_dt) {
+ tx_uses_eicr = chan_flags & MFIS_CHANNEL_EICR;
+ if (tx_uses_eicr)
+ chan += mbox->num_chans / 2;
+ } else {
+ tx_uses_eicr = priv->info->mb_tx_uses_eicr;
+ }
+
+ chan_priv = chan->con_priv;
+ chan_priv->reg = priv->info->mb_calc_reg(chan_num, tx_uses_eicr, is_only_rx);
+
+ if (!priv->info->mb_channels_are_unidir || is_only_rx) {
+ char irqname[8];
+ char suffix = tx_uses_eicr ? 'i' : 'e';
+
+ /* "ch0i" or "ch0e" */
+ scnprintf(irqname, sizeof(irqname), "ch%u%c", chan_num, suffix);
+
+ chan_priv->irq = of_irq_get_byname(mbox->dev->of_node, irqname);
+ if (chan_priv->irq < 0)
+ return ERR_PTR(chan_priv->irq);
+ if (chan_priv->irq == 0)
+ return ERR_PTR(-ENOENT);
+ }
+
+ return chan;
+}
+
+static int mfis_mb_probe(struct mfis_priv *priv)
+{
+ unsigned int num_chan = priv->info->mb_num_channels;
+ struct device *dev = priv->dev;
+ struct mbox_controller *mbox;
+ struct mbox_chan *chan;
+
+ if (priv->info->mb_channels_are_unidir) {
+ /* Channel layout: Ch0-TX, Ch0-RX, Ch1-TX... */
+ num_chan *= 2;
+ }
+
+ if (priv->info->mb_reg_comes_from_dt) {
+ /* Channel layout: <n> IICR channels, <n> EICR channels */
+ num_chan *= 2;
+ }
+
+ chan = devm_kcalloc(dev, num_chan, sizeof(*chan), GFP_KERNEL);
+ if (!chan)
+ return -ENOMEM;
+
+ priv->chan_privs = devm_kcalloc(dev, num_chan, sizeof(*priv->chan_privs),
+ GFP_KERNEL);
+ if (!priv->chan_privs)
+ return -ENOMEM;
+
+ mbox = &priv->mbox;
+
+ for (unsigned int i = 0; i < num_chan; i++)
+ chan[i].con_priv = &priv->chan_privs[i];
+
+ mbox->chans = chan;
+ mbox->num_chans = num_chan;
+ mbox->txdone_poll = true;
+ mbox->ops = &mfis_iicr_ops;
+ mbox->dev = dev;
+ mbox->of_xlate = mfis_mb_of_xlate;
+
+ return devm_mbox_controller_register(dev, mbox);
+}
+
+/********************************************************
+ * Common *
+ ********************************************************/
+static int mfis_reg_probe(struct platform_device *pdev, struct mfis_priv *priv,
+ struct mfis_reg *mreg, const char *name, bool required)
+{
+ struct resource *res;
+ void __iomem *base;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+
+ /* If there is no mailbox resource, registers are in the common space */
+ if (!res && !required) {
+ *mreg = priv->common_reg;
+ } else {
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ mreg->base = base;
+ mreg->start = res->start;
+ mreg->priv = priv;
+ }
+
+ return 0;
+}
+
+static int mfis_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mfis_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+ priv->info = of_device_get_match_data(dev);
+ if (!priv->info)
+ return -ENOENT;
+
+ spin_lock_init(&priv->unprotect_lock);
+
+ ret = mfis_reg_probe(pdev, priv, &priv->common_reg, "common", true);
+ if (ret)
+ return ret;
+
+ ret = mfis_reg_probe(pdev, priv, &priv->mbox_reg, "mboxes", false);
+ if (ret)
+ return ret;
+
+ return mfis_mb_probe(priv);
+}
+
+static const struct mfis_info mfis_info_r8a779g0 = {
+ .unprotect_mask = 0x0000ffff,
+ .mb_num_channels = 12,
+ .mb_channels_are_unidir = true,
+ .mb_calc_reg = mfis_mb_r8a779g0_calc_reg,
+};
+
+static const struct mfis_info mfis_info_r8a78000 = {
+ .unprotect_mask = 0x000fffff,
+ .mb_num_channels = 64,
+ .mb_reg_comes_from_dt = true,
+ .mb_channels_are_unidir = true,
+ .mb_calc_reg = mfis_mb_r8a78000_calc_reg,
+};
+
+static const struct mfis_info mfis_info_r8a78000_scp = {
+ .unprotect_mask = 0x000fffff,
+ .mb_num_channels = 32,
+ .mb_tx_uses_eicr = true,
+ .mb_channels_are_unidir = true,
+ .mb_calc_reg = mfis_mb_r8a78000_calc_reg,
+};
+
+static const struct of_device_id mfis_mfd_of_match[] = {
+ { .compatible = "renesas,r8a779g0-mfis", .data = &mfis_info_r8a779g0, },
+ { .compatible = "renesas,r8a779h0-mfis", .data = &mfis_info_r8a779g0, },
+ { .compatible = "renesas,r8a78000-mfis", .data = &mfis_info_r8a78000, },
+ { .compatible = "renesas,r8a78000-mfis-scp", .data = &mfis_info_r8a78000_scp, },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mfis_mfd_of_match);
+
+static struct platform_driver mfis_driver = {
+ .driver = {
+ .name = "rcar-mfis",
+ .of_match_table = mfis_mfd_of_match,
+ .suppress_bind_attrs = true,
+ },
+ .probe = mfis_probe,
+};
+module_platform_driver(mfis_driver);
+
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+MODULE_AUTHOR("Wolfram Sang <wsa+renesas@sang-engineering.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Renesas R-Car MFIS driver");
diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c
index 38ff0b823bda..18acca73064c 100644
--- a/drivers/soc/renesas/renesas-soc.c
+++ b/drivers/soc/renesas/renesas-soc.c
@@ -361,6 +361,7 @@ static const struct of_device_id renesas_socs[] __initconst __maybe_unused = {
{ .compatible = "renesas,r8a77965", .data = &soc_rcar_m3_n },
{ .compatible = "renesas,r8a779m4", .data = &soc_rcar_m3_n },
{ .compatible = "renesas,r8a779m5", .data = &soc_rcar_m3_n },
+ { .compatible = "renesas,r8a779md", .data = &soc_rcar_m3_n },
#endif
#ifdef CONFIG_ARCH_R8A77970
{ .compatible = "renesas,r8a77970", .data = &soc_rcar_v3m },
@@ -442,8 +443,14 @@ static const struct renesas_id id_prr __initconst = {
.mask = 0xff00,
};
+static const struct renesas_id id_mfis __initconst = {
+ .offset = 0x44,
+ .mask = 0xff00,
+};
+
static const struct of_device_id renesas_ids[] __initconst = {
{ .compatible = "renesas,bsid", .data = &id_bsid },
+ { .compatible = "renesas,r8a78000-mfis", .data = &id_mfis },
{ .compatible = "renesas,r9a07g043-sysc", .data = &id_rzg2l },
{ .compatible = "renesas,r9a07g044-sysc", .data = &id_rzg2l },
{ .compatible = "renesas,r9a07g054-sysc", .data = &id_rzg2l },
@@ -468,7 +475,7 @@ static int __init renesas_soc_init(void)
const char *soc_id;
int ret;
- match = of_match_node(renesas_socs, of_root);
+ match = of_machine_get_match(renesas_socs);
if (!match)
return -ENODEV;
@@ -501,7 +508,7 @@ static int __init renesas_soc_init(void)
product = readl(chipid + id->offset);
iounmap(chipid);
- if (id == &id_prr) {
+ if (id == &id_prr || id == &id_mfis) {
/* R-Car M3-W ES1.1 incorrectly identifies as ES2.0 */
if ((product & 0x7fff) == 0x5210)
product ^= 0x11;
diff --git a/drivers/soc/renesas/rzn1_irqmux.c b/drivers/soc/renesas/rzn1_irqmux.c
index b50b295f83d7..c3887db7afd1 100644
--- a/drivers/soc/renesas/rzn1_irqmux.c
+++ b/drivers/soc/renesas/rzn1_irqmux.c
@@ -8,7 +8,6 @@
#include <linux/bitmap.h>
#include <linux/bitops.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
diff --git a/drivers/soc/sophgo/sg2044-topsys.c b/drivers/soc/sophgo/sg2044-topsys.c
index 179f2620b2a9..af0a374f1556 100644
--- a/drivers/soc/sophgo/sg2044-topsys.c
+++ b/drivers/soc/sophgo/sg2044-topsys.c
@@ -6,7 +6,6 @@
*/
#include <linux/mfd/core.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/resource.h>
diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
index 446b9fc1f175..2ccaeacf8c70 100644
--- a/drivers/soc/sunxi/sunxi_sram.c
+++ b/drivers/soc/sunxi/sunxi_sram.c
@@ -12,6 +12,7 @@
#include <linux/debugfs.h>
#include <linux/io.h>
+#include <linux/limits.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -29,16 +30,16 @@ struct sunxi_sram_func {
};
struct sunxi_sram_data {
- char *name;
- u8 reg;
- u8 offset;
- u8 width;
- struct sunxi_sram_func *func;
+ char *name;
+ u8 reg;
+ u8 offset;
+ u8 width;
+ const struct sunxi_sram_func *func;
};
struct sunxi_sram_desc {
struct sunxi_sram_data data;
- bool claimed;
+ u8 claim_cnt;
};
#define SUNXI_SRAM_MAP(_reg_val, _val, _func) \
@@ -54,7 +55,7 @@ struct sunxi_sram_desc {
.reg = _reg, \
.offset = _off, \
.width = _width, \
- .func = (struct sunxi_sram_func[]){ \
+ .func = (const struct sunxi_sram_func[]){ \
__VA_ARGS__, { } }, \
}
@@ -82,6 +83,12 @@ static struct sunxi_sram_desc sun50i_a64_sram_c = {
SUNXI_SRAM_MAP(0, 1, "de2")),
};
+static struct sunxi_sram_desc sun50i_h616_ve_sram = {
+ .data = SUNXI_SRAM_DATA("VE", 0x0, 0, 1,
+ SUNXI_SRAM_MAP(1, 0, "cpu"),
+ SUNXI_SRAM_MAP(0, 1, "ve")),
+};
+
static const struct of_device_id sunxi_sram_dt_ids[] = {
{
.compatible = "allwinner,sun4i-a10-sram-a3-a4",
@@ -99,6 +106,10 @@ static const struct of_device_id sunxi_sram_dt_ids[] = {
.compatible = "allwinner,sun50i-a64-sram-c",
.data = &sun50i_a64_sram_c.data,
},
+ {
+ .compatible = "allwinner,sun50i-h616-ve-sram",
+ .data = &sun50i_h616_ve_sram.data,
+ },
{}
};
@@ -111,7 +122,7 @@ static int sunxi_sram_show(struct seq_file *s, void *data)
struct device_node *sram_node, *section_node;
const struct sunxi_sram_data *sram_data;
const struct of_device_id *match;
- struct sunxi_sram_func *func;
+ const struct sunxi_sram_func *func;
const __be32 *sram_addr_p, *section_addr_p;
u32 val;
@@ -164,69 +175,97 @@ static inline struct sunxi_sram_desc *to_sram_desc(const struct sunxi_sram_data
return container_of(data, struct sunxi_sram_desc, data);
}
-static const struct sunxi_sram_data *sunxi_sram_of_parse(struct device_node *node,
- unsigned int *reg_value)
+static const struct sunxi_sram_data *sunxi_sram_get_match(struct device_node *np, u8 val,
+ unsigned int *reg_value)
{
const struct of_device_id *match;
const struct sunxi_sram_data *data;
- struct sunxi_sram_func *func;
- struct of_phandle_args args;
- u8 val;
- int ret;
-
- ret = of_parse_phandle_with_fixed_args(node, "allwinner,sram", 1, 0,
- &args);
- if (ret)
- return ERR_PTR(ret);
+ const struct sunxi_sram_func *func;
- if (!of_device_is_available(args.np)) {
- ret = -EBUSY;
- goto err;
- }
+ if (!of_device_is_available(np))
+ return ERR_PTR(-ENODEV);
- val = args.args[0];
-
- match = of_match_node(sunxi_sram_dt_ids, args.np);
- if (!match) {
- ret = -EINVAL;
- goto err;
- }
+ match = of_match_node(sunxi_sram_dt_ids, np);
+ if (!match)
+ return ERR_PTR(-ENODEV);
data = match->data;
- if (!data) {
- ret = -EINVAL;
- goto err;
- }
-
- for (func = data->func; func->func; func++) {
- if (val == func->val) {
- if (reg_value)
- *reg_value = func->reg_val;
+ if (!data)
+ return ERR_PTR(-EINVAL);
+ for (func = data->func; func->func; func++)
+ if (val == func->val)
break;
- }
- }
- if (!func->func) {
- ret = -EINVAL;
- goto err;
- }
+ if (!func->func)
+ return ERR_PTR(-EINVAL);
- of_node_put(args.np);
- return match->data;
+ if (reg_value)
+ *reg_value = func->reg_val;
-err:
- of_node_put(args.np);
- return ERR_PTR(ret);
+ return data;
}
-int sunxi_sram_claim(struct device *dev)
+#define SUNXI_SRAM_PROP "allwinner,sram"
+#define SUNXI_SRAM_CELLS 1
+
+static int sunxi_sram_claim_one(struct device_node *np, u8 arg)
{
const struct sunxi_sram_data *sram_data;
struct sunxi_sram_desc *sram_desc;
unsigned int device;
u32 val, mask;
+ sram_data = sunxi_sram_get_match(np, arg, &device);
+ if (IS_ERR(sram_data))
+ return PTR_ERR(sram_data);
+
+ sram_desc = to_sram_desc(sram_data);
+
+ spin_lock(&sram_lock);
+
+ if (sram_desc->claim_cnt) {
+ if (!WARN_ON(sram_desc->claim_cnt == U8_MAX))
+ sram_desc->claim_cnt++;
+ } else {
+ mask = GENMASK(sram_data->offset + sram_data->width - 1,
+ sram_data->offset);
+ val = readl(base + sram_data->reg);
+ val &= ~mask;
+ writel(val | ((device << sram_data->offset) & mask),
+ base + sram_data->reg);
+
+ sram_desc->claim_cnt++;
+ }
+
+ spin_unlock(&sram_lock);
+
+ return 0;
+}
+
+static void sunxi_sram_release_one(struct device_node *np, u8 arg)
+{
+ const struct sunxi_sram_data *sram_data;
+ struct sunxi_sram_desc *sram_desc;
+
+ sram_data = sunxi_sram_get_match(np, arg, NULL);
+ if (IS_ERR(sram_data))
+ return;
+
+ sram_desc = to_sram_desc(sram_data);
+
+ spin_lock(&sram_lock);
+ if (!WARN_ON(sram_desc->claim_cnt == 0))
+ sram_desc->claim_cnt--;
+ spin_unlock(&sram_lock);
+}
+
+int sunxi_sram_claim(struct device *dev)
+{
+ struct of_phandle_iterator it;
+ int err;
+ int count = 0;
+
if (IS_ERR(base))
return PTR_ERR(base);
@@ -236,50 +275,53 @@ int sunxi_sram_claim(struct device *dev)
if (!dev || !dev->of_node)
return -EINVAL;
- sram_data = sunxi_sram_of_parse(dev->of_node, &device);
- if (IS_ERR(sram_data))
- return PTR_ERR(sram_data);
+ of_for_each_phandle(&it, err, dev->of_node, SUNXI_SRAM_PROP,
+ NULL, SUNXI_SRAM_CELLS) {
+ u32 args[SUNXI_SRAM_CELLS];
- sram_desc = to_sram_desc(sram_data);
+ of_phandle_iterator_args(&it, args, SUNXI_SRAM_CELLS);
- spin_lock(&sram_lock);
+ err = sunxi_sram_claim_one(it.node, args[0]);
+ if (err)
+ goto err;
- if (sram_desc->claimed) {
- spin_unlock(&sram_lock);
- return -EBUSY;
+ count++;
}
- mask = GENMASK(sram_data->offset + sram_data->width - 1,
- sram_data->offset);
- val = readl(base + sram_data->reg);
- val &= ~mask;
- writel(val | ((device << sram_data->offset) & mask),
- base + sram_data->reg);
-
- sram_desc->claimed = true;
- spin_unlock(&sram_lock);
+ if (count == 0)
+ return -ENOENT;
return 0;
+
+err:
+ while (count--) {
+ struct of_phandle_args args;
+
+ of_parse_phandle_with_fixed_args(dev->of_node, SUNXI_SRAM_PROP,
+ SUNXI_SRAM_CELLS, count, &args);
+ sunxi_sram_release_one(args.np, args.args[0]);
+ }
+
+ return err;
}
EXPORT_SYMBOL(sunxi_sram_claim);
void sunxi_sram_release(struct device *dev)
{
- const struct sunxi_sram_data *sram_data;
- struct sunxi_sram_desc *sram_desc;
+ struct of_phandle_iterator it;
+ int err;
if (!dev || !dev->of_node)
return;
- sram_data = sunxi_sram_of_parse(dev->of_node, NULL);
- if (IS_ERR(sram_data))
- return;
+ of_for_each_phandle(&it, err, dev->of_node, SUNXI_SRAM_PROP,
+ NULL, SUNXI_SRAM_CELLS) {
+ u32 args[SUNXI_SRAM_CELLS];
- sram_desc = to_sram_desc(sram_data);
+ of_phandle_iterator_args(&it, args, SUNXI_SRAM_CELLS);
- spin_lock(&sram_lock);
- sram_desc->claimed = false;
- spin_unlock(&sram_lock);
+ sunxi_sram_release_one(it.node, args[0]);
+ }
}
EXPORT_SYMBOL(sunxi_sram_release);
diff --git a/drivers/soc/tegra/cbb/tegra194-cbb.c b/drivers/soc/tegra/cbb/tegra194-cbb.c
index ab75d50cc85c..2f69e104c838 100644
--- a/drivers/soc/tegra/cbb/tegra194-cbb.c
+++ b/drivers/soc/tegra/cbb/tegra194-cbb.c
@@ -2342,7 +2342,7 @@ static int __init tegra194_cbb_init(void)
{
return platform_driver_register(&tegra194_cbb_driver);
}
-pure_initcall(tegra194_cbb_init);
+core_initcall(tegra194_cbb_init);
static void __exit tegra194_cbb_exit(void)
{
diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c
index fb26f085f691..785072fa4e85 100644
--- a/drivers/soc/tegra/cbb/tegra234-cbb.c
+++ b/drivers/soc/tegra/cbb/tegra234-cbb.c
@@ -1774,7 +1774,7 @@ static int __init tegra234_cbb_init(void)
{
return platform_driver_register(&tegra234_cbb_driver);
}
-pure_initcall(tegra234_cbb_init);
+core_initcall(tegra234_cbb_init);
static void __exit tegra234_cbb_exit(void)
{
diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c
index 291484595dcf..78b054d43a42 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra.c
@@ -9,7 +9,6 @@
#include <linux/kobject.h>
#include <linux/init.h>
#include <linux/io.h>
-#include <linux/mod_devicetable.h>
#include <linux/nvmem-consumer.h>
#include <linux/nvmem-provider.h>
#include <linux/of.h>
@@ -182,10 +181,6 @@ static int tegra_fuse_probe(struct platform_device *pdev)
}
fuse->soc->init(fuse);
-
- err = tegra_fuse_add_lookups(fuse);
- if (err)
- return dev_err_probe(&pdev->dev, err, "failed to add FUSE lookups\n");
}
fuse->clk = devm_clk_get_optional(&pdev->dev, "fuse");
@@ -231,6 +226,10 @@ static int tegra_fuse_probe(struct platform_device *pdev)
return err;
}
+ err = tegra_fuse_add_lookups(fuse);
+ if (err)
+ return dev_err_probe(&pdev->dev, err, "failed to add FUSE lookups\n");
+
fuse->rst = devm_reset_control_get_optional(&pdev->dev, "fuse");
if (IS_ERR(fuse->rst))
return dev_err_probe(&pdev->dev, PTR_ERR(fuse->rst), "failed to get FUSE reset\n");
@@ -473,7 +472,7 @@ static int __init tegra_init_fuse(void)
const struct of_device_id *match;
struct device_node *np;
struct resource regs;
- int err;
+ int err = 0;
tegra_init_apbmisc();
@@ -566,10 +565,6 @@ static int __init tegra_init_fuse(void)
tegra_fuse_print_sku_info(&tegra_sku_info);
- err = tegra_fuse_add_lookups(fuse);
- if (err)
- pr_err("failed to add FUSE lookups\n");
-
return err;
}
early_initcall(tegra_init_fuse);
diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c
index 0ce94fdc536f..6af69ccaa295 100644
--- a/drivers/soc/tegra/fuse/tegra-apbmisc.c
+++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c
@@ -4,10 +4,10 @@
*/
#include <linux/acpi.h>
+#include <linux/arm-smccc.h>
#include <linux/export.h>
#include <linux/io.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -27,6 +27,11 @@
#define PMC_STRAPPING_OPT_A_RAM_CODE_MASK_SHORT \
(0x3 << PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT)
+#define TEGRA_SMCCC_PLATFORM(x) (((x) >> 8) & 0xff)
+#define TEGRA_SMCCC_CHIP_ID(x) (((x) >> 4) & 0xff)
+#define TEGRA_SMCCC_MAJOR_REV(x) ((x) & 0xf)
+#define TEGRA_SMCCC_MINOR_REV(x) ((x) & 0xf)
+
static void __iomem *apbmisc_base;
static bool long_ram_code;
static u32 strapping;
@@ -34,28 +39,56 @@ static u32 chipid;
u32 tegra_read_chipid(void)
{
- WARN(!chipid, "Tegra APB MISC not yet available\n");
+ WARN(!apbmisc_base, "Tegra APB MISC not yet available\n");
+
+ if (!chipid)
+ chipid = readl_relaxed(apbmisc_base + 4);
return chipid;
}
u8 tegra_get_chip_id(void)
{
+#if IS_ENABLED(CONFIG_HAVE_ARM_SMCCC_DISCOVERY)
+ s32 soc_id = arm_smccc_get_soc_id_version();
+
+ if (soc_id >= 0)
+ return TEGRA_SMCCC_CHIP_ID(soc_id);
+#endif
return (tegra_read_chipid() >> 8) & 0xff;
}
u8 tegra_get_major_rev(void)
{
+#if IS_ENABLED(CONFIG_HAVE_ARM_SMCCC_DISCOVERY)
+ s32 soc_id = arm_smccc_get_soc_id_version();
+
+ if (soc_id >= 0)
+ return TEGRA_SMCCC_MAJOR_REV(soc_id);
+#endif
return (tegra_read_chipid() >> 4) & 0xf;
}
u8 tegra_get_minor_rev(void)
{
+#if IS_ENABLED(CONFIG_HAVE_ARM_SMCCC_DISCOVERY)
+ s32 revision = arm_smccc_get_soc_id_revision();
+
+ if (revision >= 0)
+ return TEGRA_SMCCC_MINOR_REV(revision);
+#endif
return (tegra_read_chipid() >> 16) & 0xf;
+
}
u8 tegra_get_platform(void)
{
+#if IS_ENABLED(CONFIG_HAVE_ARM_SMCCC_DISCOVERY)
+ s32 revision = arm_smccc_get_soc_id_revision();
+
+ if (revision >= 0)
+ return TEGRA_SMCCC_PLATFORM(revision);
+#endif
return (tegra_read_chipid() >> 20) & 0xf;
}
@@ -83,7 +116,7 @@ bool tegra_is_silicon(void)
u32 tegra_read_straps(void)
{
- WARN(!chipid, "Tegra ABP MISC not yet available\n");
+ WARN(!apbmisc_base, "Tegra ABP MISC not yet available\n");
return strapping;
}
@@ -170,9 +203,7 @@ static void tegra_init_apbmisc_resources(struct resource *apbmisc,
void __iomem *strapping_base;
apbmisc_base = ioremap(apbmisc->start, resource_size(apbmisc));
- if (apbmisc_base)
- chipid = readl_relaxed(apbmisc_base + 4);
- else
+ if (!apbmisc_base)
pr_err("failed to map APBMISC registers\n");
strapping_base = ioremap(straps->start, resource_size(straps));
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 2ee6539d796a..f419a5395545 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -390,8 +390,7 @@ struct tegra_pmc_soc {
const struct tegra_pmc_regs *regs;
void (*init)(struct tegra_pmc *pmc);
void (*setup_irq_polarity)(struct tegra_pmc *pmc,
- struct device_node *np,
- bool invert);
+ struct device_node *np);
void (*set_wake_filters)(struct tegra_pmc *pmc);
int (*irq_set_wake)(struct irq_data *data, unsigned int on);
int (*irq_set_type)(struct irq_data *data, unsigned int type);
@@ -444,6 +443,7 @@ struct tegra_pmc_soc {
* @cpu_pwr_good_en: CPU power good signal is enabled
* @lp0_vec_phys: physical base address of the LP0 warm boot code
* @lp0_vec_size: size of the LP0 warm boot code
+ * @invert_irq: polarity of the PMU IRQ is inverted
* @powergates_available: Bitmap of available power gates
* @powergates_lock: mutex for power gate register access
* @pctl_dev: pin controller exposed by the PMC
@@ -486,6 +486,8 @@ struct tegra_pmc {
bool cpu_pwr_good_en;
u32 lp0_vec_phys;
u32 lp0_vec_size;
+ bool invert_irq;
+
DECLARE_BITMAP(powergates_available, TEGRA_POWERGATE_MAX);
struct mutex powergates_lock;
@@ -512,10 +514,12 @@ struct tegra_pmc {
u32 *wake_status;
};
-static struct tegra_pmc *pmc = &(struct tegra_pmc) {
+#if defined(CONFIG_ARM)
+static struct tegra_pmc *early_pmc = &(struct tegra_pmc) {
.base = NULL,
.suspend_mode = TEGRA_SUSPEND_NOT_READY,
};
+#endif
static inline struct tegra_powergate *
to_powergate(struct generic_pm_domain *domain)
@@ -1064,16 +1068,6 @@ int tegra_pmc_powergate_power_on(struct tegra_pmc *pmc, unsigned int id)
EXPORT_SYMBOL(tegra_pmc_powergate_power_on);
/**
- * tegra_powergate_power_on() - power on partition
- * @id: partition ID
- */
-int tegra_powergate_power_on(unsigned int id)
-{
- return tegra_pmc_powergate_power_on(pmc, id);
-}
-EXPORT_SYMBOL(tegra_powergate_power_on);
-
-/**
* tegra_pmc_powergate_power_off() - power off partition
* @pmc: power management controller
* @id: partition ID
@@ -1088,16 +1082,6 @@ int tegra_pmc_powergate_power_off(struct tegra_pmc *pmc, unsigned int id)
EXPORT_SYMBOL(tegra_pmc_powergate_power_off);
/**
- * tegra_powergate_power_off() - power off partition
- * @id: partition ID
- */
-int tegra_powergate_power_off(unsigned int id)
-{
- return tegra_pmc_powergate_power_off(pmc, id);
-}
-EXPORT_SYMBOL(tegra_powergate_power_off);
-
-/**
* tegra_powergate_is_powered() - check if partition is powered
* @pmc: power management controller
* @id: partition ID
@@ -1125,16 +1109,6 @@ int tegra_pmc_powergate_remove_clamping(struct tegra_pmc *pmc, unsigned int id)
EXPORT_SYMBOL(tegra_pmc_powergate_remove_clamping);
/**
- * tegra_powergate_remove_clamping() - remove power clamps for partition
- * @id: partition ID
- */
-int tegra_powergate_remove_clamping(unsigned int id)
-{
- return tegra_pmc_powergate_remove_clamping(pmc, id);
-}
-EXPORT_SYMBOL(tegra_powergate_remove_clamping);
-
-/**
* tegra_pmc_powergate_sequence_power_up() - power up partition
* @pmc: power management controller
* @id: partition ID
@@ -1181,83 +1155,6 @@ int tegra_pmc_powergate_sequence_power_up(struct tegra_pmc *pmc,
}
EXPORT_SYMBOL(tegra_pmc_powergate_sequence_power_up);
-/**
- * tegra_powergate_sequence_power_up() - power up partition
- * @id: partition ID
- * @clk: clock for partition
- * @rst: reset for partition
- *
- * Must be called with clk disabled, and returns with clk enabled.
- */
-int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
- struct reset_control *rst)
-{
- return tegra_pmc_powergate_sequence_power_up(pmc, id, clk, rst);
-}
-EXPORT_SYMBOL(tegra_powergate_sequence_power_up);
-
-/**
- * tegra_get_cpu_powergate_id() - convert from CPU ID to partition ID
- * @pmc: power management controller
- * @cpuid: CPU partition ID
- *
- * Returns the partition ID corresponding to the CPU partition ID or a
- * negative error code on failure.
- */
-static int tegra_get_cpu_powergate_id(struct tegra_pmc *pmc,
- unsigned int cpuid)
-{
- if (pmc->soc && cpuid < pmc->soc->num_cpu_powergates)
- return pmc->soc->cpu_powergates[cpuid];
-
- return -EINVAL;
-}
-
-/**
- * tegra_pmc_cpu_is_powered() - check if CPU partition is powered
- * @cpuid: CPU partition ID
- */
-bool tegra_pmc_cpu_is_powered(unsigned int cpuid)
-{
- int id;
-
- id = tegra_get_cpu_powergate_id(pmc, cpuid);
- if (id < 0)
- return false;
-
- return tegra_powergate_is_powered(pmc, id);
-}
-
-/**
- * tegra_pmc_cpu_power_on() - power on CPU partition
- * @cpuid: CPU partition ID
- */
-int tegra_pmc_cpu_power_on(unsigned int cpuid)
-{
- int id;
-
- id = tegra_get_cpu_powergate_id(pmc, cpuid);
- if (id < 0)
- return id;
-
- return tegra_powergate_set(pmc, id, true);
-}
-
-/**
- * tegra_pmc_cpu_remove_clamping() - remove power clamps for CPU partition
- * @cpuid: CPU partition ID
- */
-int tegra_pmc_cpu_remove_clamping(unsigned int cpuid)
-{
- int id;
-
- id = tegra_get_cpu_powergate_id(pmc, cpuid);
- if (id < 0)
- return id;
-
- return tegra_powergate_remove_clamping(id);
-}
-
static void tegra_pmc_program_reboot_reason(struct tegra_pmc *pmc,
const char *cmd)
{
@@ -1310,7 +1207,7 @@ static int tegra_pmc_restart_handler(struct sys_off_data *data)
return NOTIFY_DONE;
}
-static int tegra_pmc_power_off_handler(struct sys_off_data *data)
+static int tegra_pmc_grouper_power_off_handler(struct sys_off_data *data)
{
struct tegra_pmc *pmc = data->cb_data;
@@ -1318,8 +1215,7 @@ static int tegra_pmc_power_off_handler(struct sys_off_data *data)
* Reboot Nexus 7 into special bootloader mode if USB cable is
* connected in order to display battery status and power off.
*/
- if (of_machine_is_compatible("asus,grouper") &&
- power_supply_is_system_supplied()) {
+ if (power_supply_is_system_supplied()) {
const u32 go_to_charger_mode = 0xa5a55a5a;
tegra_pmc_writel(pmc, go_to_charger_mode, PMC_SCRATCH37);
@@ -1531,11 +1427,6 @@ free_mem:
return err;
}
-bool tegra_pmc_core_domain_state_synced(void)
-{
- return pmc->core_domain_state_synced;
-}
-
static int
tegra_pmc_core_pd_set_performance_state(struct generic_pm_domain *genpd,
unsigned int level)
@@ -1824,18 +1715,6 @@ unlock:
EXPORT_SYMBOL(tegra_pmc_io_pad_power_enable);
/**
- * tegra_io_pad_power_enable() - enable power to I/O pad
- * @id: Tegra I/O pad ID for which to enable power
- *
- * Returns: 0 on success or a negative error code on failure.
- */
-int tegra_io_pad_power_enable(enum tegra_io_pad id)
-{
- return tegra_pmc_io_pad_power_enable(pmc, id);
-}
-EXPORT_SYMBOL(tegra_io_pad_power_enable);
-
-/**
* tegra_pmc_io_pad_power_disable() - disable power to I/O pad
* @pmc: power management controller
* @id: Tegra I/O pad ID for which to disable power
@@ -1879,18 +1758,6 @@ unlock:
}
EXPORT_SYMBOL(tegra_pmc_io_pad_power_disable);
-/**
- * tegra_io_pad_power_disable() - disable power to I/O pad
- * @id: Tegra I/O pad ID for which to disable power
- *
- * Returns: 0 on success or a negative error code on failure.
- */
-int tegra_io_pad_power_disable(enum tegra_io_pad id)
-{
- return tegra_pmc_io_pad_power_disable(pmc, id);
-}
-EXPORT_SYMBOL(tegra_io_pad_power_disable);
-
static int tegra_io_pad_is_powered(struct tegra_pmc *pmc, enum tegra_io_pad id)
{
const struct tegra_io_pad_soc *pad;
@@ -1973,57 +1840,6 @@ static int tegra_io_pad_get_voltage(struct tegra_pmc *pmc, enum tegra_io_pad id)
return TEGRA_IO_PAD_VOLTAGE_3V3;
}
-#ifdef CONFIG_PM_SLEEP
-enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void)
-{
- return pmc->suspend_mode;
-}
-
-void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode)
-{
- if (mode < TEGRA_SUSPEND_NONE || mode >= TEGRA_MAX_SUSPEND_MODE)
- return;
-
- pmc->suspend_mode = mode;
-}
-
-void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode)
-{
- unsigned long long rate = 0;
- u64 ticks;
- u32 value;
-
- switch (mode) {
- case TEGRA_SUSPEND_LP1:
- rate = 32768;
- break;
-
- case TEGRA_SUSPEND_LP2:
- rate = pmc->rate;
- break;
-
- default:
- break;
- }
-
- if (WARN_ON_ONCE(rate == 0))
- rate = 100000000;
-
- ticks = pmc->cpu_good_time * rate + USEC_PER_SEC - 1;
- do_div(ticks, USEC_PER_SEC);
- tegra_pmc_writel(pmc, ticks, PMC_CPUPWRGOOD_TIMER);
-
- ticks = pmc->cpu_off_time * rate + USEC_PER_SEC - 1;
- do_div(ticks, USEC_PER_SEC);
- tegra_pmc_writel(pmc, ticks, PMC_CPUPWROFF_TIMER);
-
- value = tegra_pmc_readl(pmc, PMC_CNTRL);
- value &= ~PMC_CNTRL_SIDE_EFFECT_LP0;
- value |= PMC_CNTRL_CPU_PWRREQ_OE;
- tegra_pmc_writel(pmc, value, PMC_CNTRL);
-}
-#endif
-
static int tegra_pmc_parse_dt(struct tegra_pmc *pmc, struct device_node *np)
{
u32 value, values[2];
@@ -2094,6 +1910,8 @@ static int tegra_pmc_parse_dt(struct tegra_pmc *pmc, struct device_node *np)
pmc->lp0_vec_phys = values[0];
pmc->lp0_vec_size = values[1];
+ pmc->invert_irq = of_property_read_bool(np, "nvidia,invert-interrupt");
+
return 0;
}
@@ -3110,6 +2928,51 @@ static int tegra_pmc_regmap_init(struct tegra_pmc *pmc)
return 0;
}
+static bool tegra_pmc_detect_tz_only(struct tegra_pmc *pmc)
+{
+ u32 value, saved;
+
+ saved = readl(pmc->base + pmc->soc->regs->scratch0);
+ value = saved ^ 0xffffffff;
+
+ if (value == 0xffffffff)
+ value = 0xdeadbeef;
+
+ /* write pattern and read it back */
+ writel(value, pmc->base + pmc->soc->regs->scratch0);
+ value = readl(pmc->base + pmc->soc->regs->scratch0);
+
+ /* if we read all-zeroes, access is restricted to TZ only */
+ if (value == 0) {
+ pr_info("access to PMC is restricted to TZ\n");
+ return true;
+ }
+
+ /* restore original value */
+ writel(saved, pmc->base + pmc->soc->regs->scratch0);
+
+ return false;
+}
+
+static void tegra_pmc_init_common(struct tegra_pmc *pmc, struct device_node *np)
+{
+ unsigned int i;
+
+ if (pmc->soc->maybe_tz_only)
+ pmc->tz_only = tegra_pmc_detect_tz_only(pmc);
+
+ /* Create a bitmap of the available and valid partitions */
+ for (i = 0; i < pmc->soc->num_powergates; i++)
+ if (pmc->soc->powergates[i])
+ set_bit(i, pmc->powergates_available);
+
+ /*
+ * Invert the interrupt polarity if a PMC device tree node exists and
+ * contains the nvidia,invert-interrupt property.
+ */
+ pmc->soc->setup_irq_polarity(pmc, np);
+}
+
static void tegra_pmc_reset_suspend_mode(void *data)
{
struct tegra_pmc *pmc = data;
@@ -3119,21 +2982,31 @@ static void tegra_pmc_reset_suspend_mode(void *data)
static int tegra_pmc_probe(struct platform_device *pdev)
{
- void __iomem *base;
+ struct tegra_pmc *pmc;
struct resource *res;
int err;
+#if defined(CONFIG_ARM)
/*
* Early initialisation should have configured an initial
* register mapping and setup the soc data pointer. If these
* are not valid then something went badly wrong!
*/
- if (WARN_ON(!pmc->base || !pmc->soc))
+ if (WARN_ON(!early_pmc->base || !early_pmc->soc))
return -ENODEV;
+#endif
+
+ pmc = devm_kzalloc(&pdev->dev, sizeof(*pmc), GFP_KERNEL);
+ if (!pmc)
+ return -ENOMEM;
+
+ pmc->soc = device_get_match_data(&pdev->dev);
+ mutex_init(&pmc->powergates_lock);
+ pmc->dev = &pdev->dev;
err = tegra_pmc_parse_dt(pmc, pdev->dev.of_node);
if (err < 0)
- return err;
+ return dev_err_probe(&pdev->dev, err, "failed to parse DT\n");
err = devm_add_action_or_reset(&pdev->dev, tegra_pmc_reset_suspend_mode,
pmc);
@@ -3141,14 +3014,14 @@ static int tegra_pmc_probe(struct platform_device *pdev)
return err;
/* take over the memory region from the early initialization */
- base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(base))
- return PTR_ERR(base);
+ pmc->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(pmc->base))
+ return PTR_ERR(pmc->base);
if (pmc->soc->has_single_mmio_aperture) {
- pmc->wake = base;
- pmc->aotag = base;
- pmc->scratch = base;
+ pmc->wake = pmc->base;
+ pmc->aotag = pmc->base;
+ pmc->scratch = pmc->base;
} else {
pmc->wake = devm_platform_ioremap_resource_byname(pdev, "wake");
if (IS_ERR(pmc->wake))
@@ -3167,7 +3040,7 @@ static int tegra_pmc_probe(struct platform_device *pdev)
/* "scratch" is an optional aperture */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "scratch");
+ "scratch");
if (res) {
pmc->scratch = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(pmc->scratch))
@@ -3182,6 +3055,8 @@ static int tegra_pmc_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, PTR_ERR(pmc->clk),
"failed to get pclk\n");
+ tegra_pmc_init_common(pmc, pdev->dev.of_node);
+
/*
* PMC should be last resort for restarting since it soft-resets
* CPU without resetting everything else.
@@ -3211,18 +3086,20 @@ static int tegra_pmc_probe(struct platform_device *pdev)
}
/*
- * PMC should be primary power-off method if it soft-resets CPU,
- * asking bootloader to shutdown hardware.
+ * PMC should be primary power-off method on Grouper if it soft-resets
+ * CPU, asking bootloader to shutdown hardware.
*/
- err = devm_register_sys_off_handler(&pdev->dev,
- SYS_OFF_MODE_POWER_OFF,
- SYS_OFF_PRIO_FIRMWARE,
- tegra_pmc_power_off_handler,
- pmc);
- if (err) {
- dev_err(&pdev->dev, "failed to register sys-off handler: %d\n",
- err);
- return err;
+ if (of_machine_is_compatible("asus,grouper")) {
+ err = devm_register_sys_off_handler(&pdev->dev,
+ SYS_OFF_MODE_POWER_OFF,
+ SYS_OFF_PRIO_FIRMWARE,
+ tegra_pmc_grouper_power_off_handler,
+ pmc);
+ if (err) {
+ dev_err(&pdev->dev, "failed to register sys-off handler: %d\n",
+ err);
+ return err;
+ }
}
/*
@@ -3243,8 +3120,6 @@ static int tegra_pmc_probe(struct platform_device *pdev)
pmc->rate = clk_get_rate(pmc->clk);
}
- pmc->dev = &pdev->dev;
-
err = tegra_pmc_init(pmc);
if (err < 0) {
dev_err(&pdev->dev, "failed to initialize PMC: %d\n", err);
@@ -3271,10 +3146,12 @@ static int tegra_pmc_probe(struct platform_device *pdev)
if (err < 0)
goto cleanup_powergates;
- mutex_lock(&pmc->powergates_lock);
- iounmap(pmc->base);
- pmc->base = base;
- mutex_unlock(&pmc->powergates_lock);
+#if defined(CONFIG_ARM)
+ mutex_lock(&early_pmc->powergates_lock);
+ iounmap(early_pmc->base);
+ early_pmc->base = pmc->base;
+ mutex_unlock(&early_pmc->powergates_lock);
+#endif
tegra_pmc_clock_register(pmc, pdev->dev.of_node);
platform_set_drvdata(pdev, pmc);
@@ -3284,7 +3161,8 @@ static int tegra_pmc_probe(struct platform_device *pdev)
if (pmc->soc->set_wake_filters)
pmc->soc->set_wake_filters(pmc);
- debugfs_create_file("powergate", 0444, NULL, pmc, &powergate_fops);
+ if (pmc->soc->num_powergates)
+ debugfs_create_file("powergate", 0444, NULL, pmc, &powergate_fops);
return 0;
@@ -3523,14 +3401,13 @@ static void tegra20_pmc_init(struct tegra_pmc *pmc)
}
static void tegra20_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
- struct device_node *np,
- bool invert)
+ struct device_node *np)
{
u32 value;
value = tegra_pmc_readl(pmc, PMC_CNTRL);
- if (invert)
+ if (pmc->invert_irq)
value |= PMC_CNTRL_INTR_POLARITY;
else
value &= ~PMC_CNTRL_INTR_POLARITY;
@@ -4136,8 +4013,7 @@ static void tegra186_pmc_init(struct tegra_pmc *pmc)
}
static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
- struct device_node *np,
- bool invert)
+ struct device_node *np)
{
struct resource regs;
void __iomem *wake;
@@ -4160,7 +4036,7 @@ static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
value = readl(wake + pmc->soc->regs->aowake_ctrl);
- if (invert)
+ if (pmc->invert_irq)
value |= WAKE_AOWAKE_CTRL_INTR_POLARITY;
else
value &= ~WAKE_AOWAKE_CTRL_INTR_POLARITY;
@@ -4595,6 +4471,164 @@ static const struct tegra_pmc_soc tegra234_pmc_soc = {
.has_single_mmio_aperture = false,
};
+static const struct tegra_io_pad_soc tegra238_io_pads[] = {
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP0, 0, 0xe028, 0xe02c, "hdmi-dp0"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_UFS, 0, 0xe06c, 0xe070, "ufs"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_EDP, 2, 0xe040, 0xe044, "edp"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1_HV, 0, 0xe058, 0xe05c, "sdmmc1-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3_HV, UINT_MAX, UINT_MAX, UINT_MAX, "sdmmc3-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, UINT_MAX, UINT_MAX, UINT_MAX, "audio-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AO_HV, UINT_MAX, UINT_MAX, UINT_MAX, "ao-hv"),
+};
+
+static const struct tegra_io_pad_vctrl tegra238_io_pad_vctrls[] = {
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_SDMMC1_HV, PMC_IMPL_E_33V_PWR, 4),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_SDMMC3_HV, PMC_IMPL_E_33V_PWR, 6),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_AUDIO_HV, PMC_IMPL_E_33V_PWR, 1),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_AO_HV, PMC_IMPL_E_33V_PWR, 0),
+};
+
+static const struct pinctrl_pin_desc tegra238_pin_descs[] = {
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP0, "hdmi-dp0"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UFS, "ufs"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_EDP, "edp"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC1_HV, "sdmmc1-hv"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC3_HV, "sdmmc3-hv"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO_HV, "audio-hv"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AO_HV, "ao-hv"),
+};
+
+static const struct tegra_pmc_regs tegra238_pmc_regs = {
+ .scratch0 = 0x2000,
+ .rst_status = 0x70,
+ .rst_source_shift = 0x2,
+ .rst_source_mask = 0xfc,
+ .rst_level_shift = 0x0,
+ .rst_level_mask = 0x3,
+ .aowake_mask_w = 0x180,
+ .aowake_status_w = 0x30c,
+ .aowake_status_r = 0x48c,
+ .aowake_tier2_routing = 0x4cc,
+ .aowake_sw_status_w = 0x49c,
+ .aowake_sw_status = 0x4a0,
+ .aowake_latch_sw = 0x498,
+ .aowake_ctrl = 0x4f4,
+};
+
+static const char * const tegra238_reset_sources[] = {
+ "SYS_RESET_N", /* 0 */
+ "AOWDT",
+ NULL,
+ "BPMPWDT",
+ NULL,
+ "SPEWDT", /* 5 */
+ NULL,
+ NULL,
+ "SENSOR",
+ NULL,
+ NULL, /* 10 */
+ "MAINSWRST",
+ "SC7",
+ NULL,
+ NULL,
+ NULL, /* 15 */
+ NULL,
+ NULL,
+ "RTC_XTAL_CSDC",
+ "BPMPBOOT",
+ "FUSECRC", /* 20 */
+ NULL,
+ "PSCWDT",
+ "PSC_SW",
+ "CSITE_SW",
+ NULL, /* 25 */
+ NULL,
+ "VREFRO_POWERBAD",
+ NULL,
+ NULL,
+ NULL, /* 30 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 35 */
+ NULL,
+ NULL,
+ "TOP0WDT",
+ "TOP1WDT",
+ "TOP2WDT", /* 40 */
+ "APE_C0WDT",
+ "APE_C1WDT",
+ "APE_C2WDT",
+ "APE_C3WDT",
+ "SCPM_SOC_XTAL", /* 45 */
+ "SCPM_RTC_XTAL",
+ "SCPM_BPMP_CORE_CLK",
+ "SCPM_PSC_SE_CLK",
+ "FMON_32K",
+ "FMON_OSC", /* 50 */
+ "VMON_SOC",
+ "VMON_CPU0",
+ NULL,
+ "POD_CPU",
+ "POD_GPU", /* 55 */
+ "POD_RTC",
+ NULL,
+ "POD_IO",
+ "POD_PLUS_SOC",
+ "POD_PLUS_IO_VMON", /* 60 */
+ "POD_PLUS_IO_PSCPLL",
+ "VMON_PLUS_0",
+ "VMON_PLUS_1", /* 63 */
+};
+
+static const struct tegra_wake_event tegra238_wake_events[] = {
+ TEGRA_WAKE_IRQ("rtc", 73, 10),
+ TEGRA_WAKE_IRQ("pmu", 24, 209),
+ TEGRA_WAKE_IRQ("usb3-port-0", 76, 167),
+ TEGRA_WAKE_IRQ("usb3-port-1", 77, 167),
+ TEGRA_WAKE_IRQ("usb3-port-2", 78, 167),
+ TEGRA_WAKE_IRQ("usb2-port-0", 79, 167),
+ TEGRA_WAKE_IRQ("usb2-port-1", 80, 167),
+ TEGRA_WAKE_IRQ("usb2-port-2", 81, 167),
+};
+
+static const struct tegra_pmc_soc tegra238_pmc_soc = {
+ .num_powergates = 0,
+ .powergates = NULL,
+ .num_cpu_powergates = 0,
+ .cpu_powergates = NULL,
+ .has_tsense_reset = false,
+ .has_gpu_clamps = false,
+ .needs_mbist_war = false,
+ .has_io_pad_wren = false,
+ .maybe_tz_only = false,
+ .num_io_pads = ARRAY_SIZE(tegra238_io_pads),
+ .io_pads = tegra238_io_pads,
+ .num_io_pad_vctrls = ARRAY_SIZE(tegra238_io_pad_vctrls),
+ .io_pad_vctrls = tegra238_io_pad_vctrls,
+ .num_pin_descs = ARRAY_SIZE(tegra238_pin_descs),
+ .pin_descs = tegra238_pin_descs,
+ .regs = &tegra238_pmc_regs,
+ .init = tegra186_pmc_init,
+ .setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
+ .set_wake_filters = tegra186_pmc_set_wake_filters,
+ .irq_set_wake = tegra186_pmc_irq_set_wake,
+ .irq_set_type = tegra186_pmc_irq_set_type,
+ .reset_sources = tegra238_reset_sources,
+ .num_reset_sources = ARRAY_SIZE(tegra238_reset_sources),
+ .reset_levels = tegra186_reset_levels,
+ .num_reset_levels = ARRAY_SIZE(tegra186_reset_levels),
+ .num_wake_events = ARRAY_SIZE(tegra238_wake_events),
+ .wake_events = tegra238_wake_events,
+ .max_wake_events = 96,
+ .max_wake_vectors = 3,
+ .pmc_clks_data = NULL,
+ .num_pmc_clks = 0,
+ .has_blink_output = false,
+ .has_single_mmio_aperture = false,
+};
+
#define TEGRA264_IO_PAD_VCTRL(_id, _offset, _ena_3v3, _ena_1v8) \
((struct tegra_io_pad_vctrl) { \
.id = (_id), \
@@ -4785,6 +4819,7 @@ static const struct tegra_pmc_soc tegra264_pmc_soc = {
static const struct of_device_id tegra_pmc_match[] = {
{ .compatible = "nvidia,tegra264-pmc", .data = &tegra264_pmc_soc },
+ { .compatible = "nvidia,tegra238-pmc", .data = &tegra238_pmc_soc },
{ .compatible = "nvidia,tegra234-pmc", .data = &tegra234_pmc_soc },
{ .compatible = "nvidia,tegra194-pmc", .data = &tegra194_pmc_soc },
{ .compatible = "nvidia,tegra186-pmc", .data = &tegra186_pmc_soc },
@@ -4799,6 +4834,7 @@ static const struct of_device_id tegra_pmc_match[] = {
static void tegra_pmc_sync_state(struct device *dev)
{
+ struct tegra_pmc *pmc = dev_get_drvdata(dev);
struct device_node *np, *child;
int err;
@@ -4856,31 +4892,124 @@ static struct platform_driver tegra_pmc_driver = {
};
builtin_platform_driver(tegra_pmc_driver);
-static bool __init tegra_pmc_detect_tz_only(struct tegra_pmc *pmc)
+#if defined(CONFIG_ARM)
+/**
+ * tegra_get_cpu_powergate_id() - convert from CPU ID to partition ID
+ * @pmc: power management controller
+ * @cpuid: CPU partition ID
+ *
+ * Returns the partition ID corresponding to the CPU partition ID or a
+ * negative error code on failure.
+ */
+static int tegra_get_cpu_powergate_id(struct tegra_pmc *pmc,
+ unsigned int cpuid)
+{
+ if (pmc->soc && cpuid < pmc->soc->num_cpu_powergates)
+ return pmc->soc->cpu_powergates[cpuid];
+
+ return -EINVAL;
+}
+
+/**
+ * tegra_pmc_cpu_is_powered() - check if CPU partition is powered
+ * @cpuid: CPU partition ID
+ */
+bool tegra_pmc_cpu_is_powered(unsigned int cpuid)
{
- u32 value, saved;
+ int id;
- saved = readl(pmc->base + pmc->soc->regs->scratch0);
- value = saved ^ 0xffffffff;
+ id = tegra_get_cpu_powergate_id(early_pmc, cpuid);
+ if (id < 0)
+ return false;
- if (value == 0xffffffff)
- value = 0xdeadbeef;
+ return tegra_powergate_is_powered(early_pmc, id);
+}
- /* write pattern and read it back */
- writel(value, pmc->base + pmc->soc->regs->scratch0);
- value = readl(pmc->base + pmc->soc->regs->scratch0);
+/**
+ * tegra_pmc_cpu_power_on() - power on CPU partition
+ * @cpuid: CPU partition ID
+ */
+int tegra_pmc_cpu_power_on(unsigned int cpuid)
+{
+ int id;
- /* if we read all-zeroes, access is restricted to TZ only */
- if (value == 0) {
- pr_info("access to PMC is restricted to TZ\n");
- return true;
+ id = tegra_get_cpu_powergate_id(early_pmc, cpuid);
+ if (id < 0)
+ return id;
+
+ return tegra_powergate_set(early_pmc, id, true);
+}
+
+/**
+ * tegra_pmc_cpu_remove_clamping() - remove power clamps for CPU partition
+ * @cpuid: CPU partition ID
+ */
+int tegra_pmc_cpu_remove_clamping(unsigned int cpuid)
+{
+ int id;
+
+ id = tegra_get_cpu_powergate_id(early_pmc, cpuid);
+ if (id < 0)
+ return id;
+
+ return tegra_pmc_powergate_remove_clamping(early_pmc, id);
+}
+
+bool tegra_pmc_core_domain_state_synced(void)
+{
+ return early_pmc->core_domain_state_synced;
+}
+
+#ifdef CONFIG_PM_SLEEP
+enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void)
+{
+ return early_pmc->suspend_mode;
+}
+
+void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode)
+{
+ if (mode < TEGRA_SUSPEND_NONE || mode >= TEGRA_MAX_SUSPEND_MODE)
+ return;
+
+ early_pmc->suspend_mode = mode;
+}
+
+void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode)
+{
+ unsigned long long rate = 0;
+ u64 ticks;
+ u32 value;
+
+ switch (mode) {
+ case TEGRA_SUSPEND_LP1:
+ rate = 32768;
+ break;
+
+ case TEGRA_SUSPEND_LP2:
+ rate = early_pmc->rate;
+ break;
+
+ default:
+ break;
}
- /* restore original value */
- writel(saved, pmc->base + pmc->soc->regs->scratch0);
+ if (WARN_ON_ONCE(rate == 0))
+ rate = 100000000;
- return false;
+ ticks = early_pmc->cpu_good_time * rate + USEC_PER_SEC - 1;
+ do_div(ticks, USEC_PER_SEC);
+ tegra_pmc_writel(early_pmc, ticks, PMC_CPUPWRGOOD_TIMER);
+
+ ticks = early_pmc->cpu_off_time * rate + USEC_PER_SEC - 1;
+ do_div(ticks, USEC_PER_SEC);
+ tegra_pmc_writel(early_pmc, ticks, PMC_CPUPWROFF_TIMER);
+
+ value = tegra_pmc_readl(early_pmc, PMC_CNTRL);
+ value &= ~PMC_CNTRL_SIDE_EFFECT_LP0;
+ value |= PMC_CNTRL_CPU_PWRREQ_OE;
+ tegra_pmc_writel(early_pmc, value, PMC_CNTRL);
}
+#endif /* CONFIG_PM_SLEEP */
/*
* Early initialization to allow access to registers in the very early boot
@@ -4891,10 +5020,9 @@ static int __init tegra_pmc_early_init(void)
const struct of_device_id *match;
struct device_node *np;
struct resource regs;
- unsigned int i;
- bool invert;
+ int err;
- mutex_init(&pmc->powergates_lock);
+ mutex_init(&early_pmc->powergates_lock);
np = of_find_matching_node_and_match(NULL, tegra_pmc_match, &match);
if (!np) {
@@ -4935,31 +5063,24 @@ static int __init tegra_pmc_early_init(void)
}
}
- pmc->base = ioremap(regs.start, resource_size(&regs));
- if (!pmc->base) {
+ early_pmc->base = ioremap(regs.start, resource_size(&regs));
+ if (!early_pmc->base) {
pr_err("failed to map PMC registers\n");
of_node_put(np);
return -ENXIO;
}
if (of_device_is_available(np)) {
- pmc->soc = match->data;
-
- if (pmc->soc->maybe_tz_only)
- pmc->tz_only = tegra_pmc_detect_tz_only(pmc);
+ early_pmc->soc = match->data;
- /* Create a bitmap of the available and valid partitions */
- for (i = 0; i < pmc->soc->num_powergates; i++)
- if (pmc->soc->powergates[i])
- set_bit(i, pmc->powergates_available);
-
- /*
- * Invert the interrupt polarity if a PMC device tree node
- * exists and contains the nvidia,invert-interrupt property.
- */
- invert = of_property_read_bool(np, "nvidia,invert-interrupt");
+ err = tegra_pmc_parse_dt(early_pmc, np);
+ if (err < 0) {
+ pr_err("failed to parse DT: %d\n", err);
+ of_node_put(np);
+ return err;
+ }
- pmc->soc->setup_irq_polarity(pmc, np, invert);
+ tegra_pmc_init_common(early_pmc, np);
of_node_put(np);
}
@@ -4967,3 +5088,4 @@ static int __init tegra_pmc_early_init(void)
return 0;
}
early_initcall(tegra_pmc_early_init);
+#endif /* CONFIG_ARM */
diff --git a/drivers/soc/ti/k3-ringacc.c b/drivers/soc/ti/k3-ringacc.c
index 7602b8a909b0..5966db4327b1 100644
--- a/drivers/soc/ti/k3-ringacc.c
+++ b/drivers/soc/ti/k3-ringacc.c
@@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/string_choices.h>
#include <linux/sys_soc.h>
#include <linux/dma/ti-cppi5.h>
#include <linux/soc/ti/k3-ringacc.h>
@@ -1012,7 +1013,7 @@ static int k3_ringacc_ring_pop_head_proxy(struct k3_ring *ring, void *elem)
static int k3_ringacc_ring_pop_tail_proxy(struct k3_ring *ring, void *elem)
{
return k3_ringacc_ring_access_proxy(ring, elem,
- K3_RINGACC_ACCESS_MODE_POP_HEAD);
+ K3_RINGACC_ACCESS_MODE_POP_TAIL);
}
static int k3_ringacc_ring_access_io(struct k3_ring *ring, void *elem,
@@ -1083,7 +1084,7 @@ static int k3_ringacc_ring_pop_io(struct k3_ring *ring, void *elem)
static int k3_ringacc_ring_pop_tail_io(struct k3_ring *ring, void *elem)
{
return k3_ringacc_ring_access_io(ring, elem,
- K3_RINGACC_ACCESS_MODE_POP_HEAD);
+ K3_RINGACC_ACCESS_MODE_POP_TAIL);
}
/*
@@ -1436,7 +1437,7 @@ static int k3_ringacc_init(struct platform_device *pdev,
ringacc->rm_gp_range->desc[0].num,
ringacc->tisci_dev_id);
dev_info(dev, "dma-ring-reset-quirk: %s\n",
- ringacc->dma_ring_reset_quirk ? "enabled" : "disabled");
+ str_enabled_disabled(ringacc->dma_ring_reset_quirk));
dev_info(dev, "RA Proxy rev. %08x, num_proxies:%u\n",
readl(&ringacc->proxy_gcfg->revision), ringacc->num_proxies);
diff --git a/drivers/soc/ti/k3-socinfo.c b/drivers/soc/ti/k3-socinfo.c
index 676041879eca..48dbef3acceb 100644
--- a/drivers/soc/ti/k3-socinfo.c
+++ b/drivers/soc/ti/k3-socinfo.c
@@ -6,6 +6,7 @@
*/
#include <linux/mfd/syscon.h>
+#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/regmap.h>
@@ -25,6 +26,8 @@
#define CTRLMMR_WKUP_JTAGID_VARIANT_SHIFT (28)
#define CTRLMMR_WKUP_JTAGID_VARIANT_MASK GENMASK(31, 28)
+#define GP_SW1_ADR_MASK GENMASK(3, 0)
+
#define CTRLMMR_WKUP_JTAGID_PARTNO_SHIFT (12)
#define CTRLMMR_WKUP_JTAGID_PARTNO_MASK GENMASK(27, 12)
@@ -70,6 +73,23 @@ static const char * const am62lx_rev_string_map[] = {
"1.0", "1.1",
};
+static const char * const am62p_gpsw_rev_string_map[] = {
+ "1.0", "1.1", "1.2",
+};
+
+static int
+k3_chipinfo_get_gpsw_variant(struct device *dev)
+{
+ u32 gpsw_val = 0;
+ int ret;
+
+ ret = nvmem_cell_read_u32(dev, "gpsw1", &gpsw_val);
+ if (ret)
+ return ret;
+
+ return gpsw_val & GP_SW1_ADR_MASK;
+}
+
static int
k3_chipinfo_partno_to_names(unsigned int partno,
struct soc_device_attribute *soc_dev_attr)
@@ -86,9 +106,11 @@ k3_chipinfo_partno_to_names(unsigned int partno,
}
static int
-k3_chipinfo_variant_to_sr(unsigned int partno, unsigned int variant,
- struct soc_device_attribute *soc_dev_attr)
+k3_chipinfo_variant_to_sr(struct device *dev, unsigned int partno,
+ unsigned int variant, struct soc_device_attribute *soc_dev_attr)
{
+ int gpsw_variant = 0;
+
switch (partno) {
case JTAG_ID_PARTNO_J721E:
if (variant >= ARRAY_SIZE(j721e_rev_string_map))
@@ -102,6 +124,19 @@ k3_chipinfo_variant_to_sr(unsigned int partno, unsigned int variant,
soc_dev_attr->revision = kasprintf(GFP_KERNEL, "SR%s",
am62lx_rev_string_map[variant]);
break;
+ case JTAG_ID_PARTNO_AM62PX:
+ /* Check GP_SW1 for silicon revision */
+ gpsw_variant = k3_chipinfo_get_gpsw_variant(dev);
+ if (gpsw_variant == -EPROBE_DEFER)
+ return gpsw_variant;
+ if (gpsw_variant < 0 || gpsw_variant >= ARRAY_SIZE(am62p_gpsw_rev_string_map)) {
+ dev_warn(dev, "Failed to get silicon variant (%d), set SR1.0\n",
+ gpsw_variant);
+ gpsw_variant = 0;
+ }
+ soc_dev_attr->revision = kasprintf(GFP_KERNEL, "SR%s",
+ am62p_gpsw_rev_string_map[gpsw_variant]);
+ break;
default:
variant++;
soc_dev_attr->revision = kasprintf(GFP_KERNEL, "SR%x.0",
@@ -173,7 +208,7 @@ static int k3_chipinfo_probe(struct platform_device *pdev)
goto err;
}
- ret = k3_chipinfo_variant_to_sr(partno_id, variant, soc_dev_attr);
+ ret = k3_chipinfo_variant_to_sr(dev, partno_id, variant, soc_dev_attr);
if (ret) {
dev_err(dev, "Unknown SoC SR[0x%08X]: %d\n", jtag_id, ret);
goto err;
diff --git a/drivers/soc/ti/knav_dma.c b/drivers/soc/ti/knav_dma.c
index e5f5e3142fc4..96df3982e47b 100644
--- a/drivers/soc/ti/knav_dma.c
+++ b/drivers/soc/ti/knav_dma.c
@@ -29,7 +29,6 @@
#define DMA_TX_FILT_EINFO BIT(30)
#define DMA_TX_PRIO_SHIFT 0
#define DMA_RX_PRIO_SHIFT 16
-#define DMA_PRIO_MASK GENMASK(3, 0)
#define DMA_PRIO_DEFAULT 0
#define DMA_RX_TIMEOUT_DEFAULT 17500 /* cycles */
#define DMA_RX_TIMEOUT_MASK GENMASK(16, 0)
@@ -388,11 +387,6 @@ static int of_channel_match_helper(struct device_node *np, const char *name,
return -ENODEV;
}
- if (args.args[0] < 0) {
- dev_err(kdev->dev, "Missing args for %s\n", name);
- return -ENODEV;
- }
-
return args.args[0];
}
@@ -526,7 +520,7 @@ static void __iomem *pktdma_get_regs(struct knav_dma_device *dma,
if (ret) {
dev_err(dev, "Can't translate of node(%pOFn) address for index(%d)\n",
node, index);
- return ERR_PTR(ret);
+ return IOMEM_ERR_PTR(ret);
}
regs = devm_ioremap_resource(kdev->dev, &res);
diff --git a/drivers/soc/ti/knav_qmss.h b/drivers/soc/ti/knav_qmss.h
index 9325e8ce2e25..037dc1b36645 100644
--- a/drivers/soc/ti/knav_qmss.h
+++ b/drivers/soc/ti/knav_qmss.h
@@ -123,7 +123,7 @@ struct knav_pdsp_info {
const char *name;
struct knav_reg_pdsp_regs __iomem *regs;
union {
- void __iomem *command;
+ u32 __iomem *command;
struct knav_reg_acc_command __iomem *acc_command;
u32 __iomem *qos_command;
};
diff --git a/drivers/soc/ti/knav_qmss_acc.c b/drivers/soc/ti/knav_qmss_acc.c
index 269b4e75ae40..1f8b5acdd462 100644
--- a/drivers/soc/ti/knav_qmss_acc.c
+++ b/drivers/soc/ti/knav_qmss_acc.c
@@ -466,7 +466,7 @@ static const struct knav_range_ops knav_acc_range_ops = {
* @node: device node
* @range: qmms range information
*
- * Return 0 on success or error
+ * Return: 0 on success, errno otherwise.
*/
int knav_init_acc_range(struct knav_device *kdev,
struct device_node *node,
diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c
index 86d7a9c9ae01..7410b63af0e6 100644
--- a/drivers/soc/ti/knav_qmss_queue.c
+++ b/drivers/soc/ti/knav_qmss_queue.c
@@ -25,11 +25,8 @@
#include "knav_qmss.h"
-static struct knav_device *kdev;
+static struct knav_device *knav_qdev;
static DEFINE_MUTEX(knav_dev_lock);
-#define knav_dev_lock_held() \
- lockdep_is_held(&knav_dev_lock)
-
/* Queue manager register indices in DTS */
#define KNAV_QUEUE_PEEK_REG_INDEX 0
#define KNAV_QUEUE_STATUS_REG_INDEX 1
@@ -58,7 +55,7 @@ static DEFINE_MUTEX(knav_dev_lock);
#define for_each_handle_rcu(qh, inst) \
list_for_each_entry_rcu(qh, &inst->handles, list, \
- knav_dev_lock_held())
+ lockdep_is_held(&knav_dev_lock))
#define for_each_instance(idx, inst, kdev) \
for (idx = 0, inst = kdev->instances; \
@@ -205,10 +202,10 @@ knav_queue_match_id_to_inst(struct knav_device *kdev, unsigned id)
static inline struct knav_queue_inst *knav_queue_find_by_id(int id)
{
- if (kdev->base_id <= id &&
- kdev->base_id + kdev->num_queues > id) {
- id -= kdev->base_id;
- return knav_queue_match_id_to_inst(kdev, id);
+ if (knav_qdev->base_id <= id &&
+ knav_qdev->base_id + knav_qdev->num_queues > id) {
+ id -= knav_qdev->base_id;
+ return knav_queue_match_id_to_inst(knav_qdev, id);
}
return NULL;
}
@@ -296,7 +293,7 @@ static struct knav_queue *knav_queue_open_by_type(const char *name,
mutex_lock(&knav_dev_lock);
- for_each_instance(idx, inst, kdev) {
+ for_each_instance(idx, inst, knav_qdev) {
if (knav_queue_is_reserved(inst))
continue;
if (!knav_queue_match_type(inst, type))
@@ -469,9 +466,9 @@ static int knav_queue_debug_show(struct seq_file *s, void *v)
mutex_lock(&knav_dev_lock);
seq_printf(s, "%s: %u-%u\n",
- dev_name(kdev->dev), kdev->base_id,
- kdev->base_id + kdev->num_queues - 1);
- for_each_instance(idx, inst, kdev)
+ dev_name(knav_qdev->dev), knav_qdev->base_id,
+ knav_qdev->base_id + knav_qdev->num_queues - 1);
+ for_each_instance(idx, inst, knav_qdev)
knav_queue_debug_show_instance(s, inst);
mutex_unlock(&knav_dev_lock);
@@ -480,8 +477,8 @@ static int knav_queue_debug_show(struct seq_file *s, void *v)
DEFINE_SHOW_ATTRIBUTE(knav_queue_debug);
-static inline int knav_queue_pdsp_wait(u32 * __iomem addr, unsigned timeout,
- u32 flags)
+static inline int knav_queue_pdsp_wait(u32 __iomem *addr, unsigned int timeout,
+ u32 flags)
{
unsigned long end;
u32 val = 0;
@@ -520,7 +517,7 @@ static int knav_queue_flush(struct knav_queue *qh)
* Subsequent attempts to open a shared queue should
* also have this flag.
*
- * Returns a handle to the open hardware queue if successful. Use IS_ERR()
+ * Return: handle to the open hardware queue on success. Use IS_ERR()
* to check the returned value for error codes.
*/
void *knav_queue_open(const char *name, unsigned id,
@@ -576,7 +573,7 @@ EXPORT_SYMBOL_GPL(knav_queue_close);
* @cmd: - control commands
* @arg: - command argument
*
- * Returns 0 on success, errno otherwise.
+ * Return: 0 on success, errno otherwise.
*/
int knav_queue_device_control(void *qhandle, enum knav_queue_ctrl_cmd cmd,
unsigned long arg)
@@ -628,7 +625,7 @@ EXPORT_SYMBOL_GPL(knav_queue_device_control);
* @size: - size of data to push
* @flags: - can be used to pass additional information
*
- * Returns 0 on success, errno otherwise.
+ * Return: 0 on success, errno otherwise.
*/
int knav_queue_push(void *qhandle, dma_addr_t dma,
unsigned size, unsigned flags)
@@ -649,7 +646,7 @@ EXPORT_SYMBOL_GPL(knav_queue_push);
* @qhandle: - hardware queue handle
* @size: - (optional) size of the data pop'ed.
*
- * Returns a DMA address on success, 0 on failure.
+ * Return: DMA address on success, 0 on failure.
*/
dma_addr_t knav_queue_pop(void *qhandle, unsigned *size)
{
@@ -750,8 +747,8 @@ EXPORT_SYMBOL_GPL(knav_pool_desc_dma_to_virt);
* @region_id: - QMSS region id from which the descriptors are to be
* allocated.
*
- * Returns a pool handle on success.
- * Use IS_ERR_OR_NULL() to identify error values on return.
+ * Return: pool handle on success. Use IS_ERR_OR_NULL() to identify
+ * error values on return.
*/
void *knav_pool_create(const char *name,
int num_desc, int region_id)
@@ -762,19 +759,17 @@ void *knav_pool_create(const char *name,
unsigned last_offset;
int ret;
- if (!kdev)
+ if (!knav_qdev)
return ERR_PTR(-EPROBE_DEFER);
- if (!kdev->dev)
+ if (!knav_qdev->dev)
return ERR_PTR(-ENODEV);
- pool = devm_kzalloc(kdev->dev, sizeof(*pool), GFP_KERNEL);
- if (!pool) {
- dev_err(kdev->dev, "out of memory allocating pool\n");
+ pool = devm_kzalloc(knav_qdev->dev, sizeof(*pool), GFP_KERNEL);
+ if (!pool)
return ERR_PTR(-ENOMEM);
- }
- for_each_region(kdev, reg_itr) {
+ for_each_region(knav_qdev, reg_itr) {
if (reg_itr->id != region_id)
continue;
region = reg_itr;
@@ -782,28 +777,28 @@ void *knav_pool_create(const char *name,
}
if (!region) {
- dev_err(kdev->dev, "region-id(%d) not found\n", region_id);
+ dev_err(knav_qdev->dev, "region-id(%d) not found\n", region_id);
ret = -EINVAL;
goto err;
}
pool->queue = knav_queue_open(name, KNAV_QUEUE_GP, 0);
if (IS_ERR(pool->queue)) {
- dev_err(kdev->dev,
- "failed to open queue for pool(%s), error %ld\n",
- name, PTR_ERR(pool->queue));
+ dev_err(knav_qdev->dev,
+ "failed to open queue for pool(%s), error %pe\n",
+ name, pool->queue);
ret = PTR_ERR(pool->queue);
goto err;
}
pool->name = kstrndup(name, KNAV_NAME_SIZE - 1, GFP_KERNEL);
- pool->kdev = kdev;
- pool->dev = kdev->dev;
+ pool->kdev = knav_qdev;
+ pool->dev = knav_qdev->dev;
mutex_lock(&knav_dev_lock);
if (num_desc > (region->num_desc - region->used_desc)) {
- dev_err(kdev->dev, "out of descs in region(%d) for pool(%s)\n",
+ dev_err(knav_qdev->dev, "out of descs in region(%d) for pool(%s)\n",
region_id, name);
ret = -ENOMEM;
goto err_unlock;
@@ -829,10 +824,10 @@ void *knav_pool_create(const char *name,
pool->num_desc = num_desc;
pool->region_offset = last_offset;
region->used_desc += num_desc;
- list_add_tail(&pool->list, &kdev->pools);
+ list_add_tail(&pool->list, &knav_qdev->pools);
list_add_tail(&pool->region_inst, node);
} else {
- dev_err(kdev->dev, "pool(%s) create failed: fragmented desc pool in region(%d)\n",
+ dev_err(knav_qdev->dev, "pool(%s) create failed: fragmented desc pool in region(%d)\n",
name, region_id);
ret = -ENOMEM;
goto err_unlock;
@@ -846,7 +841,7 @@ err_unlock:
mutex_unlock(&knav_dev_lock);
err:
kfree(pool->name);
- devm_kfree(kdev->dev, pool);
+ devm_kfree(knav_qdev->dev, pool);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(knav_pool_create);
@@ -874,7 +869,7 @@ void knav_pool_destroy(void *ph)
mutex_unlock(&knav_dev_lock);
kfree(pool->name);
- devm_kfree(kdev->dev, pool);
+ devm_kfree(knav_qdev->dev, pool);
}
EXPORT_SYMBOL_GPL(knav_pool_destroy);
@@ -883,7 +878,7 @@ EXPORT_SYMBOL_GPL(knav_pool_destroy);
* knav_pool_desc_get() - Get a descriptor from the pool
* @ph: - pool handle
*
- * Returns descriptor from the pool.
+ * Return: descriptor from the pool on success, error pointer otherwise.
*/
void *knav_pool_desc_get(void *ph)
{
@@ -922,7 +917,7 @@ EXPORT_SYMBOL_GPL(knav_pool_desc_put);
* @dma: - DMA address return pointer
* @dma_sz: - adjusted return pointer
*
- * Returns 0 on success, errno otherwise.
+ * Return: 0 on success, errno otherwise.
*/
int knav_pool_desc_map(void *ph, void *desc, unsigned size,
dma_addr_t *dma, unsigned *dma_sz)
@@ -947,7 +942,7 @@ EXPORT_SYMBOL_GPL(knav_pool_desc_map);
* @dma: - DMA address of descriptor to unmap
* @dma_sz: - size of descriptor to unmap
*
- * Returns descriptor address on success, Use IS_ERR_OR_NULL() to identify
+ * Return: descriptor address on success. Use IS_ERR_OR_NULL() to identify
* error values on return.
*/
void *knav_pool_desc_unmap(void *ph, dma_addr_t dma, unsigned dma_sz)
@@ -967,7 +962,8 @@ EXPORT_SYMBOL_GPL(knav_pool_desc_unmap);
/**
* knav_pool_count() - Get the number of descriptors in pool.
* @ph: - pool handle
- * Returns number of elements in the pool.
+ *
+ * Return: number of elements in the pool.
*/
int knav_pool_count(void *ph)
{
@@ -1025,10 +1021,8 @@ static void knav_queue_setup_region(struct knav_device *kdev,
region->dma_end = region->dma_start + size;
pool = devm_kzalloc(kdev->dev, sizeof(*pool), GFP_KERNEL);
- if (!pool) {
- dev_err(kdev->dev, "out of memory allocating dummy pool\n");
+ if (!pool)
goto fail;
- }
pool->num_desc = 0;
pool->region_offset = region->num_desc;
list_add(&pool->region_inst, &region->pools);
@@ -1211,10 +1205,8 @@ static int knav_setup_queue_range(struct knav_device *kdev,
int ret, i;
range = devm_kzalloc(dev, sizeof(*range), GFP_KERNEL);
- if (!range) {
- dev_err(dev, "out of memory allocating range\n");
+ if (!range)
return -ENOMEM;
- }
range->kdev = kdev;
range->name = knav_queue_find_name(node);
@@ -1376,7 +1368,7 @@ static void __iomem *knav_queue_map_reg(struct knav_device *kdev,
if (ret) {
dev_err(kdev->dev, "Can't translate of node(%pOFn) address for index(%d)\n",
node, index);
- return ERR_PTR(ret);
+ return IOMEM_ERR_PTR(ret);
}
regs = devm_ioremap_resource(kdev->dev, &res);
@@ -1564,7 +1556,7 @@ static int knav_queue_load_pdsp(struct knav_device *kdev,
int i, ret, fwlen;
const struct firmware *fw;
bool found = false;
- u32 *fwdata;
+ const __be32 *fwdata;
for (i = 0; i < ARRAY_SIZE(knav_acc_firmwares); i++) {
if (knav_acc_firmwares[i]) {
@@ -1586,9 +1578,9 @@ static int knav_queue_load_pdsp(struct knav_device *kdev,
dev_info(kdev->dev, "firmware file %s downloaded for PDSP\n",
knav_acc_firmwares[i]);
- writel_relaxed(pdsp->id + 1, pdsp->command + 0x18);
+ writel_relaxed(pdsp->id + 1, pdsp->command + 0x6);
/* download the firmware */
- fwdata = (u32 *)fw->data;
+ fwdata = (const __be32 *)fw->data;
fwlen = (fw->size + sizeof(u32) - 1) / sizeof(u32);
for (i = 0; i < fwlen; i++)
writel_relaxed(be32_to_cpu(fwdata[i]), pdsp->iram + i);
@@ -1689,7 +1681,7 @@ static inline struct knav_qmgr_info *knav_find_qmgr(unsigned id)
{
struct knav_qmgr_info *qmgr;
- for_each_qmgr(kdev, qmgr) {
+ for_each_qmgr(knav_qdev, qmgr) {
if ((id >= qmgr->start_queue) &&
(id < qmgr->start_queue + qmgr->num_queues))
return qmgr;
@@ -1781,22 +1773,22 @@ static int knav_queue_probe(struct platform_device *pdev)
return -ENODEV;
}
- kdev = devm_kzalloc(dev, sizeof(struct knav_device), GFP_KERNEL);
- if (!kdev) {
+ knav_qdev = devm_kzalloc(dev, sizeof(struct knav_device), GFP_KERNEL);
+ if (!knav_qdev) {
dev_err(dev, "memory allocation failed\n");
return -ENOMEM;
}
if (device_get_match_data(dev))
- kdev->version = QMSS_66AK2G;
+ knav_qdev->version = QMSS_66AK2G;
- platform_set_drvdata(pdev, kdev);
- kdev->dev = dev;
- INIT_LIST_HEAD(&kdev->queue_ranges);
- INIT_LIST_HEAD(&kdev->qmgrs);
- INIT_LIST_HEAD(&kdev->pools);
- INIT_LIST_HEAD(&kdev->regions);
- INIT_LIST_HEAD(&kdev->pdsps);
+ platform_set_drvdata(pdev, knav_qdev);
+ knav_qdev->dev = dev;
+ INIT_LIST_HEAD(&knav_qdev->queue_ranges);
+ INIT_LIST_HEAD(&knav_qdev->qmgrs);
+ INIT_LIST_HEAD(&knav_qdev->pools);
+ INIT_LIST_HEAD(&knav_qdev->regions);
+ INIT_LIST_HEAD(&knav_qdev->pdsps);
pm_runtime_enable(&pdev->dev);
ret = pm_runtime_resume_and_get(&pdev->dev);
@@ -1811,31 +1803,31 @@ static int knav_queue_probe(struct platform_device *pdev)
ret = -ENODEV;
goto err;
}
- kdev->base_id = temp[0];
- kdev->num_queues = temp[1];
+ knav_qdev->base_id = temp[0];
+ knav_qdev->num_queues = temp[1];
/* Initialize queue managers using device tree configuration */
- ret = knav_queue_init_qmgrs(kdev, node);
+ ret = knav_queue_init_qmgrs(knav_qdev, node);
if (ret)
goto err;
/* get pdsp configuration values from device tree */
- ret = knav_queue_setup_pdsps(kdev, node);
+ ret = knav_queue_setup_pdsps(knav_qdev, node);
if (ret)
goto err;
/* get usable queue range values from device tree */
- ret = knav_setup_queue_pools(kdev, node);
+ ret = knav_setup_queue_pools(knav_qdev, node);
if (ret)
goto err;
- ret = knav_get_link_ram(kdev, "linkram0", &kdev->link_rams[0]);
+ ret = knav_get_link_ram(knav_qdev, "linkram0", &knav_qdev->link_rams[0]);
if (ret) {
- dev_err(kdev->dev, "could not setup linking ram\n");
+ dev_err(knav_qdev->dev, "could not setup linking ram\n");
goto err;
}
- ret = knav_get_link_ram(kdev, "linkram1", &kdev->link_rams[1]);
+ ret = knav_get_link_ram(knav_qdev, "linkram1", &knav_qdev->link_rams[1]);
if (ret) {
/*
* nothing really, we have one linking ram already, so we just
@@ -1843,15 +1835,15 @@ static int knav_queue_probe(struct platform_device *pdev)
*/
}
- ret = knav_queue_setup_link_ram(kdev);
+ ret = knav_queue_setup_link_ram(knav_qdev);
if (ret)
goto err;
- ret = knav_queue_setup_regions(kdev, node);
+ ret = knav_queue_setup_regions(knav_qdev, node);
if (ret)
goto err;
- ret = knav_queue_init_queues(kdev);
+ ret = knav_queue_init_queues(knav_qdev);
if (ret < 0) {
dev_err(dev, "hwqueue initialization failed\n");
goto err;
@@ -1863,9 +1855,9 @@ static int knav_queue_probe(struct platform_device *pdev)
return 0;
err:
- knav_queue_stop_pdsps(kdev);
- knav_queue_free_regions(kdev);
- knav_free_queue_ranges(kdev);
+ knav_queue_stop_pdsps(knav_qdev);
+ knav_queue_free_regions(knav_qdev);
+ knav_free_queue_ranges(knav_qdev);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return ret;
@@ -1873,7 +1865,12 @@ err:
static void knav_queue_remove(struct platform_device *pdev)
{
- /* TODO: Free resources */
+ struct knav_device *kdev = platform_get_drvdata(pdev);
+
+ device_ready = false;
+ knav_queue_stop_pdsps(kdev);
+ knav_queue_free_regions(kdev);
+ knav_free_queue_ranges(kdev);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
}
diff --git a/drivers/soc/ti/smartreflex.c b/drivers/soc/ti/smartreflex.c
index ced3a73929e3..01a214c3fa21 100644
--- a/drivers/soc/ti/smartreflex.c
+++ b/drivers/soc/ti/smartreflex.c
@@ -15,7 +15,6 @@
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/io.h>
diff --git a/drivers/soc/xilinx/zynqmp_power.c b/drivers/soc/xilinx/zynqmp_power.c
index 9085db1b480a..370e61ac47d8 100644
--- a/drivers/soc/xilinx/zynqmp_power.c
+++ b/drivers/soc/xilinx/zynqmp_power.c
@@ -303,18 +303,18 @@ static int zynqmp_pm_probe(struct platform_device *pdev)
* is not available to use) or -ENODEV(Xilinx Event Manager not compiled),
* then use ipi-mailbox or interrupt method.
*/
+ zynqmp_pm_init_suspend_work = devm_kzalloc(&pdev->dev,
+ sizeof(struct zynqmp_pm_work_struct),
+ GFP_KERNEL);
+ if (!zynqmp_pm_init_suspend_work)
+ return -ENOMEM;
+
+ INIT_WORK(&zynqmp_pm_init_suspend_work->callback_work,
+ zynqmp_pm_init_suspend_work_fn);
+
ret = register_event(&pdev->dev, PM_INIT_SUSPEND_CB, 0, 0, false,
suspend_event_callback);
if (!ret) {
- zynqmp_pm_init_suspend_work = devm_kzalloc(&pdev->dev,
- sizeof(struct zynqmp_pm_work_struct),
- GFP_KERNEL);
- if (!zynqmp_pm_init_suspend_work)
- return -ENOMEM;
-
- INIT_WORK(&zynqmp_pm_init_suspend_work->callback_work,
- zynqmp_pm_init_suspend_work_fn);
-
ret = zynqmp_pm_get_family_info(&pm_family_code);
if (ret < 0)
return ret;
@@ -326,14 +326,6 @@ static int zynqmp_pm_probe(struct platform_device *pdev)
else
return -ENODEV;
- ret = register_event(&pdev->dev, PM_NOTIFY_CB, node_id, EVENT_SUBSYSTEM_RESTART,
- false, subsystem_restart_event_callback);
- if (ret) {
- dev_err(&pdev->dev, "Failed to Register with Xilinx Event manager %d\n",
- ret);
- return ret;
- }
-
zynqmp_pm_init_restart_work = devm_kzalloc(&pdev->dev,
sizeof(struct zynqmp_pm_work_struct),
GFP_KERNEL);
@@ -342,19 +334,18 @@ static int zynqmp_pm_probe(struct platform_device *pdev)
INIT_WORK(&zynqmp_pm_init_restart_work->callback_work,
zynqmp_pm_subsystem_restart_work_fn);
+
+ ret = register_event(&pdev->dev, PM_NOTIFY_CB, node_id, EVENT_SUBSYSTEM_RESTART,
+ false, subsystem_restart_event_callback);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to Register with Xilinx Event manager %d\n",
+ ret);
+ return ret;
+ }
} else if (ret != -EACCES && ret != -ENODEV) {
dev_err(&pdev->dev, "Failed to Register with Xilinx Event manager %d\n", ret);
return ret;
} else if (of_property_present(pdev->dev.of_node, "mboxes")) {
- zynqmp_pm_init_suspend_work =
- devm_kzalloc(&pdev->dev,
- sizeof(struct zynqmp_pm_work_struct),
- GFP_KERNEL);
- if (!zynqmp_pm_init_suspend_work)
- return -ENOMEM;
-
- INIT_WORK(&zynqmp_pm_init_suspend_work->callback_work,
- zynqmp_pm_init_suspend_work_fn);
client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL);
if (!client)
return -ENOMEM;
@@ -398,8 +389,10 @@ static void zynqmp_pm_remove(struct platform_device *pdev)
{
sysfs_remove_file(&pdev->dev.kobj, &dev_attr_suspend_mode.attr);
- if (!rx_chan)
+ if (rx_chan) {
mbox_free_channel(rx_chan);
+ rx_chan = NULL;
+ }
}
static const struct of_device_id pm_of_match[] = {