3
0
Fork 0
forked from mirrors/linux

sophgo: add driver for CV18XX series

mailbox core: misc cleanup
 qcom: add SM7150 APCS compatible
       apcs: added separate clock node
 imx: fix tx doorbell send
 microchip: misc compile option fix
 mediatek: Refine GCE_GCTL_VALUE setting
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE6EwehDt/SOnwFyTyf9lkf8eYP5UFAmg80Z0ACgkQf9lkf8eY
 P5UxZRAAkhDmxsKaX+8DWYSY5Au0Ng61z4FgLXecJvrT30AVlPZPMiVcgUuZ4FiU
 GBhP/8FvKD/raPpB+Os2bCND69mP+5wj4qDZBI4Tl9BOsTaxShpB85BhQLBkMaFW
 2Ec7U/fQPWb3HPPkztthjVKqghE3pVuEM9NRjZgUmqVzU1GLcFAEqYVi3GQBkBZU
 IKRFBOlYsSbnrUQwtA5JSKin75urXAba0zZs1r2Hy1jRmI2kIC/LSFnWzbjkMneq
 FY/Se5prYF6XhTWjuYVA0RCTXrhcA9PsfclslNKbCfPBupMLAz3fEyZMZ0vKlb6T
 nW/5gcux9XxkmQoT7PkukuYQ1zmeBjB2UBo91Z4yGIEV/73wkocpDNfOhDWpnNiZ
 UOmGXkQINjDQMZUPkdMo17qb1sUtziblAWfuhF2Q7IdTlHn1lf1WGqru+pJzikAM
 M/jIyHcSBcMsoo4FzhnAsvK7qOrMVvIAnWY+tkfuS0miVXKAL/MohnkdIvb0qgiY
 1nXKgwaCui50zBMpbVWVZ5wHvRXAQypgGcmaUDasNMH1tFTZiv4g7wDnynOHicGH
 HBzb/CxvjfS0RE9DNRchTXWQjGzJ+9uFCgwpmof60ra7V9WWTH3lLgydy7Tl87VZ
 L0POMD89zyTNab5HmseEnz/A707/o8wpOG9W8m6cjU35fKKdcSs=
 =4FbM
 -----END PGP SIGNATURE-----

Merge tag 'mailbox-v6.16' of git://git.kernel.org/pub/scm/linux/kernel/git/jassibrar/mailbox

Pull mailbox updates from Jassi Brar:
 "Core:
   - misc cleanup

  sophgo:
   - add driver for CV18XX series

  qcom:
   - add SM7150 APCS compatible
   - apcs: added separate clock node

  imx:
   - fix tx doorbell send

  microchip:
   - misc compile option fix

  mediatek:
   - Refine GCE_GCTL_VALUE setting"

* tag 'mailbox-v6.16' of git://git.kernel.org/pub/scm/linux/kernel/git/jassibrar/mailbox:
  mailbox: qcom-apcs-ipc: Assign OF node to clock controller child device
  dt-bindings: mailbox: qcom,apcs: Add separate node for clock-controller
  dt-bindings: mailbox: qcom: Add the SM7150 APCS compatible
  mailbox: sophgo: add mailbox driver for CV18XX series SoC
  dt-bindings: mailbox: add Sophgo CV18XX series SoC
  mailbox: Use guard/scoped_guard for spinlock
  mailbox: Use guard/scoped_guard for con_mutex
  mailbox: Remove devm_mbox_controller_unregister
  mailbox: Propagate correct error return value
  mailbox: Not protect module_put with spin_lock_irqsave
  mailbox: Use dev_err when there is error
  mailbox: mtk-cmdq: Refine GCE_GCTL_VALUE setting
  mailbox: imx: Fix TXDB_V2 sending
  mailbox: mchp-ipc-sbi: Fix COMPILE_TEST build error
This commit is contained in:
Linus Torvalds 2025-06-02 10:58:00 -07:00
commit a060795111
10 changed files with 536 additions and 220 deletions

View file

