1 /*
2 * Copyright (c) 2013 The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *    * Redistributions of source code must retain the above copyright
8 *      notice, this list of conditions and the following disclaimer.
9 *    * Redistributions in binary form must reproduce the above
10 *      copyright notice, this list of conditions and the following
11 *      disclaimer in the documentation and/or other materials provided
12 *      with the distribution.
13 *    * Neither the name of The Linux Foundation. nor the names of its
14 *      contributors may be used to endorse or promote products derived
15 *      from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 
30 #include "overlay.h"
31 #include "overlayWriteback.h"
32 #include "mdpWrapper.h"
33 
34 #define SIZE_1M 0x00100000
35 
36 namespace overlay {
37 
38 //=========== class WritebackMem ==============================================
manageMem(uint32_t size,bool isSecure)39 bool WritebackMem::manageMem(uint32_t size, bool isSecure) {
40     if(mBuf.bufSz() == size) {
41         return true;
42     }
43     if(mBuf.valid()) {
44         if(!mBuf.close()) {
45             ALOGE("%s error closing mem", __func__);
46             return false;
47         }
48     }
49     return alloc(size, isSecure);
50 }
51 
alloc(uint32_t size,bool isSecure)52 bool WritebackMem::alloc(uint32_t size, bool isSecure) {
53     if(!mBuf.open(NUM_BUFS, size, isSecure)){
54         ALOGE("%s: Failed to open", __func__);
55         mBuf.close();
56         return false;
57     }
58 
59     OVASSERT(MAP_FAILED != mBuf.addr(), "MAP failed");
60     OVASSERT(mBuf.getFD() != -1, "getFd is -1");
61 
62     mCurrOffsetIndex = 0;
63     for (uint32_t i = 0; i < NUM_BUFS; i++) {
64         mOffsets[i] = i * size;
65     }
66     return true;
67 }
68 
dealloc()69 bool WritebackMem::dealloc() {
70     bool ret = true;
71     if(mBuf.valid()) {
72         ret = mBuf.close();
73     }
74     return ret;
75 }
76 
77 //=========== class Writeback =================================================
Writeback()78 Writeback::Writeback() : mXres(0), mYres(0), mOpFmt(-1), mSecure(false) {
79     int fbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
80     if(!utils::openDev(mFd, fbNum, Res::fbPath, O_RDWR)) {
81         ALOGE("%s failed to init %s", __func__, Res::fbPath);
82         return;
83     }
84     startSession();
85 }
86 
~Writeback()87 Writeback::~Writeback() {
88     stopSession();
89     if (!mFd.close()) {
90         ALOGE("%s error closing fd", __func__);
91     }
92 }
93 
startSession()94 bool Writeback::startSession() {
95     if(!mdp_wrapper::wbInitStart(mFd.getFD())) {
96         ALOGE("%s failed", __func__);
97         return false;
98     }
99     return true;
100 }
101 
stopSession()102 bool Writeback::stopSession() {
103     if(mFd.valid()) {
104         if(!Overlay::displayCommit(mFd.getFD())) {
105             ALOGE("%s: displayCommit failed", __func__);
106             return false;
107         }
108         if(!mdp_wrapper::wbStopTerminate(mFd.getFD())) {
109             ALOGE("%s: wbStopTerminate failed", __func__);
110             return false;
111         }
112     } else {
113         ALOGE("%s Invalid fd", __func__);
114         return false;
115     }
116     return true;
117 }
118 
configureDpyInfo(int xres,int yres)119 bool Writeback::configureDpyInfo(int xres, int yres) {
120     if(mXres != xres || mYres != yres) {
121         fb_var_screeninfo vinfo;
122         memset(&vinfo, 0, sizeof(fb_var_screeninfo));
123         if(!mdp_wrapper::getVScreenInfo(mFd.getFD(), vinfo)) {
124             ALOGE("%s failed", __func__);
125             return false;
126         }
127         vinfo.xres = xres;
128         vinfo.yres = yres;
129         vinfo.xres_virtual = xres;
130         vinfo.yres_virtual = yres;
131         vinfo.xoffset = 0;
132         vinfo.yoffset = 0;
133         if(!mdp_wrapper::setVScreenInfo(mFd.getFD(), vinfo)) {
134             ALOGE("%s failed", __func__);
135             return false;
136         }
137         mXres = xres;
138         mYres = yres;
139     }
140     return true;
141 }
142 
configureMemory(uint32_t size)143 bool Writeback::configureMemory(uint32_t size) {
144     if(!mWbMem.manageMem(size, mSecure)) {
145         ALOGE("%s failed, memory failure", __func__);
146         return false;
147     }
148     return true;
149 }
150 
queueBuffer(int opFd,uint32_t opOffset)151 bool Writeback::queueBuffer(int opFd, uint32_t opOffset) {
152     memset(&mFbData, 0, sizeof(struct msmfb_data));
153     //Queue
154     mFbData.offset = opOffset;
155     mFbData.memory_id = opFd;
156     mFbData.id = 0;
157     mFbData.flags = 0;
158     if(!mdp_wrapper::wbQueueBuffer(mFd.getFD(), mFbData)) {
159         ALOGE("%s: queuebuffer failed", __func__);
160         return false;
161     }
162     return true;
163 }
164 
dequeueBuffer()165 bool Writeback::dequeueBuffer() {
166     //Dequeue
167     mFbData.flags = MSMFB_WRITEBACK_DEQUEUE_BLOCKING;
168     if(!mdp_wrapper::wbDequeueBuffer(mFd.getFD(), mFbData)) {
169         ALOGE("%s: dequeuebuffer failed", __func__);
170         return false;
171     }
172     return true;
173 }
174 
writeSync(int opFd,uint32_t opOffset)175 bool Writeback::writeSync(int opFd, uint32_t opOffset) {
176     if(!queueBuffer(opFd, opOffset)) {
177         return false;
178     }
179     if(!Overlay::displayCommit(mFd.getFD())) {
180         return false;
181     }
182     if(!dequeueBuffer()) {
183         return false;
184     }
185     return true;
186 }
187 
writeSync()188 bool Writeback::writeSync() {
189     mWbMem.useNextBuffer();
190     return writeSync(mWbMem.getDstFd(), mWbMem.getOffset());
191 }
192 
setOutputFormat(int mdpFormat)193 bool Writeback::setOutputFormat(int mdpFormat) {
194     if(mdpFormat != mOpFmt) {
195         struct msmfb_metadata metadata;
196         memset(&metadata, 0 , sizeof(metadata));
197         metadata.op = metadata_op_wb_format;
198         metadata.data.mixer_cfg.writeback_format = mdpFormat;
199         if (ioctl(mFd.getFD(), MSMFB_METADATA_SET, &metadata) < 0) {
200             ALOGE("Error setting MDP Writeback format");
201             return false;
202         }
203         mOpFmt = mdpFormat;
204     }
205     return true;
206 }
207 
getOutputFormat()208 int Writeback::getOutputFormat() {
209     if(mOpFmt < 0) {
210         struct msmfb_metadata metadata;
211         memset(&metadata, 0 , sizeof(metadata));
212         metadata.op = metadata_op_wb_format;
213         if (ioctl(mFd.getFD(), MSMFB_METADATA_GET, &metadata) < 0) {
214             ALOGE("Error retrieving MDP Writeback format");
215             return -1;
216         }
217         mOpFmt =  metadata.data.mixer_cfg.writeback_format;
218     }
219     return mOpFmt;
220 }
221 
setSecure(bool isSecure)222 bool Writeback::setSecure(bool isSecure) {
223     if(isSecure != mSecure) {
224         // Call IOCTL to set WB interface as secure
225         struct msmfb_metadata metadata;
226         memset(&metadata, 0 , sizeof(metadata));
227         metadata.op = metadata_op_wb_secure;
228         metadata.data.secure_en = isSecure;
229         if (ioctl(mFd.getFD(), MSMFB_METADATA_SET, &metadata) < 0) {
230             ALOGE("Error setting MDP WB secure");
231             return false;
232         }
233         mSecure = isSecure;
234     }
235     return true;
236 }
237 
238 //static
239 
getInstance()240 Writeback *Writeback::getInstance() {
241     if(sWb == NULL) {
242         sWb = new Writeback();
243     }
244     sUsed = true;
245     return sWb;
246 }
247 
configDone()248 void Writeback::configDone() {
249     if(sUsed == false && sWb) {
250         delete sWb;
251         sWb = NULL;
252     }
253 }
254 
clear()255 void Writeback::clear() {
256     sUsed = false;
257     if(sWb) {
258         delete sWb;
259         sWb = NULL;
260     }
261 }
262 
getDump(char * buf,size_t len)263 bool Writeback::getDump(char *buf, size_t len) {
264     if(sWb) {
265         utils::getDump(buf, len, "WBData", sWb->mFbData);
266         char outputBufferInfo[256];
267         snprintf(outputBufferInfo, sizeof(outputBufferInfo),
268                 "OutputBuffer xres=%d yres=%d format=%s\n\n",
269                 sWb->getWidth(), sWb->getHeight(),
270                 utils::getFormatString(sWb->getOutputFormat()));
271         strlcat(buf, outputBufferInfo, len);
272         return true;
273     }
274     return false;
275 }
276 
277 Writeback *Writeback::sWb = 0;
278 bool Writeback::sUsed = false;
279 
280 } //namespace overlay
281