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
36namespace overlay {
37
38//=========== class WritebackMem ==============================================
39bool 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
52bool 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
69bool WritebackMem::dealloc() {
70    bool ret = true;
71    if(mBuf.valid()) {
72        ret = mBuf.close();
73    }
74    return ret;
75}
76
77//=========== class Writeback =================================================
78Writeback::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
87Writeback::~Writeback() {
88    stopSession();
89    if (!mFd.close()) {
90        ALOGE("%s error closing fd", __func__);
91    }
92}
93
94bool Writeback::startSession() {
95    if(!mdp_wrapper::wbInitStart(mFd.getFD())) {
96        ALOGE("%s failed", __func__);
97        return false;
98    }
99    return true;
100}
101
102bool 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
119bool 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
143bool 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
151bool 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
165bool 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
175bool 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
188bool Writeback::writeSync() {
189    mWbMem.useNextBuffer();
190    return writeSync(mWbMem.getDstFd(), mWbMem.getOffset());
191}
192
193bool 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
208int 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
222bool 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
240Writeback *Writeback::getInstance() {
241    if(sWb == NULL) {
242        sWb = new Writeback();
243    }
244    sUsed = true;
245    return sWb;
246}
247
248void Writeback::configDone() {
249    if(sUsed == false && sWb) {
250        delete sWb;
251        sWb = NULL;
252    }
253}
254
255void Writeback::clear() {
256    sUsed = false;
257    if(sWb) {
258        delete sWb;
259        sWb = NULL;
260    }
261}
262
263bool 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
277Writeback *Writeback::sWb = 0;
278bool Writeback::sUsed = false;
279
280} //namespace overlay
281