@ -49,6 +49,7 @@ properties:
- qcom,qcs615-apss-shared
- qcom,sc7180-apss-shared
- qcom,sc8180x-apss-shared
- qcom,sm7150-apss-shared
- qcom,sm8150-apss-shared
- const: qcom,sdm845-apss-shared
- items:
@ -72,6 +73,7 @@ properties:
description: phandles to the parent clocks of the clock driver
minItems: 2
maxItems: 3
deprecated: true
'#mbox-cells':
const: 1
@ -82,6 +84,23 @@ properties:
clock-names:
minItems: 2
maxItems: 3
deprecated: true
clock-controller:
type: object
additionalProperties: false
properties:
clocks:
description: phandles to the parent clocks of the clock driver
minItems: 2
maxItems: 3
'#clock-cells':
enum: [0, 1]
clock-names:
minItems: 2
maxItems: 3
required:
- compatible
@ -90,6 +109,76 @@ required:
additionalProperties: false
# Clocks should be specified either on the parent node or on the child node
oneOf:
- required:
- clock-controller
properties:
clocks: false
clock-names: false
'#clock-cells': false
- properties:
clock-controller: false
$defs:
msm8916-apcs-clock-controller:
properties:
clocks:
items:
- description: primary pll parent of the clock driver
- description: auxiliary parent
clock-names:
items:
- const: pll
- const: aux
'#clock-cells':
const: 0
msm8939-apcs-clock-controller:
properties:
clocks:
items:
- description: primary pll parent of the clock driver
- description: auxiliary parent
- description: reference clock
clock-names:
items:
- const: pll
- const: aux
- const: ref
'#clock-cells':
const: 0
sdx55-apcs-clock-controller:
properties:
clocks:
items:
- description: reference clock
- description: primary pll parent of the clock driver
- description: auxiliary parent
clock-names:
items:
- const: ref
- const: pll
- const: aux
'#clock-cells':
const: 0
ipq6018-apcs-clock-controller:
properties:
clocks:
items:
- description: primary pll parent of the clock driver
- description: XO clock
- description: GCC GPLL0 clock source
clock-names:
items:
- const: pll
- const: xo
- const: gpll0
'#clock-cells':
const: 1
allOf:
- if:
properties:
@ -98,15 +187,10 @@ allOf:
enum:
- qcom,msm8916-apcs-kpss-global
then:
$ref: "#/$defs/msm8916-apcs-clock-controller"
properties:
clocks:
items:
- description: primary pll parent of the clock driver
- description: auxiliary parent
clock-names:
items:
- const: pll
- const: aux
clock-controller:
$ref: "#/$defs/msm8916-apcs-clock-controller"
- if:
properties:
@ -115,17 +199,10 @@ allOf:
enum:
- qcom,msm8939-apcs-kpss-global
then:
$ref: "#/$defs/msm8939-apcs-clock-controller"
properties:
clocks:
items:
- description: primary pll parent of the clock driver
- description: auxiliary parent
- description: reference clock
clock-names:
items:
- const: pll
- const: aux
- const: ref
clock-controller:
$ref: "#/$defs/msm8939-apcs-clock-controller"
- if:
properties:
@ -134,17 +211,10 @@ allOf:
enum:
- qcom,sdx55-apcs-gcc
then:
$ref: "#/$defs/sdx55-apcs-clock-controller"
properties:
clocks:
items:
- description: reference clock
- description: primary pll parent of the clock driver
- description: auxiliary parent
clock-names:
items:
- const: ref
- const: pll
- const: aux
clock-controller:
$ref: "#/$defs/sdx55-apcs-clock-controller"
- if:
properties:
@ -153,17 +223,10 @@ allOf:
enum:
- qcom,ipq6018-apcs-apps-global
then:
$ref: "#/$defs/ipq6018-apcs-clock-controller"
properties:
clocks:
items:
- description: primary pll parent of the clock driver
- description: XO clock
- description: GCC GPLL0 clock source
clock-names:
items:
- const: pll
- const: xo
- const: gpll0
clock-controller:
$ref: "#/$defs/ipq6018-apcs-clock-controller"
- if:
properties:
@ -179,19 +242,7 @@ allOf:
properties:
clocks: false
clock-names: false
- if:
properties:
compatible:
contains:
enum:
- qcom,ipq6018-apcs-apps-global
then:
properties:
'#clock-cells':
const: 1
else:
properties:
clock-controller: false
'#clock-cells':
const: 0
@ -216,6 +267,23 @@ examples:
};
# Example apcs with qcs404
- |
#define GCC_APSS_AHB_CLK_SRC 1
#define GCC_GPLL0_AO_OUT_MAIN 123
mailbox@b011000 {
compatible = "qcom,qcs404-apcs-apps-global",
"qcom,msm8916-apcs-kpss-global", "syscon";
reg = <0x0b011000 0x1000>;
#mbox-cells = <1>;
apcs_clk: clock-controller {
clocks = <&apcs_hfpll>, <&gcc GCC_GPLL0_AO_OUT_MAIN>;
clock-names = "pll", "aux";
#clock-cells = <0>;
};
};
# Example apcs with qcs404 (deprecated: use clock-controller subnode)
- |
#define GCC_APSS_AHB_CLK_SRC 1
#define GCC_GPLL0_AO_OUT_MAIN 123

View file

