diff options
Diffstat (limited to 'drivers/firmware/imx')
| -rw-r--r-- | drivers/firmware/imx/imx-scu.c | 27 | ||||
| -rw-r--r-- | drivers/firmware/imx/misc.c | 8 | ||||
| -rw-r--r-- | drivers/firmware/imx/scu-pd.c | 2 | 
3 files changed, 32 insertions, 5 deletions
| diff --git a/drivers/firmware/imx/imx-scu.c b/drivers/firmware/imx/imx-scu.c index 03b43b7a6d1d..f71eaa5bf52d 100644 --- a/drivers/firmware/imx/imx-scu.c +++ b/drivers/firmware/imx/imx-scu.c @@ -29,6 +29,7 @@ struct imx_sc_chan {  	struct mbox_client cl;  	struct mbox_chan *ch;  	int idx; +	struct completion tx_done;  };  struct imx_sc_ipc { @@ -100,6 +101,14 @@ int imx_scu_get_handle(struct imx_sc_ipc **ipc)  }  EXPORT_SYMBOL(imx_scu_get_handle); +/* Callback called when the word of a message is ack-ed, eg read by SCU */ +static void imx_scu_tx_done(struct mbox_client *cl, void *mssg, int r) +{ +	struct imx_sc_chan *sc_chan = container_of(cl, struct imx_sc_chan, cl); + +	complete(&sc_chan->tx_done); +} +  static void imx_scu_rx_callback(struct mbox_client *c, void *msg)  {  	struct imx_sc_chan *sc_chan = container_of(c, struct imx_sc_chan, cl); @@ -149,6 +158,19 @@ static int imx_scu_ipc_write(struct imx_sc_ipc *sc_ipc, void *msg)  	for (i = 0; i < hdr->size; i++) {  		sc_chan = &sc_ipc->chans[i % 4]; + +		/* +		 * SCU requires that all messages words are written +		 * sequentially but linux MU driver implements multiple +		 * independent channels for each register so ordering between +		 * different channels must be ensured by SCU API interface. +		 * +		 * Wait for tx_done before every send to ensure that no +		 * queueing happens at the mailbox channel level. +		 */ +		wait_for_completion(&sc_chan->tx_done); +		reinit_completion(&sc_chan->tx_done); +  		ret = mbox_send_message(sc_chan->ch, &data[i]);  		if (ret < 0)  			return ret; @@ -247,6 +269,11 @@ static int imx_scu_probe(struct platform_device *pdev)  		cl->knows_txdone = true;  		cl->rx_callback = imx_scu_rx_callback; +		/* Initial tx_done completion as "done" */ +		cl->tx_done = imx_scu_tx_done; +		init_completion(&sc_chan->tx_done); +		complete(&sc_chan->tx_done); +  		sc_chan->sc_ipc = sc_ipc;  		sc_chan->idx = i % 4;  		sc_chan->ch = mbox_request_channel_byname(cl, chan_name); diff --git a/drivers/firmware/imx/misc.c b/drivers/firmware/imx/misc.c index 4b56a587dacd..d073cb3ce699 100644 --- a/drivers/firmware/imx/misc.c +++ b/drivers/firmware/imx/misc.c @@ -16,7 +16,7 @@ struct imx_sc_msg_req_misc_set_ctrl {  	u32 ctrl;  	u32 val;  	u16 resource; -} __packed; +} __packed __aligned(4);  struct imx_sc_msg_req_cpu_start {  	struct imx_sc_rpc_msg hdr; @@ -24,18 +24,18 @@ struct imx_sc_msg_req_cpu_start {  	u32 address_lo;  	u16 resource;  	u8 enable; -} __packed; +} __packed __aligned(4);  struct imx_sc_msg_req_misc_get_ctrl {  	struct imx_sc_rpc_msg hdr;  	u32 ctrl;  	u16 resource; -} __packed; +} __packed __aligned(4);  struct imx_sc_msg_resp_misc_get_ctrl {  	struct imx_sc_rpc_msg hdr;  	u32 val; -} __packed; +} __packed __aligned(4);  /*   * This function sets a miscellaneous control value. diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c index b556612207e5..af3ae0087de4 100644 --- a/drivers/firmware/imx/scu-pd.c +++ b/drivers/firmware/imx/scu-pd.c @@ -61,7 +61,7 @@ struct imx_sc_msg_req_set_resource_power_mode {  	struct imx_sc_rpc_msg hdr;  	u16 resource;  	u8 mode; -} __packed; +} __packed __aligned(4);  #define IMX_SCU_PD_NAME_SIZE 20  struct imx_sc_pm_domain { |