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(!mdp_wrapper::wbStopTerminate(mFd.getFD())) {
105            ALOGE("%s failed", __func__);
106            return false;
107        }
108    } else {
109        ALOGE("%s Invalid fd", __func__);
110        return false;
111    }
112    return true;
113}
114
115bool Writeback::configureDpyInfo(int xres, int yres) {
116    if(mXres != xres || mYres != yres) {
117        fb_var_screeninfo vinfo;
118        memset(&vinfo, 0, sizeof(fb_var_screeninfo));
119        if(!mdp_wrapper::getVScreenInfo(mFd.getFD(), vinfo)) {
120            ALOGE("%s failed", __func__);
121            return false;
122        }
123        vinfo.xres = xres;
124        vinfo.yres = yres;
125        vinfo.xres_virtual = xres;
126        vinfo.yres_virtual = yres;
127        vinfo.xoffset = 0;
128        vinfo.yoffset = 0;
129        if(!mdp_wrapper::setVScreenInfo(mFd.getFD(), vinfo)) {
130            ALOGE("%s failed", __func__);
131            return false;
132        }
133        mXres = xres;
134        mYres = yres;
135    }
136    return true;
137}
138
139bool Writeback::configureMemory(uint32_t size) {
140    if(!mWbMem.manageMem(size, mSecure)) {
141        ALOGE("%s failed, memory failure", __func__);
142        return false;
143    }
144    return true;
145}
146
147bool Writeback::queueBuffer(int opFd, uint32_t opOffset) {
148    memset(&mFbData, 0, sizeof(struct msmfb_data));
149    //Queue
150    mFbData.offset = opOffset;
151    mFbData.memory_id = opFd;
152    mFbData.id = 0;
153    mFbData.flags = 0;
154    if(!mdp_wrapper::wbQueueBuffer(mFd.getFD(), mFbData)) {
155        ALOGE("%s: queuebuffer failed", __func__);
156        return false;
157    }
158    return true;
159}
160
161bool Writeback::dequeueBuffer() {
162    //Dequeue
163    mFbData.flags = MSMFB_WRITEBACK_DEQUEUE_BLOCKING;
164    if(!mdp_wrapper::wbDequeueBuffer(mFd.getFD(), mFbData)) {
165        ALOGE("%s: dequeuebuffer failed", __func__);
166        return false;
167    }
168    return true;
169}
170
171bool Writeback::writeSync(int opFd, uint32_t opOffset) {
172    if(!queueBuffer(opFd, opOffset)) {
173        return false;
174    }
175    if(!Overlay::displayCommit(mFd.getFD())) {
176        return false;
177    }
178    if(!dequeueBuffer()) {
179        return false;
180    }
181    return true;
182}
183
184bool Writeback::writeSync() {
185    mWbMem.useNextBuffer();
186    return writeSync(mWbMem.getDstFd(), mWbMem.getOffset());
187}
188
189bool Writeback::setOutputFormat(int mdpFormat) {
190    if(mdpFormat != mOpFmt) {
191        struct msmfb_metadata metadata;
192        memset(&metadata, 0 , sizeof(metadata));
193        metadata.op = metadata_op_wb_format;
194        metadata.data.mixer_cfg.writeback_format = mdpFormat;
195        if (ioctl(mFd.getFD(), MSMFB_METADATA_SET, &metadata) < 0) {
196            ALOGE("Error setting MDP Writeback format");
197            return false;
198        }
199        mOpFmt = mdpFormat;
200    }
201    return true;
202}
203
204int Writeback::getOutputFormat() {
205    if(mOpFmt < 0) {
206        struct msmfb_metadata metadata;
207        memset(&metadata, 0 , sizeof(metadata));
208        metadata.op = metadata_op_wb_format;
209        if (ioctl(mFd.getFD(), MSMFB_METADATA_GET, &metadata) < 0) {
210            ALOGE("Error retrieving MDP Writeback format");
211            return -1;
212        }
213        mOpFmt =  metadata.data.mixer_cfg.writeback_format;
214    }
215    return mOpFmt;
216}
217
218bool Writeback::setSecure(bool isSecure) {
219    if(isSecure != mSecure) {
220        // Call IOCTL to set WB interface as secure
221        struct msmfb_metadata metadata;
222        memset(&metadata, 0 , sizeof(metadata));
223        metadata.op = metadata_op_wb_secure;
224        metadata.data.secure_en = isSecure;
225        if (ioctl(mFd.getFD(), MSMFB_METADATA_SET, &metadata) < 0) {
226            ALOGE("Error setting MDP WB secure");
227            return false;
228        }
229        mSecure = isSecure;
230    }
231    return true;
232}
233
234//static
235
236Writeback *Writeback::getInstance() {
237    if(sWb == NULL) {
238        sWb = new Writeback();
239    }
240    sUsed = true;
241    return sWb;
242}
243
244void Writeback::configDone() {
245    if(sUsed == false && sWb) {
246        delete sWb;
247        sWb = NULL;
248    }
249}
250
251void Writeback::clear() {
252    sUsed = false;
253    if(sWb) {
254        delete sWb;
255        sWb = NULL;
256    }
257}
258
259bool Writeback::getDump(char *buf, size_t len) {
260    if(sWb) {
261        utils::getDump(buf, len, "WBData", sWb->mFbData);
262        char str[4] = {'\0'};
263        snprintf(str, 4, "\n");
264        strlcat(buf, str, len);
265        return true;
266    }
267    return false;
268}
269
270Writeback *Writeback::sWb = 0;
271bool Writeback::sUsed = false;
272
273} //namespace overlay
274