@ -0,0 +1,60 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mailbox/sophgo,cv1800b-mailbox.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Sophgo CV1800/SG2000 mailbox controller
maintainers:
- Yuntao Dai <d1581209858@live.com>
- Junhui Liu <junhui.liu@pigmoral.tech>
description:
Mailboxes integrated in Sophgo CV1800/SG2000 SoCs have 8 channels, each
shipping an 8-byte FIFO. Any processor can write to an arbitrary channel
and raise interrupts to receivers. Sending messages to itself is also
supported.
properties:
compatible:
const: sophgo,cv1800b-mailbox
reg:
maxItems: 1
interrupts:
maxItems: 1
"#mbox-cells":
const: 2
description: |
<&phandle channel target>
phandle : Label name of mailbox controller
channel : 0-7, Channel index
target : 0-3, Target processor ID
Sophgo CV1800/SG2000 SoCs include the following processors, numbered as:
<0> Cortex-A53 (Only available on CV181X/SG200X)
<1> C906B
<2> C906L
<3> 8051
required:
- compatible
- reg
- interrupts
- "#mbox-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
mailbox@1900000 {
compatible = "sophgo,cv1800b-mailbox";
reg = <0x01900000 0x1000>;
interrupts = <101 IRQ_TYPE_LEVEL_HIGH>;
#mbox-cells = <2>;
};

View file

@ -36,6 +36,16 @@ config ARM_MHU_V3
that provides different means of transports: supported extensions
will be discovered and possibly managed at probe-time.
config CV1800_MBOX
tristate "cv1800 mailbox"
depends on ARCH_SOPHGO || COMPILE_TEST
help
Mailbox driver implementation for Sophgo CV18XX SoCs. This driver
can be used to send message between different processors in SoC. Any
processer can write data in a channel, and set co-responding register
to raise interrupt to notice another processor, and it is allowed to
send data to itself.
config EXYNOS_MBOX
tristate "Exynos Mailbox"
depends on ARCH_EXYNOS || COMPILE_TEST
@ -191,8 +201,8 @@ config POLARFIRE_SOC_MAILBOX
config MCHP_SBI_IPC_MBOX
tristate "Microchip Inter-processor Communication (IPC) SBI driver"
depends on RISCV_SBI || COMPILE_TEST
depends on ARCH_MICROCHIP
depends on RISCV_SBI
depends on ARCH_MICROCHIP || COMPILE_TEST
help
Mailbox implementation for Microchip devices with an
Inter-process communication (IPC) controller.

View file

@ -11,6 +11,8 @@ obj-$(CONFIG_ARM_MHU_V2) += arm_mhuv2.o
obj-$(CONFIG_ARM_MHU_V3) += arm_mhuv3.o
obj-$(CONFIG_CV1800_MBOX) += cv1800-mailbox.o
obj-$(CONFIG_EXYNOS_MBOX) += exynos-mailbox.o
obj-$(CONFIG_IMX_MBOX) += imx-mailbox.o

View file

