diff options
Diffstat (limited to 'drivers/soc')
29 files changed, 1602 insertions, 446 deletions
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index e6e90e80519a..f31bceb69c0d 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -1,8 +1,7 @@ menu "SOC (System On Chip) specific Drivers" source "drivers/soc/bcm/Kconfig" -source "drivers/soc/fsl/qbman/Kconfig" -source "drivers/soc/fsl/qe/Kconfig" +source "drivers/soc/fsl/Kconfig" source "drivers/soc/mediatek/Kconfig" source "drivers/soc/qcom/Kconfig" source "drivers/soc/rockchip/Kconfig" diff --git a/drivers/soc/fsl/Kconfig b/drivers/soc/fsl/Kconfig new file mode 100644 index 000000000000..7a9fb9baa66d --- /dev/null +++ b/drivers/soc/fsl/Kconfig @@ -0,0 +1,18 @@ +# +# Freescale SOC drivers +# + +source "drivers/soc/fsl/qbman/Kconfig" +source "drivers/soc/fsl/qe/Kconfig" + +config FSL_GUTS + bool + select SOC_BUS + help + The global utilities block controls power management, I/O device + enabling, power-onreset(POR) configuration monitoring, alternate + function selection for multiplexed signals,and clock control. + This driver is to manage and access global utilities block. + Initially only reading SVR and registering soc device are supported. + Other guts accesses, such as reading RCW, should eventually be moved + into this driver as well. diff --git a/drivers/soc/fsl/Makefile b/drivers/soc/fsl/Makefile index 75e1f5334821..44b3bebef24a 100644 --- a/drivers/soc/fsl/Makefile +++ b/drivers/soc/fsl/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_FSL_DPAA) += qbman/ obj-$(CONFIG_QUICC_ENGINE) += qe/ obj-$(CONFIG_CPM) += qe/ +obj-$(CONFIG_FSL_GUTS) += guts.o diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c new file mode 100644 index 000000000000..6af7a11f09a5 --- /dev/null +++ b/drivers/soc/fsl/guts.c @@ -0,0 +1,239 @@ +/* + * Freescale QorIQ Platforms GUTS Driver + * + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/of_fdt.h> +#include <linux/sys_soc.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/fsl/guts.h> + +struct guts { + struct ccsr_guts __iomem *regs; + bool little_endian; +}; + +struct fsl_soc_die_attr { + char *die; + u32 svr; + u32 mask; +}; + +static struct guts *guts; +static struct soc_device_attribute soc_dev_attr; +static struct soc_device *soc_dev; + + +/* SoC die attribute definition for QorIQ platform */ +static const struct fsl_soc_die_attr fsl_soc_die[] = { + /* + * Power Architecture-based SoCs T Series + */ + + /* Die: T4240, SoC: T4240/T4160/T4080 */ + { .die = "T4240", + .svr = 0x82400000, + .mask = 0xfff00000, + }, + /* Die: T1040, SoC: T1040/T1020/T1042/T1022 */ + { .die = "T1040", + .svr = 0x85200000, + .mask = 0xfff00000, + }, + /* Die: T2080, SoC: T2080/T2081 */ + { .die = "T2080", + .svr = 0x85300000, + .mask = 0xfff00000, + }, + /* Die: T1024, SoC: T1024/T1014/T1023/T1013 */ + { .die = "T1024", + .svr = 0x85400000, + .mask = 0xfff00000, + }, + + /* + * ARM-based SoCs LS Series + */ + + /* Die: LS1043A, SoC: LS1043A/LS1023A */ + { .die = "LS1043A", + .svr = 0x87920000, + .mask = 0xffff0000, + }, + /* Die: LS2080A, SoC: LS2080A/LS2040A/LS2085A */ + { .die = "LS2080A", + .svr = 0x87010000, + .mask = 0xff3f0000, + }, + /* Die: LS1088A, SoC: LS1088A/LS1048A/LS1084A/LS1044A */ + { .die = "LS1088A", + .svr = 0x87030000, + .mask = 0xff3f0000, + }, + /* Die: LS1012A, SoC: LS1012A */ + { .die = "LS1012A", + .svr = 0x87040000, + .mask = 0xffff0000, + }, + /* Die: LS1046A, SoC: LS1046A/LS1026A */ + { .die = "LS1046A", + .svr = 0x87070000, + .mask = 0xffff0000, + }, + /* Die: LS2088A, SoC: LS2088A/LS2048A/LS2084A/LS2044A */ + { .die = "LS2088A", + .svr = 0x87090000, + .mask = 0xff3f0000, + }, + /* Die: LS1021A, SoC: LS1021A/LS1020A/LS1022A */ + { .die = "LS1021A", + .svr = 0x87000000, + .mask = 0xfff70000, + }, + { }, +}; + +static const struct fsl_soc_die_attr *fsl_soc_die_match( + u32 svr, const struct fsl_soc_die_attr *matches) +{ + while (matches->svr) { + if (matches->svr == (svr & matches->mask)) + return matches; + matches++; + }; + return NULL; +} + +u32 fsl_guts_get_svr(void) +{ + u32 svr = 0; + + if (!guts || !guts->regs) + return svr; + + if (guts->little_endian) + svr = ioread32(&guts->regs->svr); + else + svr = ioread32be(&guts->regs->svr); + + return svr; +} +EXPORT_SYMBOL(fsl_guts_get_svr); + +static int fsl_guts_probe(struct platform_device *pdev) +{ + struct device_node *root, *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct resource *res; + const struct fsl_soc_die_attr *soc_die; + const char *machine; + u32 svr; + + /* Initialize guts */ + guts = devm_kzalloc(dev, sizeof(*guts), GFP_KERNEL); + if (!guts) + return -ENOMEM; + + guts->little_endian = of_property_read_bool(np, "little-endian"); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + guts->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(guts->regs)) + return PTR_ERR(guts->regs); + + /* Register soc device */ + root = of_find_node_by_path("/"); + if (of_property_read_string(root, "model", &machine)) + of_property_read_string_index(root, "compatible", 0, &machine); + of_node_put(root); + if (machine) + soc_dev_attr.machine = devm_kstrdup(dev, machine, GFP_KERNEL); + + svr = fsl_guts_get_svr(); + soc_die = fsl_soc_die_match(svr, fsl_soc_die); + if (soc_die) { + soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL, + "QorIQ %s", soc_die->die); + } else { + soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL, "QorIQ"); + } + soc_dev_attr.soc_id = devm_kasprintf(dev, GFP_KERNEL, + "svr:0x%08x", svr); + soc_dev_attr.revision = devm_kasprintf(dev, GFP_KERNEL, "%d.%d", + (svr >> 4) & 0xf, svr & 0xf); + + soc_dev = soc_device_register(&soc_dev_attr); + if (IS_ERR(soc_dev)) + return PTR_ERR(soc_dev); + + pr_info("Machine: %s\n", soc_dev_attr.machine); + pr_info("SoC family: %s\n", soc_dev_attr.family); + pr_info("SoC ID: %s, Revision: %s\n", + soc_dev_attr.soc_id, soc_dev_attr.revision); + return 0; +} + +static int fsl_guts_remove(struct platform_device *dev) +{ + soc_device_unregister(soc_dev); + return 0; +} + +/* + * Table for matching compatible strings, for device tree + * guts node, for Freescale QorIQ SOCs. + */ +static const struct of_device_id fsl_guts_of_match[] = { + { .compatible = "fsl,qoriq-device-config-1.0", }, + { .compatible = "fsl,qoriq-device-config-2.0", }, + { .compatible = "fsl,p1010-guts", }, + { .compatible = "fsl,p1020-guts", }, + { .compatible = "fsl,p1021-guts", }, + { .compatible = "fsl,p1022-guts", }, + { .compatible = "fsl,p1023-guts", }, + { .compatible = "fsl,p2020-guts", }, + { .compatible = "fsl,bsc9131-guts", }, + { .compatible = "fsl,bsc9132-guts", }, + { .compatible = "fsl,mpc8536-guts", }, + { .compatible = "fsl,mpc8544-guts", }, + { .compatible = "fsl,mpc8548-guts", }, + { .compatible = "fsl,mpc8568-guts", }, + { .compatible = "fsl,mpc8569-guts", }, + { .compatible = "fsl,mpc8572-guts", }, + { .compatible = "fsl,ls1021a-dcfg", }, + { .compatible = "fsl,ls1043a-dcfg", }, + { .compatible = "fsl,ls2080a-dcfg", }, + {} +}; +MODULE_DEVICE_TABLE(of, fsl_guts_of_match); + +static struct platform_driver fsl_guts_driver = { + .driver = { + .name = "fsl-guts", + .of_match_table = fsl_guts_of_match, + }, + .probe = fsl_guts_probe, + .remove = fsl_guts_remove, +}; + +static int __init fsl_guts_init(void) +{ + return platform_driver_register(&fsl_guts_driver); +} +core_initcall(fsl_guts_init); + +static void __exit fsl_guts_exit(void) +{ + platform_driver_unregister(&fsl_guts_driver); +} +module_exit(fsl_guts_exit); diff --git a/drivers/soc/fsl/qbman/bman.c b/drivers/soc/fsl/qbman/bman.c index ffa48fdbb1a9..a3d6d7cfa929 100644 --- a/drivers/soc/fsl/qbman/bman.c +++ b/drivers/soc/fsl/qbman/bman.c @@ -167,12 +167,12 @@ struct bm_portal { /* Cache-inhibited register access. */ static inline u32 bm_in(struct bm_portal *p, u32 offset) { - return __raw_readl(p->addr.ci + offset); + return be32_to_cpu(__raw_readl(p->addr.ci + offset)); } static inline void bm_out(struct bm_portal *p, u32 offset, u32 val) { - __raw_writel(val, p->addr.ci + offset); + __raw_writel(cpu_to_be32(val), p->addr.ci + offset); } /* Cache Enabled Portal Access */ @@ -188,7 +188,7 @@ static inline void bm_cl_touch_ro(struct bm_portal *p, u32 offset) static inline u32 bm_ce_in(struct bm_portal *p, u32 offset) { - return __raw_readl(p->addr.ce + offset); + return be32_to_cpu(__raw_readl(p->addr.ce + offset)); } struct bman_portal { @@ -391,7 +391,7 @@ static void bm_rcr_finish(struct bm_portal *portal) i = bm_in(portal, BM_REG_RCR_PI_CINH) & (BM_RCR_SIZE - 1); if (i != rcr_ptr2idx(rcr->cursor)) - pr_crit("losing uncommited RCR entries\n"); + pr_crit("losing uncommitted RCR entries\n"); i = bm_in(portal, BM_REG_RCR_CI_CINH) & (BM_RCR_SIZE - 1); if (i != rcr->ci) diff --git a/drivers/soc/fsl/qbman/bman_ccsr.c b/drivers/soc/fsl/qbman/bman_ccsr.c index 9deb0524543f..a8e8389a6894 100644 --- a/drivers/soc/fsl/qbman/bman_ccsr.c +++ b/drivers/soc/fsl/qbman/bman_ccsr.c @@ -181,8 +181,7 @@ static int fsl_bman_probe(struct platform_device *pdev) node->full_name); return -ENXIO; } - bm_ccsr_start = devm_ioremap(dev, res->start, - res->end - res->start + 1); + bm_ccsr_start = devm_ioremap(dev, res->start, resource_size(res)); if (!bm_ccsr_start) return -ENXIO; diff --git a/drivers/soc/fsl/qbman/bman_portal.c b/drivers/soc/fsl/qbman/bman_portal.c index 986f64690e6e..8354d4dabdad 100644 --- a/drivers/soc/fsl/qbman/bman_portal.c +++ b/drivers/soc/fsl/qbman/bman_portal.c @@ -126,15 +126,19 @@ static int bman_portal_probe(struct platform_device *pdev) pcfg->irq = irq; va = ioremap_prot(addr_phys[0]->start, resource_size(addr_phys[0]), 0); - if (!va) + if (!va) { + dev_err(dev, "ioremap::CE failed\n"); goto err_ioremap1; + } pcfg->addr_virt[DPAA_PORTAL_CE] = va; va = ioremap_prot(addr_phys[1]->start, resource_size(addr_phys[1]), _PAGE_GUARDED | _PAGE_NO_CACHE); - if (!va) + if (!va) { + dev_err(dev, "ioremap::CI failed\n"); goto err_ioremap2; + } pcfg->addr_virt[DPAA_PORTAL_CI] = va; @@ -150,8 +154,10 @@ static int bman_portal_probe(struct platform_device *pdev) spin_unlock(&bman_lock); pcfg->cpu = cpu; - if (!init_pcfg(pcfg)) - goto err_ioremap2; + if (!init_pcfg(pcfg)) { + dev_err(dev, "portal init failed\n"); + goto err_portal_init; + } /* clear irq affinity if assigned cpu is offline */ if (!cpu_online(cpu)) @@ -159,10 +165,11 @@ static int bman_portal_probe(struct platform_device *pdev) return 0; +err_portal_init: + iounmap(pcfg->addr_virt[DPAA_PORTAL_CI]); err_ioremap2: iounmap(pcfg->addr_virt[DPAA_PORTAL_CE]); err_ioremap1: - dev_err(dev, "ioremap failed\n"); return -ENXIO; } diff --git a/drivers/soc/fsl/qbman/dpaa_sys.h b/drivers/soc/fsl/qbman/dpaa_sys.h index b63fd72295c6..2eaf3184f61d 100644 --- a/drivers/soc/fsl/qbman/dpaa_sys.h +++ b/drivers/soc/fsl/qbman/dpaa_sys.h @@ -38,6 +38,7 @@ #include <linux/kthread.h> #include <linux/vmalloc.h> #include <linux/platform_device.h> +#include <linux/of.h> #include <linux/of_reserved_mem.h> #include <linux/prefetch.h> #include <linux/genalloc.h> diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c index 119054bc922b..6f509f68085e 100644 --- a/drivers/soc/fsl/qbman/qman.c +++ b/drivers/soc/fsl/qbman/qman.c @@ -140,10 +140,10 @@ enum qm_mr_cmode { /* matches QCSP_CFG::MM */ struct qm_eqcr_entry { u8 _ncw_verb; /* writes to this are non-coherent */ u8 dca; - u16 seqnum; - u32 orp; /* 24-bit */ - u32 fqid; /* 24-bit */ - u32 tag; + __be16 seqnum; + u8 __reserved[4]; + __be32 fqid; /* 24-bit */ + __be32 tag; struct qm_fd fd; u8 __reserved3[32]; } __packed; @@ -183,41 +183,22 @@ struct qm_mr { }; /* MC (Management Command) command */ -/* "Query FQ" */ -struct qm_mcc_queryfq { +/* "FQ" command layout */ +struct qm_mcc_fq { u8 _ncw_verb; u8 __reserved1[3]; - u32 fqid; /* 24-bit */ + __be32 fqid; /* 24-bit */ u8 __reserved2[56]; } __packed; -/* "Alter FQ State Commands " */ -struct qm_mcc_alterfq { - u8 _ncw_verb; - u8 __reserved1[3]; - u32 fqid; /* 24-bit */ - u8 __reserved2; - u8 count; /* number of consecutive FQID */ - u8 __reserved3[10]; - u32 context_b; /* frame queue context b */ - u8 __reserved4[40]; -} __packed; -/* "Query CGR" */ -struct qm_mcc_querycgr { +/* "CGR" command layout */ +struct qm_mcc_cgr { u8 _ncw_verb; u8 __reserved1[30]; u8 cgid; u8 __reserved2[32]; }; -struct qm_mcc_querywq { - u8 _ncw_verb; - u8 __reserved; - /* select channel if verb != QUERYWQ_DEDICATED */ - u16 channel_wq; /* ignores wq (3 lsbits): _res[0-2] */ - u8 __reserved2[60]; -} __packed; - #define QM_MCC_VERB_VBIT 0x80 #define QM_MCC_VERB_MASK 0x7f /* where the verb contains; */ #define QM_MCC_VERB_INITFQ_PARKED 0x40 @@ -243,12 +224,9 @@ union qm_mc_command { u8 __reserved[63]; }; struct qm_mcc_initfq initfq; - struct qm_mcc_queryfq queryfq; - struct qm_mcc_alterfq alterfq; struct qm_mcc_initcgr initcgr; - struct qm_mcc_querycgr querycgr; - struct qm_mcc_querywq querywq; - struct qm_mcc_queryfq_np queryfq_np; + struct qm_mcc_fq fq; + struct qm_mcc_cgr cgr; }; /* MC (Management Command) result */ @@ -343,12 +321,12 @@ struct qm_portal { /* Cache-inhibited register access. */ static inline u32 qm_in(struct qm_portal *p, u32 offset) { - return __raw_readl(p->addr.ci + offset); + return be32_to_cpu(__raw_readl(p->addr.ci + offset)); } static inline void qm_out(struct qm_portal *p, u32 offset, u32 val) { - __raw_writel(val, p->addr.ci + offset); + __raw_writel(cpu_to_be32(val), p->addr.ci + offset); } /* Cache Enabled Portal Access */ @@ -364,7 +342,7 @@ static inline void qm_cl_touch_ro(struct qm_portal *p, u32 offset) static inline u32 qm_ce_in(struct qm_portal *p, u32 offset) { - return __raw_readl(p->addr.ce + offset); + return be32_to_cpu(__raw_readl(p->addr.ce + offset)); } /* --- EQCR API --- */ @@ -443,7 +421,7 @@ static inline void qm_eqcr_finish(struct qm_portal *portal) DPAA_ASSERT(!eqcr->busy); if (pi != eqcr_ptr2idx(eqcr->cursor)) - pr_crit("losing uncommited EQCR entries\n"); + pr_crit("losing uncommitted EQCR entries\n"); if (ci != eqcr->ci) pr_crit("missing existing EQCR completions\n"); if (eqcr->ci != eqcr_ptr2idx(eqcr->cursor)) @@ -492,8 +470,7 @@ static inline struct qm_eqcr_entry *qm_eqcr_start_stash(struct qm_portal static inline void eqcr_commit_checks(struct qm_eqcr *eqcr) { DPAA_ASSERT(eqcr->busy); - DPAA_ASSERT(eqcr->cursor->orp == (eqcr->cursor->orp & 0x00ffffff)); - DPAA_ASSERT(eqcr->cursor->fqid == (eqcr->cursor->fqid & 0x00ffffff)); + DPAA_ASSERT(!(be32_to_cpu(eqcr->cursor->fqid) & ~QM_FQID_MASK)); DPAA_ASSERT(eqcr->available >= 1); } @@ -962,8 +939,6 @@ struct qman_portal { u32 sdqcr; /* probing time config params for cpu-affine portals */ const struct qm_portal_config *config; - /* needed for providing a non-NULL device to dma_map_***() */ - struct platform_device *pdev; /* 2-element array. cgrs[0] is mask, cgrs[1] is snapshot. */ struct qman_cgrs *cgrs; /* linked-list of CSCN handlers. */ @@ -1133,7 +1108,6 @@ static int qman_create_portal(struct qman_portal *portal, const struct qman_cgrs *cgrs) { struct qm_portal *p; - char buf[16]; int ret; u32 isdr; @@ -1196,15 +1170,6 @@ static int qman_create_portal(struct qman_portal *portal, portal->sdqcr = QM_SDQCR_SOURCE_CHANNELS | QM_SDQCR_COUNT_UPTO3 | QM_SDQCR_DEDICATED_PRECEDENCE | QM_SDQCR_TYPE_PRIO_QOS | QM_SDQCR_TOKEN_SET(0xab) | QM_SDQCR_CHANNELS_DEDICATED; - sprintf(buf, "qportal-%d", c->channel); - portal->pdev = platform_device_alloc(buf, -1); - if (!portal->pdev) - goto fail_devalloc; - if (dma_set_mask(&portal->pdev->dev, DMA_BIT_MASK(40))) - goto fail_devadd; - ret = platform_device_add(portal->pdev); - if (ret) - goto fail_devadd; isdr = 0xffffffff; qm_out(p, QM_REG_ISDR, isdr); portal->irq_sources = 0; @@ -1239,8 +1204,8 @@ static int qman_create_portal(struct qman_portal *portal, /* special handling, drain just in case it's a few FQRNIs */ const union qm_mr_entry *e = qm_mr_current(p); - dev_err(c->dev, "MR dirty, VB 0x%x, rc 0x%x\n, addr 0x%x", - e->verb, e->ern.rc, e->ern.fd.addr_lo); + dev_err(c->dev, "MR dirty, VB 0x%x, rc 0x%x, addr 0x%llx\n", + e->verb, e->ern.rc, qm_fd_addr_get64(&e->ern.fd)); goto fail_dqrr_mr_empty; } /* Success */ @@ -1256,10 +1221,6 @@ fail_eqcr_empty: fail_affinity: free_irq(c->irq, portal); fail_irq: - platform_device_del(portal->pdev); -fail_devadd: - platform_device_put(portal->pdev); -fail_devalloc: kfree(portal->cgrs); fail_cgrs: qm_mc_finish(p); @@ -1321,9 +1282,6 @@ static void qman_destroy_portal(struct qman_portal *qm) qm_dqrr_finish(&qm->p); qm_eqcr_finish(&qm->p); - platform_device_del(qm->pdev); - platform_device_put(qm->pdev); - qm->config = NULL; } @@ -1428,7 +1386,7 @@ static void qm_mr_process_task(struct work_struct *work) case QM_MR_VERB_FQRN: case QM_MR_VERB_FQRL: /* Lookup in the retirement table */ - fq = fqid_to_fq(msg->fq.fqid); + fq = fqid_to_fq(qm_fqid_get(&msg->fq)); if (WARN_ON(!fq)) break; fq_state_change(p, fq, msg, verb); @@ -1437,7 +1395,7 @@ static void qm_mr_process_task(struct work_struct *work) break; case QM_MR_VERB_FQPN: /* Parked */ - fq = tag_to_fq(msg->fq.contextB); + fq = tag_to_fq(be32_to_cpu(msg->fq.context_b)); fq_state_change(p, fq, msg, verb); if (fq->cb.fqs) fq->cb.fqs(p, fq, msg); @@ -1451,7 +1409,7 @@ static void qm_mr_process_task(struct work_struct *work) } } else { /* Its a software ERN */ - fq = tag_to_fq(msg->ern.tag); + fq = tag_to_fq(be32_to_cpu(msg->ern.tag)); fq->cb.ern(p, fq, msg); } num++; @@ -1536,7 +1494,7 @@ static inline unsigned int __poll_portal_fast(struct qman_portal *p, if (dq->stat & QM_DQRR_STAT_UNSCHEDULED) { /* - * VDQCR: don't trust contextB as the FQ may have + * VDQCR: don't trust context_b as the FQ may have * been configured for h/w consumption and we're * draining it post-retirement. */ @@ -1562,8 +1520,8 @@ static inline unsigned int __poll_portal_fast(struct qman_portal *p, if (dq->stat & QM_DQRR_STAT_DQCR_EXPIRED) clear_vdqcr(p, fq); } else { - /* SDQCR: contextB points to the FQ */ - fq = tag_to_fq(dq->contextB); + /* SDQCR: context_b points to the FQ */ + fq = tag_to_fq(be32_to_cpu(dq->context_b)); /* Now let the callback do its stuff */ res = fq->cb.dqrr(p, fq, dq); /* @@ -1780,9 +1738,9 @@ int qman_init_fq(struct qman_fq *fq, u32 flags, struct qm_mcc_initfq *opts) if (fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY)) return -EINVAL; #endif - if (opts && (opts->we_mask & QM_INITFQ_WE_OAC)) { + if (opts && (be16_to_cpu(opts->we_mask) & QM_INITFQ_WE_OAC)) { /* And can't be set at the same time as TDTHRESH */ - if (opts->we_mask & QM_INITFQ_WE_TDTHRESH) + if (be16_to_cpu(opts->we_mask) & QM_INITFQ_WE_TDTHRESH) return -EINVAL; } /* Issue an INITFQ_[PARKED|SCHED] management command */ @@ -1796,37 +1754,49 @@ int qman_init_fq(struct qman_fq *fq, u32 flags, struct qm_mcc_initfq *opts) mcc = qm_mc_start(&p->p); if (opts) mcc->initfq = *opts; - mcc->initfq.fqid = fq->fqid; + qm_fqid_set(&mcc->fq, fq->fqid); mcc->initfq.count = 0; /* - * If the FQ does *not* have the TO_DCPORTAL flag, contextB is set as a + * If the FQ does *not* have the TO_DCPORTAL flag, context_b is set as a * demux pointer. Otherwise, the caller-provided value is allowed to * stand, don't overwrite it. */ if (fq_isclear(fq, QMAN_FQ_FLAG_TO_DCPORTAL)) { dma_addr_t phys_fq; - mcc->initfq.we_mask |= QM_INITFQ_WE_CONTEXTB; - mcc->initfq.fqd.context_b = fq_to_tag(fq); + mcc->initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_CONTEXTB); + mcc->initfq.fqd.context_b = cpu_to_be32(fq_to_tag(fq)); /* * and the physical address - NB, if the user wasn't trying to * set CONTEXTA, clear the stashing settings. */ - if (!(mcc->initfq.we_mask & QM_INITFQ_WE_CONTEXTA)) { - mcc->initfq.we_mask |= QM_INITFQ_WE_CONTEXTA; + if (!(be16_to_cpu(mcc->initfq.we_mask) & + QM_INITFQ_WE_CONTEXTA)) { + mcc->initfq.we_mask |= + cpu_to_be16(QM_INITFQ_WE_CONTEXTA); memset(&mcc->initfq.fqd.context_a, 0, sizeof(mcc->initfq.fqd.context_a)); } else { - phys_fq = dma_map_single(&p->pdev->dev, fq, sizeof(*fq), - DMA_TO_DEVICE); + struct qman_portal *p = qman_dma_portal; + + phys_fq = dma_map_single(p->config->dev, fq, + sizeof(*fq), DMA_TO_DEVICE); + if (dma_mapping_error(p->config->dev, phys_fq)) { + dev_err(p->config->dev, "dma_mapping failed\n"); + ret = -EIO; + goto out; + } + qm_fqd_stashing_set64(&mcc->initfq.fqd, phys_fq); } } if (flags & QMAN_INITFQ_FLAG_LOCAL) { int wq = 0; - if (!(mcc->initfq.we_mask & QM_INITFQ_WE_DESTWQ)) { - mcc->initfq.we_mask |= QM_INITFQ_WE_DESTWQ; + if (!(be16_to_cpu(mcc->initfq.we_mask) & + QM_INITFQ_WE_DESTWQ)) { + mcc->initfq.we_mask |= + cpu_to_be16(QM_INITFQ_WE_DESTWQ); wq = 4; } qm_fqd_set_destwq(&mcc->initfq.fqd, p->config->channel, wq); @@ -1845,13 +1815,13 @@ int qman_init_fq(struct qman_fq *fq, u32 flags, struct qm_mcc_initfq *opts) goto out; } if (opts) { - if (opts->we_mask & QM_INITFQ_WE_FQCTRL) { - if (opts->fqd.fq_ctrl & QM_FQCTRL_CGE) + if (be16_to_cpu(opts->we_mask) & QM_INITFQ_WE_FQCTRL) { + if (be16_to_cpu(opts->fqd.fq_ctrl) & QM_FQCTRL_CGE) fq_set(fq, QMAN_FQ_STATE_CGR_EN); else fq_clear(fq, QMAN_FQ_STATE_CGR_EN); } - if (opts->we_mask & QM_INITFQ_WE_CGID) + if (be16_to_cpu(opts->we_mask) & QM_INITFQ_WE_CGID) fq->cgr_groupid = opts->fqd.cgid; } fq->state = (flags & QMAN_INITFQ_FLAG_SCHED) ? @@ -1884,7 +1854,7 @@ int qman_schedule_fq(struct qman_fq *fq) goto out; } mcc = qm_mc_start(&p->p); - mcc->alterfq.fqid = fq->fqid; + qm_fqid_set(&mcc->fq, fq->fqid); qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_SCHED); if (!qm_mc_result_timeout(&p->p, &mcr)) { dev_err(p->config->dev, "ALTER_SCHED timeout\n"); @@ -1927,7 +1897,7 @@ int qman_retire_fq(struct qman_fq *fq, u32 *flags) goto out; } mcc = qm_mc_start(&p->p); - mcc->alterfq.fqid = fq->fqid; + qm_fqid_set(&mcc->fq, fq->fqid); qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_RETIRE); if (!qm_mc_result_timeout(&p->p, &mcr)) { dev_crit(p->config->dev, "ALTER_RETIRE timeout\n"); @@ -1970,8 +1940,8 @@ int qman_retire_fq(struct qman_fq *fq, u32 *flags) msg.verb = QM_MR_VERB_FQRNI; msg.fq.fqs = mcr->alterfq.fqs; - msg.fq.fqid = fq->fqid; - msg.fq.contextB = fq_to_tag(fq); + qm_fqid_set(&msg.fq, fq->fqid); + msg.fq.context_b = cpu_to_be32(fq_to_tag(fq)); fq->cb.fqs(p, fq, &msg); } } else if (res == QM_MCR_RESULT_PENDING) { @@ -2006,7 +1976,7 @@ int qman_oos_fq(struct qman_fq *fq) goto out; } mcc = qm_mc_start(&p->p); - mcc->alterfq.fqid = fq->fqid; + qm_fqid_set(&mcc->fq, fq->fqid); qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_OOS); if (!qm_mc_result_timeout(&p->p, &mcr)) { ret = -ETIMEDOUT; @@ -2032,7 +2002,7 @@ int qman_query_fq(struct qman_fq *fq, struct qm_fqd *fqd) int ret = 0; mcc = qm_mc_start(&p->p); - mcc->queryfq.fqid = fq->fqid; + qm_fqid_set(&mcc->fq, fq->fqid); qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ); if (!qm_mc_result_timeout(&p->p, &mcr)) { ret = -ETIMEDOUT; @@ -2058,7 +2028,7 @@ static int qman_query_fq_np(struct qman_fq *fq, int ret = 0; mcc = qm_mc_start(&p->p); - mcc->queryfq.fqid = fq->fqid; + qm_fqid_set(&mcc->fq, fq->fqid); qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ_NP); if (!qm_mc_result_timeout(&p->p, &mcr)) { ret = -ETIMEDOUT; @@ -2086,7 +2056,7 @@ static int qman_query_cgr(struct qman_cgr *cgr, int ret = 0; mcc = qm_mc_start(&p->p); - mcc->querycgr.cgid = cgr->cgrid; + mcc->cgr.cgid = cgr->cgrid; qm_mc_commit(&p->p, QM_MCC_VERB_QUERYCGR); if (!qm_mc_result_timeout(&p->p, &mcr)) { ret = -ETIMEDOUT; @@ -2239,8 +2209,8 @@ int qman_enqueue(struct qman_fq *fq, const struct qm_fd *fd) if (unlikely(!eq)) goto out; - eq->fqid = fq->fqid; - eq->tag = fq_to_tag(fq); + qm_fqid_set(eq, fq->fqid); + eq->tag = cpu_to_be32(fq_to_tag(fq)); eq->fd = *fd; qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_CMD_ENQUEUE); @@ -2282,7 +2252,24 @@ out: } #define PORTAL_IDX(n) (n->config->channel - QM_CHANNEL_SWPORTAL0) -#define TARG_MASK(n) (BIT(31) >> PORTAL_IDX(n)) + +/* congestion state change notification target update control */ +static void qm_cgr_cscn_targ_set(struct __qm_mc_cgr *cgr, int pi, u32 val) +{ + if (qman_ip_rev >= QMAN_REV30) + cgr->cscn_targ_upd_ctrl = cpu_to_be16(pi | + QM_CGR_TARG_UDP_CTRL_WRITE_BIT); + else + cgr->cscn_targ = cpu_to_be32(val | QM_CGR_TARG_PORTAL(pi)); +} + +static void qm_cgr_cscn_targ_clear(struct __qm_mc_cgr *cgr, int pi, u32 val) +{ + if (qman_ip_rev >= QMAN_REV30) + cgr->cscn_targ_upd_ctrl = cpu_to_be16(pi); + else + cgr->cscn_targ = cpu_to_be32(val & ~QM_CGR_TARG_PORTAL(pi)); +} static u8 qman_cgr_cpus[CGR_NUM]; @@ -2305,7 +2292,6 @@ int qman_create_cgr(struct qman_cgr *cgr, u32 flags, struct qm_mcc_initcgr *opts) { struct qm_mcr_querycgr cgr_state; - struct qm_mcc_initcgr local_opts = {}; int ret; struct qman_portal *p; @@ -2327,22 +2313,18 @@ int qman_create_cgr(struct qman_cgr *cgr, u32 flags, spin_lock(&p->cgr_lock); if (opts) { + struct qm_mcc_initcgr local_opts = *opts; + ret = qman_query_cgr(cgr, &cgr_state); if (ret) goto out; - if (opts) - local_opts = *opts; - if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) - local_opts.cgr.cscn_targ_upd_ctrl = - QM_CGR_TARG_UDP_CTRL_WRITE_BIT | PORTAL_IDX(p); - else - /* Overwrite TARG */ - local_opts.cgr.cscn_targ = cgr_state.cgr.cscn_targ | - TARG_MASK(p); - local_opts.we_mask |= QM_CGR_WE_CSCN_TARG; + + qm_cgr_cscn_targ_set(&local_opts.cgr, PORTAL_IDX(p), + be32_to_cpu(cgr_state.cgr.cscn_targ)); + local_opts.we_mask |= cpu_to_be16(QM_CGR_WE_CSCN_TARG); /* send init if flags indicate so */ - if (opts && (flags & QMAN_CGR_FLAG_USE_INIT)) + if (flags & QMAN_CGR_FLAG_USE_INIT) ret = qm_modify_cgr(cgr, QMAN_CGR_FLAG_USE_INIT, &local_opts); else @@ -2405,13 +2387,11 @@ int qman_delete_cgr(struct qman_cgr *cgr) list_add(&cgr->node, &p->cgr_cbs); goto release_lock; } - /* Overwrite TARG */ - local_opts.we_mask = QM_CGR_WE_CSCN_TARG; - if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) - local_opts.cgr.cscn_targ_upd_ctrl = PORTAL_IDX(p); - else - local_opts.cgr.cscn_targ = cgr_state.cgr.cscn_targ & - ~(TARG_MASK(p)); + + local_opts.we_mask = cpu_to_be16(QM_CGR_WE_CSCN_TARG); + qm_cgr_cscn_targ_clear(&local_opts.cgr, PORTAL_IDX(p), + be32_to_cpu(cgr_state.cgr.cscn_targ)); + ret = qm_modify_cgr(cgr, 0, &local_opts); if (ret) /* add back to the list */ @@ -2501,7 +2481,7 @@ static int _qm_dqrr_consume_and_match(struct qm_portal *p, u32 fqid, int s, } while (wait && !dqrr); while (dqrr) { - if (dqrr->fqid == fqid && (dqrr->stat & s)) + if (qm_fqid_get(dqrr) == fqid && (dqrr->stat & s)) found = 1; qm_dqrr_cdc_consume_1ptr(p, dqrr, 0); qm_dqrr_pvb_update(p); @@ -2537,7 +2517,7 @@ static int qman_shutdown_fq(u32 fqid) dev = p->config->dev; /* Determine the state of the FQID */ mcc = qm_mc_start(&p->p); - mcc->queryfq_np.fqid = fqid; + qm_fqid_set(&mcc->fq, fqid); qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ_NP); if (!qm_mc_result_timeout(&p->p, &mcr)) { dev_err(dev, "QUERYFQ_NP timeout\n"); @@ -2552,7 +2532,7 @@ static int qman_shutdown_fq(u32 fqid) /* Query which channel the FQ is using */ mcc = qm_mc_start(&p->p); - mcc->queryfq.fqid = fqid; + qm_fqid_set(&mcc->fq, fqid); qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ); if (!qm_mc_result_timeout(&p->p, &mcr)) { dev_err(dev, "QUERYFQ timeout\n"); @@ -2572,7 +2552,7 @@ static int qman_shutdown_fq(u32 fqid) case QM_MCR_NP_STATE_PARKED: orl_empty = 0; mcc = qm_mc_start(&p->p); - mcc->alterfq.fqid = fqid; + qm_fqid_set(&mcc->fq, fqid); qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_RETIRE); if (!qm_mc_result_timeout(&p->p, &mcr)) { dev_err(dev, "QUERYFQ_NP timeout\n"); @@ -2667,7 +2647,7 @@ static int qman_shutdown_fq(u32 fqid) cpu_relax(); } mcc = qm_mc_start(&p->p); - mcc->alterfq.fqid = fqid; + qm_fqid_set(&mcc->fq, fqid); qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_OOS); if (!qm_mc_result_timeout(&p->p, &mcr)) { ret = -ETIMEDOUT; @@ -2687,7 +2667,7 @@ static int qman_shutdown_fq(u32 fqid) case QM_MCR_NP_STATE_RETIRED: /* Send OOS Command */ mcc = qm_mc_start(&p->p); - mcc->alterfq.fqid = fqid; + qm_fqid_set(&mcc->fq, fqid); qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_OOS); if (!qm_mc_result_timeout(&p->p, &mcr)) { ret = -ETIMEDOUT; @@ -2722,6 +2702,7 @@ const struct qm_portal_config *qman_get_qm_portal_config( { return portal->config; } +EXPORT_SYMBOL(qman_get_qm_portal_config); struct gen_pool *qm_fqalloc; /* FQID allocator */ struct gen_pool *qm_qpalloc; /* pool-channel allocator */ @@ -2789,15 +2770,18 @@ static int qpool_cleanup(u32 qp) struct qm_mcr_queryfq_np np; err = qman_query_fq_np(&fq, &np); - if (err) + if (err == -ERANGE) /* FQID range exceeded, found no problems */ return 0; + else if (WARN_ON(err)) + return err; + if ((np.state & QM_MCR_NP_STATE_MASK) != QM_MCR_NP_STATE_OOS) { struct qm_fqd fqd; err = qman_query_fq(&fq, &fqd); if (WARN_ON(err)) - return 0; + return err; if (qm_fqd_get_chan(&fqd) == qp) { /* The channel is the FQ's target, clean it */ err = qman_shutdown_fq(fq.fqid); @@ -2836,7 +2820,7 @@ static int cgr_cleanup(u32 cgrid) * error, looking for non-OOS FQDs whose CGR is the CGR being released */ struct qman_fq fq = { - .fqid = 1 + .fqid = QM_FQID_RANGE_START }; int err; @@ -2844,16 +2828,19 @@ static int cgr_cleanup(u32 cgrid) struct qm_mcr_queryfq_np np; err = qman_query_fq_np(&fq, &np); - if (err) + if (err == -ERANGE) /* FQID range exceeded, found no problems */ return 0; + else if (WARN_ON(err)) + return err; + if ((np.state & QM_MCR_NP_STATE_MASK) != QM_MCR_NP_STATE_OOS) { struct qm_fqd fqd; err = qman_query_fq(&fq, &fqd); if (WARN_ON(err)) - return 0; - if ((fqd.fq_ctrl & QM_FQCTRL_CGE) && + return err; + if (be16_to_cpu(fqd.fq_ctrl) & QM_FQCTRL_CGE && fqd.cgid == cgrid) { pr_err("CRGID 0x%x is being used by FQID 0x%x, CGR will be leaked\n", cgrid, fq.fqid); diff --git a/drivers/soc/fsl/qbman/qman_ccsr.c b/drivers/soc/fsl/qbman/qman_ccsr.c index 0cace9e0077e..f4e6e70de259 100644 --- a/drivers/soc/fsl/qbman/qman_ccsr.c +++ b/drivers/soc/fsl/qbman/qman_ccsr.c @@ -444,6 +444,9 @@ static int zero_priv_mem(struct device *dev, struct device_node *node, /* map as cacheable, non-guarded */ void __iomem *tmpp = ioremap_prot(addr, sz, 0); + if (!tmpp) + return -ENOMEM; + memset_io(tmpp, 0, sz); flush_dcache_range((unsigned long)tmpp, (unsigned long)tmpp + sz); diff --git a/drivers/soc/fsl/qbman/qman_portal.c b/drivers/soc/fsl/qbman/qman_portal.c index d068e4820f49..adbaa30d3c5a 100644 --- a/drivers/soc/fsl/qbman/qman_portal.c +++ b/drivers/soc/fsl/qbman/qman_portal.c @@ -30,6 +30,9 @@ #include "qman_priv.h" +struct qman_portal *qman_dma_portal; +EXPORT_SYMBOL(qman_dma_portal); + /* Enable portal interupts (as opposed to polling mode) */ #define CONFIG_FSL_DPA_PIRQ_SLOW 1 #define CONFIG_FSL_DPA_PIRQ_FAST 1 @@ -150,6 +153,10 @@ static struct qman_portal *init_pcfg(struct qm_portal_config *pcfg) /* all assigned portals are initialized now */ qman_init_cgr_all(); } + + if (!qman_dma_portal) + qman_dma_portal = p; + spin_unlock(&qman_lock); dev_info(pcfg->dev, "Portal initialised, cpu %d\n", pcfg->cpu); @@ -217,9 +224,9 @@ static int qman_portal_probe(struct platform_device *pdev) struct device_node *node = dev->of_node; struct qm_portal_config *pcfg; struct resource *addr_phys[2]; - const u32 *channel; void __iomem *va; - int irq, len, cpu; + int irq, cpu, err; + u32 val; pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL); if (!pcfg) @@ -243,13 +250,13 @@ static int qman_portal_probe(struct platform_device *pdev) return -ENXIO; } - channel = of_get_property(node, "cell-index", &len); - if (!channel || (len != 4)) { + err = of_property_read_u32(node, "cell-index", &val); + if (err) { dev_err(dev, "Can't get %s property 'cell-index'\n", node->full_name); - return -ENXIO; + return err; } - pcfg->channel = *channel; + pcfg->channel = val; pcfg->cpu = -1; irq = platform_get_irq(pdev, 0); if (irq <= 0) { @@ -259,15 +266,19 @@ static int qman_portal_probe(struct platform_device *pdev) pcfg->irq = irq; va = ioremap_prot(addr_phys[0]->start, resource_size(addr_phys[0]), 0); - if (!va) + if (!va) { + dev_err(dev, "ioremap::CE failed\n"); goto err_ioremap1; + } pcfg->addr_virt[DPAA_PORTAL_CE] = va; va = ioremap_prot(addr_phys[1]->start, resource_size(addr_phys[1]), _PAGE_GUARDED | _PAGE_NO_CACHE); - if (!va) + if (!va) { + dev_err(dev, "ioremap::CI failed\n"); goto err_ioremap2; + } pcfg->addr_virt[DPAA_PORTAL_CI] = va; @@ -285,8 +296,15 @@ static int qman_portal_probe(struct platform_device *pdev) spin_unlock(&qman_lock); pcfg->cpu = cpu; - if (!init_pcfg(pcfg)) - goto err_ioremap2; + if (dma_set_mask(dev, DMA_BIT_MASK(40))) { + dev_err(dev, "dma_set_mask() failed\n"); + goto err_portal_init; + } + + if (!init_pcfg(pcfg)) { + dev_err(dev, "portal init failed\n"); + goto err_portal_init; + } /* clear irq affinity if assigned cpu is offline */ if (!cpu_online(cpu)) @@ -294,10 +312,11 @@ static int qman_portal_probe(struct platform_device *pdev) return 0; +err_portal_init: + iounmap(pcfg->addr_virt[DPAA_PORTAL_CI]); err_ioremap2: iounmap(pcfg->addr_virt[DPAA_PORTAL_CE]); err_ioremap1: - dev_err(dev, "ioremap failed\n"); return -ENXIO; } diff --git a/drivers/soc/fsl/qbman/qman_priv.h b/drivers/soc/fsl/qbman/qman_priv.h index 5cf821e623a9..53685b59718e 100644 --- a/drivers/soc/fsl/qbman/qman_priv.h +++ b/drivers/soc/fsl/qbman/qman_priv.h @@ -73,29 +73,23 @@ struct qm_mcr_querycgr { struct __qm_mc_cgr cgr; /* CGR fields */ u8 __reserved2[6]; u8 i_bcnt_hi; /* high 8-bits of 40-bit "Instant" */ - u32 i_bcnt_lo; /* low 32-bits of 40-bit */ + __be32 i_bcnt_lo; /* low 32-bits of 40-bit */ u8 __reserved3[3]; u8 a_bcnt_hi; /* high 8-bits of 40-bit "Average" */ - u32 a_bcnt_lo; /* low 32-bits of 40-bit */ - u32 cscn_targ_swp[4]; + __be32 a_bcnt_lo; /* low 32-bits of 40-bit */ + __be32 cscn_targ_swp[4]; } __packed; static inline u64 qm_mcr_querycgr_i_get64(const struct qm_mcr_querycgr *q) { - return ((u64)q->i_bcnt_hi << 32) | (u64)q->i_bcnt_lo; + return ((u64)q->i_bcnt_hi << 32) | be32_to_cpu(q->i_bcnt_lo); } static inline u64 qm_mcr_querycgr_a_get64(const struct qm_mcr_querycgr *q) { - return ((u64)q->a_bcnt_hi << 32) | (u64)q->a_bcnt_lo; + return ((u64)q->a_bcnt_hi << 32) | be32_to_cpu(q->a_bcnt_lo); } /* "Query FQ Non-Programmable Fields" */ -struct qm_mcc_queryfq_np { - u8 _ncw_verb; - u8 __reserved1[3]; - u32 fqid; /* 24-bit */ - u8 __reserved2[56]; -} __packed; struct qm_mcr_queryfq_np { u8 verb; @@ -367,5 +361,6 @@ int qman_alloc_fq_table(u32 num_fqids); #define QM_PIRQ_VISIBLE (QM_PIRQ_SLOW | QM_PIRQ_DQRI) extern struct qman_portal *affine_portals[NR_CPUS]; +extern struct qman_portal *qman_dma_portal; const struct qm_portal_config *qman_get_qm_portal_config( struct qman_portal *portal); diff --git a/drivers/soc/fsl/qbman/qman_test_api.c b/drivers/soc/fsl/qbman/qman_test_api.c index 6880ff17f45e..2895d062cf51 100644 --- a/drivers/soc/fsl/qbman/qman_test_api.c +++ b/drivers/soc/fsl/qbman/qman_test_api.c @@ -65,7 +65,7 @@ static void fd_init(struct qm_fd *fd) { qm_fd_addr_set64(fd, 0xabdeadbeefLLU); qm_fd_set_contig_big(fd, 0x0000ffff); - fd->cmd = 0xfeedf00d; + fd->cmd = cpu_to_be32(0xfeedf00d); } static void fd_inc(struct qm_fd *fd) @@ -86,26 +86,19 @@ static void fd_inc(struct qm_fd *fd) len--; qm_fd_set_param(fd, fmt, off, len); - fd->cmd++; + fd->cmd = cpu_to_be32(be32_to_cpu(fd->cmd) + 1); } /* The only part of the 'fd' we can't memcmp() is the ppid */ -static int fd_cmp(const struct qm_fd *a, const struct qm_fd *b) +static bool fd_neq(const struct qm_fd *a, const struct qm_fd *b) { - int r = (qm_fd_addr_get64(a) == qm_fd_addr_get64(b)) ? 0 : -1; + bool neq = qm_fd_addr_get64(a) != qm_fd_addr_get64(b); - if (!r) { - enum qm_fd_format fmt_a, fmt_b; + neq |= qm_fd_get_format(a) != qm_fd_get_format(b); + neq |= a->cfg != b->cfg; + neq |= a->cmd != b->cmd; - fmt_a = qm_fd_get_format(a); - fmt_b = qm_fd_get_format(b); - r = fmt_a - fmt_b; - } - if (!r) - r = a->cfg - b->cfg; - if (!r) - r = a->cmd - b->cmd; - return r; + return neq; } /* test */ @@ -217,12 +210,12 @@ static enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *p, struct qman_fq *fq, const struct qm_dqrr_entry *dq) { - if (WARN_ON(fd_cmp(&fd_dq, &dq->fd))) { + if (WARN_ON(fd_neq(&fd_dq, &dq->fd))) { pr_err("BADNESS: dequeued frame doesn't match;\n"); return qman_cb_dqrr_consume; } fd_inc(&fd_dq); - if (!(dq->stat & QM_DQRR_STAT_UNSCHEDULED) && !fd_cmp(&fd_dq, &fd)) { + if (!(dq->stat & QM_DQRR_STAT_UNSCHEDULED) && !fd_neq(&fd_dq, &fd)) { sdqcr_complete = 1; wake_up(&waitqueue); } diff --git a/drivers/soc/fsl/qbman/qman_test_stash.c b/drivers/soc/fsl/qbman/qman_test_stash.c index 43cf66ba42f5..e87b65403b67 100644 --- a/drivers/soc/fsl/qbman/qman_test_stash.c +++ b/drivers/soc/fsl/qbman/qman_test_stash.c @@ -175,7 +175,7 @@ static DEFINE_PER_CPU(struct hp_cpu, hp_cpus); /* links together the hp_cpu structs, in first-come first-serve order. */ static LIST_HEAD(hp_cpu_list); -static spinlock_t hp_lock = __SPIN_LOCK_UNLOCKED(hp_lock); +static DEFINE_SPINLOCK(hp_lock); static unsigned int hp_cpu_list_length; @@ -191,6 +191,9 @@ static void *__frame_ptr; static u32 *frame_ptr; static dma_addr_t frame_dma; +/* needed for dma_map*() */ +static const struct qm_portal_config *pcfg; + /* the main function waits on this */ static DECLARE_WAIT_QUEUE_HEAD(queue); @@ -210,16 +213,14 @@ static int allocate_frame_data(void) { u32 lfsr = HP_FIRST_WORD; int loop; - struct platform_device *pdev = platform_device_alloc("foobar", -1); - if (!pdev) { - pr_crit("platform_device_alloc() failed"); - return -EIO; - } - if (platform_device_add(pdev)) { - pr_crit("platform_device_add() failed"); + if (!qman_dma_portal) { + pr_crit("portal not available\n"); return -EIO; } + + pcfg = qman_get_qm_portal_config(qman_dma_portal); + __frame_ptr = kmalloc(4 * HP_NUM_WORDS, GFP_KERNEL); if (!__frame_ptr) return -ENOMEM; @@ -229,15 +230,22 @@ static int allocate_frame_data(void) frame_ptr[loop] = lfsr; lfsr = do_lfsr(lfsr); } - frame_dma = dma_map_single(&pdev->dev, frame_ptr, 4 * HP_NUM_WORDS, + + frame_dma = dma_map_single(pcfg->dev, frame_ptr, 4 * HP_NUM_WORDS, DMA_BIDIRECTIONAL); - platform_device_del(pdev); - platform_device_put(pdev); + if (dma_mapping_error(pcfg->dev, frame_dma)) { + pr_crit("dma mapping failure\n"); + kfree(__frame_ptr); + return -EIO; + } + return 0; } static void deallocate_frame_data(void) { + dma_unmap_single(pcfg->dev, frame_dma, 4 * HP_NUM_WORDS, + DMA_BIDIRECTIONAL); kfree(__frame_ptr); } @@ -249,7 +257,8 @@ static inline int process_frame_data(struct hp_handler *handler, int loop; if (qm_fd_addr_get64(fd) != handler->addr) { - pr_crit("bad frame address"); + pr_crit("bad frame address, [%llX != %llX]\n", + qm_fd_addr_get64(fd), handler->addr); return -EIO; } for (loop = 0; loop < HP_NUM_WORDS; loop++, p++) { @@ -397,8 +406,9 @@ static int init_handler(void *h) goto failed; } memset(&opts, 0, sizeof(opts)); - opts.we_mask = QM_INITFQ_WE_FQCTRL | QM_INITFQ_WE_CONTEXTA; - opts.fqd.fq_ctrl = QM_FQCTRL_CTXASTASHING; + opts.we_mask = cpu_to_be16(QM_INITFQ_WE_FQCTRL | + QM_INITFQ_WE_CONTEXTA); + opts.fqd.fq_ctrl = cpu_to_be16(QM_FQCTRL_CTXASTASHING); qm_fqd_set_stashing(&opts.fqd, 0, STASH_DATA_CL, STASH_CTX_CL); err = qman_init_fq(&handler->rx, QMAN_INITFQ_FLAG_SCHED | QMAN_INITFQ_FLAG_LOCAL, &opts); diff --git a/drivers/soc/fsl/qe/qe.c b/drivers/soc/fsl/qe/qe.c index 2707a827261b..ade168f5328e 100644 --- a/drivers/soc/fsl/qe/qe.c +++ b/drivers/soc/fsl/qe/qe.c @@ -717,9 +717,5 @@ static struct platform_driver qe_driver = { .resume = qe_resume, }; -static int __init qe_drv_init(void) -{ - return platform_driver_register(&qe_driver); -} -device_initcall(qe_drv_init); +builtin_platform_driver(qe_driver); #endif /* defined(CONFIG_SUSPEND) && defined(CONFIG_PPC_85xx) */ diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig index 0a4ea809a61b..609bb3424c14 100644 --- a/drivers/soc/mediatek/Kconfig +++ b/drivers/soc/mediatek/Kconfig @@ -23,7 +23,7 @@ config MTK_PMIC_WRAP config MTK_SCPSYS bool "MediaTek SCPSYS Support" depends on ARCH_MEDIATEK || COMPILE_TEST - default ARM64 && ARCH_MEDIATEK + default ARCH_MEDIATEK select REGMAP select MTK_INFRACFG select PM_GENERIC_DOMAINS if PM diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c index 837effe19907..beb79162369a 100644 --- a/drivers/soc/mediatek/mtk-scpsys.c +++ b/drivers/soc/mediatek/mtk-scpsys.c @@ -11,17 +11,16 @@ * GNU General Public License for more details. */ #include <linux/clk.h> -#include <linux/delay.h> +#include <linux/init.h> #include <linux/io.h> -#include <linux/kernel.h> #include <linux/mfd/syscon.h> -#include <linux/init.h> #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm_domain.h> -#include <linux/regmap.h> -#include <linux/soc/mediatek/infracfg.h> #include <linux/regulator/consumer.h> +#include <linux/soc/mediatek/infracfg.h> + +#include <dt-bindings/power/mt2701-power.h> #include <dt-bindings/power/mt8173-power.h> #define SPM_VDE_PWR_CON 0x0210 @@ -29,11 +28,17 @@ #define SPM_VEN_PWR_CON 0x0230 #define SPM_ISP_PWR_CON 0x0238 #define SPM_DIS_PWR_CON 0x023c +#define SPM_CONN_PWR_CON 0x0280 #define SPM_VEN2_PWR_CON 0x0298 -#define SPM_AUDIO_PWR_CON 0x029c +#define SPM_AUDIO_PWR_CON 0x029c /* MT8173 */ +#define SPM_BDP_PWR_CON 0x029c /* MT2701 */ +#define SPM_ETH_PWR_CON 0x02a0 +#define SPM_HIF_PWR_CON 0x02a4 +#define SPM_IFR_MSC_PWR_CON 0x02a8 #define SPM_MFG_2D_PWR_CON 0x02c0 #define SPM_MFG_ASYNC_PWR_CON 0x02c4 #define SPM_USB_PWR_CON 0x02cc + #define SPM_PWR_STATUS 0x060c #define SPM_PWR_STATUS_2ND 0x0610 @@ -43,10 +48,15 @@ #define PWR_ON_2ND_BIT BIT(3) #define PWR_CLK_DIS_BIT BIT(4) +#define PWR_STATUS_CONN BIT(1) #define PWR_STATUS_DISP BIT(3) #define PWR_STATUS_MFG BIT(4) #define PWR_STATUS_ISP BIT(5) #define PWR_STATUS_VDEC BIT(7) +#define PWR_STATUS_BDP BIT(14) +#define PWR_STATUS_ETH BIT(15) +#define PWR_STATUS_HIF BIT(16) +#define PWR_STATUS_IFR_MSC BIT(17) #define PWR_STATUS_VENC_LT BIT(20) #define PWR_STATUS_VENC BIT(21) #define PWR_STATUS_MFG_2D BIT(22) @@ -55,12 +65,23 @@ #define PWR_STATUS_USB BIT(25) enum clk_id { - MT8173_CLK_NONE, - MT8173_CLK_MM, - MT8173_CLK_MFG, - MT8173_CLK_VENC, - MT8173_CLK_VENC_LT, - MT8173_CLK_MAX, + CLK_NONE, + CLK_MM, + CLK_MFG, + CLK_VENC, + CLK_VENC_LT, + CLK_ETHIF, + CLK_MAX, +}; + +static const char * const clk_names[] = { + NULL, + "mm", + "mfg", + "venc", + "venc_lt", + "ethif", + NULL, }; #define MAX_CLKS 2 @@ -76,98 +97,6 @@ struct scp_domain_data { bool active_wakeup; }; -static const struct scp_domain_data scp_domain_data[] = { - [MT8173_POWER_DOMAIN_VDEC] = { - .name = "vdec", - .sta_mask = PWR_STATUS_VDEC, - .ctl_offs = SPM_VDE_PWR_CON, - .sram_pdn_bits = GENMASK(11, 8), - .sram_pdn_ack_bits = GENMASK(12, 12), - .clk_id = {MT8173_CLK_MM}, - }, - [MT8173_POWER_DOMAIN_VENC] = { - .name = "venc", - .sta_mask = PWR_STATUS_VENC, - .ctl_offs = SPM_VEN_PWR_CON, - .sram_pdn_bits = GENMASK(11, 8), - .sram_pdn_ack_bits = GENMASK(15, 12), - .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC}, - }, - [MT8173_POWER_DOMAIN_ISP] = { - .name = "isp", - .sta_mask = PWR_STATUS_ISP, - .ctl_offs = SPM_ISP_PWR_CON, - .sram_pdn_bits = GENMASK(11, 8), - .sram_pdn_ack_bits = GENMASK(13, 12), - .clk_id = {MT8173_CLK_MM}, - }, - [MT8173_POWER_DOMAIN_MM] = { - .name = "mm", - .sta_mask = PWR_STATUS_DISP, - .ctl_offs = SPM_DIS_PWR_CON, - .sram_pdn_bits = GENMASK(11, 8), - .sram_pdn_ack_bits = GENMASK(12, 12), - .clk_id = {MT8173_CLK_MM}, - .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | - MT8173_TOP_AXI_PROT_EN_MM_M1, - }, - [MT8173_POWER_DOMAIN_VENC_LT] = { - .name = "venc_lt", - .sta_mask = PWR_STATUS_VENC_LT, - .ctl_offs = SPM_VEN2_PWR_CON, - .sram_pdn_bits = GENMASK(11, 8), - .sram_pdn_ack_bits = GENMASK(15, 12), - .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC_LT}, - }, - [MT8173_POWER_DOMAIN_AUDIO] = { - .name = "audio", - .sta_mask = PWR_STATUS_AUDIO, - .ctl_offs = SPM_AUDIO_PWR_CON, - .sram_pdn_bits = GENMASK(11, 8), - .sram_pdn_ack_bits = GENMASK(15, 12), - .clk_id = {MT8173_CLK_NONE}, - }, - [MT8173_POWER_DOMAIN_USB] = { - .name = "usb", - .sta_mask = PWR_STATUS_USB, - .ctl_offs = SPM_USB_PWR_CON, - .sram_pdn_bits = GENMASK(11, 8), - .sram_pdn_ack_bits = GENMASK(15, 12), - .clk_id = {MT8173_CLK_NONE}, - .active_wakeup = true, - }, - [MT8173_POWER_DOMAIN_MFG_ASYNC] = { - .name = "mfg_async", - .sta_mask = PWR_STATUS_MFG_ASYNC, - .ctl_offs = SPM_MFG_ASYNC_PWR_CON, - .sram_pdn_bits = GENMASK(11, 8), - .sram_pdn_ack_bits = 0, - .clk_id = {MT8173_CLK_MFG}, - }, - [MT8173_POWER_DOMAIN_MFG_2D] = { - .name = "mfg_2d", - .sta_mask = PWR_STATUS_MFG_2D, - .ctl_offs = SPM_MFG_2D_PWR_CON, - .sram_pdn_bits = GENMASK(11, 8), - .sram_pdn_ack_bits = GENMASK(13, 12), - .clk_id = {MT8173_CLK_NONE}, - }, - [MT8173_POWER_DOMAIN_MFG] = { - .name = "mfg", - .sta_mask = PWR_STATUS_MFG, - .ctl_offs = SPM_MFG_PWR_CON, - .sram_pdn_bits = GENMASK(13, 8), - .sram_pdn_ack_bits = GENMASK(21, 16), - .clk_id = {MT8173_CLK_NONE}, - .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | - MT8173_TOP_AXI_PROT_EN_MFG_M0 | - MT8173_TOP_AXI_PROT_EN_MFG_M1 | - MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT, - }, -}; - -#define NUM_DOMAINS ARRAY_SIZE(scp_domain_data) - struct scp; struct scp_domain { @@ -179,7 +108,7 @@ struct scp_domain { }; struct scp { - struct scp_domain domains[NUM_DOMAINS]; + struct scp_domain *domains; struct genpd_onecell_data pd_data; struct device *dev; void __iomem *base; @@ -408,57 +337,55 @@ static bool scpsys_active_wakeup(struct device *dev) return scpd->data->active_wakeup; } -static int scpsys_probe(struct platform_device *pdev) +static void init_clks(struct platform_device *pdev, struct clk **clk) +{ + int i; + + for (i = CLK_NONE + 1; i < CLK_MAX; i++) + clk[i] = devm_clk_get(&pdev->dev, clk_names[i]); +} + +static struct scp *init_scp(struct platform_device *pdev, + const struct scp_domain_data *scp_domain_data, int num) { struct genpd_onecell_data *pd_data; struct resource *res; - int i, j, ret; + int i, j; struct scp *scp; - struct clk *clk[MT8173_CLK_MAX]; + struct clk *clk[CLK_MAX]; scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL); if (!scp) - return -ENOMEM; + return ERR_PTR(-ENOMEM); scp->dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); scp->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(scp->base)) - return PTR_ERR(scp->base); + return ERR_CAST(scp->base); + + scp->domains = devm_kzalloc(&pdev->dev, + sizeof(*scp->domains) * num, GFP_KERNEL); + if (!scp->domains) + return ERR_PTR(-ENOMEM); pd_data = &scp->pd_data; pd_data->domains = devm_kzalloc(&pdev->dev, - sizeof(*pd_data->domains) * NUM_DOMAINS, GFP_KERNEL); + sizeof(*pd_data->domains) * num, GFP_KERNEL); if (!pd_data->domains) - return -ENOMEM; - - clk[MT8173_CLK_MM] = devm_clk_get(&pdev->dev, "mm"); - if (IS_ERR(clk[MT8173_CLK_MM])) - return PTR_ERR(clk[MT8173_CLK_MM]); - - clk[MT8173_CLK_MFG] = devm_clk_get(&pdev->dev, "mfg"); - if (IS_ERR(clk[MT8173_CLK_MFG])) - return PTR_ERR(clk[MT8173_CLK_MFG]); - - clk[MT8173_CLK_VENC] = devm_clk_get(&pdev->dev, "venc"); - if (IS_ERR(clk[MT8173_CLK_VENC])) - return PTR_ERR(clk[MT8173_CLK_VENC]); - - clk[MT8173_CLK_VENC_LT] = devm_clk_get(&pdev->dev, "venc_lt"); - if (IS_ERR(clk[MT8173_CLK_VENC_LT])) - return PTR_ERR(clk[MT8173_CLK_VENC_LT]); + return ERR_PTR(-ENOMEM); scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "infracfg"); if (IS_ERR(scp->infracfg)) { dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n", PTR_ERR(scp->infracfg)); - return PTR_ERR(scp->infracfg); + return ERR_CAST(scp->infracfg); } - for (i = 0; i < NUM_DOMAINS; i++) { + for (i = 0; i < num; i++) { struct scp_domain *scpd = &scp->domains[i]; const struct scp_domain_data *data = &scp_domain_data[i]; @@ -467,13 +394,15 @@ static int scpsys_probe(struct platform_device *pdev) if (PTR_ERR(scpd->supply) == -ENODEV) scpd->supply = NULL; else - return PTR_ERR(scpd->supply); + return ERR_CAST(scpd->supply); } } - pd_data->num_domains = NUM_DOMAINS; + pd_data->num_domains = num; + + init_clks(pdev, clk); - for (i = 0; i < NUM_DOMAINS; i++) { + for (i = 0; i < num; i++) { struct scp_domain *scpd = &scp->domains[i]; struct generic_pm_domain *genpd = &scpd->genpd; const struct scp_domain_data *data = &scp_domain_data[i]; @@ -482,13 +411,37 @@ static int scpsys_probe(struct platform_device *pdev) scpd->scp = scp; scpd->data = data; - for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) - scpd->clk[j] = clk[data->clk_id[j]]; + + for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) { + struct clk *c = clk[data->clk_id[j]]; + + if (IS_ERR(c)) { + dev_err(&pdev->dev, "%s: clk unavailable\n", + data->name); + return ERR_CAST(c); + } + + scpd->clk[j] = c; + } genpd->name = data->name; genpd->power_off = scpsys_power_off; genpd->power_on = scpsys_power_on; genpd->dev_ops.active_wakeup = scpsys_active_wakeup; + } + + return scp; +} + +static void mtk_register_power_domains(struct platform_device *pdev, + struct scp *scp, int num) +{ + struct genpd_onecell_data *pd_data; + int i, ret; + + for (i = 0; i < num; i++) { + struct scp_domain *scpd = &scp->domains[i]; + struct generic_pm_domain *genpd = &scpd->genpd; /* * Initially turn on all domains to make the domains usable @@ -507,6 +460,222 @@ static int scpsys_probe(struct platform_device *pdev) * valid. */ + pd_data = &scp->pd_data; + + ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data); + if (ret) + dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret); +} + +/* + * MT2701 power domain support + */ + +static const struct scp_domain_data scp_domain_data_mt2701[] = { + [MT2701_POWER_DOMAIN_CONN] = { + .name = "conn", + .sta_mask = PWR_STATUS_CONN, + .ctl_offs = SPM_CONN_PWR_CON, + .bus_prot_mask = 0x0104, + .clk_id = {CLK_NONE}, + .active_wakeup = true, + }, + [MT2701_POWER_DOMAIN_DISP] = { + .name = "disp", + .sta_mask = PWR_STATUS_DISP, + .ctl_offs = SPM_DIS_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .clk_id = {CLK_MM}, + .bus_prot_mask = 0x0002, + .active_wakeup = true, + }, + [MT2701_POWER_DOMAIN_MFG] = { + .name = "mfg", + .sta_mask = PWR_STATUS_MFG, + .ctl_offs = SPM_MFG_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .clk_id = {CLK_MFG}, + .active_wakeup = true, + }, + [MT2701_POWER_DOMAIN_VDEC] = { + .name = "vdec", + .sta_mask = PWR_STATUS_VDEC, + .ctl_offs = SPM_VDE_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .clk_id = {CLK_MM}, + .active_wakeup = true, + }, + [MT2701_POWER_DOMAIN_ISP] = { + .name = "isp", + .sta_mask = PWR_STATUS_ISP, + .ctl_offs = SPM_ISP_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + .clk_id = {CLK_MM}, + .active_wakeup = true, + }, + [MT2701_POWER_DOMAIN_BDP] = { + .name = "bdp", + .sta_mask = PWR_STATUS_BDP, + .ctl_offs = SPM_BDP_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .clk_id = {CLK_NONE}, + .active_wakeup = true, + }, + [MT2701_POWER_DOMAIN_ETH] = { + .name = "eth", + .sta_mask = PWR_STATUS_ETH, + .ctl_offs = SPM_ETH_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_ETHIF}, + .active_wakeup = true, + }, + [MT2701_POWER_DOMAIN_HIF] = { + .name = "hif", + .sta_mask = PWR_STATUS_HIF, + .ctl_offs = SPM_HIF_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_ETHIF}, + .active_wakeup = true, + }, + [MT2701_POWER_DOMAIN_IFR_MSC] = { + .name = "ifr_msc", + .sta_mask = PWR_STATUS_IFR_MSC, + .ctl_offs = SPM_IFR_MSC_PWR_CON, + .clk_id = {CLK_NONE}, + .active_wakeup = true, + }, +}; + +#define NUM_DOMAINS_MT2701 ARRAY_SIZE(scp_domain_data_mt2701) + +static int __init scpsys_probe_mt2701(struct platform_device *pdev) +{ + struct scp *scp; + + scp = init_scp(pdev, scp_domain_data_mt2701, NUM_DOMAINS_MT2701); + if (IS_ERR(scp)) + return PTR_ERR(scp); + + mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT2701); + + return 0; +} + +/* + * MT8173 power domain support + */ + +static const struct scp_domain_data scp_domain_data_mt8173[] = { + [MT8173_POWER_DOMAIN_VDEC] = { + .name = "vdec", + .sta_mask = PWR_STATUS_VDEC, + .ctl_offs = SPM_VDE_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .clk_id = {CLK_MM}, + }, + [MT8173_POWER_DOMAIN_VENC] = { + .name = "venc", + .sta_mask = PWR_STATUS_VENC, + .ctl_offs = SPM_VEN_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_MM, CLK_VENC}, + }, + [MT8173_POWER_DOMAIN_ISP] = { + .name = "isp", + .sta_mask = PWR_STATUS_ISP, + .ctl_offs = SPM_ISP_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + .clk_id = {CLK_MM}, + }, + [MT8173_POWER_DOMAIN_MM] = { + .name = "mm", + .sta_mask = PWR_STATUS_DISP, + .ctl_offs = SPM_DIS_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .clk_id = {CLK_MM}, + .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | + MT8173_TOP_AXI_PROT_EN_MM_M1, + }, + [MT8173_POWER_DOMAIN_VENC_LT] = { + .name = "venc_lt", + .sta_mask = PWR_STATUS_VENC_LT, + .ctl_offs = SPM_VEN2_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_MM, CLK_VENC_LT}, + }, + [MT8173_POWER_DOMAIN_AUDIO] = { + .name = "audio", + .sta_mask = PWR_STATUS_AUDIO, + .ctl_offs = SPM_AUDIO_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_NONE}, + }, + [MT8173_POWER_DOMAIN_USB] = { + .name = "usb", + .sta_mask = PWR_STATUS_USB, + .ctl_offs = SPM_USB_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_NONE}, + .active_wakeup = true, + }, + [MT8173_POWER_DOMAIN_MFG_ASYNC] = { + .name = "mfg_async", + .sta_mask = PWR_STATUS_MFG_ASYNC, + .ctl_offs = SPM_MFG_ASYNC_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = 0, + .clk_id = {CLK_MFG}, + }, + [MT8173_POWER_DOMAIN_MFG_2D] = { + .name = "mfg_2d", + .sta_mask = PWR_STATUS_MFG_2D, + .ctl_offs = SPM_MFG_2D_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + .clk_id = {CLK_NONE}, + }, + [MT8173_POWER_DOMAIN_MFG] = { + .name = "mfg", + .sta_mask = PWR_STATUS_MFG, + .ctl_offs = SPM_MFG_PWR_CON, + .sram_pdn_bits = GENMASK(13, 8), + .sram_pdn_ack_bits = GENMASK(21, 16), + .clk_id = {CLK_NONE}, + .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | + MT8173_TOP_AXI_PROT_EN_MFG_M0 | + MT8173_TOP_AXI_PROT_EN_MFG_M1 | + MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT, + }, +}; + +#define NUM_DOMAINS_MT8173 ARRAY_SIZE(scp_domain_data_mt8173) + +static int __init scpsys_probe_mt8173(struct platform_device *pdev) +{ + struct scp *scp; + struct genpd_onecell_data *pd_data; + int ret; + + scp = init_scp(pdev, scp_domain_data_mt8173, NUM_DOMAINS_MT8173); + if (IS_ERR(scp)) + return PTR_ERR(scp); + + mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT8173); + + pd_data = &scp->pd_data; + ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_ASYNC], pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D]); if (ret && IS_ENABLED(CONFIG_PM)) @@ -517,21 +686,39 @@ static int scpsys_probe(struct platform_device *pdev) if (ret && IS_ENABLED(CONFIG_PM)) dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret); - ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data); - if (ret) - dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret); - return 0; } +/* + * scpsys driver init + */ + static const struct of_device_id of_scpsys_match_tbl[] = { { + .compatible = "mediatek,mt2701-scpsys", + .data = scpsys_probe_mt2701, + }, { .compatible = "mediatek,mt8173-scpsys", + .data = scpsys_probe_mt8173, }, { /* sentinel */ } }; +static int scpsys_probe(struct platform_device *pdev) +{ + int (*probe)(struct platform_device *); + const struct of_device_id *of_id; + + of_id = of_match_node(of_scpsys_match_tbl, pdev->dev.of_node); + if (!of_id || !of_id->data) + return -EINVAL; + + probe = of_id->data; + + return probe(pdev); +} + static struct platform_driver scpsys_drv = { .probe = scpsys_probe, .driver = { diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile index 623039c3514c..d9115cb5ed9d 100644 --- a/drivers/soc/renesas/Makefile +++ b/drivers/soc/renesas/Makefile @@ -1,3 +1,12 @@ +obj-$(CONFIG_SOC_BUS) += renesas-soc.o + +obj-$(CONFIG_ARCH_RCAR_GEN1) += rcar-rst.o +obj-$(CONFIG_ARCH_RCAR_GEN2) += rcar-rst.o +obj-$(CONFIG_ARCH_R8A7795) += rcar-rst.o +obj-$(CONFIG_ARCH_R8A7796) += rcar-rst.o + +obj-$(CONFIG_ARCH_R8A7743) += rcar-sysc.o r8a7743-sysc.o +obj-$(CONFIG_ARCH_R8A7745) += rcar-sysc.o r8a7745-sysc.o obj-$(CONFIG_ARCH_R8A7779) += rcar-sysc.o r8a7779-sysc.o obj-$(CONFIG_ARCH_R8A7790) += rcar-sysc.o r8a7790-sysc.o obj-$(CONFIG_ARCH_R8A7791) += rcar-sysc.o r8a7791-sysc.o diff --git a/drivers/soc/renesas/r8a7743-sysc.c b/drivers/soc/renesas/r8a7743-sysc.c new file mode 100644 index 000000000000..9583a327d90c --- /dev/null +++ b/drivers/soc/renesas/r8a7743-sysc.c @@ -0,0 +1,32 @@ +/* + * Renesas RZ/G1M System Controller + * + * Copyright (C) 2016 Cogent Embedded Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; of the License. + */ + +#include <linux/bug.h> +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a7743-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a7743_areas[] __initconst = { + { "always-on", 0, 0, R8A7743_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca15-scu", 0x180, 0, R8A7743_PD_CA15_SCU, R8A7743_PD_ALWAYS_ON, + PD_SCU }, + { "ca15-cpu0", 0x40, 0, R8A7743_PD_CA15_CPU0, R8A7743_PD_CA15_SCU, + PD_CPU_NOCR }, + { "ca15-cpu1", 0x40, 1, R8A7743_PD_CA15_CPU1, R8A7743_PD_CA15_SCU, + PD_CPU_NOCR }, + { "sgx", 0xc0, 0, R8A7743_PD_SGX, R8A7743_PD_ALWAYS_ON }, +}; + +const struct rcar_sysc_info r8a7743_sysc_info __initconst = { + .areas = r8a7743_areas, + .num_areas = ARRAY_SIZE(r8a7743_areas), +}; diff --git a/drivers/soc/renesas/r8a7745-sysc.c b/drivers/soc/renesas/r8a7745-sysc.c new file mode 100644 index 000000000000..d17887c08aa1 --- /dev/null +++ b/drivers/soc/renesas/r8a7745-sysc.c @@ -0,0 +1,32 @@ +/* + * Renesas RZ/G1E System Controller + * + * Copyright (C) 2016 Cogent Embedded Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; of the License. + */ + +#include <linux/bug.h> +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a7745-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a7745_areas[] __initconst = { + { "always-on", 0, 0, R8A7745_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca7-scu", 0x100, 0, R8A7745_PD_CA7_SCU, R8A7745_PD_ALWAYS_ON, + PD_SCU }, + { "ca7-cpu0", 0x1c0, 0, R8A7745_PD_CA7_CPU0, R8A7745_PD_CA7_SCU, + PD_CPU_NOCR }, + { "ca7-cpu1", 0x1c0, 1, R8A7745_PD_CA7_CPU1, R8A7745_PD_CA7_SCU, + PD_CPU_NOCR }, + { "sgx", 0xc0, 0, R8A7745_PD_SGX, R8A7745_PD_ALWAYS_ON }, +}; + +const struct rcar_sysc_info r8a7745_sysc_info __initconst = { + .areas = r8a7745_areas, + .num_areas = ARRAY_SIZE(r8a7745_areas), +}; diff --git a/drivers/soc/renesas/rcar-rst.c b/drivers/soc/renesas/rcar-rst.c new file mode 100644 index 000000000000..a6d1c26d3167 --- /dev/null +++ b/drivers/soc/renesas/rcar-rst.c @@ -0,0 +1,92 @@ +/* + * R-Car Gen1 RESET/WDT, R-Car Gen2, Gen3, and RZ/G RST Driver + * + * Copyright (C) 2016 Glider bvba + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of_address.h> +#include <linux/soc/renesas/rcar-rst.h> + +struct rst_config { + unsigned int modemr; /* Mode Monitoring Register Offset */ +}; + +static const struct rst_config rcar_rst_gen1 __initconst = { + .modemr = 0x20, +}; + +static const struct rst_config rcar_rst_gen2 __initconst = { + .modemr = 0x60, +}; + +static const struct of_device_id rcar_rst_matches[] __initconst = { + /* RZ/G is handled like R-Car Gen2 */ + { .compatible = "renesas,r8a7743-rst", .data = &rcar_rst_gen2 }, + { .compatible = "renesas,r8a7745-rst", .data = &rcar_rst_gen2 }, + /* R-Car Gen1 */ + { .compatible = "renesas,r8a7778-reset-wdt", .data = &rcar_rst_gen1 }, + { .compatible = "renesas,r8a7779-reset-wdt", .data = &rcar_rst_gen1 }, + /* R-Car Gen2 */ + { .compatible = "renesas,r8a7790-rst", .data = &rcar_rst_gen2 }, + { .compatible = "renesas,r8a7791-rst", .data = &rcar_rst_gen2 }, + { .compatible = "renesas,r8a7792-rst", .data = &rcar_rst_gen2 }, + { .compatible = "renesas,r8a7793-rst", .data = &rcar_rst_gen2 }, + { .compatible = "renesas,r8a7794-rst", .data = &rcar_rst_gen2 }, + /* R-Car Gen3 is handled like R-Car Gen2 */ + { .compatible = "renesas,r8a7795-rst", .data = &rcar_rst_gen2 }, + { .compatible = "renesas,r8a7796-rst", .data = &rcar_rst_gen2 }, + { /* sentinel */ } +}; + +static void __iomem *rcar_rst_base __initdata; +static u32 saved_mode __initdata; + +static int __init rcar_rst_init(void) +{ + const struct of_device_id *match; + const struct rst_config *cfg; + struct device_node *np; + void __iomem *base; + int error = 0; + + np = of_find_matching_node_and_match(NULL, rcar_rst_matches, &match); + if (!np) + return -ENODEV; + + base = of_iomap(np, 0); + if (!base) { + pr_warn("%s: Cannot map regs\n", np->full_name); + error = -ENOMEM; + goto out_put; + } + + rcar_rst_base = base; + cfg = match->data; + saved_mode = ioread32(base + cfg->modemr); + + pr_debug("%s: MODE = 0x%08x\n", np->full_name, saved_mode); + +out_put: + of_node_put(np); + return error; +} + +int __init rcar_rst_read_mode_pins(u32 *mode) +{ + int error; + + if (!rcar_rst_base) { + error = rcar_rst_init(); + if (error) + return error; + } + + *mode = saved_mode; + return 0; +} diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c index 65c8e1eb90c0..225c35c79d9a 100644 --- a/drivers/soc/renesas/rcar-sysc.c +++ b/drivers/soc/renesas/rcar-sysc.c @@ -275,6 +275,12 @@ finalize: } static const struct of_device_id rcar_sysc_matches[] = { +#ifdef CONFIG_ARCH_R8A7743 + { .compatible = "renesas,r8a7743-sysc", .data = &r8a7743_sysc_info }, +#endif +#ifdef CONFIG_ARCH_R8A7745 + { .compatible = "renesas,r8a7745-sysc", .data = &r8a7745_sysc_info }, +#endif #ifdef CONFIG_ARCH_R8A7779 { .compatible = "renesas,r8a7779-sysc", .data = &r8a7779_sysc_info }, #endif diff --git a/drivers/soc/renesas/rcar-sysc.h b/drivers/soc/renesas/rcar-sysc.h index 77dbe861473f..f6e842e2976e 100644 --- a/drivers/soc/renesas/rcar-sysc.h +++ b/drivers/soc/renesas/rcar-sysc.h @@ -50,6 +50,8 @@ struct rcar_sysc_info { unsigned int num_areas; }; +extern const struct rcar_sysc_info r8a7743_sysc_info; +extern const struct rcar_sysc_info r8a7745_sysc_info; extern const struct rcar_sysc_info r8a7779_sysc_info; extern const struct rcar_sysc_info r8a7790_sysc_info; extern const struct rcar_sysc_info r8a7791_sysc_info; diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c new file mode 100644 index 000000000000..330960312296 --- /dev/null +++ b/drivers/soc/renesas/renesas-soc.c @@ -0,0 +1,257 @@ +/* + * Renesas SoC Identification + * + * Copyright (C) 2014-2016 Glider bvba + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/sys_soc.h> + + +struct renesas_family { + const char name[16]; + u32 reg; /* CCCR or PRR, if not in DT */ +}; + +static const struct renesas_family fam_rcar_gen1 __initconst __maybe_unused = { + .name = "R-Car Gen1", + .reg = 0xff000044, /* PRR (Product Register) */ +}; + +static const struct renesas_family fam_rcar_gen2 __initconst __maybe_unused = { + .name = "R-Car Gen2", + .reg = 0xff000044, /* PRR (Product Register) */ +}; + +static const struct renesas_family fam_rcar_gen3 __initconst __maybe_unused = { + .name = "R-Car Gen3", + .reg = 0xfff00044, /* PRR (Product Register) */ +}; + +static const struct renesas_family fam_rmobile __initconst __maybe_unused = { + .name = "R-Mobile", + .reg = 0xe600101c, /* CCCR (Common Chip Code Register) */ +}; + +static const struct renesas_family fam_rza __initconst __maybe_unused = { + .name = "RZ/A", +}; + +static const struct renesas_family fam_rzg __initconst __maybe_unused = { + .name = "RZ/G", + .reg = 0xff000044, /* PRR (Product Register) */ +}; + +static const struct renesas_family fam_shmobile __initconst __maybe_unused = { + .name = "SH-Mobile", + .reg = 0xe600101c, /* CCCR (Common Chip Code Register) */ +}; + + +struct renesas_soc { + const struct renesas_family *family; + u8 id; +}; + +static const struct renesas_soc soc_rz_a1h __initconst __maybe_unused = { + .family = &fam_rza, +}; + +static const struct renesas_soc soc_rmobile_ape6 __initconst __maybe_unused = { + .family = &fam_rmobile, + .id = 0x3f, +}; + +static const struct renesas_soc soc_rmobile_a1 __initconst __maybe_unused = { + .family = &fam_rmobile, + .id = 0x40, +}; + +static const struct renesas_soc soc_rz_g1m __initconst __maybe_unused = { + .family = &fam_rzg, + .id = 0x47, +}; + +static const struct renesas_soc soc_rz_g1e __initconst __maybe_unused = { + .family = &fam_rzg, + .id = 0x4c, +}; + +static const struct renesas_soc soc_rcar_m1a __initconst __maybe_unused = { + .family = &fam_rcar_gen1, +}; + +static const struct renesas_soc soc_rcar_h1 __initconst __maybe_unused = { + .family = &fam_rcar_gen1, + .id = 0x3b, +}; + +static const struct renesas_soc soc_rcar_h2 __initconst __maybe_unused = { + .family = &fam_rcar_gen2, + .id = 0x45, +}; + +static const struct renesas_soc soc_rcar_m2_w __initconst __maybe_unused = { + .family = &fam_rcar_gen2, + .id = 0x47, +}; + +static const struct renesas_soc soc_rcar_v2h __initconst __maybe_unused = { + .family = &fam_rcar_gen2, + .id = 0x4a, +}; + +static const struct renesas_soc soc_rcar_m2_n __initconst __maybe_unused = { + .family = &fam_rcar_gen2, + .id = 0x4b, +}; + +static const struct renesas_soc soc_rcar_e2 __initconst __maybe_unused = { + .family = &fam_rcar_gen2, + .id = 0x4c, +}; + +static const struct renesas_soc soc_rcar_h3 __initconst __maybe_unused = { + .family = &fam_rcar_gen3, + .id = 0x4f, +}; + +static const struct renesas_soc soc_rcar_m3_w __initconst __maybe_unused = { + .family = &fam_rcar_gen3, + .id = 0x52, +}; + +static const struct renesas_soc soc_shmobile_ag5 __initconst __maybe_unused = { + .family = &fam_shmobile, + .id = 0x37, +}; + + +static const struct of_device_id renesas_socs[] __initconst = { +#ifdef CONFIG_ARCH_R7S72100 + { .compatible = "renesas,r7s72100", .data = &soc_rz_a1h }, +#endif +#ifdef CONFIG_ARCH_R8A73A4 + { .compatible = "renesas,r8a73a4", .data = &soc_rmobile_ape6 }, +#endif +#ifdef CONFIG_ARCH_R8A7740 + { .compatible = "renesas,r8a7740", .data = &soc_rmobile_a1 }, +#endif +#ifdef CONFIG_ARCH_R8A7743 + { .compatible = "renesas,r8a7743", .data = &soc_rz_g1m }, +#endif +#ifdef CONFIG_ARCH_R8A7745 + { .compatible = "renesas,r8a7745", .data = &soc_rz_g1e }, +#endif +#ifdef CONFIG_ARCH_R8A7778 + { .compatible = "renesas,r8a7778", .data = &soc_rcar_m1a }, +#endif +#ifdef CONFIG_ARCH_R8A7779 + { .compatible = "renesas,r8a7779", .data = &soc_rcar_h1 }, +#endif +#ifdef CONFIG_ARCH_R8A7790 + { .compatible = "renesas,r8a7790", .data = &soc_rcar_h2 }, +#endif +#ifdef CONFIG_ARCH_R8A7791 + { .compatible = "renesas,r8a7791", .data = &soc_rcar_m2_w }, +#endif +#ifdef CONFIG_ARCH_R8A7792 + { .compatible = "renesas,r8a7792", .data = &soc_rcar_v2h }, +#endif +#ifdef CONFIG_ARCH_R8A7793 + { .compatible = "renesas,r8a7793", .data = &soc_rcar_m2_n }, +#endif +#ifdef CONFIG_ARCH_R8A7794 + { .compatible = "renesas,r8a7794", .data = &soc_rcar_e2 }, +#endif +#ifdef CONFIG_ARCH_R8A7795 + { .compatible = "renesas,r8a7795", .data = &soc_rcar_h3 }, +#endif +#ifdef CONFIG_ARCH_R8A7796 + { .compatible = "renesas,r8a7796", .data = &soc_rcar_m3_w }, +#endif +#ifdef CONFIG_ARCH_SH73A0 + { .compatible = "renesas,sh73a0", .data = &soc_shmobile_ag5 }, +#endif + { /* sentinel */ } +}; + +static int __init renesas_soc_init(void) +{ + struct soc_device_attribute *soc_dev_attr; + const struct renesas_family *family; + const struct of_device_id *match; + const struct renesas_soc *soc; + void __iomem *chipid = NULL; + struct soc_device *soc_dev; + struct device_node *np; + unsigned int product; + + match = of_match_node(renesas_socs, of_root); + if (!match) + return -ENODEV; + + soc = match->data; + family = soc->family; + + /* Try PRR first, then hardcoded fallback */ + np = of_find_compatible_node(NULL, NULL, "renesas,prr"); + if (np) { + chipid = of_iomap(np, 0); + of_node_put(np); + } else if (soc->id) { + chipid = ioremap(family->reg, 4); + } + if (chipid) { + product = readl(chipid); + iounmap(chipid); + if (soc->id && ((product >> 8) & 0xff) != soc->id) { + pr_warn("SoC mismatch (product = 0x%x)\n", product); + return -ENODEV; + } + } + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return -ENOMEM; + + np = of_find_node_by_path("/"); + of_property_read_string(np, "model", &soc_dev_attr->machine); + of_node_put(np); + + soc_dev_attr->family = kstrdup_const(family->name, GFP_KERNEL); + soc_dev_attr->soc_id = kstrdup_const(strchr(match->compatible, ',') + 1, + GFP_KERNEL); + if (chipid) + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "ES%u.%u", + ((product >> 4) & 0x0f) + 1, + product & 0xf); + + pr_info("Detected Renesas %s %s %s\n", soc_dev_attr->family, + soc_dev_attr->soc_id, soc_dev_attr->revision ?: ""); + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr->revision); + kfree_const(soc_dev_attr->soc_id); + kfree_const(soc_dev_attr->family); + kfree(soc_dev_attr); + return PTR_ERR(soc_dev); + } + + return 0; +} +core_initcall(renesas_soc_init); diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index 7acd1517dd37..1c78c42416c6 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -9,6 +9,7 @@ */ #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/err.h> #include <linux/pm_clock.h> #include <linux/pm_domain.h> @@ -105,12 +106,24 @@ static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd) return (val & pd_info->idle_mask) == pd_info->idle_mask; } +static unsigned int rockchip_pmu_read_ack(struct rockchip_pmu *pmu) +{ + unsigned int val; + + regmap_read(pmu->regmap, pmu->info->ack_offset, &val); + return val; +} + static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd, bool idle) { const struct rockchip_domain_info *pd_info = pd->info; + struct generic_pm_domain *genpd = &pd->genpd; struct rockchip_pmu *pmu = pd->pmu; + unsigned int target_ack; unsigned int val; + bool is_idle; + int ret; if (pd_info->req_mask == 0) return 0; @@ -120,12 +133,26 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd, dsb(sy); - do { - regmap_read(pmu->regmap, pmu->info->ack_offset, &val); - } while ((val & pd_info->ack_mask) != (idle ? pd_info->ack_mask : 0)); + /* Wait util idle_ack = 1 */ + target_ack = idle ? pd_info->ack_mask : 0; + ret = readx_poll_timeout_atomic(rockchip_pmu_read_ack, pmu, val, + (val & pd_info->ack_mask) == target_ack, + 0, 10000); + if (ret) { + dev_err(pmu->dev, + "failed to get ack on domain '%s', val=0x%x\n", + genpd->name, val); + return ret; + } - while (rockchip_pmu_domain_is_idle(pd) != idle) - cpu_relax(); + ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_idle, pd, + is_idle, is_idle == idle, 0, 10000); + if (ret) { + dev_err(pmu->dev, + "failed to set idle on domain '%s', val=%d\n", + genpd->name, is_idle); + return ret; + } return 0; } @@ -198,6 +225,8 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd, bool on) { struct rockchip_pmu *pmu = pd->pmu; + struct generic_pm_domain *genpd = &pd->genpd; + bool is_on; if (pd->info->pwr_mask == 0) return; @@ -207,8 +236,13 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd, dsb(sy); - while (rockchip_pmu_domain_is_on(pd) != on) - cpu_relax(); + if (readx_poll_timeout_atomic(rockchip_pmu_domain_is_on, pd, is_on, + is_on == on, 0, 10000)) { + dev_err(pmu->dev, + "failed to set domain '%s', val=%d\n", + genpd->name, is_on); + return; + } } static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on) @@ -445,7 +479,16 @@ err_out: static void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd) { - int i; + int i, ret; + + /* + * We're in the error cleanup already, so we only complain, + * but won't emit another error on top of the original one. + */ + ret = pm_genpd_remove(&pd->genpd); + if (ret < 0) + dev_err(pd->pmu->dev, "failed to remove domain '%s' : %d - state may be inconsistent\n", + pd->genpd.name, ret); for (i = 0; i < pd->num_clks; i++) { clk_unprepare(pd->clks[i]); @@ -597,10 +640,12 @@ static int rockchip_pm_domain_probe(struct platform_device *pdev) * Configure power up and down transition delays for CORE * and GPU domains. */ - rockchip_configure_pd_cnt(pmu, pmu_info->core_pwrcnt_offset, - pmu_info->core_power_transition_time); - rockchip_configure_pd_cnt(pmu, pmu_info->gpu_pwrcnt_offset, - pmu_info->gpu_power_transition_time); + if (pmu_info->core_power_transition_time) + rockchip_configure_pd_cnt(pmu, pmu_info->core_pwrcnt_offset, + pmu_info->core_power_transition_time); + if (pmu_info->gpu_pwrcnt_offset) + rockchip_configure_pd_cnt(pmu, pmu_info->gpu_pwrcnt_offset, + pmu_info->gpu_power_transition_time); error = -ENODEV; @@ -627,7 +672,11 @@ static int rockchip_pm_domain_probe(struct platform_device *pdev) goto err_out; } - of_genpd_add_provider_onecell(np, &pmu->genpd_data); + error = of_genpd_add_provider_onecell(np, &pmu->genpd_data); + if (error) { + dev_err(dev, "failed to add provider: %d\n", error); + goto err_out; + } return 0; @@ -722,11 +771,7 @@ static const struct rockchip_pmu_info rk3399_pmu = { .idle_offset = 0x64, .ack_offset = 0x68, - .core_pwrcnt_offset = 0x9c, - .gpu_pwrcnt_offset = 0xa4, - - .core_power_transition_time = 24, - .gpu_power_transition_time = 24, + /* ARM Trusted Firmware manages power transition times */ .num_domains = ARRAY_SIZE(rk3399_pm_domains), .domain_info = rk3399_pm_domains, diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig index 03089ad2fc65..e5e124c07066 100644 --- a/drivers/soc/tegra/Kconfig +++ b/drivers/soc/tegra/Kconfig @@ -77,5 +77,19 @@ config ARCH_TEGRA_210_SOC controllers, such as GPIO, I2C, SPI, SDHCI, PCIe, SATA and XHCI, to name only a few. +config ARCH_TEGRA_186_SOC + bool "NVIDIA Tegra186 SoC" + select MAILBOX + select TEGRA_BPMP + select TEGRA_HSP_MBOX + select TEGRA_IVC + help + Enable support for the NVIDIA Tegar186 SoC. The Tegra186 features a + combination of Denver and Cortex-A57 CPU cores and a GPU based on + the Pascal architecture. It contains an ADSP with a Cortex-A9 CPU + used for audio processing, hardware video encoders/decoders with + multi-format support, ISP for image capture processing and BPMP for + power management. + endif endif diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 7792ed88d80b..e233dd5dcab3 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -45,29 +45,31 @@ #include <soc/tegra/pmc.h> #define PMC_CNTRL 0x0 -#define PMC_CNTRL_SYSCLK_POLARITY (1 << 10) /* sys clk polarity */ -#define PMC_CNTRL_SYSCLK_OE (1 << 11) /* system clock enable */ -#define PMC_CNTRL_SIDE_EFFECT_LP0 (1 << 14) /* LP0 when CPU pwr gated */ -#define PMC_CNTRL_CPU_PWRREQ_POLARITY (1 << 15) /* CPU pwr req polarity */ -#define PMC_CNTRL_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */ -#define PMC_CNTRL_INTR_POLARITY (1 << 17) /* inverts INTR polarity */ -#define PMC_CNTRL_MAIN_RST (1 << 4) +#define PMC_CNTRL_INTR_POLARITY BIT(17) /* inverts INTR polarity */ +#define PMC_CNTRL_CPU_PWRREQ_OE BIT(16) /* CPU pwr req enable */ +#define PMC_CNTRL_CPU_PWRREQ_POLARITY BIT(15) /* CPU pwr req polarity */ +#define PMC_CNTRL_SIDE_EFFECT_LP0 BIT(14) /* LP0 when CPU pwr gated */ +#define PMC_CNTRL_SYSCLK_OE BIT(11) /* system clock enable */ +#define PMC_CNTRL_SYSCLK_POLARITY BIT(10) /* sys clk polarity */ +#define PMC_CNTRL_MAIN_RST BIT(4) #define DPD_SAMPLE 0x020 -#define DPD_SAMPLE_ENABLE (1 << 0) +#define DPD_SAMPLE_ENABLE BIT(0) #define DPD_SAMPLE_DISABLE (0 << 0) #define PWRGATE_TOGGLE 0x30 -#define PWRGATE_TOGGLE_START (1 << 8) +#define PWRGATE_TOGGLE_START BIT(8) #define REMOVE_CLAMPING 0x34 #define PWRGATE_STATUS 0x38 +#define PMC_PWR_DET 0x48 + #define PMC_SCRATCH0 0x50 -#define PMC_SCRATCH0_MODE_RECOVERY (1 << 31) -#define PMC_SCRATCH0_MODE_BOOTLOADER (1 << 30) -#define PMC_SCRATCH0_MODE_RCM (1 << 1) +#define PMC_SCRATCH0_MODE_RECOVERY BIT(31) +#define PMC_SCRATCH0_MODE_BOOTLOADER BIT(30) +#define PMC_SCRATCH0_MODE_RCM BIT(1) #define PMC_SCRATCH0_MODE_MASK (PMC_SCRATCH0_MODE_RECOVERY | \ PMC_SCRATCH0_MODE_BOOTLOADER | \ PMC_SCRATCH0_MODE_RCM) @@ -75,11 +77,13 @@ #define PMC_CPUPWRGOOD_TIMER 0xc8 #define PMC_CPUPWROFF_TIMER 0xcc +#define PMC_PWR_DET_VALUE 0xe4 + #define PMC_SCRATCH41 0x140 #define PMC_SENSOR_CTRL 0x1b0 -#define PMC_SENSOR_CTRL_SCRATCH_WRITE (1 << 2) -#define PMC_SENSOR_CTRL_ENABLE_RST (1 << 1) +#define PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2) +#define PMC_SENSOR_CTRL_ENABLE_RST BIT(1) #define PMC_RST_STATUS 0x1b4 #define PMC_RST_STATUS_POR 0 @@ -90,10 +94,10 @@ #define PMC_RST_STATUS_AOTAG 5 #define IO_DPD_REQ 0x1b8 -#define IO_DPD_REQ_CODE_IDLE (0 << 30) -#define IO_DPD_REQ_CODE_OFF (1 << 30) -#define IO_DPD_REQ_CODE_ON (2 << 30) -#define IO_DPD_REQ_CODE_MASK (3 << 30) +#define IO_DPD_REQ_CODE_IDLE (0U << 30) +#define IO_DPD_REQ_CODE_OFF (1U << 30) +#define IO_DPD_REQ_CODE_ON (2U << 30) +#define IO_DPD_REQ_CODE_MASK (3U << 30) #define IO_DPD_STATUS 0x1bc #define IO_DPD2_REQ 0x1c0 @@ -101,16 +105,16 @@ #define SEL_DPD_TIM 0x1c8 #define PMC_SCRATCH54 0x258 -#define PMC_SCRATCH54_DATA_SHIFT 8 -#define PMC_SCRATCH54_ADDR_SHIFT 0 +#define PMC_SCRATCH54_DATA_SHIFT 8 +#define PMC_SCRATCH54_ADDR_SHIFT 0 #define PMC_SCRATCH55 0x25c -#define PMC_SCRATCH55_RESET_TEGRA (1 << 31) -#define PMC_SCRATCH55_CNTRL_ID_SHIFT 27 -#define PMC_SCRATCH55_PINMUX_SHIFT 24 -#define PMC_SCRATCH55_16BITOP (1 << 15) -#define PMC_SCRATCH55_CHECKSUM_SHIFT 16 -#define PMC_SCRATCH55_I2CSLV1_SHIFT 0 +#define PMC_SCRATCH55_RESET_TEGRA BIT(31) +#define PMC_SCRATCH55_CNTRL_ID_SHIFT 27 +#define PMC_SCRATCH55_PINMUX_SHIFT 24 +#define PMC_SCRATCH55_16BITOP BIT(15) +#define PMC_SCRATCH55_CHECKSUM_SHIFT 16 +#define PMC_SCRATCH55_I2CSLV1_SHIFT 0 #define GPU_RG_CNTRL 0x2d4 @@ -124,6 +128,12 @@ struct tegra_powergate { unsigned int num_resets; }; +struct tegra_io_pad_soc { + enum tegra_io_pad id; + unsigned int dpd; + unsigned int voltage; +}; + struct tegra_pmc_soc { unsigned int num_powergates; const char *const *powergates; @@ -132,6 +142,9 @@ struct tegra_pmc_soc { bool has_tsense_reset; bool has_gpu_clamps; + + const struct tegra_io_pad_soc *io_pads; + unsigned int num_io_pads; }; /** @@ -238,8 +251,6 @@ static int tegra_powergate_lookup(struct tegra_pmc *pmc, const char *name) return i; } - dev_err(pmc->dev, "powergate %s not found\n", name); - return -ENODEV; } @@ -456,13 +467,12 @@ disable_clks: static int tegra_genpd_power_on(struct generic_pm_domain *domain) { struct tegra_powergate *pg = to_powergate(domain); - struct tegra_pmc *pmc = pg->pmc; int err; err = tegra_powergate_power_up(pg, true); if (err) - dev_err(pmc->dev, "failed to turn on PM domain %s: %d\n", - pg->genpd.name, err); + pr_err("failed to turn on PM domain %s: %d\n", pg->genpd.name, + err); return err; } @@ -470,13 +480,12 @@ static int tegra_genpd_power_on(struct generic_pm_domain *domain) static int tegra_genpd_power_off(struct generic_pm_domain *domain) { struct tegra_powergate *pg = to_powergate(domain); - struct tegra_pmc *pmc = pg->pmc; int err; err = tegra_powergate_power_down(pg); if (err) - dev_err(pmc->dev, "failed to turn off PM domain %s: %d\n", - pg->genpd.name, err); + pr_err("failed to turn off PM domain %s: %d\n", + pg->genpd.name, err); return err; } @@ -801,8 +810,7 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) id = tegra_powergate_lookup(pmc, np->name); if (id < 0) { - dev_err(pmc->dev, "powergate lookup failed for %s: %d\n", - np->name, id); + pr_err("powergate lookup failed for %s: %d\n", np->name, id); goto free_mem; } @@ -822,20 +830,22 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) err = tegra_powergate_of_get_clks(pg, np); if (err < 0) { - dev_err(pmc->dev, "failed to get clocks for %s: %d\n", - np->name, err); + pr_err("failed to get clocks for %s: %d\n", np->name, err); goto set_available; } err = tegra_powergate_of_get_resets(pg, np, off); if (err < 0) { - dev_err(pmc->dev, "failed to get resets for %s: %d\n", - np->name, err); + pr_err("failed to get resets for %s: %d\n", np->name, err); goto remove_clks; } - if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) - goto power_on_cleanup; + if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) { + if (off) + WARN_ON(tegra_powergate_power_up(pg, true)); + + goto remove_resets; + } /* * FIXME: If XHCI is enabled for Tegra, then power-up the XUSB @@ -846,25 +856,33 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) * to be unused. */ if (IS_ENABLED(CONFIG_USB_XHCI_TEGRA) && - (id == TEGRA_POWERGATE_XUSBA || id == TEGRA_POWERGATE_XUSBC)) - goto power_on_cleanup; + (id == TEGRA_POWERGATE_XUSBA || id == TEGRA_POWERGATE_XUSBC)) { + if (off) + WARN_ON(tegra_powergate_power_up(pg, true)); + + goto remove_resets; + } - pm_genpd_init(&pg->genpd, NULL, off); + err = pm_genpd_init(&pg->genpd, NULL, off); + if (err < 0) { + pr_err("failed to initialise PM domain %s: %d\n", np->name, + err); + goto remove_resets; + } err = of_genpd_add_provider_simple(np, &pg->genpd); if (err < 0) { - dev_err(pmc->dev, "failed to add genpd provider for %s: %d\n", - np->name, err); - goto remove_resets; + pr_err("failed to add PM domain provider for %s: %d\n", + np->name, err); + goto remove_genpd; } - dev_dbg(pmc->dev, "added power domain %s\n", pg->genpd.name); + pr_debug("added PM domain %s\n", pg->genpd.name); return; -power_on_cleanup: - if (off) - WARN_ON(tegra_powergate_power_up(pg, true)); +remove_genpd: + pm_genpd_remove(&pg->genpd); remove_resets: while (pg->num_resets--) @@ -908,21 +926,36 @@ static void tegra_powergate_init(struct tegra_pmc *pmc, of_node_put(np); } -static int tegra_io_rail_prepare(unsigned int id, unsigned long *request, - unsigned long *status, unsigned int *bit) +static const struct tegra_io_pad_soc * +tegra_io_pad_find(struct tegra_pmc *pmc, enum tegra_io_pad id) { + unsigned int i; + + for (i = 0; i < pmc->soc->num_io_pads; i++) + if (pmc->soc->io_pads[i].id == id) + return &pmc->soc->io_pads[i]; + + return NULL; +} + +static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request, + unsigned long *status, u32 *mask) +{ + const struct tegra_io_pad_soc *pad; unsigned long rate, value; - *bit = id % 32; + pad = tegra_io_pad_find(pmc, id); + if (!pad) { + pr_err("invalid I/O pad ID %u\n", id); + return -ENOENT; + } - /* - * There are two sets of 30 bits to select IO rails, but bits 30 and - * 31 are control bits rather than IO rail selection bits. - */ - if (id > 63 || *bit == 30 || *bit == 31) - return -EINVAL; + if (pad->dpd == UINT_MAX) + return -ENOTSUPP; - if (id < 32) { + *mask = BIT(pad->dpd % 32); + + if (pad->dpd < 32) { *status = IO_DPD_STATUS; *request = IO_DPD_REQ; } else { @@ -931,6 +964,10 @@ static int tegra_io_rail_prepare(unsigned int id, unsigned long *request, } rate = clk_get_rate(pmc->clk); + if (!rate) { + pr_err("failed to get clock rate\n"); + return -ENODEV; + } tegra_pmc_writel(DPD_SAMPLE_ENABLE, DPD_SAMPLE); @@ -942,10 +979,10 @@ static int tegra_io_rail_prepare(unsigned int id, unsigned long *request, return 0; } -static int tegra_io_rail_poll(unsigned long offset, unsigned long mask, - unsigned long val, unsigned long timeout) +static int tegra_io_pad_poll(unsigned long offset, u32 mask, + u32 val, unsigned long timeout) { - unsigned long value; + u32 value; timeout = jiffies + msecs_to_jiffies(timeout); @@ -960,67 +997,164 @@ static int tegra_io_rail_poll(unsigned long offset, unsigned long mask, return -ETIMEDOUT; } -static void tegra_io_rail_unprepare(void) +static void tegra_io_pad_unprepare(void) { tegra_pmc_writel(DPD_SAMPLE_DISABLE, DPD_SAMPLE); } -int tegra_io_rail_power_on(unsigned int id) +/** + * 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) { unsigned long request, status; - unsigned int bit; + u32 mask; int err; mutex_lock(&pmc->powergates_lock); - err = tegra_io_rail_prepare(id, &request, &status, &bit); - if (err) - goto error; + err = tegra_io_pad_prepare(id, &request, &status, &mask); + if (err < 0) { + pr_err("failed to prepare I/O pad: %d\n", err); + goto unlock; + } - tegra_pmc_writel(IO_DPD_REQ_CODE_OFF | BIT(bit), request); + tegra_pmc_writel(IO_DPD_REQ_CODE_OFF | mask, request); - err = tegra_io_rail_poll(status, BIT(bit), 0, 250); - if (err) { - pr_info("tegra_io_rail_poll() failed: %d\n", err); - goto error; + err = tegra_io_pad_poll(status, mask, 0, 250); + if (err < 0) { + pr_err("failed to enable I/O pad: %d\n", err); + goto unlock; } - tegra_io_rail_unprepare(); + tegra_io_pad_unprepare(); -error: +unlock: mutex_unlock(&pmc->powergates_lock); - return err; } -EXPORT_SYMBOL(tegra_io_rail_power_on); +EXPORT_SYMBOL(tegra_io_pad_power_enable); -int tegra_io_rail_power_off(unsigned int id) +/** + * 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) { unsigned long request, status; - unsigned int bit; + u32 mask; int err; mutex_lock(&pmc->powergates_lock); - err = tegra_io_rail_prepare(id, &request, &status, &bit); - if (err) { - pr_info("tegra_io_rail_prepare() failed: %d\n", err); - goto error; + err = tegra_io_pad_prepare(id, &request, &status, &mask); + if (err < 0) { + pr_err("failed to prepare I/O pad: %d\n", err); + goto unlock; } - tegra_pmc_writel(IO_DPD_REQ_CODE_ON | BIT(bit), request); + tegra_pmc_writel(IO_DPD_REQ_CODE_ON | mask, request); - err = tegra_io_rail_poll(status, BIT(bit), BIT(bit), 250); - if (err) - goto error; + err = tegra_io_pad_poll(status, mask, mask, 250); + if (err < 0) { + pr_err("failed to disable I/O pad: %d\n", err); + goto unlock; + } - tegra_io_rail_unprepare(); + tegra_io_pad_unprepare(); -error: +unlock: mutex_unlock(&pmc->powergates_lock); - return err; } +EXPORT_SYMBOL(tegra_io_pad_power_disable); + +int tegra_io_pad_set_voltage(enum tegra_io_pad id, + enum tegra_io_pad_voltage voltage) +{ + const struct tegra_io_pad_soc *pad; + u32 value; + + pad = tegra_io_pad_find(pmc, id); + if (!pad) + return -ENOENT; + + if (pad->voltage == UINT_MAX) + return -ENOTSUPP; + + mutex_lock(&pmc->powergates_lock); + + /* write-enable PMC_PWR_DET_VALUE[pad->voltage] */ + value = tegra_pmc_readl(PMC_PWR_DET); + value |= BIT(pad->voltage); + tegra_pmc_writel(value, PMC_PWR_DET); + + /* update I/O voltage */ + value = tegra_pmc_readl(PMC_PWR_DET_VALUE); + + if (voltage == TEGRA_IO_PAD_1800000UV) + value &= ~BIT(pad->voltage); + else + value |= BIT(pad->voltage); + + tegra_pmc_writel(value, PMC_PWR_DET_VALUE); + + mutex_unlock(&pmc->powergates_lock); + + usleep_range(100, 250); + + return 0; +} +EXPORT_SYMBOL(tegra_io_pad_set_voltage); + +int tegra_io_pad_get_voltage(enum tegra_io_pad id) +{ + const struct tegra_io_pad_soc *pad; + u32 value; + + pad = tegra_io_pad_find(pmc, id); + if (!pad) + return -ENOENT; + + if (pad->voltage == UINT_MAX) + return -ENOTSUPP; + + value = tegra_pmc_readl(PMC_PWR_DET_VALUE); + + if ((value & BIT(pad->voltage)) == 0) + return TEGRA_IO_PAD_1800000UV; + + return TEGRA_IO_PAD_3300000UV; +} +EXPORT_SYMBOL(tegra_io_pad_get_voltage); + +/** + * tegra_io_rail_power_on() - enable power to I/O rail + * @id: Tegra I/O pad ID for which to enable power + * + * See also: tegra_io_pad_power_enable() + */ +int tegra_io_rail_power_on(unsigned int id) +{ + return tegra_io_pad_power_enable(id); +} +EXPORT_SYMBOL(tegra_io_rail_power_on); + +/** + * tegra_io_rail_power_off() - disable power to I/O rail + * @id: Tegra I/O pad ID for which to disable power + * + * See also: tegra_io_pad_power_disable() + */ +int tegra_io_rail_power_off(unsigned int id) +{ + return tegra_io_pad_power_disable(id); +} EXPORT_SYMBOL(tegra_io_rail_power_off); #ifdef CONFIG_PM_SLEEP @@ -1454,6 +1588,39 @@ static const u8 tegra124_cpu_powergates[] = { TEGRA_POWERGATE_CPU3, }; +static const struct tegra_io_pad_soc tegra124_io_pads[] = { + { .id = TEGRA_IO_PAD_AUDIO, .dpd = 17, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_BB, .dpd = 15, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CAM, .dpd = 36, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_COMP, .dpd = 22, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIA, .dpd = 0, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIB, .dpd = 1, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIE, .dpd = 44, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSI, .dpd = 2, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSIB, .dpd = 39, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSIC, .dpd = 40, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSID, .dpd = 41, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_HDMI, .dpd = 28, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_HSIC, .dpd = 19, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_HV, .dpd = 38, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_LVDS, .dpd = 57, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_MIPI_BIAS, .dpd = 3, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_NAND, .dpd = 13, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_BIAS, .dpd = 4, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK1, .dpd = 5, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 6, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CNTRL, .dpd = 32, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SDMMC1, .dpd = 33, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SDMMC3, .dpd = 34, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SDMMC4, .dpd = 35, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SYS_DDC, .dpd = 58, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_UART, .dpd = 14, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB0, .dpd = 9, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB1, .dpd = 10, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB2, .dpd = 11, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB_BIAS, .dpd = 12, .voltage = UINT_MAX }, +}; + static const struct tegra_pmc_soc tegra124_pmc_soc = { .num_powergates = ARRAY_SIZE(tegra124_powergates), .powergates = tegra124_powergates, @@ -1461,6 +1628,8 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { .cpu_powergates = tegra124_cpu_powergates, .has_tsense_reset = true, .has_gpu_clamps = true, + .num_io_pads = ARRAY_SIZE(tegra124_io_pads), + .io_pads = tegra124_io_pads, }; static const char * const tegra210_powergates[] = { @@ -1497,6 +1666,47 @@ static const u8 tegra210_cpu_powergates[] = { TEGRA_POWERGATE_CPU3, }; +static const struct tegra_io_pad_soc tegra210_io_pads[] = { + { .id = TEGRA_IO_PAD_AUDIO, .dpd = 17, .voltage = 5 }, + { .id = TEGRA_IO_PAD_AUDIO_HV, .dpd = 61, .voltage = 18 }, + { .id = TEGRA_IO_PAD_CAM, .dpd = 36, .voltage = 10 }, + { .id = TEGRA_IO_PAD_CSIA, .dpd = 0, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIB, .dpd = 1, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIC, .dpd = 42, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSID, .dpd = 43, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIE, .dpd = 44, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIF, .dpd = 45, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DBG, .dpd = 25, .voltage = 19 }, + { .id = TEGRA_IO_PAD_DEBUG_NONAO, .dpd = 26, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DMIC, .dpd = 50, .voltage = 20 }, + { .id = TEGRA_IO_PAD_DP, .dpd = 51, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSI, .dpd = 2, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSIB, .dpd = 39, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSIC, .dpd = 40, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSID, .dpd = 41, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_EMMC, .dpd = 35, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_EMMC2, .dpd = 37, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_GPIO, .dpd = 27, .voltage = 21 }, + { .id = TEGRA_IO_PAD_HDMI, .dpd = 28, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_HSIC, .dpd = 19, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_LVDS, .dpd = 57, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_MIPI_BIAS, .dpd = 3, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_BIAS, .dpd = 4, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK1, .dpd = 5, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 6, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CNTRL, .dpd = UINT_MAX, .voltage = 11 }, + { .id = TEGRA_IO_PAD_SDMMC1, .dpd = 33, .voltage = 12 }, + { .id = TEGRA_IO_PAD_SDMMC3, .dpd = 34, .voltage = 13 }, + { .id = TEGRA_IO_PAD_SPI, .dpd = 46, .voltage = 22 }, + { .id = TEGRA_IO_PAD_SPI_HV, .dpd = 47, .voltage = 23 }, + { .id = TEGRA_IO_PAD_UART, .dpd = 14, .voltage = 2 }, + { .id = TEGRA_IO_PAD_USB0, .dpd = 9, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB1, .dpd = 10, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB2, .dpd = 11, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB3, .dpd = 18, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB_BIAS, .dpd = 12, .voltage = UINT_MAX }, +}; + static const struct tegra_pmc_soc tegra210_pmc_soc = { .num_powergates = ARRAY_SIZE(tegra210_powergates), .powergates = tegra210_powergates, @@ -1504,6 +1714,8 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = { .cpu_powergates = tegra210_cpu_powergates, .has_tsense_reset = true, .has_gpu_clamps = true, + .num_io_pads = ARRAY_SIZE(tegra210_io_pads), + .io_pads = tegra210_io_pads, }; static const struct of_device_id tegra_pmc_match[] = { diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c index b73e3534f67b..eacad57f2977 100644 --- a/drivers/soc/ti/knav_qmss_queue.c +++ b/drivers/soc/ti/knav_qmss_queue.c @@ -1228,7 +1228,7 @@ static int knav_setup_queue_range(struct knav_device *kdev, range->num_irqs++; - if (oirq.args_count == 3) + if (IS_ENABLED(CONFIG_SMP) && oirq.args_count == 3) range->irqs[i].cpu_map = (oirq.args[2] & 0x0000ff00) >> 8; } diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c index 8823cc81ae45..5bb376009d98 100644 --- a/drivers/soc/ti/wkup_m3_ipc.c +++ b/drivers/soc/ti/wkup_m3_ipc.c @@ -459,6 +459,7 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev) if (IS_ERR(task)) { dev_err(dev, "can't create rproc_boot thread\n"); + ret = PTR_ERR(task); goto err_put_rproc; } |