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