@ -0,0 +1,220 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2024 Sophgo Technology Inc.
* Copyright (C) 2024 Yuntao Dai <d1581209858@live.com>
* Copyright (C) 2025 Junhui Liu <junhui.liu@pigmoral.tech>
*/
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kfifo.h>
#include <linux/mailbox_client.h>
#include <linux/mailbox_controller.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#define RECV_CPU 1
#define MAILBOX_MAX_CHAN 8
#define MAILBOX_MSG_LEN 8
#define MBOX_EN_REG(cpu) (cpu << 2)
#define MBOX_DONE_REG(cpu) ((cpu << 2) + 2)
#define MBOX_SET_CLR_REG(cpu) (0x10 + (cpu << 4))
#define MBOX_SET_INT_REG(cpu) (0x18 + (cpu << 4))
#define MBOX_SET_REG 0x60
#define MAILBOX_CONTEXT_OFFSET 0x0400
#define MAILBOX_CONTEXT_SIZE 0x0040
#define MBOX_CONTEXT_BASE_INDEX(base, index) \
((u64 __iomem *)(base + MAILBOX_CONTEXT_OFFSET) + index)
/**
* struct cv1800_mbox_chan_priv - cv1800 mailbox channel private data
* @idx: index of channel
* @cpu: send to which processor
*/
struct cv1800_mbox_chan_priv {
int idx;
int cpu;
};
struct cv1800_mbox {
struct mbox_controller mbox;
struct cv1800_mbox_chan_priv priv[MAILBOX_MAX_CHAN];
struct mbox_chan chans[MAILBOX_MAX_CHAN];
u64 __iomem *content[MAILBOX_MAX_CHAN];
void __iomem *mbox_base;
int recvid;
};
static irqreturn_t cv1800_mbox_isr(int irq, void *dev_id)
{
struct cv1800_mbox *mbox = (struct cv1800_mbox *)dev_id;
size_t i;
u64 msg;
int ret = IRQ_NONE;
for (i = 0; i < MAILBOX_MAX_CHAN; i++) {
if (mbox->content[i] && mbox->chans[i].cl) {
memcpy_fromio(&msg, mbox->content[i], MAILBOX_MSG_LEN);
mbox->content[i] = NULL;
mbox_chan_received_data(&mbox->chans[i], (void *)&msg);
ret = IRQ_HANDLED;
}
}
return ret;
}
static irqreturn_t cv1800_mbox_irq(int irq, void *dev_id)
{
struct cv1800_mbox *mbox = (struct cv1800_mbox *)dev_id;
u8 set, valid;
size_t i;
int ret = IRQ_NONE;
set = readb(mbox->mbox_base + MBOX_SET_INT_REG(RECV_CPU));
if (!set)
return ret;
for (i = 0; i < MAILBOX_MAX_CHAN; i++) {
valid = set & BIT(i);
if (valid) {
mbox->content[i] =
MBOX_CONTEXT_BASE_INDEX(mbox->mbox_base, i);
writeb(valid, mbox->mbox_base +
MBOX_SET_CLR_REG(RECV_CPU));
writeb(~valid, mbox->mbox_base + MBOX_EN_REG(RECV_CPU));
ret = IRQ_WAKE_THREAD;
}
}
return ret;
}
static int cv1800_mbox_send_data(struct mbox_chan *chan, void *data)
{
struct cv1800_mbox_chan_priv *priv =
(struct cv1800_mbox_chan_priv *)chan->con_priv;
struct cv1800_mbox *mbox = dev_get_drvdata(chan->mbox->dev);
int idx = priv->idx;
int cpu = priv->cpu;
u8 en, valid;
memcpy_toio(MBOX_CONTEXT_BASE_INDEX(mbox->mbox_base, idx),
data, MAILBOX_MSG_LEN);
valid = BIT(idx);
writeb(valid, mbox->mbox_base + MBOX_SET_CLR_REG(cpu));
en = readb(mbox->mbox_base + MBOX_EN_REG(cpu));
writeb(en | valid, mbox->mbox_base + MBOX_EN_REG(cpu));
writeb(valid, mbox->mbox_base + MBOX_SET_REG);
return 0;
}
static bool cv1800_last_tx_done(struct mbox_chan *chan)
{
struct cv1800_mbox_chan_priv *priv =
(struct cv1800_mbox_chan_priv *)chan->con_priv;
struct cv1800_mbox *mbox = dev_get_drvdata(chan->mbox->dev);
u8 en;
en = readb(mbox->mbox_base + MBOX_EN_REG(priv->cpu));
return !(en & BIT(priv->idx));
}
static const struct mbox_chan_ops cv1800_mbox_chan_ops = {
.send_data = cv1800_mbox_send_data,
.last_tx_done = cv1800_last_tx_done,
};
static struct mbox_chan *cv1800_mbox_xlate(struct mbox_controller *mbox,
const struct of_phandle_args *spec)
{
struct cv1800_mbox_chan_priv *priv;
int idx = spec->args[0];
int cpu = spec->args[1];
if (idx >= mbox->num_chans)
return ERR_PTR(-EINVAL);
priv = mbox->chans[idx].con_priv;
priv->cpu = cpu;
return &mbox->chans[idx];
}
static const struct of_device_id cv1800_mbox_of_match[] = {
{ .compatible = "sophgo,cv1800b-mailbox", },
{},
};
MODULE_DEVICE_TABLE(of, cv1800_mbox_of_match);
static int cv1800_mbox_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct cv1800_mbox *mb;
int irq, idx, err;
mb = devm_kzalloc(dev, sizeof(*mb), GFP_KERNEL);
if (!mb)
return -ENOMEM;
mb->mbox_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(mb->mbox_base))
return dev_err_probe(dev, PTR_ERR(mb->mbox_base),
"Failed to map resource\n");
mb->mbox.dev = dev;
mb->mbox.chans = mb->chans;
mb->mbox.txdone_poll = true;
mb->mbox.ops = &cv1800_mbox_chan_ops;
mb->mbox.num_chans = MAILBOX_MAX_CHAN;
mb->mbox.of_xlate = cv1800_mbox_xlate;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
err = devm_request_threaded_irq(dev, irq, cv1800_mbox_irq,
cv1800_mbox_isr, IRQF_ONESHOT,
dev_name(&pdev->dev), mb);
if (err < 0)
return dev_err_probe(dev, err, "Failed to register irq\n");
for (idx = 0; idx < MAILBOX_MAX_CHAN; idx++) {
mb->priv[idx].idx = idx;
mb->mbox.chans[idx].con_priv = &mb->priv[idx];
}
platform_set_drvdata(pdev, mb);
err = devm_mbox_controller_register(dev, &mb->mbox);
if (err)
return dev_err_probe(dev, err, "Failed to register mailbox\n");
return 0;
}
static struct platform_driver cv1800_mbox_driver = {
.driver = {
.name = "cv1800-mbox",
.of_match_table = cv1800_mbox_of_match,
},
.probe = cv1800_mbox_probe,
};
module_platform_driver(cv1800_mbox_driver);
MODULE_DESCRIPTION("cv1800 mailbox driver");
MODULE_LICENSE("GPL");

