18c2ecf20Sopenharmony_ci============================
28c2ecf20Sopenharmony_ciThe Common Mailbox Framework
38c2ecf20Sopenharmony_ci============================
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci:Author: Jassi Brar <jaswinder.singh@linaro.org>
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ciThis document aims to help developers write client and controller
88c2ecf20Sopenharmony_cidrivers for the API. But before we start, let us note that the
98c2ecf20Sopenharmony_ciclient (especially) and controller drivers are likely going to be
108c2ecf20Sopenharmony_civery platform specific because the remote firmware is likely to be
118c2ecf20Sopenharmony_ciproprietary and implement non-standard protocol. So even if two
128c2ecf20Sopenharmony_ciplatforms employ, say, PL320 controller, the client drivers can't
138c2ecf20Sopenharmony_cibe shared across them. Even the PL320 driver might need to accommodate
148c2ecf20Sopenharmony_cisome platform specific quirks. So the API is meant mainly to avoid
158c2ecf20Sopenharmony_cisimilar copies of code written for each platform. Having said that,
168c2ecf20Sopenharmony_cinothing prevents the remote f/w to also be Linux based and use the
178c2ecf20Sopenharmony_cisame api there. However none of that helps us locally because we only
188c2ecf20Sopenharmony_ciever deal at client's protocol level.
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ciSome of the choices made during implementation are the result of this
218c2ecf20Sopenharmony_cipeculiarity of this "common" framework.
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ciController Driver (See include/linux/mailbox_controller.h)
268c2ecf20Sopenharmony_ci==========================================================
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ciAllocate mbox_controller and the array of mbox_chan.
308c2ecf20Sopenharmony_ciPopulate mbox_chan_ops, except peek_data() all are mandatory.
318c2ecf20Sopenharmony_ciThe controller driver might know a message has been consumed
328c2ecf20Sopenharmony_ciby the remote by getting an IRQ or polling some hardware flag
338c2ecf20Sopenharmony_cior it can never know (the client knows by way of the protocol).
348c2ecf20Sopenharmony_ciThe method in order of preference is IRQ -> Poll -> None, which
358c2ecf20Sopenharmony_cithe controller driver should set via 'txdone_irq' or 'txdone_poll'
368c2ecf20Sopenharmony_cior neither.
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ciClient Driver (See include/linux/mailbox_client.h)
408c2ecf20Sopenharmony_ci==================================================
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ciThe client might want to operate in blocking mode (synchronously
448c2ecf20Sopenharmony_cisend a message through before returning) or non-blocking/async mode (submit
458c2ecf20Sopenharmony_cia message and a callback function to the API and return immediately).
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci::
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	struct demo_client {
508c2ecf20Sopenharmony_ci		struct mbox_client cl;
518c2ecf20Sopenharmony_ci		struct mbox_chan *mbox;
528c2ecf20Sopenharmony_ci		struct completion c;
538c2ecf20Sopenharmony_ci		bool async;
548c2ecf20Sopenharmony_ci		/* ... */
558c2ecf20Sopenharmony_ci	};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	/*
588c2ecf20Sopenharmony_ci	* This is the handler for data received from remote. The behaviour is purely
598c2ecf20Sopenharmony_ci	* dependent upon the protocol. This is just an example.
608c2ecf20Sopenharmony_ci	*/
618c2ecf20Sopenharmony_ci	static void message_from_remote(struct mbox_client *cl, void *mssg)
628c2ecf20Sopenharmony_ci	{
638c2ecf20Sopenharmony_ci		struct demo_client *dc = container_of(cl, struct demo_client, cl);
648c2ecf20Sopenharmony_ci		if (dc->async) {
658c2ecf20Sopenharmony_ci			if (is_an_ack(mssg)) {
668c2ecf20Sopenharmony_ci				/* An ACK to our last sample sent */
678c2ecf20Sopenharmony_ci				return; /* Or do something else here */
688c2ecf20Sopenharmony_ci			} else { /* A new message from remote */
698c2ecf20Sopenharmony_ci				queue_req(mssg);
708c2ecf20Sopenharmony_ci			}
718c2ecf20Sopenharmony_ci		} else {
728c2ecf20Sopenharmony_ci			/* Remote f/w sends only ACK packets on this channel */
738c2ecf20Sopenharmony_ci			return;
748c2ecf20Sopenharmony_ci		}
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	static void sample_sent(struct mbox_client *cl, void *mssg, int r)
788c2ecf20Sopenharmony_ci	{
798c2ecf20Sopenharmony_ci		struct demo_client *dc = container_of(cl, struct demo_client, cl);
808c2ecf20Sopenharmony_ci		complete(&dc->c);
818c2ecf20Sopenharmony_ci	}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	static void client_demo(struct platform_device *pdev)
848c2ecf20Sopenharmony_ci	{
858c2ecf20Sopenharmony_ci		struct demo_client *dc_sync, *dc_async;
868c2ecf20Sopenharmony_ci		/* The controller already knows async_pkt and sync_pkt */
878c2ecf20Sopenharmony_ci		struct async_pkt ap;
888c2ecf20Sopenharmony_ci		struct sync_pkt sp;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci		dc_sync = kzalloc(sizeof(*dc_sync), GFP_KERNEL);
918c2ecf20Sopenharmony_ci		dc_async = kzalloc(sizeof(*dc_async), GFP_KERNEL);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci		/* Populate non-blocking mode client */
948c2ecf20Sopenharmony_ci		dc_async->cl.dev = &pdev->dev;
958c2ecf20Sopenharmony_ci		dc_async->cl.rx_callback = message_from_remote;
968c2ecf20Sopenharmony_ci		dc_async->cl.tx_done = sample_sent;
978c2ecf20Sopenharmony_ci		dc_async->cl.tx_block = false;
988c2ecf20Sopenharmony_ci		dc_async->cl.tx_tout = 0; /* doesn't matter here */
998c2ecf20Sopenharmony_ci		dc_async->cl.knows_txdone = false; /* depending upon protocol */
1008c2ecf20Sopenharmony_ci		dc_async->async = true;
1018c2ecf20Sopenharmony_ci		init_completion(&dc_async->c);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci		/* Populate blocking mode client */
1048c2ecf20Sopenharmony_ci		dc_sync->cl.dev = &pdev->dev;
1058c2ecf20Sopenharmony_ci		dc_sync->cl.rx_callback = message_from_remote;
1068c2ecf20Sopenharmony_ci		dc_sync->cl.tx_done = NULL; /* operate in blocking mode */
1078c2ecf20Sopenharmony_ci		dc_sync->cl.tx_block = true;
1088c2ecf20Sopenharmony_ci		dc_sync->cl.tx_tout = 500; /* by half a second */
1098c2ecf20Sopenharmony_ci		dc_sync->cl.knows_txdone = false; /* depending upon protocol */
1108c2ecf20Sopenharmony_ci		dc_sync->async = false;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci		/* ASync mailbox is listed second in 'mboxes' property */
1138c2ecf20Sopenharmony_ci		dc_async->mbox = mbox_request_channel(&dc_async->cl, 1);
1148c2ecf20Sopenharmony_ci		/* Populate data packet */
1158c2ecf20Sopenharmony_ci		/* ap.xxx = 123; etc */
1168c2ecf20Sopenharmony_ci		/* Send async message to remote */
1178c2ecf20Sopenharmony_ci		mbox_send_message(dc_async->mbox, &ap);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci		/* Sync mailbox is listed first in 'mboxes' property */
1208c2ecf20Sopenharmony_ci		dc_sync->mbox = mbox_request_channel(&dc_sync->cl, 0);
1218c2ecf20Sopenharmony_ci		/* Populate data packet */
1228c2ecf20Sopenharmony_ci		/* sp.abc = 123; etc */
1238c2ecf20Sopenharmony_ci		/* Send message to remote in blocking mode */
1248c2ecf20Sopenharmony_ci		mbox_send_message(dc_sync->mbox, &sp);
1258c2ecf20Sopenharmony_ci		/* At this point 'sp' has been sent */
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci		/* Now wait for async chan to be done */
1288c2ecf20Sopenharmony_ci		wait_for_completion(&dc_async->c);
1298c2ecf20Sopenharmony_ci	}
130