Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+536 -220
+119 -51
Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml
··· 49 49 - qcom,qcs615-apss-shared 50 50 - qcom,sc7180-apss-shared 51 51 - qcom,sc8180x-apss-shared 52 + - qcom,sm7150-apss-shared 52 53 - qcom,sm8150-apss-shared 53 54 - const: qcom,sdm845-apss-shared 54 55 - items: ··· 73 72 description: phandles to the parent clocks of the clock driver 74 73 minItems: 2 75 74 maxItems: 3 75 + deprecated: true 76 76 77 77 '#mbox-cells': 78 78 const: 1 ··· 84 82 clock-names: 85 83 minItems: 2 86 84 maxItems: 3 85 + deprecated: true 86 + 87 + clock-controller: 88 + type: object 89 + additionalProperties: false 90 + properties: 91 + clocks: 92 + description: phandles to the parent clocks of the clock driver 93 + minItems: 2 94 + maxItems: 3 95 + 96 + '#clock-cells': 97 + enum: [0, 1] 98 + 99 + clock-names: 100 + minItems: 2 101 + maxItems: 3 87 102 88 103 required: 89 104 - compatible ··· 108 89 - '#mbox-cells' 109 90 110 91 additionalProperties: false 92 + 93 + # Clocks should be specified either on the parent node or on the child node 94 + oneOf: 95 + - required: 96 + - clock-controller 97 + properties: 98 + clocks: false 99 + clock-names: false 100 + '#clock-cells': false 101 + - properties: 102 + clock-controller: false 103 + 104 + $defs: 105 + msm8916-apcs-clock-controller: 106 + properties: 107 + clocks: 108 + items: 109 + - description: primary pll parent of the clock driver 110 + - description: auxiliary parent 111 + clock-names: 112 + items: 113 + - const: pll 114 + - const: aux 115 + '#clock-cells': 116 + const: 0 117 + 118 + msm8939-apcs-clock-controller: 119 + properties: 120 + clocks: 121 + items: 122 + - description: primary pll parent of the clock driver 123 + - description: auxiliary parent 124 + - description: reference clock 125 + clock-names: 126 + items: 127 + - const: pll 128 + - const: aux 129 + - const: ref 130 + '#clock-cells': 131 + const: 0 132 + 133 + sdx55-apcs-clock-controller: 134 + properties: 135 + clocks: 136 + items: 137 + - description: reference clock 138 + - description: primary pll parent of the clock driver 139 + - description: auxiliary parent 140 + clock-names: 141 + items: 142 + - const: ref 143 + - const: pll 144 + - const: aux 145 + '#clock-cells': 146 + const: 0 147 + 148 + ipq6018-apcs-clock-controller: 149 + properties: 150 + clocks: 151 + items: 152 + - description: primary pll parent of the clock driver 153 + - description: XO clock 154 + - description: GCC GPLL0 clock source 155 + clock-names: 156 + items: 157 + - const: pll 158 + - const: xo 159 + - const: gpll0 160 + '#clock-cells': 161 + const: 1 111 162 112 163 allOf: 113 164 - if: ··· 187 98 enum: 188 99 - qcom,msm8916-apcs-kpss-global 189 100 then: 101 + $ref: "#/$defs/msm8916-apcs-clock-controller" 190 102 properties: 191 - clocks: 192 - items: 193 - - description: primary pll parent of the clock driver 194 - - description: auxiliary parent 195 - clock-names: 196 - items: 197 - - const: pll 198 - - const: aux 103 + clock-controller: 104 + $ref: "#/$defs/msm8916-apcs-clock-controller" 199 105 200 106 - if: 201 107 properties: ··· 199 115 enum: 200 116 - qcom,msm8939-apcs-kpss-global 201 117 then: 118 + $ref: "#/$defs/msm8939-apcs-clock-controller" 202 119 properties: 203 - clocks: 204 - items: 205 - - description: primary pll parent of the clock driver 206 - - description: auxiliary parent 207 - - description: reference clock 208 - clock-names: 209 - items: 210 - - const: pll 211 - - const: aux 212 - - const: ref 120 + clock-controller: 121 + $ref: "#/$defs/msm8939-apcs-clock-controller" 213 122 214 123 - if: 215 124 properties: ··· 211 134 enum: 212 135 - qcom,sdx55-apcs-gcc 213 136 then: 137 + $ref: "#/$defs/sdx55-apcs-clock-controller" 214 138 properties: 215 - clocks: 216 - items: 217 - - description: reference clock 218 - - description: primary pll parent of the clock driver 219 - - description: auxiliary parent 220 - clock-names: 221 - items: 222 - - const: ref 223 - - const: pll 224 - - const: aux 139 + clock-controller: 140 + $ref: "#/$defs/sdx55-apcs-clock-controller" 225 141 226 142 - if: 227 143 properties: ··· 223 153 enum: 224 154 - qcom,ipq6018-apcs-apps-global 225 155 then: 156 + $ref: "#/$defs/ipq6018-apcs-clock-controller" 226 157 properties: 227 - clocks: 228 - items: 229 - - description: primary pll parent of the clock driver 230 - - description: XO clock 231 - - description: GCC GPLL0 clock source 232 - clock-names: 233 - items: 234 - - const: pll 235 - - const: xo 236 - - const: gpll0 158 + clock-controller: 159 + $ref: "#/$defs/ipq6018-apcs-clock-controller" 237 160 238 161 - if: 239 162 properties: ··· 242 179 properties: 243 180 clocks: false 244 181 clock-names: false 245 - 246 - - if: 247 - properties: 248 - compatible: 249 - contains: 250 - enum: 251 - - qcom,ipq6018-apcs-apps-global 252 - then: 253 - properties: 254 - '#clock-cells': 255 - const: 1 256 - else: 257 - properties: 182 + clock-controller: false 258 183 '#clock-cells': 259 184 const: 0 260 185 ··· 267 216 }; 268 217 269 218 # Example apcs with qcs404 219 + - | 220 + #define GCC_APSS_AHB_CLK_SRC 1 221 + #define GCC_GPLL0_AO_OUT_MAIN 123 222 + mailbox@b011000 { 223 + compatible = "qcom,qcs404-apcs-apps-global", 224 + "qcom,msm8916-apcs-kpss-global", "syscon"; 225 + reg = <0x0b011000 0x1000>; 226 + #mbox-cells = <1>; 227 + 228 + apcs_clk: clock-controller { 229 + clocks = <&apcs_hfpll>, <&gcc GCC_GPLL0_AO_OUT_MAIN>; 230 + clock-names = "pll", "aux"; 231 + #clock-cells = <0>; 232 + }; 233 + }; 234 + 235 + # Example apcs with qcs404 (deprecated: use clock-controller subnode) 270 236 - | 271 237 #define GCC_APSS_AHB_CLK_SRC 1 272 238 #define GCC_GPLL0_AO_OUT_MAIN 123
+60
Documentation/devicetree/bindings/mailbox/sophgo,cv1800b-mailbox.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/mailbox/sophgo,cv1800b-mailbox.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Sophgo CV1800/SG2000 mailbox controller 8 + 9 + maintainers: 10 + - Yuntao Dai <d1581209858@live.com> 11 + - Junhui Liu <junhui.liu@pigmoral.tech> 12 + 13 + description: 14 + Mailboxes integrated in Sophgo CV1800/SG2000 SoCs have 8 channels, each 15 + shipping an 8-byte FIFO. Any processor can write to an arbitrary channel 16 + and raise interrupts to receivers. Sending messages to itself is also 17 + supported. 18 + 19 + properties: 20 + compatible: 21 + const: sophgo,cv1800b-mailbox 22 + 23 + reg: 24 + maxItems: 1 25 + 26 + interrupts: 27 + maxItems: 1 28 + 29 + "#mbox-cells": 30 + const: 2 31 + description: | 32 + <&phandle channel target> 33 + phandle : Label name of mailbox controller 34 + channel : 0-7, Channel index 35 + target : 0-3, Target processor ID 36 + 37 + Sophgo CV1800/SG2000 SoCs include the following processors, numbered as: 38 + <0> Cortex-A53 (Only available on CV181X/SG200X) 39 + <1> C906B 40 + <2> C906L 41 + <3> 8051 42 + 43 + required: 44 + - compatible 45 + - reg 46 + - interrupts 47 + - "#mbox-cells" 48 + 49 + additionalProperties: false 50 + 51 + examples: 52 + - | 53 + #include <dt-bindings/interrupt-controller/irq.h> 54 + 55 + mailbox@1900000 { 56 + compatible = "sophgo,cv1800b-mailbox"; 57 + reg = <0x01900000 0x1000>; 58 + interrupts = <101 IRQ_TYPE_LEVEL_HIGH>; 59 + #mbox-cells = <2>; 60 + };
+12 -2
drivers/mailbox/Kconfig
··· 36 36 that provides different means of transports: supported extensions 37 37 will be discovered and possibly managed at probe-time. 38 38 39 + config CV1800_MBOX 40 + tristate "cv1800 mailbox" 41 + depends on ARCH_SOPHGO || COMPILE_TEST 42 + help 43 + Mailbox driver implementation for Sophgo CV18XX SoCs. This driver 44 + can be used to send message between different processors in SoC. Any 45 + processer can write data in a channel, and set co-responding register 46 + to raise interrupt to notice another processor, and it is allowed to 47 + send data to itself. 48 + 39 49 config EXYNOS_MBOX 40 50 tristate "Exynos Mailbox" 41 51 depends on ARCH_EXYNOS || COMPILE_TEST ··· 201 191 202 192 config MCHP_SBI_IPC_MBOX 203 193 tristate "Microchip Inter-processor Communication (IPC) SBI driver" 204 - depends on RISCV_SBI || COMPILE_TEST 205 - depends on ARCH_MICROCHIP 194 + depends on RISCV_SBI 195 + depends on ARCH_MICROCHIP || COMPILE_TEST 206 196 help 207 197 Mailbox implementation for Microchip devices with an 208 198 Inter-process communication (IPC) controller.
+2
drivers/mailbox/Makefile
··· 11 11 12 12 obj-$(CONFIG_ARM_MHU_V3) += arm_mhuv3.o 13 13 14 + obj-$(CONFIG_CV1800_MBOX) += cv1800-mailbox.o 15 + 14 16 obj-$(CONFIG_EXYNOS_MBOX) += exynos-mailbox.o 15 17 16 18 obj-$(CONFIG_IMX_MBOX) += imx-mailbox.o
+220
drivers/mailbox/cv1800-mailbox.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Copyright (C) 2024 Sophgo Technology Inc. 4 + * Copyright (C) 2024 Yuntao Dai <d1581209858@live.com> 5 + * Copyright (C) 2025 Junhui Liu <junhui.liu@pigmoral.tech> 6 + */ 7 + 8 + #include <linux/bits.h> 9 + #include <linux/device.h> 10 + #include <linux/err.h> 11 + #include <linux/interrupt.h> 12 + #include <linux/io.h> 13 + #include <linux/kfifo.h> 14 + #include <linux/mailbox_client.h> 15 + #include <linux/mailbox_controller.h> 16 + #include <linux/module.h> 17 + #include <linux/platform_device.h> 18 + #include <linux/slab.h> 19 + 20 + #define RECV_CPU 1 21 + 22 + #define MAILBOX_MAX_CHAN 8 23 + #define MAILBOX_MSG_LEN 8 24 + 25 + #define MBOX_EN_REG(cpu) (cpu << 2) 26 + #define MBOX_DONE_REG(cpu) ((cpu << 2) + 2) 27 + #define MBOX_SET_CLR_REG(cpu) (0x10 + (cpu << 4)) 28 + #define MBOX_SET_INT_REG(cpu) (0x18 + (cpu << 4)) 29 + #define MBOX_SET_REG 0x60 30 + 31 + #define MAILBOX_CONTEXT_OFFSET 0x0400 32 + #define MAILBOX_CONTEXT_SIZE 0x0040 33 + 34 + #define MBOX_CONTEXT_BASE_INDEX(base, index) \ 35 + ((u64 __iomem *)(base + MAILBOX_CONTEXT_OFFSET) + index) 36 + 37 + /** 38 + * struct cv1800_mbox_chan_priv - cv1800 mailbox channel private data 39 + * @idx: index of channel 40 + * @cpu: send to which processor 41 + */ 42 + struct cv1800_mbox_chan_priv { 43 + int idx; 44 + int cpu; 45 + }; 46 + 47 + struct cv1800_mbox { 48 + struct mbox_controller mbox; 49 + struct cv1800_mbox_chan_priv priv[MAILBOX_MAX_CHAN]; 50 + struct mbox_chan chans[MAILBOX_MAX_CHAN]; 51 + u64 __iomem *content[MAILBOX_MAX_CHAN]; 52 + void __iomem *mbox_base; 53 + int recvid; 54 + }; 55 + 56 + static irqreturn_t cv1800_mbox_isr(int irq, void *dev_id) 57 + { 58 + struct cv1800_mbox *mbox = (struct cv1800_mbox *)dev_id; 59 + size_t i; 60 + u64 msg; 61 + int ret = IRQ_NONE; 62 + 63 + for (i = 0; i < MAILBOX_MAX_CHAN; i++) { 64 + if (mbox->content[i] && mbox->chans[i].cl) { 65 + memcpy_fromio(&msg, mbox->content[i], MAILBOX_MSG_LEN); 66 + mbox->content[i] = NULL; 67 + mbox_chan_received_data(&mbox->chans[i], (void *)&msg); 68 + ret = IRQ_HANDLED; 69 + } 70 + } 71 + 72 + return ret; 73 + } 74 + 75 + static irqreturn_t cv1800_mbox_irq(int irq, void *dev_id) 76 + { 77 + struct cv1800_mbox *mbox = (struct cv1800_mbox *)dev_id; 78 + u8 set, valid; 79 + size_t i; 80 + int ret = IRQ_NONE; 81 + 82 + set = readb(mbox->mbox_base + MBOX_SET_INT_REG(RECV_CPU)); 83 + 84 + if (!set) 85 + return ret; 86 + 87 + for (i = 0; i < MAILBOX_MAX_CHAN; i++) { 88 + valid = set & BIT(i); 89 + if (valid) { 90 + mbox->content[i] = 91 + MBOX_CONTEXT_BASE_INDEX(mbox->mbox_base, i); 92 + writeb(valid, mbox->mbox_base + 93 + MBOX_SET_CLR_REG(RECV_CPU)); 94 + writeb(~valid, mbox->mbox_base + MBOX_EN_REG(RECV_CPU)); 95 + ret = IRQ_WAKE_THREAD; 96 + } 97 + } 98 + 99 + return ret; 100 + } 101 + 102 + static int cv1800_mbox_send_data(struct mbox_chan *chan, void *data) 103 + { 104 + struct cv1800_mbox_chan_priv *priv = 105 + (struct cv1800_mbox_chan_priv *)chan->con_priv; 106 + struct cv1800_mbox *mbox = dev_get_drvdata(chan->mbox->dev); 107 + int idx = priv->idx; 108 + int cpu = priv->cpu; 109 + u8 en, valid; 110 + 111 + memcpy_toio(MBOX_CONTEXT_BASE_INDEX(mbox->mbox_base, idx), 112 + data, MAILBOX_MSG_LEN); 113 + 114 + valid = BIT(idx); 115 + writeb(valid, mbox->mbox_base + MBOX_SET_CLR_REG(cpu)); 116 + en = readb(mbox->mbox_base + MBOX_EN_REG(cpu)); 117 + writeb(en | valid, mbox->mbox_base + MBOX_EN_REG(cpu)); 118 + writeb(valid, mbox->mbox_base + MBOX_SET_REG); 119 + 120 + return 0; 121 + } 122 + 123 + static bool cv1800_last_tx_done(struct mbox_chan *chan) 124 + { 125 + struct cv1800_mbox_chan_priv *priv = 126 + (struct cv1800_mbox_chan_priv *)chan->con_priv; 127 + struct cv1800_mbox *mbox = dev_get_drvdata(chan->mbox->dev); 128 + u8 en; 129 + 130 + en = readb(mbox->mbox_base + MBOX_EN_REG(priv->cpu)); 131 + 132 + return !(en & BIT(priv->idx)); 133 + } 134 + 135 + static const struct mbox_chan_ops cv1800_mbox_chan_ops = { 136 + .send_data = cv1800_mbox_send_data, 137 + .last_tx_done = cv1800_last_tx_done, 138 + }; 139 + 140 + static struct mbox_chan *cv1800_mbox_xlate(struct mbox_controller *mbox, 141 + const struct of_phandle_args *spec) 142 + { 143 + struct cv1800_mbox_chan_priv *priv; 144 + 145 + int idx = spec->args[0]; 146 + int cpu = spec->args[1]; 147 + 148 + if (idx >= mbox->num_chans) 149 + return ERR_PTR(-EINVAL); 150 + 151 + priv = mbox->chans[idx].con_priv; 152 + priv->cpu = cpu; 153 + 154 + return &mbox->chans[idx]; 155 + } 156 + 157 + static const struct of_device_id cv1800_mbox_of_match[] = { 158 + { .compatible = "sophgo,cv1800b-mailbox", }, 159 + {}, 160 + }; 161 + MODULE_DEVICE_TABLE(of, cv1800_mbox_of_match); 162 + 163 + static int cv1800_mbox_probe(struct platform_device *pdev) 164 + { 165 + struct device *dev = &pdev->dev; 166 + struct cv1800_mbox *mb; 167 + int irq, idx, err; 168 + 169 + mb = devm_kzalloc(dev, sizeof(*mb), GFP_KERNEL); 170 + if (!mb) 171 + return -ENOMEM; 172 + 173 + mb->mbox_base = devm_platform_ioremap_resource(pdev, 0); 174 + if (IS_ERR(mb->mbox_base)) 175 + return dev_err_probe(dev, PTR_ERR(mb->mbox_base), 176 + "Failed to map resource\n"); 177 + 178 + mb->mbox.dev = dev; 179 + mb->mbox.chans = mb->chans; 180 + mb->mbox.txdone_poll = true; 181 + mb->mbox.ops = &cv1800_mbox_chan_ops; 182 + mb->mbox.num_chans = MAILBOX_MAX_CHAN; 183 + mb->mbox.of_xlate = cv1800_mbox_xlate; 184 + 185 + irq = platform_get_irq(pdev, 0); 186 + if (irq < 0) 187 + return irq; 188 + 189 + err = devm_request_threaded_irq(dev, irq, cv1800_mbox_irq, 190 + cv1800_mbox_isr, IRQF_ONESHOT, 191 + dev_name(&pdev->dev), mb); 192 + if (err < 0) 193 + return dev_err_probe(dev, err, "Failed to register irq\n"); 194 + 195 + for (idx = 0; idx < MAILBOX_MAX_CHAN; idx++) { 196 + mb->priv[idx].idx = idx; 197 + mb->mbox.chans[idx].con_priv = &mb->priv[idx]; 198 + } 199 + 200 + platform_set_drvdata(pdev, mb); 201 + 202 + err = devm_mbox_controller_register(dev, &mb->mbox); 203 + if (err) 204 + return dev_err_probe(dev, err, "Failed to register mailbox\n"); 205 + 206 + return 0; 207 + } 208 + 209 + static struct platform_driver cv1800_mbox_driver = { 210 + .driver = { 211 + .name = "cv1800-mbox", 212 + .of_match_table = cv1800_mbox_of_match, 213 + }, 214 + .probe = cv1800_mbox_probe, 215 + }; 216 + 217 + module_platform_driver(cv1800_mbox_driver); 218 + 219 + MODULE_DESCRIPTION("cv1800 mailbox driver"); 220 + MODULE_LICENSE("GPL");
+15 -6
drivers/mailbox/imx-mailbox.c
··· 226 226 { 227 227 u32 *arg = data; 228 228 u32 val; 229 - int ret; 229 + int ret, count; 230 230 231 231 switch (cp->type) { 232 232 case IMX_MU_TYPE_TX: ··· 240 240 case IMX_MU_TYPE_TXDB_V2: 241 241 imx_mu_write(priv, IMX_MU_xCR_GIRn(priv->dcfg->type, cp->idx), 242 242 priv->dcfg->xCR[IMX_MU_GCR]); 243 - ret = readl_poll_timeout(priv->base + priv->dcfg->xCR[IMX_MU_GCR], val, 244 - !(val & IMX_MU_xCR_GIRn(priv->dcfg->type, cp->idx)), 245 - 0, 1000); 246 - if (ret) 247 - dev_warn_ratelimited(priv->dev, "channel type: %d failure\n", cp->type); 243 + ret = -ETIMEDOUT; 244 + count = 0; 245 + while (ret && (count < 10)) { 246 + ret = 247 + readl_poll_timeout(priv->base + priv->dcfg->xCR[IMX_MU_GCR], val, 248 + !(val & IMX_MU_xCR_GIRn(priv->dcfg->type, cp->idx)), 249 + 0, 10000); 250 + 251 + if (ret) { 252 + dev_warn_ratelimited(priv->dev, 253 + "channel type: %d timeout, %d times, retry\n", 254 + cp->type, ++count); 255 + } 256 + } 248 257 break; 249 258 default: 250 259 dev_warn_ratelimited(priv->dev, "Send data on wrong channel type: %d\n", cp->type);
+74 -125
drivers/mailbox/mailbox.c
··· 6 6 * Author: Jassi Brar <jassisinghbrar@gmail.com> 7 7 */ 8 8 9 + #include <linux/cleanup.h> 9 10 #include <linux/delay.h> 10 11 #include <linux/device.h> 11 12 #include <linux/err.h> ··· 25 24 static int add_to_rbuf(struct mbox_chan *chan, void *mssg) 26 25 { 27 26 int idx; 28 - unsigned long flags; 29 27 30 - spin_lock_irqsave(&chan->lock, flags); 28 + guard(spinlock_irqsave)(&chan->lock); 31 29 32 30 /* See if there is any space left */ 33 - if (chan->msg_count == MBOX_TX_QUEUE_LEN) { 34 - spin_unlock_irqrestore(&chan->lock, flags); 31 + if (chan->msg_count == MBOX_TX_QUEUE_LEN) 35 32 return -ENOBUFS; 36 - } 37 33 38 34 idx = chan->msg_free; 39 35 chan->msg_data[idx] = mssg; ··· 41 43 else 42 44 chan->msg_free++; 43 45 44 - spin_unlock_irqrestore(&chan->lock, flags); 45 - 46 46 return idx; 47 47 } 48 48 49 49 static void msg_submit(struct mbox_chan *chan) 50 50 { 51 51 unsigned count, idx; 52 - unsigned long flags; 53 52 void *data; 54 53 int err = -EBUSY; 55 54 56 - spin_lock_irqsave(&chan->lock, flags); 55 + scoped_guard(spinlock_irqsave, &chan->lock) { 56 + if (!chan->msg_count || chan->active_req) 57 + break; 57 58 58 - if (!chan->msg_count || chan->active_req) 59 - goto exit; 59 + count = chan->msg_count; 60 + idx = chan->msg_free; 61 + if (idx >= count) 62 + idx -= count; 63 + else 64 + idx += MBOX_TX_QUEUE_LEN - count; 60 65 61 - count = chan->msg_count; 62 - idx = chan->msg_free; 63 - if (idx >= count) 64 - idx -= count; 65 - else 66 - idx += MBOX_TX_QUEUE_LEN - count; 66 + data = chan->msg_data[idx]; 67 67 68 - data = chan->msg_data[idx]; 69 - 70 - if (chan->cl->tx_prepare) 71 - chan->cl->tx_prepare(chan->cl, data); 72 - /* Try to submit a message to the MBOX controller */ 73 - err = chan->mbox->ops->send_data(chan, data); 74 - if (!err) { 75 - chan->active_req = data; 76 - chan->msg_count--; 68 + if (chan->cl->tx_prepare) 69 + chan->cl->tx_prepare(chan->cl, data); 70 + /* Try to submit a message to the MBOX controller */ 71 + err = chan->mbox->ops->send_data(chan, data); 72 + if (!err) { 73 + chan->active_req = data; 74 + chan->msg_count--; 75 + } 77 76 } 78 - exit: 79 - spin_unlock_irqrestore(&chan->lock, flags); 80 77 81 78 if (!err && (chan->txdone_method & TXDONE_BY_POLL)) { 82 79 /* kick start the timer immediately to avoid delays */ 83 - spin_lock_irqsave(&chan->mbox->poll_hrt_lock, flags); 84 - hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL); 85 - spin_unlock_irqrestore(&chan->mbox->poll_hrt_lock, flags); 80 + scoped_guard(spinlock_irqsave, &chan->mbox->poll_hrt_lock) 81 + hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL); 86 82 } 87 83 } 88 84 89 85 static void tx_tick(struct mbox_chan *chan, int r) 90 86 { 91 - unsigned long flags; 92 87 void *mssg; 93 88 94 - spin_lock_irqsave(&chan->lock, flags); 95 - mssg = chan->active_req; 96 - chan->active_req = NULL; 97 - spin_unlock_irqrestore(&chan->lock, flags); 89 + scoped_guard(spinlock_irqsave, &chan->lock) { 90 + mssg = chan->active_req; 91 + chan->active_req = NULL; 92 + } 98 93 99 94 /* Submit next message */ 100 95 msg_submit(chan); ··· 109 118 container_of(hrtimer, struct mbox_controller, poll_hrt); 110 119 bool txdone, resched = false; 111 120 int i; 112 - unsigned long flags; 113 121 114 122 for (i = 0; i < mbox->num_chans; i++) { 115 123 struct mbox_chan *chan = &mbox->chans[i]; ··· 123 133 } 124 134 125 135 if (resched) { 126 - spin_lock_irqsave(&mbox->poll_hrt_lock, flags); 127 - if (!hrtimer_is_queued(hrtimer)) 128 - hrtimer_forward_now(hrtimer, ms_to_ktime(mbox->txpoll_period)); 129 - spin_unlock_irqrestore(&mbox->poll_hrt_lock, flags); 136 + scoped_guard(spinlock_irqsave, &mbox->poll_hrt_lock) { 137 + if (!hrtimer_is_queued(hrtimer)) 138 + hrtimer_forward_now(hrtimer, ms_to_ktime(mbox->txpoll_period)); 139 + } 130 140 131 141 return HRTIMER_RESTART; 132 142 } ··· 308 318 static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl) 309 319 { 310 320 struct device *dev = cl->dev; 311 - unsigned long flags; 312 321 int ret; 313 322 314 323 if (chan->cl || !try_module_get(chan->mbox->dev->driver->owner)) { 315 - dev_dbg(dev, "%s: mailbox not free\n", __func__); 324 + dev_err(dev, "%s: mailbox not free\n", __func__); 316 325 return -EBUSY; 317 326 } 318 327 319 - spin_lock_irqsave(&chan->lock, flags); 320 - chan->msg_free = 0; 321 - chan->msg_count = 0; 322 - chan->active_req = NULL; 323 - chan->cl = cl; 324 - init_completion(&chan->tx_complete); 328 + scoped_guard(spinlock_irqsave, &chan->lock) { 329 + chan->msg_free = 0; 330 + chan->msg_count = 0; 331 + chan->active_req = NULL; 332 + chan->cl = cl; 333 + init_completion(&chan->tx_complete); 325 334 326 - if (chan->txdone_method == TXDONE_BY_POLL && cl->knows_txdone) 327 - chan->txdone_method = TXDONE_BY_ACK; 328 - 329 - spin_unlock_irqrestore(&chan->lock, flags); 335 + if (chan->txdone_method == TXDONE_BY_POLL && cl->knows_txdone) 336 + chan->txdone_method = TXDONE_BY_ACK; 337 + } 330 338 331 339 if (chan->mbox->ops->startup) { 332 340 ret = chan->mbox->ops->startup(chan); ··· 358 370 */ 359 371 int mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl) 360 372 { 361 - int ret; 373 + guard(mutex)(&con_mutex); 362 374 363 - mutex_lock(&con_mutex); 364 - ret = __mbox_bind_client(chan, cl); 365 - mutex_unlock(&con_mutex); 366 - 367 - return ret; 375 + return __mbox_bind_client(chan, cl); 368 376 } 369 377 EXPORT_SYMBOL_GPL(mbox_bind_client); 370 378 ··· 397 413 ret = of_parse_phandle_with_args(dev->of_node, "mboxes", "#mbox-cells", 398 414 index, &spec); 399 415 if (ret) { 400 - dev_dbg(dev, "%s: can't parse \"mboxes\" property\n", __func__); 416 + dev_err(dev, "%s: can't parse \"mboxes\" property\n", __func__); 401 417 return ERR_PTR(ret); 402 418 } 403 419 404 - mutex_lock(&con_mutex); 420 + scoped_guard(mutex, &con_mutex) { 421 + chan = ERR_PTR(-EPROBE_DEFER); 422 + list_for_each_entry(mbox, &mbox_cons, node) 423 + if (mbox->dev->of_node == spec.np) { 424 + chan = mbox->of_xlate(mbox, &spec); 425 + if (!IS_ERR(chan)) 426 + break; 427 + } 405 428 406 - chan = ERR_PTR(-EPROBE_DEFER); 407 - list_for_each_entry(mbox, &mbox_cons, node) 408 - if (mbox->dev->of_node == spec.np) { 409 - chan = mbox->of_xlate(mbox, &spec); 410 - if (!IS_ERR(chan)) 411 - break; 412 - } 429 + of_node_put(spec.np); 413 430 414 - of_node_put(spec.np); 431 + if (IS_ERR(chan)) 432 + return chan; 415 433 416 - if (IS_ERR(chan)) { 417 - mutex_unlock(&con_mutex); 418 - return chan; 434 + ret = __mbox_bind_client(chan, cl); 435 + if (ret) 436 + chan = ERR_PTR(ret); 419 437 } 420 438 421 - ret = __mbox_bind_client(chan, cl); 422 - if (ret) 423 - chan = ERR_PTR(ret); 424 - 425 - mutex_unlock(&con_mutex); 426 439 return chan; 427 440 } 428 441 EXPORT_SYMBOL_GPL(mbox_request_channel); ··· 439 458 if (index < 0) { 440 459 dev_err(cl->dev, "%s() could not locate channel named \"%s\"\n", 441 460 __func__, name); 442 - return ERR_PTR(-EINVAL); 461 + return ERR_PTR(index); 443 462 } 444 463 return mbox_request_channel(cl, index); 445 464 } ··· 452 471 */ 453 472 void mbox_free_channel(struct mbox_chan *chan) 454 473 { 455 - unsigned long flags; 456 - 457 474 if (!chan || !chan->cl) 458 475 return; 459 476 ··· 459 480 chan->mbox->ops->shutdown(chan); 460 481 461 482 /* The queued TX requests are simply aborted, no callbacks are made */ 462 - spin_lock_irqsave(&chan->lock, flags); 463 - chan->cl = NULL; 464 - chan->active_req = NULL; 465 - if (chan->txdone_method == TXDONE_BY_ACK) 466 - chan->txdone_method = TXDONE_BY_POLL; 483 + scoped_guard(spinlock_irqsave, &chan->lock) { 484 + chan->cl = NULL; 485 + chan->active_req = NULL; 486 + if (chan->txdone_method == TXDONE_BY_ACK) 487 + chan->txdone_method = TXDONE_BY_POLL; 488 + } 467 489 468 490 module_put(chan->mbox->dev->driver->owner); 469 - spin_unlock_irqrestore(&chan->lock, flags); 470 491 } 471 492 EXPORT_SYMBOL_GPL(mbox_free_channel); 472 493 ··· 526 547 if (!mbox->of_xlate) 527 548 mbox->of_xlate = of_mbox_index_xlate; 528 549 529 - mutex_lock(&con_mutex); 530 - list_add_tail(&mbox->node, &mbox_cons); 531 - mutex_unlock(&con_mutex); 550 + scoped_guard(mutex, &con_mutex) 551 + list_add_tail(&mbox->node, &mbox_cons); 532 552 533 553 return 0; 534 554 } ··· 544 566 if (!mbox) 545 567 return; 546 568 547 - mutex_lock(&con_mutex); 569 + scoped_guard(mutex, &con_mutex) { 570 + list_del(&mbox->node); 548 571 549 - list_del(&mbox->node); 572 + for (i = 0; i < mbox->num_chans; i++) 573 + mbox_free_channel(&mbox->chans[i]); 550 574 551 - for (i = 0; i < mbox->num_chans; i++) 552 - mbox_free_channel(&mbox->chans[i]); 553 - 554 - if (mbox->txdone_poll) 555 - hrtimer_cancel(&mbox->poll_hrt); 556 - 557 - mutex_unlock(&con_mutex); 575 + if (mbox->txdone_poll) 576 + hrtimer_cancel(&mbox->poll_hrt); 577 + } 558 578 } 559 579 EXPORT_SYMBOL_GPL(mbox_controller_unregister); 560 580 ··· 561 585 struct mbox_controller **mbox = res; 562 586 563 587 mbox_controller_unregister(*mbox); 564 - } 565 - 566 - static int devm_mbox_controller_match(struct device *dev, void *res, void *data) 567 - { 568 - struct mbox_controller **mbox = res; 569 - 570 - if (WARN_ON(!mbox || !*mbox)) 571 - return 0; 572 - 573 - return *mbox == data; 574 588 } 575 589 576 590 /** ··· 598 632 return 0; 599 633 } 600 634 EXPORT_SYMBOL_GPL(devm_mbox_controller_register); 601 - 602 - /** 603 - * devm_mbox_controller_unregister() - managed mbox_controller_unregister() 604 - * @dev: device owning the mailbox controller being unregistered 605 - * @mbox: mailbox controller being unregistered 606 - * 607 - * This function unregisters the mailbox controller and removes the device- 608 - * managed resource that was set up to automatically unregister the mailbox 609 - * controller on driver probe failure or driver removal. It's typically not 610 - * necessary to call this function. 611 - */ 612 - void devm_mbox_controller_unregister(struct device *dev, struct mbox_controller *mbox) 613 - { 614 - WARN_ON(devres_release(dev, __devm_mbox_controller_unregister, 615 - devm_mbox_controller_match, mbox)); 616 - } 617 - EXPORT_SYMBOL_GPL(devm_mbox_controller_unregister);
+22 -29
drivers/mailbox/mtk-cmdq-mailbox.c
··· 92 92 u32 gce_num; 93 93 }; 94 94 95 - static void cmdq_sw_ddr_enable(struct cmdq *cmdq, bool enable) 96 - { 97 - WARN_ON(clk_bulk_enable(cmdq->pdata->gce_num, cmdq->clocks)); 98 - 99 - if (enable) 100 - writel(GCE_DDR_EN | GCE_CTRL_BY_SW, cmdq->base + GCE_GCTL_VALUE); 101 - else 102 - writel(GCE_CTRL_BY_SW, cmdq->base + GCE_GCTL_VALUE); 103 - 104 - clk_bulk_disable(cmdq->pdata->gce_num, cmdq->clocks); 105 - } 106 - 107 95 u8 cmdq_get_shift_pa(struct mbox_chan *chan) 108 96 { 109 97 struct cmdq *cmdq = container_of(chan->mbox, struct cmdq, mbox); ··· 99 111 return cmdq->pdata->shift; 100 112 } 101 113 EXPORT_SYMBOL(cmdq_get_shift_pa); 114 + 115 + static void cmdq_gctl_value_toggle(struct cmdq *cmdq, bool ddr_enable) 116 + { 117 + u32 val = cmdq->pdata->control_by_sw ? GCE_CTRL_BY_SW : 0; 118 + 119 + if (!cmdq->pdata->control_by_sw && !cmdq->pdata->sw_ddr_en) 120 + return; 121 + 122 + if (cmdq->pdata->sw_ddr_en && ddr_enable) 123 + val |= GCE_DDR_EN; 124 + 125 + writel(val, cmdq->base + GCE_GCTL_VALUE); 126 + } 102 127 103 128 static int cmdq_thread_suspend(struct cmdq *cmdq, struct cmdq_thread *thread) 104 129 { ··· 141 140 static void cmdq_init(struct cmdq *cmdq) 142 141 { 143 142 int i; 144 - u32 gctl_regval = 0; 145 143 146 144 WARN_ON(clk_bulk_enable(cmdq->pdata->gce_num, cmdq->clocks)); 147 - if (cmdq->pdata->control_by_sw) 148 - gctl_regval = GCE_CTRL_BY_SW; 149 - if (cmdq->pdata->sw_ddr_en) 150 - gctl_regval |= GCE_DDR_EN; 151 145 152 - if (gctl_regval) 153 - writel(gctl_regval, cmdq->base + GCE_GCTL_VALUE); 146 + cmdq_gctl_value_toggle(cmdq, true); 154 147 155 148 writel(CMDQ_THR_ACTIVE_SLOT_CYCLES, cmdq->base + CMDQ_THR_SLOT_CYCLES); 156 149 for (i = 0; i <= CMDQ_MAX_EVENT; i++) ··· 310 315 static int cmdq_runtime_resume(struct device *dev) 311 316 { 312 317 struct cmdq *cmdq = dev_get_drvdata(dev); 318 + int ret; 313 319 314 - return clk_bulk_enable(cmdq->pdata->gce_num, cmdq->clocks); 320 + ret = clk_bulk_enable(cmdq->pdata->gce_num, cmdq->clocks); 321 + if (ret) 322 + return ret; 323 + 324 + cmdq_gctl_value_toggle(cmdq, true); 325 + return 0; 315 326 } 316 327 317 328 static int cmdq_runtime_suspend(struct device *dev) 318 329 { 319 330 struct cmdq *cmdq = dev_get_drvdata(dev); 320 331 332 + cmdq_gctl_value_toggle(cmdq, false); 321 333 clk_bulk_disable(cmdq->pdata->gce_num, cmdq->clocks); 322 334 return 0; 323 335 } ··· 349 347 if (task_running) 350 348 dev_warn(dev, "exist running task(s) in suspend\n"); 351 349 352 - if (cmdq->pdata->sw_ddr_en) 353 - cmdq_sw_ddr_enable(cmdq, false); 354 - 355 350 return pm_runtime_force_suspend(dev); 356 351 } 357 352 ··· 359 360 WARN_ON(pm_runtime_force_resume(dev)); 360 361 cmdq->suspended = false; 361 362 362 - if (cmdq->pdata->sw_ddr_en) 363 - cmdq_sw_ddr_enable(cmdq, true); 364 - 365 363 return 0; 366 364 } 367 365 368 366 static void cmdq_remove(struct platform_device *pdev) 369 367 { 370 368 struct cmdq *cmdq = platform_get_drvdata(pdev); 371 - 372 - if (cmdq->pdata->sw_ddr_en) 373 - cmdq_sw_ddr_enable(cmdq, false); 374 369 375 370 if (!IS_ENABLED(CONFIG_PM)) 376 371 cmdq_runtime_suspend(&pdev->dev);
+12 -4
drivers/mailbox/qcom-apcs-ipc-mailbox.c
··· 116 116 } 117 117 118 118 if (apcs_data->clk_name) { 119 - apcs->clk = platform_device_register_data(&pdev->dev, 120 - apcs_data->clk_name, 121 - PLATFORM_DEVID_AUTO, 122 - NULL, 0); 119 + struct device_node *np = of_get_child_by_name(pdev->dev.of_node, 120 + "clock-controller"); 121 + struct platform_device_info pdevinfo = { 122 + .parent = &pdev->dev, 123 + .name = apcs_data->clk_name, 124 + .id = PLATFORM_DEVID_AUTO, 125 + .fwnode = of_fwnode_handle(np) ?: pdev->dev.fwnode, 126 + .of_node_reused = !np, 127 + }; 128 + 129 + apcs->clk = platform_device_register_full(&pdevinfo); 130 + of_node_put(np); 123 131 if (IS_ERR(apcs->clk)) 124 132 dev_err(&pdev->dev, "failed to register APCS clk\n"); 125 133 }
-3
include/linux/mailbox_controller.h
··· 134 134 135 135 int devm_mbox_controller_register(struct device *dev, 136 136 struct mbox_controller *mbox); 137 - void devm_mbox_controller_unregister(struct device *dev, 138 - struct mbox_controller *mbox); 139 - 140 137 #endif /* __MAILBOX_CONTROLLER_H */