162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2018 Pengutronix, Oleksij Rempel <o.rempel@pengutronix.de> 462306a36Sopenharmony_ci * Copyright 2022 NXP, Peng Fan <peng.fan@nxp.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/clk.h> 862306a36Sopenharmony_ci#include <linux/firmware/imx/ipc.h> 962306a36Sopenharmony_ci#include <linux/firmware/imx/s4.h> 1062306a36Sopenharmony_ci#include <linux/interrupt.h> 1162306a36Sopenharmony_ci#include <linux/io.h> 1262306a36Sopenharmony_ci#include <linux/iopoll.h> 1362306a36Sopenharmony_ci#include <linux/jiffies.h> 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/mailbox_controller.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/of.h> 1862306a36Sopenharmony_ci#include <linux/platform_device.h> 1962306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2062306a36Sopenharmony_ci#include <linux/suspend.h> 2162306a36Sopenharmony_ci#include <linux/slab.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define IMX_MU_CHANS 17 2462306a36Sopenharmony_ci/* TX0/RX0/RXDB[0-3] */ 2562306a36Sopenharmony_ci#define IMX_MU_SCU_CHANS 6 2662306a36Sopenharmony_ci/* TX0/RX0 */ 2762306a36Sopenharmony_ci#define IMX_MU_S4_CHANS 2 2862306a36Sopenharmony_ci#define IMX_MU_CHAN_NAME_SIZE 20 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define IMX_MU_NUM_RR 4 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define IMX_MU_SECO_TX_TOUT (msecs_to_jiffies(3000)) 3362306a36Sopenharmony_ci#define IMX_MU_SECO_RX_TOUT (msecs_to_jiffies(3000)) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* Please not change TX & RX */ 3662306a36Sopenharmony_cienum imx_mu_chan_type { 3762306a36Sopenharmony_ci IMX_MU_TYPE_TX = 0, /* Tx */ 3862306a36Sopenharmony_ci IMX_MU_TYPE_RX = 1, /* Rx */ 3962306a36Sopenharmony_ci IMX_MU_TYPE_TXDB = 2, /* Tx doorbell */ 4062306a36Sopenharmony_ci IMX_MU_TYPE_RXDB = 3, /* Rx doorbell */ 4162306a36Sopenharmony_ci IMX_MU_TYPE_RST = 4, /* Reset */ 4262306a36Sopenharmony_ci}; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cienum imx_mu_xcr { 4562306a36Sopenharmony_ci IMX_MU_CR, 4662306a36Sopenharmony_ci IMX_MU_GIER, 4762306a36Sopenharmony_ci IMX_MU_GCR, 4862306a36Sopenharmony_ci IMX_MU_TCR, 4962306a36Sopenharmony_ci IMX_MU_RCR, 5062306a36Sopenharmony_ci IMX_MU_xCR_MAX, 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cienum imx_mu_xsr { 5462306a36Sopenharmony_ci IMX_MU_SR, 5562306a36Sopenharmony_ci IMX_MU_GSR, 5662306a36Sopenharmony_ci IMX_MU_TSR, 5762306a36Sopenharmony_ci IMX_MU_RSR, 5862306a36Sopenharmony_ci IMX_MU_xSR_MAX, 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistruct imx_sc_rpc_msg_max { 6262306a36Sopenharmony_ci struct imx_sc_rpc_msg hdr; 6362306a36Sopenharmony_ci u32 data[30]; 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistruct imx_s4_rpc_msg_max { 6762306a36Sopenharmony_ci struct imx_s4_rpc_msg hdr; 6862306a36Sopenharmony_ci u32 data[254]; 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistruct imx_mu_con_priv { 7262306a36Sopenharmony_ci unsigned int idx; 7362306a36Sopenharmony_ci char irq_desc[IMX_MU_CHAN_NAME_SIZE]; 7462306a36Sopenharmony_ci enum imx_mu_chan_type type; 7562306a36Sopenharmony_ci struct mbox_chan *chan; 7662306a36Sopenharmony_ci struct tasklet_struct txdb_tasklet; 7762306a36Sopenharmony_ci}; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistruct imx_mu_priv { 8062306a36Sopenharmony_ci struct device *dev; 8162306a36Sopenharmony_ci void __iomem *base; 8262306a36Sopenharmony_ci void *msg; 8362306a36Sopenharmony_ci spinlock_t xcr_lock; /* control register lock */ 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci struct mbox_controller mbox; 8662306a36Sopenharmony_ci struct mbox_chan mbox_chans[IMX_MU_CHANS]; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci struct imx_mu_con_priv con_priv[IMX_MU_CHANS]; 8962306a36Sopenharmony_ci const struct imx_mu_dcfg *dcfg; 9062306a36Sopenharmony_ci struct clk *clk; 9162306a36Sopenharmony_ci int irq[IMX_MU_CHANS]; 9262306a36Sopenharmony_ci bool suspend; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci u32 xcr[IMX_MU_xCR_MAX]; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci bool side_b; 9762306a36Sopenharmony_ci}; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cienum imx_mu_type { 10062306a36Sopenharmony_ci IMX_MU_V1, 10162306a36Sopenharmony_ci IMX_MU_V2 = BIT(1), 10262306a36Sopenharmony_ci IMX_MU_V2_S4 = BIT(15), 10362306a36Sopenharmony_ci IMX_MU_V2_IRQ = BIT(16), 10462306a36Sopenharmony_ci}; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistruct imx_mu_dcfg { 10762306a36Sopenharmony_ci int (*tx)(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp, void *data); 10862306a36Sopenharmony_ci int (*rx)(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp); 10962306a36Sopenharmony_ci int (*rxdb)(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp); 11062306a36Sopenharmony_ci void (*init)(struct imx_mu_priv *priv); 11162306a36Sopenharmony_ci enum imx_mu_type type; 11262306a36Sopenharmony_ci u32 xTR; /* Transmit Register0 */ 11362306a36Sopenharmony_ci u32 xRR; /* Receive Register0 */ 11462306a36Sopenharmony_ci u32 xSR[IMX_MU_xSR_MAX]; /* Status Registers */ 11562306a36Sopenharmony_ci u32 xCR[IMX_MU_xCR_MAX]; /* Control Registers */ 11662306a36Sopenharmony_ci}; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci#define IMX_MU_xSR_GIPn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(28 + (3 - (x)))) 11962306a36Sopenharmony_ci#define IMX_MU_xSR_RFn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(24 + (3 - (x)))) 12062306a36Sopenharmony_ci#define IMX_MU_xSR_TEn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(20 + (3 - (x)))) 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/* General Purpose Interrupt Enable */ 12362306a36Sopenharmony_ci#define IMX_MU_xCR_GIEn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(28 + (3 - (x)))) 12462306a36Sopenharmony_ci/* Receive Interrupt Enable */ 12562306a36Sopenharmony_ci#define IMX_MU_xCR_RIEn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(24 + (3 - (x)))) 12662306a36Sopenharmony_ci/* Transmit Interrupt Enable */ 12762306a36Sopenharmony_ci#define IMX_MU_xCR_TIEn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(20 + (3 - (x)))) 12862306a36Sopenharmony_ci/* General Purpose Interrupt Request */ 12962306a36Sopenharmony_ci#define IMX_MU_xCR_GIRn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(16 + (3 - (x)))) 13062306a36Sopenharmony_ci/* MU reset */ 13162306a36Sopenharmony_ci#define IMX_MU_xCR_RST(type) (type & IMX_MU_V2 ? BIT(0) : BIT(5)) 13262306a36Sopenharmony_ci#define IMX_MU_xSR_RST(type) (type & IMX_MU_V2 ? BIT(0) : BIT(7)) 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci return container_of(mbox, struct imx_mu_priv, mbox); 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci iowrite32(val, priv->base + offs); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci return ioread32(priv->base + offs); 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic int imx_mu_tx_waiting_write(struct imx_mu_priv *priv, u32 val, u32 idx) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci u64 timeout_time = get_jiffies_64() + IMX_MU_SECO_TX_TOUT; 15362306a36Sopenharmony_ci u32 status; 15462306a36Sopenharmony_ci u32 can_write; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci dev_dbg(priv->dev, "Trying to write %.8x to idx %d\n", val, idx); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci do { 15962306a36Sopenharmony_ci status = imx_mu_read(priv, priv->dcfg->xSR[IMX_MU_TSR]); 16062306a36Sopenharmony_ci can_write = status & IMX_MU_xSR_TEn(priv->dcfg->type, idx % 4); 16162306a36Sopenharmony_ci } while (!can_write && time_is_after_jiffies64(timeout_time)); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (!can_write) { 16462306a36Sopenharmony_ci dev_err(priv->dev, "timeout trying to write %.8x at %d(%.8x)\n", 16562306a36Sopenharmony_ci val, idx, status); 16662306a36Sopenharmony_ci return -ETIME; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci imx_mu_write(priv, val, priv->dcfg->xTR + (idx % 4) * 4); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci return 0; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic int imx_mu_rx_waiting_read(struct imx_mu_priv *priv, u32 *val, u32 idx) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci u64 timeout_time = get_jiffies_64() + IMX_MU_SECO_RX_TOUT; 17762306a36Sopenharmony_ci u32 status; 17862306a36Sopenharmony_ci u32 can_read; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci dev_dbg(priv->dev, "Trying to read from idx %d\n", idx); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci do { 18362306a36Sopenharmony_ci status = imx_mu_read(priv, priv->dcfg->xSR[IMX_MU_RSR]); 18462306a36Sopenharmony_ci can_read = status & IMX_MU_xSR_RFn(priv->dcfg->type, idx % 4); 18562306a36Sopenharmony_ci } while (!can_read && time_is_after_jiffies64(timeout_time)); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (!can_read) { 18862306a36Sopenharmony_ci dev_err(priv->dev, "timeout trying to read idx %d (%.8x)\n", 18962306a36Sopenharmony_ci idx, status); 19062306a36Sopenharmony_ci return -ETIME; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci *val = imx_mu_read(priv, priv->dcfg->xRR + (idx % 4) * 4); 19462306a36Sopenharmony_ci dev_dbg(priv->dev, "Read %.8x\n", *val); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return 0; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic u32 imx_mu_xcr_rmw(struct imx_mu_priv *priv, enum imx_mu_xcr type, u32 set, u32 clr) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci unsigned long flags; 20262306a36Sopenharmony_ci u32 val; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci spin_lock_irqsave(&priv->xcr_lock, flags); 20562306a36Sopenharmony_ci val = imx_mu_read(priv, priv->dcfg->xCR[type]); 20662306a36Sopenharmony_ci val &= ~clr; 20762306a36Sopenharmony_ci val |= set; 20862306a36Sopenharmony_ci imx_mu_write(priv, val, priv->dcfg->xCR[type]); 20962306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->xcr_lock, flags); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci return val; 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic int imx_mu_generic_tx(struct imx_mu_priv *priv, 21562306a36Sopenharmony_ci struct imx_mu_con_priv *cp, 21662306a36Sopenharmony_ci void *data) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci u32 *arg = data; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci switch (cp->type) { 22162306a36Sopenharmony_ci case IMX_MU_TYPE_TX: 22262306a36Sopenharmony_ci imx_mu_write(priv, *arg, priv->dcfg->xTR + cp->idx * 4); 22362306a36Sopenharmony_ci imx_mu_xcr_rmw(priv, IMX_MU_TCR, IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx), 0); 22462306a36Sopenharmony_ci break; 22562306a36Sopenharmony_ci case IMX_MU_TYPE_TXDB: 22662306a36Sopenharmony_ci imx_mu_xcr_rmw(priv, IMX_MU_GCR, IMX_MU_xCR_GIRn(priv->dcfg->type, cp->idx), 0); 22762306a36Sopenharmony_ci tasklet_schedule(&cp->txdb_tasklet); 22862306a36Sopenharmony_ci break; 22962306a36Sopenharmony_ci default: 23062306a36Sopenharmony_ci dev_warn_ratelimited(priv->dev, "Send data on wrong channel type: %d\n", cp->type); 23162306a36Sopenharmony_ci return -EINVAL; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return 0; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic int imx_mu_generic_rx(struct imx_mu_priv *priv, 23862306a36Sopenharmony_ci struct imx_mu_con_priv *cp) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci u32 dat; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci dat = imx_mu_read(priv, priv->dcfg->xRR + (cp->idx) * 4); 24362306a36Sopenharmony_ci mbox_chan_received_data(cp->chan, (void *)&dat); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci return 0; 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic int imx_mu_generic_rxdb(struct imx_mu_priv *priv, 24962306a36Sopenharmony_ci struct imx_mu_con_priv *cp) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci imx_mu_write(priv, IMX_MU_xSR_GIPn(priv->dcfg->type, cp->idx), 25262306a36Sopenharmony_ci priv->dcfg->xSR[IMX_MU_GSR]); 25362306a36Sopenharmony_ci mbox_chan_received_data(cp->chan, NULL); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci return 0; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic int imx_mu_specific_tx(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp, void *data) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci u32 *arg = data; 26162306a36Sopenharmony_ci int i, ret; 26262306a36Sopenharmony_ci u32 xsr; 26362306a36Sopenharmony_ci u32 size, max_size, num_tr; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (priv->dcfg->type & IMX_MU_V2_S4) { 26662306a36Sopenharmony_ci size = ((struct imx_s4_rpc_msg_max *)data)->hdr.size; 26762306a36Sopenharmony_ci max_size = sizeof(struct imx_s4_rpc_msg_max); 26862306a36Sopenharmony_ci num_tr = 8; 26962306a36Sopenharmony_ci } else { 27062306a36Sopenharmony_ci size = ((struct imx_sc_rpc_msg_max *)data)->hdr.size; 27162306a36Sopenharmony_ci max_size = sizeof(struct imx_sc_rpc_msg_max); 27262306a36Sopenharmony_ci num_tr = 4; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci switch (cp->type) { 27662306a36Sopenharmony_ci case IMX_MU_TYPE_TX: 27762306a36Sopenharmony_ci /* 27862306a36Sopenharmony_ci * msg->hdr.size specifies the number of u32 words while 27962306a36Sopenharmony_ci * sizeof yields bytes. 28062306a36Sopenharmony_ci */ 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (size > max_size / 4) { 28362306a36Sopenharmony_ci /* 28462306a36Sopenharmony_ci * The real message size can be different to 28562306a36Sopenharmony_ci * struct imx_sc_rpc_msg_max/imx_s4_rpc_msg_max size 28662306a36Sopenharmony_ci */ 28762306a36Sopenharmony_ci dev_err(priv->dev, "Maximal message size (%u bytes) exceeded on TX; got: %i bytes\n", max_size, size << 2); 28862306a36Sopenharmony_ci return -EINVAL; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci for (i = 0; i < num_tr && i < size; i++) 29262306a36Sopenharmony_ci imx_mu_write(priv, *arg++, priv->dcfg->xTR + (i % num_tr) * 4); 29362306a36Sopenharmony_ci for (; i < size; i++) { 29462306a36Sopenharmony_ci ret = readl_poll_timeout(priv->base + priv->dcfg->xSR[IMX_MU_TSR], 29562306a36Sopenharmony_ci xsr, 29662306a36Sopenharmony_ci xsr & IMX_MU_xSR_TEn(priv->dcfg->type, i % num_tr), 29762306a36Sopenharmony_ci 0, 5 * USEC_PER_SEC); 29862306a36Sopenharmony_ci if (ret) { 29962306a36Sopenharmony_ci dev_err(priv->dev, "Send data index: %d timeout\n", i); 30062306a36Sopenharmony_ci return ret; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci imx_mu_write(priv, *arg++, priv->dcfg->xTR + (i % num_tr) * 4); 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci imx_mu_xcr_rmw(priv, IMX_MU_TCR, IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx), 0); 30662306a36Sopenharmony_ci break; 30762306a36Sopenharmony_ci default: 30862306a36Sopenharmony_ci dev_warn_ratelimited(priv->dev, "Send data on wrong channel type: %d\n", cp->type); 30962306a36Sopenharmony_ci return -EINVAL; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci return 0; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic int imx_mu_specific_rx(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci u32 *data; 31862306a36Sopenharmony_ci int i, ret; 31962306a36Sopenharmony_ci u32 xsr; 32062306a36Sopenharmony_ci u32 size, max_size; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci data = (u32 *)priv->msg; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci imx_mu_xcr_rmw(priv, IMX_MU_RCR, 0, IMX_MU_xCR_RIEn(priv->dcfg->type, 0)); 32562306a36Sopenharmony_ci *data++ = imx_mu_read(priv, priv->dcfg->xRR); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (priv->dcfg->type & IMX_MU_V2_S4) { 32862306a36Sopenharmony_ci size = ((struct imx_s4_rpc_msg_max *)priv->msg)->hdr.size; 32962306a36Sopenharmony_ci max_size = sizeof(struct imx_s4_rpc_msg_max); 33062306a36Sopenharmony_ci } else { 33162306a36Sopenharmony_ci size = ((struct imx_sc_rpc_msg_max *)priv->msg)->hdr.size; 33262306a36Sopenharmony_ci max_size = sizeof(struct imx_sc_rpc_msg_max); 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (size > max_size / 4) { 33662306a36Sopenharmony_ci dev_err(priv->dev, "Maximal message size (%u bytes) exceeded on RX; got: %i bytes\n", max_size, size << 2); 33762306a36Sopenharmony_ci return -EINVAL; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci for (i = 1; i < size; i++) { 34162306a36Sopenharmony_ci ret = readl_poll_timeout(priv->base + priv->dcfg->xSR[IMX_MU_RSR], xsr, 34262306a36Sopenharmony_ci xsr & IMX_MU_xSR_RFn(priv->dcfg->type, i % 4), 0, 34362306a36Sopenharmony_ci 5 * USEC_PER_SEC); 34462306a36Sopenharmony_ci if (ret) { 34562306a36Sopenharmony_ci dev_err(priv->dev, "timeout read idx %d\n", i); 34662306a36Sopenharmony_ci return ret; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci *data++ = imx_mu_read(priv, priv->dcfg->xRR + (i % 4) * 4); 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci imx_mu_xcr_rmw(priv, IMX_MU_RCR, IMX_MU_xCR_RIEn(priv->dcfg->type, 0), 0); 35262306a36Sopenharmony_ci mbox_chan_received_data(cp->chan, (void *)priv->msg); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci return 0; 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic int imx_mu_seco_tx(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp, 35862306a36Sopenharmony_ci void *data) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci struct imx_sc_rpc_msg_max *msg = data; 36162306a36Sopenharmony_ci u32 *arg = data; 36262306a36Sopenharmony_ci u32 byte_size; 36362306a36Sopenharmony_ci int err; 36462306a36Sopenharmony_ci int i; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci dev_dbg(priv->dev, "Sending message\n"); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci switch (cp->type) { 36962306a36Sopenharmony_ci case IMX_MU_TYPE_TXDB: 37062306a36Sopenharmony_ci byte_size = msg->hdr.size * sizeof(u32); 37162306a36Sopenharmony_ci if (byte_size > sizeof(*msg)) { 37262306a36Sopenharmony_ci /* 37362306a36Sopenharmony_ci * The real message size can be different to 37462306a36Sopenharmony_ci * struct imx_sc_rpc_msg_max size 37562306a36Sopenharmony_ci */ 37662306a36Sopenharmony_ci dev_err(priv->dev, 37762306a36Sopenharmony_ci "Exceed max msg size (%zu) on TX, got: %i\n", 37862306a36Sopenharmony_ci sizeof(*msg), byte_size); 37962306a36Sopenharmony_ci return -EINVAL; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci print_hex_dump_debug("from client ", DUMP_PREFIX_OFFSET, 4, 4, 38362306a36Sopenharmony_ci data, byte_size, false); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* Send first word */ 38662306a36Sopenharmony_ci dev_dbg(priv->dev, "Sending header\n"); 38762306a36Sopenharmony_ci imx_mu_write(priv, *arg++, priv->dcfg->xTR); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci /* Send signaling */ 39062306a36Sopenharmony_ci dev_dbg(priv->dev, "Sending signaling\n"); 39162306a36Sopenharmony_ci imx_mu_xcr_rmw(priv, IMX_MU_GCR, 39262306a36Sopenharmony_ci IMX_MU_xCR_GIRn(priv->dcfg->type, cp->idx), 0); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci /* Send words to fill the mailbox */ 39562306a36Sopenharmony_ci for (i = 1; i < 4 && i < msg->hdr.size; i++) { 39662306a36Sopenharmony_ci dev_dbg(priv->dev, "Sending word %d\n", i); 39762306a36Sopenharmony_ci imx_mu_write(priv, *arg++, 39862306a36Sopenharmony_ci priv->dcfg->xTR + (i % 4) * 4); 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci /* Send rest of message waiting for remote read */ 40262306a36Sopenharmony_ci for (; i < msg->hdr.size; i++) { 40362306a36Sopenharmony_ci dev_dbg(priv->dev, "Sending word %d\n", i); 40462306a36Sopenharmony_ci err = imx_mu_tx_waiting_write(priv, *arg++, i); 40562306a36Sopenharmony_ci if (err) { 40662306a36Sopenharmony_ci dev_err(priv->dev, "Timeout tx %d\n", i); 40762306a36Sopenharmony_ci return err; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci /* Simulate hack for mbox framework */ 41262306a36Sopenharmony_ci tasklet_schedule(&cp->txdb_tasklet); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci break; 41562306a36Sopenharmony_ci default: 41662306a36Sopenharmony_ci dev_warn_ratelimited(priv->dev, 41762306a36Sopenharmony_ci "Send data on wrong channel type: %d\n", 41862306a36Sopenharmony_ci cp->type); 41962306a36Sopenharmony_ci return -EINVAL; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci return 0; 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic int imx_mu_seco_rxdb(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci struct imx_sc_rpc_msg_max msg; 42862306a36Sopenharmony_ci u32 *data = (u32 *)&msg; 42962306a36Sopenharmony_ci u32 byte_size; 43062306a36Sopenharmony_ci int err = 0; 43162306a36Sopenharmony_ci int i; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci dev_dbg(priv->dev, "Receiving message\n"); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci /* Read header */ 43662306a36Sopenharmony_ci dev_dbg(priv->dev, "Receiving header\n"); 43762306a36Sopenharmony_ci *data++ = imx_mu_read(priv, priv->dcfg->xRR); 43862306a36Sopenharmony_ci byte_size = msg.hdr.size * sizeof(u32); 43962306a36Sopenharmony_ci if (byte_size > sizeof(msg)) { 44062306a36Sopenharmony_ci dev_err(priv->dev, "Exceed max msg size (%zu) on RX, got: %i\n", 44162306a36Sopenharmony_ci sizeof(msg), byte_size); 44262306a36Sopenharmony_ci err = -EINVAL; 44362306a36Sopenharmony_ci goto error; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* Read message waiting they are written */ 44762306a36Sopenharmony_ci for (i = 1; i < msg.hdr.size; i++) { 44862306a36Sopenharmony_ci dev_dbg(priv->dev, "Receiving word %d\n", i); 44962306a36Sopenharmony_ci err = imx_mu_rx_waiting_read(priv, data++, i); 45062306a36Sopenharmony_ci if (err) { 45162306a36Sopenharmony_ci dev_err(priv->dev, "Timeout rx %d\n", i); 45262306a36Sopenharmony_ci goto error; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* Clear GIP */ 45762306a36Sopenharmony_ci imx_mu_write(priv, IMX_MU_xSR_GIPn(priv->dcfg->type, cp->idx), 45862306a36Sopenharmony_ci priv->dcfg->xSR[IMX_MU_GSR]); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci print_hex_dump_debug("to client ", DUMP_PREFIX_OFFSET, 4, 4, 46162306a36Sopenharmony_ci &msg, byte_size, false); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* send data to client */ 46462306a36Sopenharmony_ci dev_dbg(priv->dev, "Sending message to client\n"); 46562306a36Sopenharmony_ci mbox_chan_received_data(cp->chan, (void *)&msg); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci goto exit; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cierror: 47062306a36Sopenharmony_ci mbox_chan_received_data(cp->chan, ERR_PTR(err)); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ciexit: 47362306a36Sopenharmony_ci return err; 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic void imx_mu_txdb_tasklet(unsigned long data) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci struct imx_mu_con_priv *cp = (struct imx_mu_con_priv *)data; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci mbox_chan_txdone(cp->chan, 0); 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic irqreturn_t imx_mu_isr(int irq, void *p) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct mbox_chan *chan = p; 48662306a36Sopenharmony_ci struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox); 48762306a36Sopenharmony_ci struct imx_mu_con_priv *cp = chan->con_priv; 48862306a36Sopenharmony_ci u32 val, ctrl; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci switch (cp->type) { 49162306a36Sopenharmony_ci case IMX_MU_TYPE_TX: 49262306a36Sopenharmony_ci ctrl = imx_mu_read(priv, priv->dcfg->xCR[IMX_MU_TCR]); 49362306a36Sopenharmony_ci val = imx_mu_read(priv, priv->dcfg->xSR[IMX_MU_TSR]); 49462306a36Sopenharmony_ci val &= IMX_MU_xSR_TEn(priv->dcfg->type, cp->idx) & 49562306a36Sopenharmony_ci (ctrl & IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx)); 49662306a36Sopenharmony_ci break; 49762306a36Sopenharmony_ci case IMX_MU_TYPE_RX: 49862306a36Sopenharmony_ci ctrl = imx_mu_read(priv, priv->dcfg->xCR[IMX_MU_RCR]); 49962306a36Sopenharmony_ci val = imx_mu_read(priv, priv->dcfg->xSR[IMX_MU_RSR]); 50062306a36Sopenharmony_ci val &= IMX_MU_xSR_RFn(priv->dcfg->type, cp->idx) & 50162306a36Sopenharmony_ci (ctrl & IMX_MU_xCR_RIEn(priv->dcfg->type, cp->idx)); 50262306a36Sopenharmony_ci break; 50362306a36Sopenharmony_ci case IMX_MU_TYPE_RXDB: 50462306a36Sopenharmony_ci ctrl = imx_mu_read(priv, priv->dcfg->xCR[IMX_MU_GIER]); 50562306a36Sopenharmony_ci val = imx_mu_read(priv, priv->dcfg->xSR[IMX_MU_GSR]); 50662306a36Sopenharmony_ci val &= IMX_MU_xSR_GIPn(priv->dcfg->type, cp->idx) & 50762306a36Sopenharmony_ci (ctrl & IMX_MU_xCR_GIEn(priv->dcfg->type, cp->idx)); 50862306a36Sopenharmony_ci break; 50962306a36Sopenharmony_ci case IMX_MU_TYPE_RST: 51062306a36Sopenharmony_ci return IRQ_NONE; 51162306a36Sopenharmony_ci default: 51262306a36Sopenharmony_ci dev_warn_ratelimited(priv->dev, "Unhandled channel type %d\n", 51362306a36Sopenharmony_ci cp->type); 51462306a36Sopenharmony_ci return IRQ_NONE; 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci if (!val) 51862306a36Sopenharmony_ci return IRQ_NONE; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci if ((val == IMX_MU_xSR_TEn(priv->dcfg->type, cp->idx)) && 52162306a36Sopenharmony_ci (cp->type == IMX_MU_TYPE_TX)) { 52262306a36Sopenharmony_ci imx_mu_xcr_rmw(priv, IMX_MU_TCR, 0, IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx)); 52362306a36Sopenharmony_ci mbox_chan_txdone(chan, 0); 52462306a36Sopenharmony_ci } else if ((val == IMX_MU_xSR_RFn(priv->dcfg->type, cp->idx)) && 52562306a36Sopenharmony_ci (cp->type == IMX_MU_TYPE_RX)) { 52662306a36Sopenharmony_ci priv->dcfg->rx(priv, cp); 52762306a36Sopenharmony_ci } else if ((val == IMX_MU_xSR_GIPn(priv->dcfg->type, cp->idx)) && 52862306a36Sopenharmony_ci (cp->type == IMX_MU_TYPE_RXDB)) { 52962306a36Sopenharmony_ci priv->dcfg->rxdb(priv, cp); 53062306a36Sopenharmony_ci } else { 53162306a36Sopenharmony_ci dev_warn_ratelimited(priv->dev, "Not handled interrupt\n"); 53262306a36Sopenharmony_ci return IRQ_NONE; 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if (priv->suspend) 53662306a36Sopenharmony_ci pm_system_wakeup(); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci return IRQ_HANDLED; 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic int imx_mu_send_data(struct mbox_chan *chan, void *data) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox); 54462306a36Sopenharmony_ci struct imx_mu_con_priv *cp = chan->con_priv; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci return priv->dcfg->tx(priv, cp, data); 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cistatic int imx_mu_startup(struct mbox_chan *chan) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox); 55262306a36Sopenharmony_ci struct imx_mu_con_priv *cp = chan->con_priv; 55362306a36Sopenharmony_ci unsigned long irq_flag = 0; 55462306a36Sopenharmony_ci int ret; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci pm_runtime_get_sync(priv->dev); 55762306a36Sopenharmony_ci if (cp->type == IMX_MU_TYPE_TXDB) { 55862306a36Sopenharmony_ci /* Tx doorbell don't have ACK support */ 55962306a36Sopenharmony_ci tasklet_init(&cp->txdb_tasklet, imx_mu_txdb_tasklet, 56062306a36Sopenharmony_ci (unsigned long)cp); 56162306a36Sopenharmony_ci return 0; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci /* IPC MU should be with IRQF_NO_SUSPEND set */ 56562306a36Sopenharmony_ci if (!priv->dev->pm_domain) 56662306a36Sopenharmony_ci irq_flag |= IRQF_NO_SUSPEND; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if (!(priv->dcfg->type & IMX_MU_V2_IRQ)) 56962306a36Sopenharmony_ci irq_flag |= IRQF_SHARED; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci ret = request_irq(priv->irq[cp->type], imx_mu_isr, irq_flag, cp->irq_desc, chan); 57262306a36Sopenharmony_ci if (ret) { 57362306a36Sopenharmony_ci dev_err(priv->dev, "Unable to acquire IRQ %d\n", priv->irq[cp->type]); 57462306a36Sopenharmony_ci return ret; 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci switch (cp->type) { 57862306a36Sopenharmony_ci case IMX_MU_TYPE_RX: 57962306a36Sopenharmony_ci imx_mu_xcr_rmw(priv, IMX_MU_RCR, IMX_MU_xCR_RIEn(priv->dcfg->type, cp->idx), 0); 58062306a36Sopenharmony_ci break; 58162306a36Sopenharmony_ci case IMX_MU_TYPE_RXDB: 58262306a36Sopenharmony_ci imx_mu_xcr_rmw(priv, IMX_MU_GIER, IMX_MU_xCR_GIEn(priv->dcfg->type, cp->idx), 0); 58362306a36Sopenharmony_ci break; 58462306a36Sopenharmony_ci default: 58562306a36Sopenharmony_ci break; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci return 0; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic void imx_mu_shutdown(struct mbox_chan *chan) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox); 59462306a36Sopenharmony_ci struct imx_mu_con_priv *cp = chan->con_priv; 59562306a36Sopenharmony_ci int ret; 59662306a36Sopenharmony_ci u32 sr; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci if (cp->type == IMX_MU_TYPE_TXDB) { 59962306a36Sopenharmony_ci tasklet_kill(&cp->txdb_tasklet); 60062306a36Sopenharmony_ci pm_runtime_put_sync(priv->dev); 60162306a36Sopenharmony_ci return; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci switch (cp->type) { 60562306a36Sopenharmony_ci case IMX_MU_TYPE_TX: 60662306a36Sopenharmony_ci imx_mu_xcr_rmw(priv, IMX_MU_TCR, 0, IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx)); 60762306a36Sopenharmony_ci break; 60862306a36Sopenharmony_ci case IMX_MU_TYPE_RX: 60962306a36Sopenharmony_ci imx_mu_xcr_rmw(priv, IMX_MU_RCR, 0, IMX_MU_xCR_RIEn(priv->dcfg->type, cp->idx)); 61062306a36Sopenharmony_ci break; 61162306a36Sopenharmony_ci case IMX_MU_TYPE_RXDB: 61262306a36Sopenharmony_ci imx_mu_xcr_rmw(priv, IMX_MU_GIER, 0, IMX_MU_xCR_GIEn(priv->dcfg->type, cp->idx)); 61362306a36Sopenharmony_ci break; 61462306a36Sopenharmony_ci case IMX_MU_TYPE_RST: 61562306a36Sopenharmony_ci imx_mu_xcr_rmw(priv, IMX_MU_CR, IMX_MU_xCR_RST(priv->dcfg->type), 0); 61662306a36Sopenharmony_ci ret = readl_poll_timeout(priv->base + priv->dcfg->xSR[IMX_MU_SR], sr, 61762306a36Sopenharmony_ci !(sr & IMX_MU_xSR_RST(priv->dcfg->type)), 1, 5); 61862306a36Sopenharmony_ci if (ret) 61962306a36Sopenharmony_ci dev_warn(priv->dev, "RST channel timeout\n"); 62062306a36Sopenharmony_ci break; 62162306a36Sopenharmony_ci default: 62262306a36Sopenharmony_ci break; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci free_irq(priv->irq[cp->type], chan); 62662306a36Sopenharmony_ci pm_runtime_put_sync(priv->dev); 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_cistatic const struct mbox_chan_ops imx_mu_ops = { 63062306a36Sopenharmony_ci .send_data = imx_mu_send_data, 63162306a36Sopenharmony_ci .startup = imx_mu_startup, 63262306a36Sopenharmony_ci .shutdown = imx_mu_shutdown, 63362306a36Sopenharmony_ci}; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic struct mbox_chan *imx_mu_specific_xlate(struct mbox_controller *mbox, 63662306a36Sopenharmony_ci const struct of_phandle_args *sp) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci u32 type, idx, chan; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci if (sp->args_count != 2) { 64162306a36Sopenharmony_ci dev_err(mbox->dev, "Invalid argument count %d\n", sp->args_count); 64262306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci type = sp->args[0]; /* channel type */ 64662306a36Sopenharmony_ci idx = sp->args[1]; /* index */ 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci switch (type) { 64962306a36Sopenharmony_ci case IMX_MU_TYPE_TX: 65062306a36Sopenharmony_ci case IMX_MU_TYPE_RX: 65162306a36Sopenharmony_ci if (idx != 0) 65262306a36Sopenharmony_ci dev_err(mbox->dev, "Invalid chan idx: %d\n", idx); 65362306a36Sopenharmony_ci chan = type; 65462306a36Sopenharmony_ci break; 65562306a36Sopenharmony_ci case IMX_MU_TYPE_RXDB: 65662306a36Sopenharmony_ci chan = 2 + idx; 65762306a36Sopenharmony_ci break; 65862306a36Sopenharmony_ci default: 65962306a36Sopenharmony_ci dev_err(mbox->dev, "Invalid chan type: %d\n", type); 66062306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (chan >= mbox->num_chans) { 66462306a36Sopenharmony_ci dev_err(mbox->dev, "Not supported channel number: %d. (type: %d, idx: %d)\n", chan, type, idx); 66562306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci return &mbox->chans[chan]; 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistatic struct mbox_chan * imx_mu_xlate(struct mbox_controller *mbox, 67262306a36Sopenharmony_ci const struct of_phandle_args *sp) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci u32 type, idx, chan; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci if (sp->args_count != 2) { 67762306a36Sopenharmony_ci dev_err(mbox->dev, "Invalid argument count %d\n", sp->args_count); 67862306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci type = sp->args[0]; /* channel type */ 68262306a36Sopenharmony_ci idx = sp->args[1]; /* index */ 68362306a36Sopenharmony_ci chan = type * 4 + idx; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if (chan >= mbox->num_chans) { 68662306a36Sopenharmony_ci dev_err(mbox->dev, "Not supported channel number: %d. (type: %d, idx: %d)\n", chan, type, idx); 68762306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci return &mbox->chans[chan]; 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_cistatic struct mbox_chan *imx_mu_seco_xlate(struct mbox_controller *mbox, 69462306a36Sopenharmony_ci const struct of_phandle_args *sp) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci u32 type; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci if (sp->args_count < 1) { 69962306a36Sopenharmony_ci dev_err(mbox->dev, "Invalid argument count %d\n", sp->args_count); 70062306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci type = sp->args[0]; /* channel type */ 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci /* Only supports TXDB and RXDB */ 70662306a36Sopenharmony_ci if (type == IMX_MU_TYPE_TX || type == IMX_MU_TYPE_RX) { 70762306a36Sopenharmony_ci dev_err(mbox->dev, "Invalid type: %d\n", type); 70862306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci return imx_mu_xlate(mbox, sp); 71262306a36Sopenharmony_ci} 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_cistatic void imx_mu_init_generic(struct imx_mu_priv *priv) 71562306a36Sopenharmony_ci{ 71662306a36Sopenharmony_ci unsigned int i; 71762306a36Sopenharmony_ci unsigned int val; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci for (i = 0; i < IMX_MU_CHANS; i++) { 72062306a36Sopenharmony_ci struct imx_mu_con_priv *cp = &priv->con_priv[i]; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci cp->idx = i % 4; 72362306a36Sopenharmony_ci cp->type = i >> 2; 72462306a36Sopenharmony_ci cp->chan = &priv->mbox_chans[i]; 72562306a36Sopenharmony_ci priv->mbox_chans[i].con_priv = cp; 72662306a36Sopenharmony_ci snprintf(cp->irq_desc, sizeof(cp->irq_desc), 72762306a36Sopenharmony_ci "imx_mu_chan[%i-%i]", cp->type, cp->idx); 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci priv->mbox.num_chans = IMX_MU_CHANS; 73162306a36Sopenharmony_ci priv->mbox.of_xlate = imx_mu_xlate; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci if (priv->side_b) 73462306a36Sopenharmony_ci return; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci /* Set default MU configuration */ 73762306a36Sopenharmony_ci for (i = 0; i < IMX_MU_xCR_MAX; i++) 73862306a36Sopenharmony_ci imx_mu_write(priv, 0, priv->dcfg->xCR[i]); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci /* Clear any pending GIP */ 74162306a36Sopenharmony_ci val = imx_mu_read(priv, priv->dcfg->xSR[IMX_MU_GSR]); 74262306a36Sopenharmony_ci imx_mu_write(priv, val, priv->dcfg->xSR[IMX_MU_GSR]); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci /* Clear any pending RSR */ 74562306a36Sopenharmony_ci for (i = 0; i < IMX_MU_NUM_RR; i++) 74662306a36Sopenharmony_ci imx_mu_read(priv, priv->dcfg->xRR + (i % 4) * 4); 74762306a36Sopenharmony_ci} 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_cistatic void imx_mu_init_specific(struct imx_mu_priv *priv) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci unsigned int i; 75262306a36Sopenharmony_ci int num_chans = priv->dcfg->type & IMX_MU_V2_S4 ? IMX_MU_S4_CHANS : IMX_MU_SCU_CHANS; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci for (i = 0; i < num_chans; i++) { 75562306a36Sopenharmony_ci struct imx_mu_con_priv *cp = &priv->con_priv[i]; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci cp->idx = i < 2 ? 0 : i - 2; 75862306a36Sopenharmony_ci cp->type = i < 2 ? i : IMX_MU_TYPE_RXDB; 75962306a36Sopenharmony_ci cp->chan = &priv->mbox_chans[i]; 76062306a36Sopenharmony_ci priv->mbox_chans[i].con_priv = cp; 76162306a36Sopenharmony_ci snprintf(cp->irq_desc, sizeof(cp->irq_desc), 76262306a36Sopenharmony_ci "imx_mu_chan[%i-%i]", cp->type, cp->idx); 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci priv->mbox.num_chans = num_chans; 76662306a36Sopenharmony_ci priv->mbox.of_xlate = imx_mu_specific_xlate; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci /* Set default MU configuration */ 76962306a36Sopenharmony_ci for (i = 0; i < IMX_MU_xCR_MAX; i++) 77062306a36Sopenharmony_ci imx_mu_write(priv, 0, priv->dcfg->xCR[i]); 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cistatic void imx_mu_init_seco(struct imx_mu_priv *priv) 77462306a36Sopenharmony_ci{ 77562306a36Sopenharmony_ci imx_mu_init_generic(priv); 77662306a36Sopenharmony_ci priv->mbox.of_xlate = imx_mu_seco_xlate; 77762306a36Sopenharmony_ci} 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_cistatic int imx_mu_probe(struct platform_device *pdev) 78062306a36Sopenharmony_ci{ 78162306a36Sopenharmony_ci struct device *dev = &pdev->dev; 78262306a36Sopenharmony_ci struct device_node *np = dev->of_node; 78362306a36Sopenharmony_ci struct imx_mu_priv *priv; 78462306a36Sopenharmony_ci const struct imx_mu_dcfg *dcfg; 78562306a36Sopenharmony_ci int i, ret; 78662306a36Sopenharmony_ci u32 size; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 78962306a36Sopenharmony_ci if (!priv) 79062306a36Sopenharmony_ci return -ENOMEM; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci priv->dev = dev; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci priv->base = devm_platform_ioremap_resource(pdev, 0); 79562306a36Sopenharmony_ci if (IS_ERR(priv->base)) 79662306a36Sopenharmony_ci return PTR_ERR(priv->base); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci dcfg = of_device_get_match_data(dev); 79962306a36Sopenharmony_ci if (!dcfg) 80062306a36Sopenharmony_ci return -EINVAL; 80162306a36Sopenharmony_ci priv->dcfg = dcfg; 80262306a36Sopenharmony_ci if (priv->dcfg->type & IMX_MU_V2_IRQ) { 80362306a36Sopenharmony_ci priv->irq[IMX_MU_TYPE_TX] = platform_get_irq_byname(pdev, "tx"); 80462306a36Sopenharmony_ci if (priv->irq[IMX_MU_TYPE_TX] < 0) 80562306a36Sopenharmony_ci return priv->irq[IMX_MU_TYPE_TX]; 80662306a36Sopenharmony_ci priv->irq[IMX_MU_TYPE_RX] = platform_get_irq_byname(pdev, "rx"); 80762306a36Sopenharmony_ci if (priv->irq[IMX_MU_TYPE_RX] < 0) 80862306a36Sopenharmony_ci return priv->irq[IMX_MU_TYPE_RX]; 80962306a36Sopenharmony_ci } else { 81062306a36Sopenharmony_ci ret = platform_get_irq(pdev, 0); 81162306a36Sopenharmony_ci if (ret < 0) 81262306a36Sopenharmony_ci return ret; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci for (i = 0; i < IMX_MU_CHANS; i++) 81562306a36Sopenharmony_ci priv->irq[i] = ret; 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci if (priv->dcfg->type & IMX_MU_V2_S4) 81962306a36Sopenharmony_ci size = sizeof(struct imx_s4_rpc_msg_max); 82062306a36Sopenharmony_ci else 82162306a36Sopenharmony_ci size = sizeof(struct imx_sc_rpc_msg_max); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci priv->msg = devm_kzalloc(dev, size, GFP_KERNEL); 82462306a36Sopenharmony_ci if (!priv->msg) 82562306a36Sopenharmony_ci return -ENOMEM; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci priv->clk = devm_clk_get(dev, NULL); 82862306a36Sopenharmony_ci if (IS_ERR(priv->clk)) { 82962306a36Sopenharmony_ci if (PTR_ERR(priv->clk) != -ENOENT) 83062306a36Sopenharmony_ci return PTR_ERR(priv->clk); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci priv->clk = NULL; 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci ret = clk_prepare_enable(priv->clk); 83662306a36Sopenharmony_ci if (ret) { 83762306a36Sopenharmony_ci dev_err(dev, "Failed to enable clock\n"); 83862306a36Sopenharmony_ci return ret; 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci priv->side_b = of_property_read_bool(np, "fsl,mu-side-b"); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci priv->dcfg->init(priv); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci spin_lock_init(&priv->xcr_lock); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci priv->mbox.dev = dev; 84862306a36Sopenharmony_ci priv->mbox.ops = &imx_mu_ops; 84962306a36Sopenharmony_ci priv->mbox.chans = priv->mbox_chans; 85062306a36Sopenharmony_ci priv->mbox.txdone_irq = true; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci platform_set_drvdata(pdev, priv); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci ret = devm_mbox_controller_register(dev, &priv->mbox); 85562306a36Sopenharmony_ci if (ret) { 85662306a36Sopenharmony_ci clk_disable_unprepare(priv->clk); 85762306a36Sopenharmony_ci return ret; 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci pm_runtime_enable(dev); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(dev); 86362306a36Sopenharmony_ci if (ret < 0) 86462306a36Sopenharmony_ci goto disable_runtime_pm; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci ret = pm_runtime_put_sync(dev); 86762306a36Sopenharmony_ci if (ret < 0) 86862306a36Sopenharmony_ci goto disable_runtime_pm; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci clk_disable_unprepare(priv->clk); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci return 0; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_cidisable_runtime_pm: 87562306a36Sopenharmony_ci pm_runtime_disable(dev); 87662306a36Sopenharmony_ci clk_disable_unprepare(priv->clk); 87762306a36Sopenharmony_ci return ret; 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_cistatic int imx_mu_remove(struct platform_device *pdev) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci struct imx_mu_priv *priv = platform_get_drvdata(pdev); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci pm_runtime_disable(priv->dev); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci return 0; 88762306a36Sopenharmony_ci} 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_cistatic const struct imx_mu_dcfg imx_mu_cfg_imx6sx = { 89062306a36Sopenharmony_ci .tx = imx_mu_generic_tx, 89162306a36Sopenharmony_ci .rx = imx_mu_generic_rx, 89262306a36Sopenharmony_ci .rxdb = imx_mu_generic_rxdb, 89362306a36Sopenharmony_ci .init = imx_mu_init_generic, 89462306a36Sopenharmony_ci .xTR = 0x0, 89562306a36Sopenharmony_ci .xRR = 0x10, 89662306a36Sopenharmony_ci .xSR = {0x20, 0x20, 0x20, 0x20}, 89762306a36Sopenharmony_ci .xCR = {0x24, 0x24, 0x24, 0x24, 0x24}, 89862306a36Sopenharmony_ci}; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_cistatic const struct imx_mu_dcfg imx_mu_cfg_imx7ulp = { 90162306a36Sopenharmony_ci .tx = imx_mu_generic_tx, 90262306a36Sopenharmony_ci .rx = imx_mu_generic_rx, 90362306a36Sopenharmony_ci .rxdb = imx_mu_generic_rxdb, 90462306a36Sopenharmony_ci .init = imx_mu_init_generic, 90562306a36Sopenharmony_ci .xTR = 0x20, 90662306a36Sopenharmony_ci .xRR = 0x40, 90762306a36Sopenharmony_ci .xSR = {0x60, 0x60, 0x60, 0x60}, 90862306a36Sopenharmony_ci .xCR = {0x64, 0x64, 0x64, 0x64, 0x64}, 90962306a36Sopenharmony_ci}; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_cistatic const struct imx_mu_dcfg imx_mu_cfg_imx8ulp = { 91262306a36Sopenharmony_ci .tx = imx_mu_generic_tx, 91362306a36Sopenharmony_ci .rx = imx_mu_generic_rx, 91462306a36Sopenharmony_ci .rxdb = imx_mu_generic_rxdb, 91562306a36Sopenharmony_ci .init = imx_mu_init_generic, 91662306a36Sopenharmony_ci .type = IMX_MU_V2, 91762306a36Sopenharmony_ci .xTR = 0x200, 91862306a36Sopenharmony_ci .xRR = 0x280, 91962306a36Sopenharmony_ci .xSR = {0xC, 0x118, 0x124, 0x12C}, 92062306a36Sopenharmony_ci .xCR = {0x8, 0x110, 0x114, 0x120, 0x128}, 92162306a36Sopenharmony_ci}; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_cistatic const struct imx_mu_dcfg imx_mu_cfg_imx8ulp_s4 = { 92462306a36Sopenharmony_ci .tx = imx_mu_specific_tx, 92562306a36Sopenharmony_ci .rx = imx_mu_specific_rx, 92662306a36Sopenharmony_ci .init = imx_mu_init_specific, 92762306a36Sopenharmony_ci .type = IMX_MU_V2 | IMX_MU_V2_S4, 92862306a36Sopenharmony_ci .xTR = 0x200, 92962306a36Sopenharmony_ci .xRR = 0x280, 93062306a36Sopenharmony_ci .xSR = {0xC, 0x118, 0x124, 0x12C}, 93162306a36Sopenharmony_ci .xCR = {0x8, 0x110, 0x114, 0x120, 0x128}, 93262306a36Sopenharmony_ci}; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_cistatic const struct imx_mu_dcfg imx_mu_cfg_imx93_s4 = { 93562306a36Sopenharmony_ci .tx = imx_mu_specific_tx, 93662306a36Sopenharmony_ci .rx = imx_mu_specific_rx, 93762306a36Sopenharmony_ci .init = imx_mu_init_specific, 93862306a36Sopenharmony_ci .type = IMX_MU_V2 | IMX_MU_V2_S4 | IMX_MU_V2_IRQ, 93962306a36Sopenharmony_ci .xTR = 0x200, 94062306a36Sopenharmony_ci .xRR = 0x280, 94162306a36Sopenharmony_ci .xSR = {0xC, 0x118, 0x124, 0x12C}, 94262306a36Sopenharmony_ci .xCR = {0x8, 0x110, 0x114, 0x120, 0x128}, 94362306a36Sopenharmony_ci}; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_cistatic const struct imx_mu_dcfg imx_mu_cfg_imx8_scu = { 94662306a36Sopenharmony_ci .tx = imx_mu_specific_tx, 94762306a36Sopenharmony_ci .rx = imx_mu_specific_rx, 94862306a36Sopenharmony_ci .init = imx_mu_init_specific, 94962306a36Sopenharmony_ci .rxdb = imx_mu_generic_rxdb, 95062306a36Sopenharmony_ci .xTR = 0x0, 95162306a36Sopenharmony_ci .xRR = 0x10, 95262306a36Sopenharmony_ci .xSR = {0x20, 0x20, 0x20, 0x20}, 95362306a36Sopenharmony_ci .xCR = {0x24, 0x24, 0x24, 0x24, 0x24}, 95462306a36Sopenharmony_ci}; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_cistatic const struct imx_mu_dcfg imx_mu_cfg_imx8_seco = { 95762306a36Sopenharmony_ci .tx = imx_mu_seco_tx, 95862306a36Sopenharmony_ci .rx = imx_mu_generic_rx, 95962306a36Sopenharmony_ci .rxdb = imx_mu_seco_rxdb, 96062306a36Sopenharmony_ci .init = imx_mu_init_seco, 96162306a36Sopenharmony_ci .xTR = 0x0, 96262306a36Sopenharmony_ci .xRR = 0x10, 96362306a36Sopenharmony_ci .xSR = {0x20, 0x20, 0x20, 0x20}, 96462306a36Sopenharmony_ci .xCR = {0x24, 0x24, 0x24, 0x24, 0x24}, 96562306a36Sopenharmony_ci}; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_cistatic const struct of_device_id imx_mu_dt_ids[] = { 96862306a36Sopenharmony_ci { .compatible = "fsl,imx7ulp-mu", .data = &imx_mu_cfg_imx7ulp }, 96962306a36Sopenharmony_ci { .compatible = "fsl,imx6sx-mu", .data = &imx_mu_cfg_imx6sx }, 97062306a36Sopenharmony_ci { .compatible = "fsl,imx8ulp-mu", .data = &imx_mu_cfg_imx8ulp }, 97162306a36Sopenharmony_ci { .compatible = "fsl,imx8ulp-mu-s4", .data = &imx_mu_cfg_imx8ulp_s4 }, 97262306a36Sopenharmony_ci { .compatible = "fsl,imx93-mu-s4", .data = &imx_mu_cfg_imx93_s4 }, 97362306a36Sopenharmony_ci { .compatible = "fsl,imx8-mu-scu", .data = &imx_mu_cfg_imx8_scu }, 97462306a36Sopenharmony_ci { .compatible = "fsl,imx8-mu-seco", .data = &imx_mu_cfg_imx8_seco }, 97562306a36Sopenharmony_ci { }, 97662306a36Sopenharmony_ci}; 97762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, imx_mu_dt_ids); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_cistatic int __maybe_unused imx_mu_suspend_noirq(struct device *dev) 98062306a36Sopenharmony_ci{ 98162306a36Sopenharmony_ci struct imx_mu_priv *priv = dev_get_drvdata(dev); 98262306a36Sopenharmony_ci int i; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci if (!priv->clk) { 98562306a36Sopenharmony_ci for (i = 0; i < IMX_MU_xCR_MAX; i++) 98662306a36Sopenharmony_ci priv->xcr[i] = imx_mu_read(priv, priv->dcfg->xCR[i]); 98762306a36Sopenharmony_ci } 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci priv->suspend = true; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci return 0; 99262306a36Sopenharmony_ci} 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_cistatic int __maybe_unused imx_mu_resume_noirq(struct device *dev) 99562306a36Sopenharmony_ci{ 99662306a36Sopenharmony_ci struct imx_mu_priv *priv = dev_get_drvdata(dev); 99762306a36Sopenharmony_ci int i; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci /* 100062306a36Sopenharmony_ci * ONLY restore MU when context lost, the TIE could 100162306a36Sopenharmony_ci * be set during noirq resume as there is MU data 100262306a36Sopenharmony_ci * communication going on, and restore the saved 100362306a36Sopenharmony_ci * value will overwrite the TIE and cause MU data 100462306a36Sopenharmony_ci * send failed, may lead to system freeze. This issue 100562306a36Sopenharmony_ci * is observed by testing freeze mode suspend. 100662306a36Sopenharmony_ci */ 100762306a36Sopenharmony_ci if (!priv->clk && !imx_mu_read(priv, priv->dcfg->xCR[0])) { 100862306a36Sopenharmony_ci for (i = 0; i < IMX_MU_xCR_MAX; i++) 100962306a36Sopenharmony_ci imx_mu_write(priv, priv->xcr[i], priv->dcfg->xCR[i]); 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci priv->suspend = false; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci return 0; 101562306a36Sopenharmony_ci} 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_cistatic int __maybe_unused imx_mu_runtime_suspend(struct device *dev) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci struct imx_mu_priv *priv = dev_get_drvdata(dev); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci clk_disable_unprepare(priv->clk); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci return 0; 102462306a36Sopenharmony_ci} 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_cistatic int __maybe_unused imx_mu_runtime_resume(struct device *dev) 102762306a36Sopenharmony_ci{ 102862306a36Sopenharmony_ci struct imx_mu_priv *priv = dev_get_drvdata(dev); 102962306a36Sopenharmony_ci int ret; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci ret = clk_prepare_enable(priv->clk); 103262306a36Sopenharmony_ci if (ret) 103362306a36Sopenharmony_ci dev_err(dev, "failed to enable clock\n"); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci return ret; 103662306a36Sopenharmony_ci} 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_cistatic const struct dev_pm_ops imx_mu_pm_ops = { 103962306a36Sopenharmony_ci SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_mu_suspend_noirq, 104062306a36Sopenharmony_ci imx_mu_resume_noirq) 104162306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(imx_mu_runtime_suspend, 104262306a36Sopenharmony_ci imx_mu_runtime_resume, NULL) 104362306a36Sopenharmony_ci}; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_cistatic struct platform_driver imx_mu_driver = { 104662306a36Sopenharmony_ci .probe = imx_mu_probe, 104762306a36Sopenharmony_ci .remove = imx_mu_remove, 104862306a36Sopenharmony_ci .driver = { 104962306a36Sopenharmony_ci .name = "imx_mu", 105062306a36Sopenharmony_ci .of_match_table = imx_mu_dt_ids, 105162306a36Sopenharmony_ci .pm = &imx_mu_pm_ops, 105262306a36Sopenharmony_ci }, 105362306a36Sopenharmony_ci}; 105462306a36Sopenharmony_cimodule_platform_driver(imx_mu_driver); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ciMODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>"); 105762306a36Sopenharmony_ciMODULE_DESCRIPTION("Message Unit driver for i.MX"); 105862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1059