View file

@ -226,7 +226,7 @@ static int imx_mu_generic_tx(struct imx_mu_priv *priv,
{
u32 *arg = data;
u32 val;
int ret;
int ret, count;
switch (cp->type) {
case IMX_MU_TYPE_TX:
@ -240,11 +240,20 @@ static int imx_mu_generic_tx(struct imx_mu_priv *priv,
case IMX_MU_TYPE_TXDB_V2:
imx_mu_write(priv, IMX_MU_xCR_GIRn(priv->dcfg->type, cp->idx),
priv->dcfg->xCR[IMX_MU_GCR]);
ret = readl_poll_timeout(priv->base + priv->dcfg->xCR[IMX_MU_GCR], val,
!(val & IMX_MU_xCR_GIRn(priv->dcfg->type, cp->idx)),
0, 1000);
if (ret)
dev_warn_ratelimited(priv->dev, "channel type: %d failure\n", cp->type);
ret = -ETIMEDOUT;
count = 0;
while (ret && (count < 10)) {
ret =
readl_poll_timeout(priv->base + priv->dcfg->xCR[IMX_MU_GCR], val,
!(val & IMX_MU_xCR_GIRn(priv->dcfg->type, cp->idx)),
0, 10000);
if (ret) {
dev_warn_ratelimited(priv->dev,
"channel type: %d timeout, %d times, retry\n",
cp->type, ++count);
}
}
break;
default:
dev_warn_ratelimited(priv->dev, "Send data on wrong channel type: %d\n", cp->type);

View file

@ -6,6 +6,7 @@
* Author: Jassi Brar <jassisinghbrar@gmail.com>
*/
#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
@ -24,15 +25,12 @@ static DEFINE_MUTEX(con_mutex);
static int add_to_rbuf(struct mbox_chan *chan, void *mssg)
{
int idx;
unsigned long flags;
spin_lock_irqsave(&chan->lock, flags);
guard(spinlock_irqsave)(&chan->lock);
/* See if there is any space left */
if (chan->msg_count == MBOX_TX_QUEUE_LEN) {
spin_unlock_irqrestore(&chan->lock, flags);
if (chan->msg_count == MBOX_TX_QUEUE_LEN)
return -ENOBUFS;
}
idx = chan->msg_free;
chan->msg_data[idx] = mssg;
@ -43,60 +41,53 @@ static int add_to_rbuf(struct mbox_chan *chan, void *mssg)
else
chan->msg_free++;
spin_unlock_irqrestore(&chan->lock, flags);
return idx;
}
static void msg_submit(struct mbox_chan *chan)
{
unsigned count, idx;
unsigned long flags;
void *data;
int err = -EBUSY;
spin_lock_irqsave(&chan->lock, flags);
scoped_guard(spinlock_irqsave, &chan->lock) {
if (!chan->msg_count || chan->active_req)
break;
if (!chan->msg_count || chan->active_req)
goto exit;
count = chan->msg_count;
idx = chan->msg_free;
if (idx >= count)
idx -= count;
else
idx += MBOX_TX_QUEUE_LEN - count;
count = chan->msg_count;
idx = chan->msg_free;
if (idx >= count)
idx -= count;
else
idx += MBOX_TX_QUEUE_LEN - count;
data = chan->msg_data[idx];
data = chan->msg_data[idx];
if (chan->cl->tx_prepare)
chan->cl->tx_prepare(chan->cl, data);
/* Try to submit a message to the MBOX controller */
err = chan->mbox->ops->send_data(chan, data);
if (!err) {
chan->active_req = data;
chan->msg_count--;
if (chan->cl->tx_prepare)
chan->cl->tx_prepare(chan->cl, data);
/* Try to submit a message to the MBOX controller */
err = chan->mbox->ops->send_data(chan, data);
if (!err) {
chan->active_req = data;
chan->msg_count--;
}
}
exit:
spin_unlock_irqrestore(&chan->lock, flags);
if (!err && (chan->txdone_method & TXDONE_BY_POLL)) {
/* kick start the timer immediately to avoid delays */
spin_lock_irqsave(&chan->mbox->poll_hrt_lock, flags);
hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);
spin_unlock_irqrestore(&chan->mbox->poll_hrt_lock, flags);
scoped_guard(spinlock_irqsave, &chan->mbox->poll_hrt_lock)
hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);
}
}
static void tx_tick(struct mbox_chan *chan, int r)
{
unsigned long flags;
void *mssg;
spin_lock_irqsave(&chan->lock, flags);
mssg = chan->active_req;
chan->active_req = NULL;
spin_unlock_irqrestore(&chan->lock, flags);
scoped_guard(spinlock_irqsave, &chan->lock) {
mssg = chan->active_req;
chan->active_req = NULL;
}
/* Submit next message */
msg_submit(chan);
@ -118,7 +109,6 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer)
container_of(hrtimer, struct mbox_controller, poll_hrt);
bool txdone, resched = false;
int i;
unsigned long flags;
for (i = 0; i < mbox->num_chans; i++) {
struct mbox_chan *chan = &mbox->chans[i];
@ -133,10 +123,10 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer)
}
if (resched) {
spin_lock_irqsave(&mbox->poll_hrt_lock, flags);
if (!hrtimer_is_queued(hrtimer))
hrtimer_forward_now(hrtimer, ms_to_ktime(mbox->txpoll_period));
spin_unlock_irqrestore(&mbox->poll_hrt_lock, flags);
scoped_guard(spinlock_irqsave, &mbox->poll_hrt_lock) {
if (!hrtimer_is_queued(hrtimer))
hrtimer_forward_now(hrtimer, ms_to_ktime(mbox->txpoll_period));
}
return HRTIMER_RESTART;
}
@ -318,25 +308,23 @@ EXPORT_SYMBOL_GPL(mbox_flush);
static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl)
{
struct device *dev = cl->dev;
unsigned long flags;
int ret;
if (chan->cl || !try_module_get(chan->mbox->dev->driver->owner)) {
dev_dbg(dev, "%s: mailbox not free\n", __func__);
dev_err(dev, "%s: mailbox not free\n", __func__);
return -EBUSY;
}
spin_lock_irqsave(&chan->lock, flags);
chan->msg_free = 0;
chan->msg_count = 0;
chan->active_req = NULL;
chan->cl = cl;
init_completion(&chan->tx_complete);
scoped_guard(spinlock_irqsave, &chan->lock) {
chan->msg_free = 0;
chan->msg_count = 0;
chan->active_req = NULL;
chan->cl = cl;
init_completion(&chan->tx_complete);
if (chan->txdone_method == TXDONE_BY_POLL && cl->knows_txdone)
chan->txdone_method = TXDONE_BY_ACK;
spin_unlock_irqrestore(&chan->lock, flags);
if (chan->txdone_method == TXDONE_BY_POLL && cl->knows_txdone)
chan->txdone_method = TXDONE_BY_ACK;
}
if (chan->mbox->ops->startup) {
ret = chan->mbox->ops->startup(chan);
@ -370,13 +358,9 @@ static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl)
*/
int mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl)
{
int ret;
guard(mutex)(&con_mutex);
mutex_lock(&con_mutex);
ret = __mbox_bind_client(chan, cl);
mutex_unlock(&con_mutex);
return ret;
return __mbox_bind_client(chan, cl);
}
EXPORT_SYMBOL_GPL(mbox_bind_client);
@ -413,32 +397,29 @@ struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index)
ret = of_parse_phandle_with_args(dev->of_node, "mboxes", "#mbox-cells",
index, &spec);
if (ret) {
dev_dbg(dev, "%s: can't parse \"mboxes\" property\n", __func__);
dev_err(dev, "%s: can't parse \"mboxes\" property\n", __func__);
return ERR_PTR(ret);
}
mutex_lock(&con_mutex);
scoped_guard(mutex, &con_mutex) {
chan = ERR_PTR(-EPROBE_DEFER);
list_for_each_entry(mbox, &mbox_cons, node)
if (mbox->dev->of_node == spec.np) {
chan = mbox->of_xlate(mbox, &spec);
if (!IS_ERR(chan))
break;
}
chan = ERR_PTR(-EPROBE_DEFER);
list_for_each_entry(mbox, &mbox_cons, node)
if (mbox->dev->of_node == spec.np) {
chan = mbox->of_xlate(mbox, &spec);
if (!IS_ERR(chan))
break;
}
of_node_put(spec.np);
of_node_put(spec.np);
if (IS_ERR(chan))
return chan;
if (IS_ERR(chan)) {
mutex_unlock(&con_mutex);
return chan;
ret = __mbox_bind_client(chan, cl);
if (ret)
chan = ERR_PTR(ret);
}
ret = __mbox_bind_client(chan, cl);
if (ret)
chan = ERR_PTR(ret);
mutex_unlock(&con_mutex);
return chan;
}
EXPORT_SYMBOL_GPL(mbox_request_channel);
@ -458,7 +439,7 @@ struct mbox_chan *mbox_request_channel_byname(struct mbox_client *cl,
if (index < 0) {
dev_err(cl->dev, "%s() could not locate channel named \"%s\"\n",
__func__, name);
return ERR_PTR(-EINVAL);
return ERR_PTR(index);
}
return mbox_request_channel(cl, index);
}
@ -471,8 +452,6 @@ EXPORT_SYMBOL_GPL(mbox_request_channel_byname);
*/
void mbox_free_channel(struct mbox_chan *chan)
{
unsigned long flags;
if (!chan || !chan->cl)
return;
@ -480,14 +459,14 @@ void mbox_free_channel(struct mbox_chan *chan)
chan->mbox->ops->shutdown(chan);
/* The queued TX requests are simply aborted, no callbacks are made */
spin_lock_irqsave(&chan->lock, flags);
chan->cl = NULL;
chan->active_req = NULL;
if (chan->txdone_method == TXDONE_BY_ACK)
chan->txdone_method = TXDONE_BY_POLL;
scoped_guard(spinlock_irqsave, &chan->lock) {
chan->cl = NULL;
chan->active_req = NULL;
if (chan->txdone_method == TXDONE_BY_ACK)
chan->txdone_method = TXDONE_BY_POLL;
}
module_put(chan->mbox->dev->driver->owner);
spin_unlock_irqrestore(&chan->lock, flags);
}
EXPORT_SYMBOL_GPL(mbox_free_channel);
@ -547,9 +526,8 @@ int mbox_controller_register(struct mbox_controller *mbox)
if (!mbox->of_xlate)
mbox->of_xlate = of_mbox_index_xlate;
mutex_lock(&con_mutex);
list_add_tail(&mbox->node, &mbox_cons);
mutex_unlock(&con_mutex);
scoped_guard(mutex, &con_mutex)
list_add_tail(&mbox->node, &mbox_cons);
return 0;
}
@ -566,17 +544,15 @@ void mbox_controller_unregister(struct mbox_controller *mbox)
if (!mbox)
return;
mutex_lock(&con_mutex);
scoped_guard(mutex, &con_mutex) {
list_del(&mbox->node);
list_del(&mbox->node);
for (i = 0; i < mbox->num_chans; i++)
mbox_free_channel(&mbox->chans[i]);
for (i = 0; i < mbox->num_chans; i++)
mbox_free_channel(&mbox->chans[i]);
if (mbox->txdone_poll)
hrtimer_cancel(&mbox->poll_hrt);
mutex_unlock(&con_mutex);
if (mbox->txdone_poll)
hrtimer_cancel(&mbox->poll_hrt);
}
}
EXPORT_SYMBOL_GPL(mbox_controller_unregister);
@ -587,16 +563,6 @@ static void __devm_mbox_controller_unregister(struct device *dev, void *res)
mbox_controller_unregister(*mbox);
}
static int devm_mbox_controller_match(struct device *dev, void *res, void *data)
{
struct mbox_controller **mbox = res;
if (WARN_ON(!mbox || !*mbox))
return 0;
return *mbox == data;
}
/**
* devm_mbox_controller_register() - managed mbox_controller_register()
* @dev: device owning the mailbox controller being registered
@ -632,20 +598,3 @@ int devm_mbox_controller_register(struct device *dev,
return 0;
}
EXPORT_SYMBOL_GPL(devm_mbox_controller_register);
/**
* devm_mbox_controller_unregister() - managed mbox_controller_unregister()
* @dev: device owning the mailbox controller being unregistered
* @mbox: mailbox controller being unregistered
*
* This function unregisters the mailbox controller and removes the device-
* managed resource that was set up to automatically unregister the mailbox
* controller on driver probe failure or driver removal. It's typically not
* necessary to call this function.
*/
void devm_mbox_controller_unregister(struct device *dev, struct mbox_controller *mbox)
{
WARN_ON(devres_release(dev, __devm_mbox_controller_unregister,
devm_mbox_controller_match, mbox));
}
EXPORT_SYMBOL_GPL(devm_mbox_controller_unregister);

