1*d8451dfcSMauro Carvalho Chehab============================ 2*d8451dfcSMauro Carvalho ChehabThe Common Mailbox Framework 3*d8451dfcSMauro Carvalho Chehab============================ 4*d8451dfcSMauro Carvalho Chehab 5*d8451dfcSMauro Carvalho Chehab:Author: Jassi Brar <jaswinder.singh@linaro.org> 6*d8451dfcSMauro Carvalho Chehab 7*d8451dfcSMauro Carvalho ChehabThis document aims to help developers write client and controller 8*d8451dfcSMauro Carvalho Chehabdrivers for the API. But before we start, let us note that the 9*d8451dfcSMauro Carvalho Chehabclient (especially) and controller drivers are likely going to be 10*d8451dfcSMauro Carvalho Chehabvery platform specific because the remote firmware is likely to be 11*d8451dfcSMauro Carvalho Chehabproprietary and implement non-standard protocol. So even if two 12*d8451dfcSMauro Carvalho Chehabplatforms employ, say, PL320 controller, the client drivers can't 13*d8451dfcSMauro Carvalho Chehabbe shared across them. Even the PL320 driver might need to accommodate 14*d8451dfcSMauro Carvalho Chehabsome platform specific quirks. So the API is meant mainly to avoid 15*d8451dfcSMauro Carvalho Chehabsimilar copies of code written for each platform. Having said that, 16*d8451dfcSMauro Carvalho Chehabnothing prevents the remote f/w to also be Linux based and use the 17*d8451dfcSMauro Carvalho Chehabsame api there. However none of that helps us locally because we only 18*d8451dfcSMauro Carvalho Chehabever deal at client's protocol level. 19*d8451dfcSMauro Carvalho Chehab 20*d8451dfcSMauro Carvalho ChehabSome of the choices made during implementation are the result of this 21*d8451dfcSMauro Carvalho Chehabpeculiarity of this "common" framework. 22*d8451dfcSMauro Carvalho Chehab 23*d8451dfcSMauro Carvalho Chehab 24*d8451dfcSMauro Carvalho Chehab 25*d8451dfcSMauro Carvalho ChehabController Driver (See include/linux/mailbox_controller.h) 26*d8451dfcSMauro Carvalho Chehab========================================================== 27*d8451dfcSMauro Carvalho Chehab 28*d8451dfcSMauro Carvalho Chehab 29*d8451dfcSMauro Carvalho ChehabAllocate mbox_controller and the array of mbox_chan. 30*d8451dfcSMauro Carvalho ChehabPopulate mbox_chan_ops, except peek_data() all are mandatory. 31*d8451dfcSMauro Carvalho ChehabThe controller driver might know a message has been consumed 32*d8451dfcSMauro Carvalho Chehabby the remote by getting an IRQ or polling some hardware flag 33*d8451dfcSMauro Carvalho Chehabor it can never know (the client knows by way of the protocol). 34*d8451dfcSMauro Carvalho ChehabThe method in order of preference is IRQ -> Poll -> None, which 35*d8451dfcSMauro Carvalho Chehabthe controller driver should set via 'txdone_irq' or 'txdone_poll' 36*d8451dfcSMauro Carvalho Chehabor neither. 37*d8451dfcSMauro Carvalho Chehab 38*d8451dfcSMauro Carvalho Chehab 39*d8451dfcSMauro Carvalho ChehabClient Driver (See include/linux/mailbox_client.h) 40*d8451dfcSMauro Carvalho Chehab================================================== 41*d8451dfcSMauro Carvalho Chehab 42*d8451dfcSMauro Carvalho Chehab 43*d8451dfcSMauro Carvalho ChehabThe client might want to operate in blocking mode (synchronously 44*d8451dfcSMauro Carvalho Chehabsend a message through before returning) or non-blocking/async mode (submit 45*d8451dfcSMauro Carvalho Chehaba message and a callback function to the API and return immediately). 46*d8451dfcSMauro Carvalho Chehab 47*d8451dfcSMauro Carvalho Chehab:: 48*d8451dfcSMauro Carvalho Chehab 49*d8451dfcSMauro Carvalho Chehab struct demo_client { 50*d8451dfcSMauro Carvalho Chehab struct mbox_client cl; 51*d8451dfcSMauro Carvalho Chehab struct mbox_chan *mbox; 52*d8451dfcSMauro Carvalho Chehab struct completion c; 53*d8451dfcSMauro Carvalho Chehab bool async; 54*d8451dfcSMauro Carvalho Chehab /* ... */ 55*d8451dfcSMauro Carvalho Chehab }; 56*d8451dfcSMauro Carvalho Chehab 57*d8451dfcSMauro Carvalho Chehab /* 58*d8451dfcSMauro Carvalho Chehab * This is the handler for data received from remote. The behaviour is purely 59*d8451dfcSMauro Carvalho Chehab * dependent upon the protocol. This is just an example. 60*d8451dfcSMauro Carvalho Chehab */ 61*d8451dfcSMauro Carvalho Chehab static void message_from_remote(struct mbox_client *cl, void *mssg) 62*d8451dfcSMauro Carvalho Chehab { 63*d8451dfcSMauro Carvalho Chehab struct demo_client *dc = container_of(cl, struct demo_client, cl); 64*d8451dfcSMauro Carvalho Chehab if (dc->async) { 65*d8451dfcSMauro Carvalho Chehab if (is_an_ack(mssg)) { 66*d8451dfcSMauro Carvalho Chehab /* An ACK to our last sample sent */ 67*d8451dfcSMauro Carvalho Chehab return; /* Or do something else here */ 68*d8451dfcSMauro Carvalho Chehab } else { /* A new message from remote */ 69*d8451dfcSMauro Carvalho Chehab queue_req(mssg); 70*d8451dfcSMauro Carvalho Chehab } 71*d8451dfcSMauro Carvalho Chehab } else { 72*d8451dfcSMauro Carvalho Chehab /* Remote f/w sends only ACK packets on this channel */ 73*d8451dfcSMauro Carvalho Chehab return; 74*d8451dfcSMauro Carvalho Chehab } 75*d8451dfcSMauro Carvalho Chehab } 76*d8451dfcSMauro Carvalho Chehab 77*d8451dfcSMauro Carvalho Chehab static void sample_sent(struct mbox_client *cl, void *mssg, int r) 78*d8451dfcSMauro Carvalho Chehab { 79*d8451dfcSMauro Carvalho Chehab struct demo_client *dc = container_of(cl, struct demo_client, cl); 80*d8451dfcSMauro Carvalho Chehab complete(&dc->c); 81*d8451dfcSMauro Carvalho Chehab } 82*d8451dfcSMauro Carvalho Chehab 83*d8451dfcSMauro Carvalho Chehab static void client_demo(struct platform_device *pdev) 84*d8451dfcSMauro Carvalho Chehab { 85*d8451dfcSMauro Carvalho Chehab struct demo_client *dc_sync, *dc_async; 86*d8451dfcSMauro Carvalho Chehab /* The controller already knows async_pkt and sync_pkt */ 87*d8451dfcSMauro Carvalho Chehab struct async_pkt ap; 88*d8451dfcSMauro Carvalho Chehab struct sync_pkt sp; 89*d8451dfcSMauro Carvalho Chehab 90*d8451dfcSMauro Carvalho Chehab dc_sync = kzalloc(sizeof(*dc_sync), GFP_KERNEL); 91*d8451dfcSMauro Carvalho Chehab dc_async = kzalloc(sizeof(*dc_async), GFP_KERNEL); 92*d8451dfcSMauro Carvalho Chehab 93*d8451dfcSMauro Carvalho Chehab /* Populate non-blocking mode client */ 94*d8451dfcSMauro Carvalho Chehab dc_async->cl.dev = &pdev->dev; 95*d8451dfcSMauro Carvalho Chehab dc_async->cl.rx_callback = message_from_remote; 96*d8451dfcSMauro Carvalho Chehab dc_async->cl.tx_done = sample_sent; 97*d8451dfcSMauro Carvalho Chehab dc_async->cl.tx_block = false; 98*d8451dfcSMauro Carvalho Chehab dc_async->cl.tx_tout = 0; /* doesn't matter here */ 99*d8451dfcSMauro Carvalho Chehab dc_async->cl.knows_txdone = false; /* depending upon protocol */ 100*d8451dfcSMauro Carvalho Chehab dc_async->async = true; 101*d8451dfcSMauro Carvalho Chehab init_completion(&dc_async->c); 102*d8451dfcSMauro Carvalho Chehab 103*d8451dfcSMauro Carvalho Chehab /* Populate blocking mode client */ 104*d8451dfcSMauro Carvalho Chehab dc_sync->cl.dev = &pdev->dev; 105*d8451dfcSMauro Carvalho Chehab dc_sync->cl.rx_callback = message_from_remote; 106*d8451dfcSMauro Carvalho Chehab dc_sync->cl.tx_done = NULL; /* operate in blocking mode */ 107*d8451dfcSMauro Carvalho Chehab dc_sync->cl.tx_block = true; 108*d8451dfcSMauro Carvalho Chehab dc_sync->cl.tx_tout = 500; /* by half a second */ 109*d8451dfcSMauro Carvalho Chehab dc_sync->cl.knows_txdone = false; /* depending upon protocol */ 110*d8451dfcSMauro Carvalho Chehab dc_sync->async = false; 111*d8451dfcSMauro Carvalho Chehab 112*d8451dfcSMauro Carvalho Chehab /* ASync mailbox is listed second in 'mboxes' property */ 113*d8451dfcSMauro Carvalho Chehab dc_async->mbox = mbox_request_channel(&dc_async->cl, 1); 114*d8451dfcSMauro Carvalho Chehab /* Populate data packet */ 115*d8451dfcSMauro Carvalho Chehab /* ap.xxx = 123; etc */ 116*d8451dfcSMauro Carvalho Chehab /* Send async message to remote */ 117*d8451dfcSMauro Carvalho Chehab mbox_send_message(dc_async->mbox, &ap); 118*d8451dfcSMauro Carvalho Chehab 119*d8451dfcSMauro Carvalho Chehab /* Sync mailbox is listed first in 'mboxes' property */ 120*d8451dfcSMauro Carvalho Chehab dc_sync->mbox = mbox_request_channel(&dc_sync->cl, 0); 121*d8451dfcSMauro Carvalho Chehab /* Populate data packet */ 122*d8451dfcSMauro Carvalho Chehab /* sp.abc = 123; etc */ 123*d8451dfcSMauro Carvalho Chehab /* Send message to remote in blocking mode */ 124*d8451dfcSMauro Carvalho Chehab mbox_send_message(dc_sync->mbox, &sp); 125*d8451dfcSMauro Carvalho Chehab /* At this point 'sp' has been sent */ 126*d8451dfcSMauro Carvalho Chehab 127*d8451dfcSMauro Carvalho Chehab /* Now wait for async chan to be done */ 128*d8451dfcSMauro Carvalho Chehab wait_for_completion(&dc_async->c); 129*d8451dfcSMauro Carvalho Chehab } 130