View file

@ -92,18 +92,6 @@ struct gce_plat {
u32 gce_num;
};
static void cmdq_sw_ddr_enable(struct cmdq *cmdq, bool enable)
{
WARN_ON(clk_bulk_enable(cmdq->pdata->gce_num, cmdq->clocks));
if (enable)
writel(GCE_DDR_EN | GCE_CTRL_BY_SW, cmdq->base + GCE_GCTL_VALUE);
else
writel(GCE_CTRL_BY_SW, cmdq->base + GCE_GCTL_VALUE);
clk_bulk_disable(cmdq->pdata->gce_num, cmdq->clocks);
}
u8 cmdq_get_shift_pa(struct mbox_chan *chan)
{
struct cmdq *cmdq = container_of(chan->mbox, struct cmdq, mbox);
@ -112,6 +100,19 @@ u8 cmdq_get_shift_pa(struct mbox_chan *chan)
}
EXPORT_SYMBOL(cmdq_get_shift_pa);
static void cmdq_gctl_value_toggle(struct cmdq *cmdq, bool ddr_enable)
{
u32 val = cmdq->pdata->control_by_sw ? GCE_CTRL_BY_SW : 0;
if (!cmdq->pdata->control_by_sw && !cmdq->pdata->sw_ddr_en)
return;
if (cmdq->pdata->sw_ddr_en && ddr_enable)
val |= GCE_DDR_EN;
writel(val, cmdq->base + GCE_GCTL_VALUE);
}
static int cmdq_thread_suspend(struct cmdq *cmdq, struct cmdq_thread *thread)
{
u32 status;
@ -140,16 +141,10 @@ static void cmdq_thread_resume(struct cmdq_thread *thread)
static void cmdq_init(struct cmdq *cmdq)
{
int i;
u32 gctl_regval = 0;
WARN_ON(clk_bulk_enable(cmdq->pdata->gce_num, cmdq->clocks));
if (cmdq->pdata->control_by_sw)
gctl_regval = GCE_CTRL_BY_SW;
if (cmdq->pdata->sw_ddr_en)
gctl_regval |= GCE_DDR_EN;
if (gctl_regval)
writel(gctl_regval, cmdq->base + GCE_GCTL_VALUE);
cmdq_gctl_value_toggle(cmdq, true);
writel(CMDQ_THR_ACTIVE_SLOT_CYCLES, cmdq->base + CMDQ_THR_SLOT_CYCLES);
for (i = 0; i <= CMDQ_MAX_EVENT; i++)
@ -315,14 +310,21 @@ static irqreturn_t cmdq_irq_handler(int irq, void *dev)
static int cmdq_runtime_resume(struct device *dev)
{
struct cmdq *cmdq = dev_get_drvdata(dev);
int ret;
return clk_bulk_enable(cmdq->pdata->gce_num, cmdq->clocks);
ret = clk_bulk_enable(cmdq->pdata->gce_num, cmdq->clocks);
if (ret)
return ret;
cmdq_gctl_value_toggle(cmdq, true);
return 0;
}
static int cmdq_runtime_suspend(struct device *dev)
{
struct cmdq *cmdq = dev_get_drvdata(dev);
cmdq_gctl_value_toggle(cmdq, false);
clk_bulk_disable(cmdq->pdata->gce_num, cmdq->clocks);
return 0;
}
@ -347,9 +349,6 @@ static int cmdq_suspend(struct device *dev)
if (task_running)
dev_warn(dev, "exist running task(s) in suspend\n");
if (cmdq->pdata->sw_ddr_en)
cmdq_sw_ddr_enable(cmdq, false);
return pm_runtime_force_suspend(dev);
}
@ -360,9 +359,6 @@ static int cmdq_resume(struct device *dev)
WARN_ON(pm_runtime_force_resume(dev));
cmdq->suspended = false;
if (cmdq->pdata->sw_ddr_en)
cmdq_sw_ddr_enable(cmdq, true);
return 0;
}
@ -370,9 +366,6 @@ static void cmdq_remove(struct platform_device *pdev)
{
struct cmdq *cmdq = platform_get_drvdata(pdev);
if (cmdq->pdata->sw_ddr_en)
cmdq_sw_ddr_enable(cmdq, false);
if (!IS_ENABLED(CONFIG_PM))
cmdq_runtime_suspend(&pdev->dev);

View file

@ -116,10 +116,18 @@ static int qcom_apcs_ipc_probe(struct platform_device *pdev)
}
if (apcs_data->clk_name) {
apcs->clk = platform_device_register_data(&pdev->dev,
apcs_data->clk_name,
PLATFORM_DEVID_AUTO,
NULL, 0);
struct device_node *np = of_get_child_by_name(pdev->dev.of_node,
"clock-controller");
struct platform_device_info pdevinfo = {
.parent = &pdev->dev,
.name = apcs_data->clk_name,
.id = PLATFORM_DEVID_AUTO,
.fwnode = of_fwnode_handle(np) ?: pdev->dev.fwnode,
.of_node_reused = !np,
};
apcs->clk = platform_device_register_full(&pdevinfo);
of_node_put(np);
if (IS_ERR(apcs->clk))
dev_err(&pdev->dev, "failed to register APCS clk\n");
}

View file

@ -134,7 +134,4 @@ void mbox_chan_txdone(struct mbox_chan *chan, int r); /* atomic */
int devm_mbox_controller_register(struct device *dev,
struct mbox_controller *mbox);
void devm_mbox_controller_unregister(struct device *dev,
struct mbox_controller *mbox);
#endif /* __MAILBOX_CONTROLLER_H */