1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510 |
- /* drivers/video/msm/msm_fb.c
- *
- * Core MSM framebuffer driver.
- *
- * Copyright (C) 2007 Google Incorporated
- * Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include <linux/module.h>
- #include <linux/moduleparam.h>
- #include <linux/kernel.h>
- #include <linux/slab.h>
- #include <linux/delay.h>
- #include <linux/mm.h>
- #include <linux/fb.h>
- #include <linux/msm_mdp.h>
- #include <linux/init.h>
- #include <linux/ioport.h>
- #include <linux/device.h>
- #include <linux/dma-mapping.h>
- #include <mach/board.h>
- #include <linux/uaccess.h>
- #include <mach/iommu_domains.h>
- #include <linux/workqueue.h>
- #include <linux/string.h>
- #include <linux/version.h>
- #include <linux/proc_fs.h>
- #include <linux/vmalloc.h>
- #include <linux/debugfs.h>
- #include <linux/console.h>
- #include <linux/leds.h>
- #include <linux/pm_runtime.h>
- #include <linux/sync.h>
- #include <linux/sw_sync.h>
- #include <linux/file.h>
- #ifdef CONFIG_SEC_DEBUG
- #include <mach/sec_debug.h>
- #endif
- #define MSM_FB_C
- #include "msm_fb.h"
- #include "mddihosti.h"
- #include "tvenc.h"
- #include "mdp.h"
- #include "mdp4.h"
- #ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
- #define MSM_FB_NUM 3
- #endif
- static unsigned char *fbram;
- static unsigned char *fbram_phys;
- static int fbram_size;
- static boolean bf_supported;
- /* Set backlight on resume after 50 ms after first
- * pan display on the panel. This is to avoid panel specific
- * transients during resume.
- */
- unsigned long backlight_duration = (HZ/20);
- static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
- static int pdev_list_cnt;
- int vsync_mode = 1;
- #define MAX_BLIT_REQ 256
- #define MAX_FBI_LIST 32
- static struct fb_info *fbi_list[MAX_FBI_LIST];
- static int fbi_list_index;
- static struct msm_fb_data_type *mfd_list[MAX_FBI_LIST];
- static int mfd_list_index;
- static u32 msm_fb_pseudo_palette[16] = {
- 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
- 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
- 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
- 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
- };
- static struct ion_client *iclient;
- u32 msm_fb_debug_enabled;
- /* Setting msm_fb_msg_level to 8 prints out ALL messages */
- u32 msm_fb_msg_level = 7;
- /* Setting mddi_msg_level to 8 prints out ALL messages */
- u32 mddi_msg_level = 5;
- extern int32 mdp_block_power_cnt[MDP_MAX_BLOCK];
- extern unsigned long mdp_timer_duration;
- static int msm_fb_register(struct msm_fb_data_type *mfd);
- static int msm_fb_open(struct fb_info *info, int user);
- static int msm_fb_release(struct fb_info *info, int user);
- static int msm_fb_pan_display(struct fb_var_screeninfo *var,
- struct fb_info *info);
- static int msm_fb_stop_sw_refresher(struct msm_fb_data_type *mfd);
- int msm_fb_resume_sw_refresher(struct msm_fb_data_type *mfd);
- static int msm_fb_check_var(struct fb_var_screeninfo *var,
- struct fb_info *info);
- static int msm_fb_set_par(struct fb_info *info);
- static int msm_fb_blank_sub(int blank_mode, struct fb_info *info,
- boolean op_enable);
- static int msm_fb_suspend_sub(struct msm_fb_data_type *mfd);
- static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd,
- unsigned long arg);
- static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma);
- static int mdp_bl_scale_config(struct msm_fb_data_type *mfd,
- struct mdp_bl_scale_data *data);
- static void msm_fb_scale_bl(__u32 *bl_lvl);
- static void msm_fb_commit_wq_handler(struct work_struct *work);
- static int msm_fb_pan_idle(struct msm_fb_data_type *mfd);
- #ifdef MSM_FB_ENABLE_DBGFS
- #define MSM_FB_MAX_DBGFS 1024
- #define MAX_BACKLIGHT_BRIGHTNESS 255
- /* 200 ms for time out */
- #define WAIT_FENCE_TIMEOUT 200
- int msm_fb_debugfs_file_index;
- struct dentry *msm_fb_debugfs_root;
- struct dentry *msm_fb_debugfs_file[MSM_FB_MAX_DBGFS];
- static int bl_scale, bl_min_lvl;
- DEFINE_MUTEX(msm_fb_notify_update_sem);
- void msmfb_no_update_notify_timer_cb(unsigned long data)
- {
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
- if (!mfd)
- pr_err("%s mfd NULL\n", __func__);
- complete(&mfd->msmfb_no_update_notify);
- }
- struct dentry *msm_fb_get_debugfs_root(void)
- {
- if (msm_fb_debugfs_root == NULL)
- msm_fb_debugfs_root = debugfs_create_dir("msm_fb", NULL);
- return msm_fb_debugfs_root;
- }
- void msm_fb_debugfs_file_create(struct dentry *root, const char *name,
- u32 *var)
- {
- if (msm_fb_debugfs_file_index >= MSM_FB_MAX_DBGFS)
- return;
- msm_fb_debugfs_file[msm_fb_debugfs_file_index++] =
- debugfs_create_u32(name, S_IRUGO | S_IWUSR, root, var);
- }
- #endif
- int msm_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
- {
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- if (!mfd->cursor_update)
- return -ENODEV;
- return mfd->cursor_update(info, cursor);
- }
- static int msm_fb_resource_initialized;
- #ifndef CONFIG_FB_BACKLIGHT
- static int lcd_backlight_registered;
- static void msm_fb_set_bl_brightness(struct led_classdev *led_cdev,
- enum led_brightness value)
- {
- struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent);
- int bl_lvl;
- if (value > MAX_BACKLIGHT_BRIGHTNESS)
- value = MAX_BACKLIGHT_BRIGHTNESS;
- /* This maps android backlight level 0 to 255 into
- driver backlight level 0 to bl_max with rounding */
- bl_lvl = (2 * value * mfd->panel_info.bl_max + MAX_BACKLIGHT_BRIGHTNESS)
- /(2 * MAX_BACKLIGHT_BRIGHTNESS);
- if (!bl_lvl && value)
- bl_lvl = 1;
- down(&mfd->sem);
- msm_fb_set_backlight(mfd, bl_lvl);
- up(&mfd->sem);
- }
- static struct led_classdev backlight_led = {
- .name = "lcd-backlight",
- .brightness = MAX_BACKLIGHT_BRIGHTNESS,
- .brightness_set = msm_fb_set_bl_brightness,
- };
- #endif
- static struct msm_fb_platform_data *msm_fb_pdata;
- unsigned char hdmi_prim_display;
- unsigned char hdmi_prim_resolution;
- int msm_fb_detect_client(const char *name)
- {
- int ret = 0;
- u32 len;
- #ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
- u32 id;
- #endif
- if (!msm_fb_pdata)
- return -EPERM;
- len = strnlen(name, PANEL_NAME_MAX_LEN);
- if (strnlen(msm_fb_pdata->prim_panel_name, PANEL_NAME_MAX_LEN)) {
- pr_err("\n name = %s, prim_display = %s",
- name, msm_fb_pdata->prim_panel_name);
- if (!strncmp((char *)msm_fb_pdata->prim_panel_name,
- name, len)) {
- if (!strncmp((char *)msm_fb_pdata->prim_panel_name,
- "hdmi_msm", len))
- hdmi_prim_display = 1;
- hdmi_prim_resolution =
- msm_fb_pdata->ext_resolution;
- return 0;
- } else {
- ret = -EPERM;
- }
- }
- if (strnlen(msm_fb_pdata->ext_panel_name, PANEL_NAME_MAX_LEN)) {
- pr_err("\n name = %s, ext_display = %s",
- name, msm_fb_pdata->ext_panel_name);
- if (!strncmp((char *)msm_fb_pdata->ext_panel_name, name, len))
- return 0;
- else
- ret = -EPERM;
- }
- if (ret)
- return ret;
- ret = -EPERM;
- if (msm_fb_pdata && msm_fb_pdata->detect_client) {
- ret = msm_fb_pdata->detect_client(name);
- /* if it's non mddi panel, we need to pre-scan
- mddi client to see if we can disable mddi host */
- #ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
- if (!ret && msm_fb_pdata->mddi_prescan)
- id = mddi_get_client_id();
- #endif
- }
- return ret;
- }
- static ssize_t msm_fb_fps_level_change(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- struct fb_info *fbi = dev_get_drvdata(dev);
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
- struct msm_fb_panel_data *pdata =
- (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
- unsigned long val;
- int ret;
- ret = kstrtoul(buf, 10, &val);
- if (ret)
- return ret;
- if ((val <= 0) || (val > 100))
- return -EINVAL;
- if (pdata->fps_level_change)
- pdata->fps_level_change(mfd->pdev, (u32)val);
- return count;
- }
- static ssize_t msm_fb_msm_fb_type(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- ssize_t ret = 0;
- struct fb_info *fbi = dev_get_drvdata(dev);
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
- struct msm_fb_panel_data *pdata =
- (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
- switch (pdata->panel_info.type) {
- case NO_PANEL:
- ret = snprintf(buf, PAGE_SIZE, "no panel\n");
- break;
- case MDDI_PANEL:
- ret = snprintf(buf, PAGE_SIZE, "mddi panel\n");
- break;
- case EBI2_PANEL:
- ret = snprintf(buf, PAGE_SIZE, "ebi2 panel\n");
- break;
- case LCDC_PANEL:
- ret = snprintf(buf, PAGE_SIZE, "lcdc panel\n");
- break;
- case EXT_MDDI_PANEL:
- ret = snprintf(buf, PAGE_SIZE, "ext mddi panel\n");
- break;
- case TV_PANEL:
- ret = snprintf(buf, PAGE_SIZE, "tv panel\n");
- break;
- case HDMI_PANEL:
- ret = snprintf(buf, PAGE_SIZE, "hdmi panel\n");
- break;
- case LVDS_PANEL:
- ret = snprintf(buf, PAGE_SIZE, "lvds panel\n");
- break;
- case DTV_PANEL:
- ret = snprintf(buf, PAGE_SIZE, "dtv panel\n");
- break;
- case MIPI_VIDEO_PANEL:
- ret = snprintf(buf, PAGE_SIZE, "mipi dsi video panel\n");
- break;
- case MIPI_CMD_PANEL:
- ret = snprintf(buf, PAGE_SIZE, "mipi dsi cmd panel\n");
- break;
- case WRITEBACK_PANEL:
- ret = snprintf(buf, PAGE_SIZE, "writeback panel\n");
- break;
- default:
- ret = snprintf(buf, PAGE_SIZE, "unknown panel\n");
- break;
- }
- return ret;
- }
- static int pcc_r = 32768, pcc_g = 32768, pcc_b = 32768;
- static ssize_t mdp_get_rgb(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- return sprintf(buf, "%d %d %d\n", pcc_r, pcc_g, pcc_b);
- }
- /**
- * simple color temperature interface using polynomial color correction
- *
- * input values are r/g/b adjustments from 0-32768 representing 0 -> 1
- *
- * example adjustment @ 3500K:
- * 1.0000 / 0.5515 / 0.2520 = 32768 / 25828 / 17347
- *
- * reference chart:
- * http://www.vendian.org/mncharity/dir3/blackbody/UnstableURLs/bbr_color.html
- */
- static ssize_t mdp_set_rgb(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- uint32_t r = 0, g = 0, b = 0;
- struct mdp_pcc_cfg_data pcc_cfg;
- if (count > 19)
- return -EINVAL;
- sscanf(buf, "%d %d %d", &r, &g, &b);
- if (r < 0 || r > 32768)
- return -EINVAL;
- if (g < 0 || g > 32768)
- return -EINVAL;
- if (b < 0 || b > 32768)
- return -EINVAL;
- pr_info("%s: r=%d g=%d b=%d", __func__, r, g, b);
- memset(&pcc_cfg, 0, sizeof(struct mdp_pcc_cfg_data));
- pcc_cfg.block = MDP_BLOCK_DMA_P;
- pcc_cfg.ops = MDP_PP_OPS_ENABLE | MDP_PP_OPS_WRITE;
- pcc_cfg.r.r = r;
- pcc_cfg.g.g = g;
- pcc_cfg.b.b = b;
- if (mdp4_pcc_cfg(&pcc_cfg) == 0) {
- pcc_r = r;
- pcc_g = g;
- pcc_b = b;
- return count;
- }
- return -EINVAL;
- }
- void mdp_restore_rgb(void)
- {
- struct mdp_pcc_cfg_data pcc_cfg;
- memset(&pcc_cfg, 0, sizeof(struct mdp_pcc_cfg_data));
- pcc_cfg.block = MDP_BLOCK_DMA_P;
- pcc_cfg.ops = MDP_PP_OPS_ENABLE | MDP_PP_OPS_WRITE;
- pcc_cfg.r.r = pcc_r;
- pcc_cfg.g.g = pcc_g;
- pcc_cfg.b.b = pcc_b;
- mdp4_pcc_cfg(&pcc_cfg);
- }
- static DEVICE_ATTR(msm_fb_type, S_IRUGO, msm_fb_msm_fb_type, NULL);
- static DEVICE_ATTR(msm_fb_fps_level, S_IRUGO | S_IWUGO, NULL, \
- msm_fb_fps_level_change);
- static DEVICE_ATTR(rgb, S_IRUGO | S_IWUSR | S_IWGRP, mdp_get_rgb, \
- mdp_set_rgb);
- static struct attribute *msm_fb_attrs[] = {
- &dev_attr_msm_fb_type.attr,
- &dev_attr_msm_fb_fps_level.attr,
- &dev_attr_rgb.attr,
- NULL,
- };
- static struct attribute_group msm_fb_attr_group = {
- .attrs = msm_fb_attrs,
- };
- static int msm_fb_create_sysfs(struct platform_device *pdev)
- {
- int rc;
- struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
- rc = sysfs_create_group(&mfd->fbi->dev->kobj, &msm_fb_attr_group);
- if (rc)
- MSM_FB_ERR("%s: sysfs group creation failed, rc=%d\n", __func__,
- rc);
- return rc;
- }
- static void msm_fb_remove_sysfs(struct platform_device *pdev)
- {
- struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
- sysfs_remove_group(&mfd->fbi->dev->kobj, &msm_fb_attr_group);
- }
- static void bl_workqueue_handler(struct work_struct *work);
- static int msm_fb_probe(struct platform_device *pdev)
- {
- struct msm_fb_data_type *mfd;
- int rc;
- int err = 0;
- MSM_FB_DEBUG("msm_fb_probe\n");
- if ((pdev->id == 0) && (pdev->num_resources > 0)) {
- msm_fb_pdata = pdev->dev.platform_data;
- fbram_size =
- pdev->resource[0].end - pdev->resource[0].start + 1;
- fbram_phys = (char *)pdev->resource[0].start;
- fbram = __va(fbram_phys);
- if (!fbram) {
- printk(KERN_ERR "fbram ioremap failed!\n");
- return -ENOMEM;
- }
- MSM_FB_DEBUG("msm_fb_probe: phy_Addr = 0x%x virt = 0x%x\n",
- (int)fbram_phys, (int)fbram);
- iclient = msm_ion_client_create(-1, pdev->name);
- if (IS_ERR_OR_NULL(iclient)) {
- pr_err("msm_ion_client_create() return"
- " error, val %pK\n", iclient);
- iclient = NULL;
- }
- msm_fb_resource_initialized = 1;
- return 0;
- }
- if (!msm_fb_resource_initialized)
- return -EPERM;
- mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
- INIT_DELAYED_WORK(&mfd->backlight_worker, bl_workqueue_handler);
- if (!mfd)
- return -ENODEV;
- if (mfd->key != MFD_KEY)
- return -EINVAL;
- if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
- return -ENOMEM;
- vsync_cntrl.dev = mfd->fbi->dev;
- mfd->panel_info.frame_count = 0;
- mfd->bl_level = 0;
- bl_scale = 1024;
- bl_min_lvl = 255;
- #ifdef CONFIG_FB_MSM_OVERLAY
- mfd->overlay_play_enable = 1;
- #endif
- bf_supported = mdp4_overlay_borderfill_supported();
- rc = msm_fb_register(mfd);
- if (rc)
- return rc;
- err = pm_runtime_set_active(mfd->fbi->dev);
- if (err < 0)
- printk(KERN_ERR "pm_runtime: fail to set active.\n");
- pm_runtime_enable(mfd->fbi->dev);
- #ifdef CONFIG_FB_BACKLIGHT
- msm_fb_config_backlight(mfd);
- #else
- /* android supports only one lcd-backlight/lcd for now */
- if (!lcd_backlight_registered) {
- if (led_classdev_register(&pdev->dev, &backlight_led))
- printk(KERN_ERR "led_classdev_register failed\n");
- else
- lcd_backlight_registered = 1;
- }
- #endif
- pdev_list[pdev_list_cnt++] = pdev;
- msm_fb_create_sysfs(pdev);
- if (mfd->timeline == NULL) {
- mfd->timeline = sw_sync_timeline_create("mdp-timeline");
- if (mfd->timeline == NULL) {
- pr_err("%s: cannot create time line", __func__);
- return -ENOMEM;
- } else {
- mfd->timeline_value = 0;
- }
- }
- return 0;
- }
- static int msm_fb_remove(struct platform_device *pdev)
- {
- struct msm_fb_data_type *mfd;
- MSM_FB_DEBUG("msm_fb_remove\n");
- mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
- msm_fb_remove_sysfs(pdev);
- pm_runtime_disable(mfd->fbi->dev);
- if (!mfd)
- return -ENODEV;
- if (mfd->key != MFD_KEY)
- return -EINVAL;
- if (msm_fb_suspend_sub(mfd))
- printk(KERN_ERR "msm_fb_remove: can't stop the device %d\n", mfd->index);
- if (mfd->channel_irq != 0)
- free_irq(mfd->channel_irq, (void *)mfd);
- if (mfd->vsync_width_boundary)
- vfree(mfd->vsync_width_boundary);
- if (mfd->vsync_resync_timer.function)
- del_timer(&mfd->vsync_resync_timer);
- if (mfd->refresh_timer.function)
- del_timer(&mfd->refresh_timer);
- if (mfd->dma_hrtimer.function)
- hrtimer_cancel(&mfd->dma_hrtimer);
- if (mfd->msmfb_no_update_notify_timer.function)
- del_timer(&mfd->msmfb_no_update_notify_timer);
- complete(&mfd->msmfb_no_update_notify);
- complete(&mfd->msmfb_update_notify);
- /* remove /dev/fb* */
- unregister_framebuffer(mfd->fbi);
- #ifdef CONFIG_FB_BACKLIGHT
- /* remove /sys/class/backlight */
- backlight_device_unregister(mfd->fbi->bl_dev);
- #else
- if (lcd_backlight_registered) {
- lcd_backlight_registered = 0;
- led_classdev_unregister(&backlight_led);
- }
- #endif
- #ifdef MSM_FB_ENABLE_DBGFS
- if (mfd->sub_dir)
- debugfs_remove(mfd->sub_dir);
- #endif
- return 0;
- }
- #if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND)
- static int msm_fb_suspend(struct platform_device *pdev, pm_message_t state)
- {
- struct msm_fb_data_type *mfd;
- int ret = 0;
- MSM_FB_DEBUG("msm_fb_suspend\n");
- mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
- if ((!mfd) || (mfd->key != MFD_KEY))
- return 0;
- console_lock();
- fb_set_suspend(mfd->fbi, FBINFO_STATE_SUSPENDED);
- ret = msm_fb_suspend_sub(mfd);
- if (ret != 0) {
- printk(KERN_ERR "msm_fb: failed to suspend! %d\n", ret);
- fb_set_suspend(mfd->fbi, FBINFO_STATE_RUNNING);
- } else {
- pdev->dev.power.power_state = state;
- }
- console_unlock();
- return ret;
- }
- #else
- #define msm_fb_suspend NULL
- #endif
- static int msm_fb_suspend_sub(struct msm_fb_data_type *mfd)
- {
- int ret = 0;
- if ((!mfd) || (mfd->key != MFD_KEY))
- return 0;
- if (mfd->msmfb_no_update_notify_timer.function)
- del_timer(&mfd->msmfb_no_update_notify_timer);
- complete(&mfd->msmfb_no_update_notify);
- /*
- * suspend this channel
- */
- mfd->suspend.sw_refreshing_enable = mfd->sw_refreshing_enable;
- mfd->suspend.op_enable = mfd->op_enable;
- mfd->suspend.panel_power_on = mfd->panel_power_on;
- mfd->suspend.op_suspend = true;
- if (mfd->op_enable) {
- ret =
- msm_fb_blank_sub(FB_BLANK_POWERDOWN, mfd->fbi,
- mfd->suspend.op_enable);
- if (ret) {
- MSM_FB_INFO
- ("msm_fb_suspend: can't turn off display!\n");
- return ret;
- }
- mfd->op_enable = FALSE;
- }
- /*
- * try to power down
- */
- mdp_pipe_ctrl(MDP_MASTER_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
- /*
- * detach display channel irq if there's any
- * or wait until vsync-resync completes
- */
- if ((mfd->dest == DISPLAY_LCD)) {
- if (mfd->panel_info.lcd.vsync_enable) {
- if (mfd->panel_info.lcd.hw_vsync_mode) {
- if (mfd->channel_irq != 0)
- disable_irq(mfd->channel_irq);
- } else {
- volatile boolean vh_pending;
- do {
- vh_pending = mfd->vsync_handler_pending;
- } while (vh_pending);
- }
- }
- }
- return 0;
- }
- #ifdef CONFIG_PM
- static int msm_fb_resume_sub(struct msm_fb_data_type *mfd)
- {
- int ret = 0;
- struct msm_fb_panel_data *pdata = NULL;
- if ((!mfd) || (mfd->key != MFD_KEY))
- return 0;
- pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
- /* attach display channel irq if there's any */
- if (mfd->channel_irq != 0)
- enable_irq(mfd->channel_irq);
- /* resume state var recover */
- mfd->sw_refreshing_enable = mfd->suspend.sw_refreshing_enable;
- mfd->op_enable = mfd->suspend.op_enable;
- if (mfd->suspend.panel_power_on) {
- ret =
- msm_fb_blank_sub(FB_BLANK_UNBLANK, mfd->fbi,
- mfd->op_enable);
- if (ret)
- MSM_FB_INFO("msm_fb_resume: can't turn on display!\n");
- }
- mfd->suspend.op_suspend = false;
- return ret;
- }
- #endif
- #if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND)
- static int msm_fb_resume(struct platform_device *pdev)
- {
- /* This resume function is called when interrupt is enabled.
- */
- int ret = 0;
- struct msm_fb_data_type *mfd;
- MSM_FB_DEBUG("msm_fb_resume\n");
- mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
- if ((!mfd) || (mfd->key != MFD_KEY))
- return 0;
- console_lock();
- ret = msm_fb_resume_sub(mfd);
- pdev->dev.power.power_state = PMSG_ON;
- fb_set_suspend(mfd->fbi, FBINFO_STATE_RUNNING);
- console_unlock();
- return ret;
- }
- #else
- #define msm_fb_resume NULL
- #endif
- static int msm_fb_runtime_suspend(struct device *dev)
- {
- dev_dbg(dev, "pm_runtime: suspending...\n");
- return 0;
- }
- static int msm_fb_runtime_resume(struct device *dev)
- {
- dev_dbg(dev, "pm_runtime: resuming...\n");
- return 0;
- }
- static int msm_fb_runtime_idle(struct device *dev)
- {
- dev_dbg(dev, "pm_runtime: idling...\n");
- return 0;
- }
- #if (defined(CONFIG_SUSPEND) && defined(CONFIG_FB_MSM_HDMI_MSM_PANEL))
- static int msm_fb_ext_suspend(struct device *dev)
- {
- struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
- struct msm_fb_panel_data *pdata = NULL;
- int ret = 0;
- if ((!mfd) || (mfd->key != MFD_KEY))
- return 0;
- pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
- if (mfd->panel_info.type == HDMI_PANEL ||
- mfd->panel_info.type == DTV_PANEL) {
- ret = msm_fb_suspend_sub(mfd);
- /* Turn off the HPD circuitry */
- if (pdata->power_ctrl) {
- MSM_FB_INFO("%s: Turning off HPD circuitry\n",
- __func__);
- pdata->power_ctrl(FALSE);
- }
- }
- return ret;
- }
- static int msm_fb_ext_resume(struct device *dev)
- {
- struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
- struct msm_fb_panel_data *pdata = NULL;
- int ret = 0;
- if ((!mfd) || (mfd->key != MFD_KEY))
- return 0;
- pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
- if (mfd->panel_info.type == HDMI_PANEL ||
- mfd->panel_info.type == DTV_PANEL) {
- /* Turn on the HPD circuitry */
- if (pdata->power_ctrl) {
- pdata->power_ctrl(TRUE);
- MSM_FB_INFO("%s: Turning on HPD circuitry\n",
- __func__);
- }
- ret = msm_fb_resume_sub(mfd);
- }
- return ret;
- }
- #endif
- static struct dev_pm_ops msm_fb_dev_pm_ops = {
- .runtime_suspend = msm_fb_runtime_suspend,
- .runtime_resume = msm_fb_runtime_resume,
- .runtime_idle = msm_fb_runtime_idle,
- #if (defined(CONFIG_SUSPEND) && defined(CONFIG_FB_MSM_HDMI_MSM_PANEL))
- .suspend = msm_fb_ext_suspend,
- .resume = msm_fb_ext_resume,
- #endif
- };
- static struct platform_driver msm_fb_driver = {
- .probe = msm_fb_probe,
- .remove = msm_fb_remove,
- #ifndef CONFIG_HAS_EARLYSUSPEND
- .suspend = msm_fb_suspend,
- .resume = msm_fb_resume,
- #endif
- .shutdown = NULL,
- .driver = {
- /* Driver name must match the device name added in platform.c. */
- .name = "msm_fb",
- .pm = &msm_fb_dev_pm_ops,
- },
- };
- #ifdef CONFIG_HAS_EARLYSUSPEND
- static void msmfb_early_suspend(struct early_suspend *h)
- {
- struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
- early_suspend);
- msm_fb_suspend_sub(mfd);
- }
- static void msmfb_early_resume(struct early_suspend *h)
- {
- struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
- early_suspend);
- msm_fb_resume_sub(mfd);
- }
- #endif
- static int unset_bl_level, bl_updated;
- static int bl_level_old;
- static int mdp_bl_scale_config(struct msm_fb_data_type *mfd,
- struct mdp_bl_scale_data *data)
- {
- int ret = 0;
- int curr_bl;
- down(&mfd->sem);
- curr_bl = mfd->bl_level;
- bl_scale = data->scale;
- bl_min_lvl = data->min_lvl;
- pr_debug("%s: update scale = %d, min_lvl = %d\n", __func__, bl_scale,
- bl_min_lvl);
- /* update current backlight to use new scaling*/
- msm_fb_set_backlight(mfd, curr_bl);
- up(&mfd->sem);
- return ret;
- }
- static void msm_fb_scale_bl(__u32 *bl_lvl)
- {
- __u32 temp = *bl_lvl;
- pr_debug("%s: input = %d, scale = %d", __func__, temp, bl_scale);
- if (temp >= bl_min_lvl) {
- /* bl_scale is the numerator of scaling fraction (x/1024)*/
- temp = ((*bl_lvl) * bl_scale) / 1024;
- /*if less than minimum level, use min level*/
- if (temp < bl_min_lvl)
- temp = bl_min_lvl;
- }
- pr_debug("%s: output = %d", __func__, temp);
- (*bl_lvl) = temp;
- }
- /*must call this function from within mfd->sem*/
- void msm_fb_set_backlight(struct msm_fb_data_type *mfd, __u32 bkl_lvl)
- {
- struct msm_fb_panel_data *pdata;
- __u32 temp = bkl_lvl;
- if (!mfd->panel_power_on || !bl_updated) {
- unset_bl_level = bkl_lvl;
- return;
- } else {
- unset_bl_level = 0;
- }
- pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
- if ((pdata) && (pdata->set_backlight)) {
- msm_fb_scale_bl(&temp);
- if (bl_level_old == temp) {
- return;
- }
- mfd->bl_level = temp;
- pdata->set_backlight(mfd);
- mfd->bl_level = bkl_lvl;
- bl_level_old = temp;
- }
- }
- static int msm_fb_blank_sub(int blank_mode, struct fb_info *info,
- boolean op_enable)
- {
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- struct msm_fb_panel_data *pdata = NULL;
- int ret = 0;
- if (!op_enable)
- return -EPERM;
- pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
- if ((!pdata) || (!pdata->on) || (!pdata->off)) {
- printk(KERN_ERR "msm_fb_blank_sub: no panel operation detected!\n");
- return -ENODEV;
- }
- switch (blank_mode) {
- case FB_BLANK_UNBLANK:
- if (!mfd->panel_power_on) {
- msleep(16);
- ret = pdata->on(mfd->pdev);
- if (ret == 0) {
- mfd->panel_power_on = TRUE;
- /* ToDo: possible conflict with android which doesn't expect sw refresher */
- /*
- if (!mfd->hw_refresh)
- {
- if ((ret = msm_fb_resume_sw_refresher(mfd)) != 0)
- {
- MSM_FB_INFO("msm_fb_blank_sub: msm_fb_resume_sw_refresher failed = %d!\n",ret);
- }
- }
- */
- }
- }
- break;
- case FB_BLANK_VSYNC_SUSPEND:
- case FB_BLANK_HSYNC_SUSPEND:
- case FB_BLANK_NORMAL:
- case FB_BLANK_POWERDOWN:
- default:
- if (mfd->panel_power_on) {
- int curr_pwr_state;
- mfd->op_enable = FALSE;
- curr_pwr_state = mfd->panel_power_on;
- mfd->panel_power_on = FALSE;
- cancel_delayed_work_sync(&mfd->backlight_worker);
- bl_updated = 0;
- msleep(16);
- ret = pdata->off(mfd->pdev);
- if (ret)
- mfd->panel_power_on = curr_pwr_state;
- if (mfd->timeline) {
- /* Adding 1 is enough when pan_display is still
- * a blocking call and with mutex protection.
- * But if it is an async call, we will still
- * need to add 2. Adding 2 can be safer in
- * order to signal all existing fences, and it
- * is harmless. */
- sw_sync_timeline_inc(mfd->timeline, 2);
- mfd->timeline_value += 2;
- }
- mfd->op_enable = TRUE;
- }
- break;
- }
- return ret;
- }
- int calc_fb_offset(struct msm_fb_data_type *mfd, struct fb_info *fbi, int bpp)
- {
- struct msm_panel_info *panel_info = &mfd->panel_info;
- int remainder, yres, offset;
- if (panel_info->mode2_yres != 0) {
- yres = panel_info->mode2_yres;
- remainder = (fbi->fix.line_length*yres) & (PAGE_SIZE - 1);
- } else {
- yres = panel_info->yres;
- remainder = (fbi->fix.line_length*yres) & (PAGE_SIZE - 1);
- }
- if (!remainder)
- remainder = PAGE_SIZE;
- if (fbi->var.yoffset < yres) {
- offset = (fbi->var.xoffset * bpp);
- /* iBuf->buf += fbi->var.xoffset * bpp + 0 *
- yres * fbi->fix.line_length; */
- } else if (fbi->var.yoffset >= yres && fbi->var.yoffset < 2 * yres) {
- offset = (fbi->var.xoffset * bpp + yres *
- fbi->fix.line_length + PAGE_SIZE - remainder);
- } else {
- offset = (fbi->var.xoffset * bpp + 2 * yres *
- fbi->fix.line_length + 2 * (PAGE_SIZE - remainder));
- }
- return offset;
- }
- static void msm_fb_fillrect(struct fb_info *info,
- const struct fb_fillrect *rect)
- {
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- msm_fb_pan_idle(mfd);
- cfb_fillrect(info, rect);
- if (!mfd->hw_refresh && (info->var.yoffset == 0) &&
- !mfd->sw_currently_refreshing) {
- struct fb_var_screeninfo var;
- var = info->var;
- var.reserved[0] = 0x54445055;
- var.reserved[1] = (rect->dy << 16) | (rect->dx);
- var.reserved[2] = ((rect->dy + rect->height) << 16) |
- (rect->dx + rect->width);
- msm_fb_pan_display(&var, info);
- }
- }
- static void msm_fb_copyarea(struct fb_info *info,
- const struct fb_copyarea *area)
- {
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- msm_fb_pan_idle(mfd);
- cfb_copyarea(info, area);
- if (!mfd->hw_refresh && (info->var.yoffset == 0) &&
- !mfd->sw_currently_refreshing) {
- struct fb_var_screeninfo var;
- var = info->var;
- var.reserved[0] = 0x54445055;
- var.reserved[1] = (area->dy << 16) | (area->dx);
- var.reserved[2] = ((area->dy + area->height) << 16) |
- (area->dx + area->width);
- msm_fb_pan_display(&var, info);
- }
- }
- static void msm_fb_imageblit(struct fb_info *info, const struct fb_image *image)
- {
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- msm_fb_pan_idle(mfd);
- cfb_imageblit(info, image);
- if (!mfd->hw_refresh && (info->var.yoffset == 0) &&
- !mfd->sw_currently_refreshing) {
- struct fb_var_screeninfo var;
- var = info->var;
- var.reserved[0] = 0x54445055;
- var.reserved[1] = (image->dy << 16) | (image->dx);
- var.reserved[2] = ((image->dy + image->height) << 16) |
- (image->dx + image->width);
- msm_fb_pan_display(&var, info);
- }
- }
- static int msm_fb_blank(int blank_mode, struct fb_info *info)
- {
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- msm_fb_pan_idle(mfd);
- return msm_fb_blank_sub(blank_mode, info, mfd->op_enable);
- }
- static int msm_fb_set_lut(struct fb_cmap *cmap, struct fb_info *info)
- {
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- if (!mfd->lut_update)
- return -ENODEV;
- mfd->lut_update(info, cmap);
- return 0;
- }
- /*
- * Custom Framebuffer mmap() function for MSM driver.
- * Differs from standard mmap() function by allowing for customized
- * page-protection.
- */
- static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma)
- {
- /* Get frame buffer memory range. */
- unsigned long start = info->fix.smem_start;
- u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
- unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- msm_fb_pan_idle(mfd);
- if (off >= len) {
- /* memory mapped io */
- off -= len;
- if (info->var.accel_flags) {
- mutex_unlock(&info->lock);
- return -EINVAL;
- }
- start = info->fix.mmio_start;
- len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
- }
- /* Set VM flags. */
- start &= PAGE_MASK;
- if ((vma->vm_end - vma->vm_start + off) > len)
- return -EINVAL;
- off += start;
- vma->vm_pgoff = off >> PAGE_SHIFT;
- /* This is an IO map - tell maydump to skip this VMA */
- vma->vm_flags |= VM_IO | VM_RESERVED;
- /* Set VM page protection */
- if (mfd->mdp_fb_page_protection == MDP_FB_PAGE_PROTECTION_WRITECOMBINE)
- vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
- else if (mfd->mdp_fb_page_protection ==
- MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE)
- vma->vm_page_prot = pgprot_writethroughcache(vma->vm_page_prot);
- else if (mfd->mdp_fb_page_protection ==
- MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE)
- vma->vm_page_prot = pgprot_writebackcache(vma->vm_page_prot);
- else if (mfd->mdp_fb_page_protection ==
- MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE)
- vma->vm_page_prot = pgprot_writebackwacache(vma->vm_page_prot);
- else
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- /* Remap the frame buffer I/O range */
- if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot))
- return -EAGAIN;
- return 0;
- }
- static struct fb_ops msm_fb_ops = {
- .owner = THIS_MODULE,
- .fb_open = msm_fb_open,
- .fb_release = msm_fb_release,
- .fb_read = NULL,
- .fb_write = NULL,
- .fb_cursor = NULL,
- .fb_check_var = msm_fb_check_var, /* vinfo check */
- .fb_set_par = msm_fb_set_par, /* set the video mode according to info->var */
- .fb_setcolreg = NULL, /* set color register */
- .fb_blank = msm_fb_blank, /* blank display */
- .fb_pan_display = msm_fb_pan_display, /* pan display */
- .fb_fillrect = msm_fb_fillrect, /* Draws a rectangle */
- .fb_copyarea = msm_fb_copyarea, /* Copy data from area to another */
- .fb_imageblit = msm_fb_imageblit, /* Draws a image to the display */
- .fb_rotate = NULL,
- .fb_sync = NULL, /* wait for blit idle, optional */
- .fb_ioctl = msm_fb_ioctl, /* perform fb specific ioctl (optional) */
- .fb_mmap = msm_fb_mmap,
- };
- static __u32 msm_fb_line_length(__u32 fb_index, __u32 xres, int bpp)
- {
- /* The adreno GPU hardware requires that the pitch be aligned to
- 32 pixels for color buffers, so for the cases where the GPU
- is writing directly to fb0, the framebuffer pitch
- also needs to be 32 pixel aligned */
- if (fb_index == 0)
- return ALIGN(xres, 32) * bpp;
- else
- return xres * bpp;
- }
- static int msm_fb_register(struct msm_fb_data_type *mfd)
- {
- int ret = -ENODEV;
- int bpp;
- struct msm_panel_info *panel_info = &mfd->panel_info;
- struct fb_info *fbi = mfd->fbi;
- struct fb_fix_screeninfo *fix;
- struct fb_var_screeninfo *var;
- int *id;
- int fbram_offset;
- int remainder, remainder_mode2;
- /*
- * fb info initialization
- */
- fix = &fbi->fix;
- var = &fbi->var;
- fix->type_aux = 0; /* if type == FB_TYPE_INTERLEAVED_PLANES */
- fix->visual = FB_VISUAL_TRUECOLOR; /* True Color */
- fix->ywrapstep = 0; /* No support */
- fix->mmio_start = 0; /* No MMIO Address */
- fix->mmio_len = 0; /* No MMIO Address */
- fix->accel = FB_ACCEL_NONE;/* FB_ACCEL_MSM needes to be added in fb.h */
- var->xoffset = 0, /* Offset from virtual to visible */
- var->yoffset = 0, /* resolution */
- var->grayscale = 0, /* No graylevels */
- var->nonstd = 0, /* standard pixel format */
- var->activate = FB_ACTIVATE_VBL, /* activate it at vsync */
- var->height = -1, /* height of picture in mm */
- var->width = -1, /* width of picture in mm */
- var->accel_flags = 0, /* acceleration flags */
- var->sync = 0, /* see FB_SYNC_* */
- var->rotate = 0, /* angle we rotate counter clockwise */
- mfd->op_enable = FALSE;
- switch (mfd->fb_imgType) {
- case MDP_RGB_565:
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->xpanstep = 1;
- fix->ypanstep = 1;
- var->vmode = FB_VMODE_NONINTERLACED;
- var->blue.offset = 0;
- var->green.offset = 5;
- var->red.offset = 11;
- var->blue.length = 5;
- var->green.length = 6;
- var->red.length = 5;
- var->blue.msb_right = 0;
- var->green.msb_right = 0;
- var->red.msb_right = 0;
- var->transp.offset = 0;
- var->transp.length = 0;
- bpp = 2;
- break;
- case MDP_RGB_888:
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->xpanstep = 1;
- fix->ypanstep = 1;
- var->vmode = FB_VMODE_NONINTERLACED;
- var->blue.offset = 0;
- var->green.offset = 8;
- var->red.offset = 16;
- var->blue.length = 8;
- var->green.length = 8;
- var->red.length = 8;
- var->blue.msb_right = 0;
- var->green.msb_right = 0;
- var->red.msb_right = 0;
- var->transp.offset = 0;
- var->transp.length = 0;
- bpp = 3;
- break;
- case MDP_ARGB_8888:
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->xpanstep = 1;
- fix->ypanstep = 1;
- var->vmode = FB_VMODE_NONINTERLACED;
- var->blue.offset = 0;
- var->green.offset = 8;
- var->red.offset = 16;
- var->blue.length = 8;
- var->green.length = 8;
- var->red.length = 8;
- var->blue.msb_right = 0;
- var->green.msb_right = 0;
- var->red.msb_right = 0;
- var->transp.offset = 24;
- var->transp.length = 8;
- bpp = 4;
- break;
- case MDP_RGBA_8888:
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->xpanstep = 1;
- fix->ypanstep = 1;
- var->vmode = FB_VMODE_NONINTERLACED;
- var->blue.offset = 8;
- var->green.offset = 16;
- var->red.offset = 24;
- var->blue.length = 8;
- var->green.length = 8;
- var->red.length = 8;
- var->blue.msb_right = 0;
- var->green.msb_right = 0;
- var->red.msb_right = 0;
- var->transp.offset = 0;
- var->transp.length = 8;
- bpp = 4;
- break;
- case MDP_BGRA_8888:
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->xpanstep = 1;
- fix->ypanstep = 1;
- var->vmode = FB_VMODE_NONINTERLACED;
- var->blue.offset = 0;
- var->green.offset = 8;
- var->red.offset = 16;
- var->blue.length = 8;
- var->green.length = 8;
- var->red.length = 8;
- var->blue.msb_right = 0;
- var->green.msb_right = 0;
- var->red.msb_right = 0;
- var->transp.offset = 24;
- var->transp.length = 8;
- bpp = 4;
- break;
- case MDP_YCRYCB_H2V1:
- /* ToDo: need to check TV-Out YUV422i framebuffer format */
- /* we might need to create new type define */
- fix->type = FB_TYPE_INTERLEAVED_PLANES;
- fix->xpanstep = 2;
- fix->ypanstep = 1;
- var->vmode = FB_VMODE_NONINTERLACED;
- /* how about R/G/B offset? */
- var->blue.offset = 0;
- var->green.offset = 5;
- var->red.offset = 11;
- var->blue.length = 5;
- var->green.length = 6;
- var->red.length = 5;
- var->blue.msb_right = 0;
- var->green.msb_right = 0;
- var->red.msb_right = 0;
- var->transp.offset = 0;
- var->transp.length = 0;
- bpp = 2;
- break;
- default:
- MSM_FB_ERR("msm_fb_init: fb %d unkown image type!\n",
- mfd->index);
- return ret;
- }
- fix->type = panel_info->is_3d_panel;
- fix->line_length = msm_fb_line_length(mfd->index, panel_info->xres,
- bpp);
- /* Make sure all buffers can be addressed on a page boundary by an x
- * and y offset */
- remainder = (fix->line_length * panel_info->yres) & (PAGE_SIZE - 1);
- /* PAGE_SIZE is a power of 2 */
- if (!remainder)
- remainder = PAGE_SIZE;
- remainder_mode2 = (fix->line_length *
- panel_info->mode2_yres) & (PAGE_SIZE - 1);
- if (!remainder_mode2)
- remainder_mode2 = PAGE_SIZE;
- /*
- * calculate smem_len based on max size of two supplied modes.
- * Only fb0 has mem. fb1 and fb2 don't have mem.
- */
- if (!bf_supported || mfd->index == 0)
- fix->smem_len = MAX((msm_fb_line_length(mfd->index,
- panel_info->xres,
- bpp) *
- panel_info->yres + PAGE_SIZE -
- remainder) * mfd->fb_page,
- (msm_fb_line_length(mfd->index,
- panel_info->mode2_xres,
- bpp) *
- panel_info->mode2_yres + PAGE_SIZE -
- remainder_mode2) * mfd->fb_page);
- else if (mfd->index == 1 || mfd->index == 2) {
- pr_debug("%s:%d no memory is allocated for fb%d!\n",
- __func__, __LINE__, mfd->index);
- fix->smem_len = 0;
- }
- mfd->var_xres = panel_info->xres;
- mfd->var_yres = panel_info->yres;
- mfd->var_frame_rate = panel_info->frame_rate;
- var->pixclock = mfd->panel_info.clk_rate;
- mfd->var_pixclock = var->pixclock;
- var->xres = panel_info->xres;
- var->yres = panel_info->yres;
- var->xres_virtual = panel_info->xres;
- var->yres_virtual = panel_info->yres * mfd->fb_page +
- ((PAGE_SIZE - remainder)/fix->line_length) * mfd->fb_page;
- var->bits_per_pixel = bpp * 8; /* FrameBuffer color depth */
- /*
- * id field for fb app
- */
- id = (int *)&mfd->panel;
- switch (mdp_rev) {
- case MDP_REV_20:
- snprintf(fix->id, sizeof(fix->id), "msmfb20_%x", (__u32) *id);
- break;
- case MDP_REV_22:
- snprintf(fix->id, sizeof(fix->id), "msmfb22_%x", (__u32) *id);
- break;
- case MDP_REV_30:
- snprintf(fix->id, sizeof(fix->id), "msmfb30_%x", (__u32) *id);
- break;
- case MDP_REV_303:
- snprintf(fix->id, sizeof(fix->id), "msmfb303_%x", (__u32) *id);
- break;
- case MDP_REV_31:
- snprintf(fix->id, sizeof(fix->id), "msmfb31_%x", (__u32) *id);
- break;
- case MDP_REV_40:
- snprintf(fix->id, sizeof(fix->id), "msmfb40_%x", (__u32) *id);
- break;
- case MDP_REV_41:
- snprintf(fix->id, sizeof(fix->id), "msmfb41_%x", (__u32) *id);
- break;
- case MDP_REV_42:
- snprintf(fix->id, sizeof(fix->id), "msmfb42_%x", (__u32) *id);
- break;
- case MDP_REV_43:
- snprintf(fix->id, sizeof(fix->id), "msmfb43_%x", (__u32) *id);
- break;
- case MDP_REV_44:
- snprintf(fix->id, sizeof(fix->id), "msmfb44_%x", (__u32) *id);
- break;
- default:
- snprintf(fix->id, sizeof(fix->id), "msmfb0_%x", (__u32) *id);
- break;
- }
- fbi->fbops = &msm_fb_ops;
- fbi->flags = FBINFO_FLAG_DEFAULT;
- fbi->pseudo_palette = msm_fb_pseudo_palette;
- mfd->ref_cnt = 0;
- mfd->sw_currently_refreshing = FALSE;
- mfd->sw_refreshing_enable = TRUE;
- mfd->panel_power_on = FALSE;
- mfd->pan_waiting = FALSE;
- init_completion(&mfd->pan_comp);
- init_completion(&mfd->refresher_comp);
- sema_init(&mfd->sem, 1);
- init_timer(&mfd->msmfb_no_update_notify_timer);
- mfd->msmfb_no_update_notify_timer.function =
- msmfb_no_update_notify_timer_cb;
- mfd->msmfb_no_update_notify_timer.data = (unsigned long)mfd;
- init_completion(&mfd->msmfb_update_notify);
- init_completion(&mfd->msmfb_no_update_notify);
- init_completion(&mfd->commit_comp);
- mutex_init(&mfd->sync_mutex);
- INIT_WORK(&mfd->commit_work, msm_fb_commit_wq_handler);
- mfd->msm_fb_backup = kzalloc(sizeof(struct msm_fb_backup_type),
- GFP_KERNEL);
- if (mfd->msm_fb_backup == 0) {
- pr_err("error: not enough memory!\n");
- return -ENOMEM;
- }
- fbram_offset = PAGE_ALIGN((int)fbram)-(int)fbram;
- fbram += fbram_offset;
- fbram_phys += fbram_offset;
- fbram_size -= fbram_offset;
- if (!bf_supported || mfd->index == 0)
- if (fbram_size < fix->smem_len) {
- pr_err("error: no more framebuffer memory!\n");
- return -ENOMEM;
- }
- fbi->screen_base = fbram;
- fbi->fix.smem_start = (unsigned long)fbram_phys;
- msm_iommu_map_contig_buffer(fbi->fix.smem_start,
- DISPLAY_WRITE_DOMAIN,
- GEN_POOL,
- fbi->fix.smem_len,
- SZ_4K,
- 0,
- &(mfd->display_iova));
- msm_iommu_map_contig_buffer(fbi->fix.smem_start,
- DISPLAY_READ_DOMAIN,
- GEN_POOL,
- fbi->fix.smem_len,
- SZ_4K,
- 0,
- &(mfd->display_iova));
- msm_iommu_map_contig_buffer(fbi->fix.smem_start,
- ROTATOR_SRC_DOMAIN,
- GEN_POOL,
- fbi->fix.smem_len,
- SZ_4K,
- 0,
- &(mfd->rotator_iova));
- if (!bf_supported || mfd->index == 0)
- memset(fbi->screen_base, 0x0, fix->smem_len);
- mfd->op_enable = TRUE;
- mfd->panel_power_on = FALSE;
- /* cursor memory allocation */
- if (mfd->cursor_update) {
- unsigned long cursor_buf_iommu = 0;
- mfd->cursor_buf = dma_alloc_coherent(NULL,
- MDP_CURSOR_SIZE,
- (dma_addr_t *) &mfd->cursor_buf_phys,
- GFP_KERNEL);
- msm_iommu_map_contig_buffer((unsigned long)mfd->cursor_buf_phys,
- DISPLAY_READ_DOMAIN,
- GEN_POOL,
- MDP_CURSOR_SIZE,
- SZ_4K,
- 0,
- &cursor_buf_iommu);
- if (cursor_buf_iommu)
- mfd->cursor_buf_phys = (void *)cursor_buf_iommu;
- if (!mfd->cursor_buf)
- mfd->cursor_update = 0;
- }
- if (mfd->lut_update) {
- ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
- if (ret)
- printk(KERN_ERR "%s: fb_alloc_cmap() failed!\n",
- __func__);
- }
- if (register_framebuffer(fbi) < 0) {
- if (mfd->lut_update)
- fb_dealloc_cmap(&fbi->cmap);
- if (mfd->cursor_buf)
- dma_free_coherent(NULL,
- MDP_CURSOR_SIZE,
- mfd->cursor_buf,
- (dma_addr_t) mfd->cursor_buf_phys);
- mfd->op_enable = FALSE;
- return -EPERM;
- }
- fbram += fix->smem_len;
- fbram_phys += fix->smem_len;
- fbram_size -= fix->smem_len;
- MSM_FB_INFO
- ("FrameBuffer[%d] %dx%d size=%d bytes is registered successfully!\n",
- mfd->index, fbi->var.xres, fbi->var.yres, fbi->fix.smem_len);
- #ifdef CONFIG_FB_MSM_LOGO
- /* Flip buffer */
- if (!load_565rle_image(INIT_IMAGE_FILE, bf_supported))
- ;
- #endif
- ret = 0;
- #ifdef CONFIG_HAS_EARLYSUSPEND
- if (mfd->panel_info.type != DTV_PANEL) {
- mfd->early_suspend.suspend = msmfb_early_suspend;
- mfd->early_suspend.resume = msmfb_early_resume;
- mfd->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 2;
- register_early_suspend(&mfd->early_suspend);
- }
- #endif
- #ifdef MSM_FB_ENABLE_DBGFS
- {
- struct dentry *root;
- struct dentry *sub_dir;
- char sub_name[2];
- root = msm_fb_get_debugfs_root();
- if (root != NULL) {
- sub_name[0] = (char)(mfd->index + 0x30);
- sub_name[1] = '\0';
- sub_dir = debugfs_create_dir(sub_name, root);
- } else {
- sub_dir = NULL;
- }
- mfd->sub_dir = sub_dir;
- if (sub_dir) {
- msm_fb_debugfs_file_create(sub_dir, "op_enable",
- (u32 *) &mfd->op_enable);
- msm_fb_debugfs_file_create(sub_dir, "panel_power_on",
- (u32 *) &mfd->
- panel_power_on);
- msm_fb_debugfs_file_create(sub_dir, "ref_cnt",
- (u32 *) &mfd->ref_cnt);
- msm_fb_debugfs_file_create(sub_dir, "fb_imgType",
- (u32 *) &mfd->fb_imgType);
- msm_fb_debugfs_file_create(sub_dir,
- "sw_currently_refreshing",
- (u32 *) &mfd->
- sw_currently_refreshing);
- msm_fb_debugfs_file_create(sub_dir,
- "sw_refreshing_enable",
- (u32 *) &mfd->
- sw_refreshing_enable);
- msm_fb_debugfs_file_create(sub_dir, "xres",
- (u32 *) &mfd->panel_info.
- xres);
- msm_fb_debugfs_file_create(sub_dir, "yres",
- (u32 *) &mfd->panel_info.
- yres);
- msm_fb_debugfs_file_create(sub_dir, "bpp",
- (u32 *) &mfd->panel_info.
- bpp);
- msm_fb_debugfs_file_create(sub_dir, "type",
- (u32 *) &mfd->panel_info.
- type);
- msm_fb_debugfs_file_create(sub_dir, "wait_cycle",
- (u32 *) &mfd->panel_info.
- wait_cycle);
- msm_fb_debugfs_file_create(sub_dir, "pdest",
- (u32 *) &mfd->panel_info.
- pdest);
- msm_fb_debugfs_file_create(sub_dir, "backbuff",
- (u32 *) &mfd->panel_info.
- fb_num);
- msm_fb_debugfs_file_create(sub_dir, "clk_rate",
- (u32 *) &mfd->panel_info.
- clk_rate);
- msm_fb_debugfs_file_create(sub_dir, "frame_count",
- (u32 *) &mfd->panel_info.
- frame_count);
- switch (mfd->dest) {
- case DISPLAY_LCD:
- msm_fb_debugfs_file_create(sub_dir,
- "vsync_enable",
- (u32 *)&mfd->panel_info.lcd.vsync_enable);
- msm_fb_debugfs_file_create(sub_dir,
- "refx100",
- (u32 *) &mfd->panel_info.lcd. refx100);
- msm_fb_debugfs_file_create(sub_dir,
- "v_back_porch",
- (u32 *) &mfd->panel_info.lcd.v_back_porch);
- msm_fb_debugfs_file_create(sub_dir,
- "v_front_porch",
- (u32 *) &mfd->panel_info.lcd.v_front_porch);
- msm_fb_debugfs_file_create(sub_dir,
- "v_pulse_width",
- (u32 *) &mfd->panel_info.lcd.v_pulse_width);
- msm_fb_debugfs_file_create(sub_dir,
- "hw_vsync_mode",
- (u32 *) &mfd->panel_info.lcd.hw_vsync_mode);
- msm_fb_debugfs_file_create(sub_dir,
- "vsync_notifier_period", (u32 *)
- &mfd->panel_info.lcd.vsync_notifier_period);
- break;
- case DISPLAY_LCDC:
- msm_fb_debugfs_file_create(sub_dir,
- "h_back_porch",
- (u32 *) &mfd->panel_info.lcdc.h_back_porch);
- msm_fb_debugfs_file_create(sub_dir,
- "h_front_porch",
- (u32 *) &mfd->panel_info.lcdc.h_front_porch);
- msm_fb_debugfs_file_create(sub_dir,
- "h_pulse_width",
- (u32 *) &mfd->panel_info.lcdc.h_pulse_width);
- msm_fb_debugfs_file_create(sub_dir,
- "v_back_porch",
- (u32 *) &mfd->panel_info.lcdc.v_back_porch);
- msm_fb_debugfs_file_create(sub_dir,
- "v_front_porch",
- (u32 *) &mfd->panel_info.lcdc.v_front_porch);
- msm_fb_debugfs_file_create(sub_dir,
- "v_pulse_width",
- (u32 *) &mfd->panel_info.lcdc.v_pulse_width);
- msm_fb_debugfs_file_create(sub_dir,
- "border_clr",
- (u32 *) &mfd->panel_info.lcdc.border_clr);
- msm_fb_debugfs_file_create(sub_dir,
- "underflow_clr",
- (u32 *) &mfd->panel_info.lcdc.underflow_clr);
- msm_fb_debugfs_file_create(sub_dir,
- "hsync_skew",
- (u32 *) &mfd->panel_info.lcdc.hsync_skew);
- break;
- default:
- break;
- }
- }
- }
- #endif /* MSM_FB_ENABLE_DBGFS */
- return ret;
- }
- static int msm_fb_open(struct fb_info *info, int user)
- {
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- bool unblank = true;
- int result;
- result = pm_runtime_get_sync(info->dev);
- if (result < 0) {
- printk(KERN_ERR "pm_runtime: fail to wake up\n");
- }
- if (info->node == 0 && !(mfd->cont_splash_done)) { /* primary */
- mfd->ref_cnt++;
- return 0;
- }
- if (!mfd->ref_cnt) {
- if (!bf_supported ||
- (info->node != 1 && info->node != 2))
- mdp_set_dma_pan_info(info, NULL, TRUE);
- else
- pr_debug("%s:%d no mdp_set_dma_pan_info %d\n",
- __func__, __LINE__, info->node);
- if (mfd->is_panel_ready && !mfd->is_panel_ready())
- unblank = false;
- if (unblank) {
- if (msm_fb_blank_sub(FB_BLANK_UNBLANK,
- info, mfd->op_enable)) {
- MSM_FB_ERR("%s: can't turn on display!\n",
- __func__);
- return -EPERM;
- }
- }
- }
- mfd->ref_cnt++;
- return 0;
- }
- static int msm_fb_release(struct fb_info *info, int user)
- {
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- int ret = 0;
- if (!mfd->ref_cnt) {
- MSM_FB_INFO("msm_fb_release: try to close unopened fb %d!\n",
- mfd->index);
- return -EINVAL;
- }
- mfd->ref_cnt--;
- if (!mfd->ref_cnt) {
- if ((ret =
- msm_fb_blank_sub(FB_BLANK_POWERDOWN, info,
- mfd->op_enable)) != 0) {
- printk(KERN_ERR "msm_fb_release: can't turn off display!\n");
- return ret;
- }
- }
- pm_runtime_put(info->dev);
- return ret;
- }
- int msm_fb_wait_for_fence(struct msm_fb_data_type *mfd)
- {
- int i, ret = 0;
- /* buf sync */
- for (i = 0; i < mfd->acq_fen_cnt; i++) {
- ret = sync_fence_wait(mfd->acq_fen[i], WAIT_FENCE_TIMEOUT);
- sync_fence_put(mfd->acq_fen[i]);
- if (ret < 0) {
- pr_err("%s: sync_fence_wait failed! ret = %x\n",
- __func__, ret);
- break;
- }
- }
- mfd->acq_fen_cnt = 0;
- return ret;
- }
- int msm_fb_signal_timeline(struct msm_fb_data_type *mfd)
- {
- mutex_lock(&mfd->sync_mutex);
- if (mfd->timeline) {
- sw_sync_timeline_inc(mfd->timeline, 1);
- mfd->timeline_value++;
- }
- mfd->last_rel_fence = mfd->cur_rel_fence;
- mfd->cur_rel_fence = 0;
- mutex_unlock(&mfd->sync_mutex);
- return 0;
- }
- static void bl_workqueue_handler(struct work_struct *work)
- {
- struct msm_fb_data_type *mfd = container_of(to_delayed_work(work),
- struct msm_fb_data_type, backlight_worker);
- struct msm_fb_panel_data *pdata = mfd->pdev->dev.platform_data;
- if ((pdata) && (pdata->set_backlight) && (!bl_updated)) {
- down(&mfd->sem);
- mfd->bl_level = unset_bl_level;
- pdata->set_backlight(mfd);
- bl_level_old = unset_bl_level;
- bl_updated = 1;
- up(&mfd->sem);
- }
- }
- DEFINE_SEMAPHORE(msm_fb_pan_sem);
- static int msm_fb_pan_idle(struct msm_fb_data_type *mfd)
- {
- int ret = 0;
- mutex_lock(&mfd->sync_mutex);
- if (mfd->is_committing) {
- mutex_unlock(&mfd->sync_mutex);
- ret = wait_for_completion_interruptible_timeout(
- &mfd->commit_comp,
- msecs_to_jiffies(WAIT_FENCE_TIMEOUT));
- if (ret <= 0)
- ret = -ERESTARTSYS;
- else if (!ret)
- pr_err("%s wait for commit_comp timeout %d %d",
- __func__, ret, mfd->is_committing);
- } else {
- mutex_unlock(&mfd->sync_mutex);
- }
- return ret;
- }
- static int msm_fb_pan_display_ex(struct fb_var_screeninfo *var,
- struct fb_info *info, u32 wait_for_finish)
- {
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- struct msm_fb_backup_type *fb_backup;
- int ret = 0;
- /*
- * If framebuffer is 2, io pen display is not allowed.
- */
- if (bf_supported && info->node == 2) {
- pr_err("%s: no pan display for fb%d!",
- __func__, info->node);
- return -EPERM;
- }
- if (info->node != 0 || mfd->cont_splash_done) /* primary */
- if ((!mfd->op_enable) || (!mfd->panel_power_on))
- return -EPERM;
- if (var->xoffset > (info->var.xres_virtual - info->var.xres))
- return -EINVAL;
- if (var->yoffset > (info->var.yres_virtual - info->var.yres))
- return -EINVAL;
- msm_fb_pan_idle(mfd);
- mutex_lock(&mfd->sync_mutex);
- if (info->fix.xpanstep)
- info->var.xoffset =
- (var->xoffset / info->fix.xpanstep) * info->fix.xpanstep;
- if (info->fix.ypanstep)
- info->var.yoffset =
- (var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
- fb_backup = (struct msm_fb_backup_type *)mfd->msm_fb_backup;
- memcpy(&fb_backup->info, info, sizeof(struct fb_info));
- memcpy(&fb_backup->var, var, sizeof(struct fb_var_screeninfo));
- mfd->is_committing = 1;
- INIT_COMPLETION(mfd->commit_comp);
- schedule_work(&mfd->commit_work);
- mutex_unlock(&mfd->sync_mutex);
- if (wait_for_finish)
- msm_fb_pan_idle(mfd);
- return ret;
- }
- static inline int rt_policy(int policy)
- {
- if (unlikely(policy == SCHED_FIFO) ||
- unlikely(policy == SCHED_RR))
- return 1;
- return 0;
- }
- static inline int task_has_rt_policy(struct task_struct *p)
- {
- return rt_policy(p->policy);
- }
- static int msm_fb_pan_display(struct fb_var_screeninfo *var,
- struct fb_info *info)
- {
- return msm_fb_pan_display_ex(var, info, TRUE);
- }
- static int msm_fb_pan_display_sub(struct fb_var_screeninfo *var,
- struct fb_info *info)
- {
- struct sched_param s = { .sched_priority = 1 };
- struct mdp_dirty_region dirty;
- struct mdp_dirty_region *dirtyPtr = NULL;
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- /*
- * If framebuffer is 2, io pen display is not allowed.
- */
- if (bf_supported && info->node == 2) {
- pr_err("%s: no pan display for fb%d!",
- __func__, info->node);
- return -EPERM;
- }
- if (!task_has_rt_policy(current)) {
- struct cred *new = prepare_creds();
- cap_raise(new->cap_effective, CAP_SYS_NICE);
- commit_creds(new);
- if ((sched_setscheduler(current, SCHED_RR, &s)) < 0)
- pr_err("sched_setscheduler failed\n");
- }
- if (info->node != 0 || mfd->cont_splash_done) /* primary */
- if ((!mfd->op_enable) || (!mfd->panel_power_on))
- return -EPERM;
- if (var->xoffset > (info->var.xres_virtual - info->var.xres))
- return -EINVAL;
- if (var->yoffset > (info->var.yres_virtual - info->var.yres))
- return -EINVAL;
- if (info->fix.xpanstep)
- info->var.xoffset =
- (var->xoffset / info->fix.xpanstep) * info->fix.xpanstep;
- if (info->fix.ypanstep)
- info->var.yoffset =
- (var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
- /* "UPDT" */
- if (var->reserved[0] == 0x54445055) {
- dirty.xoffset = var->reserved[1] & 0xffff;
- dirty.yoffset = (var->reserved[1] >> 16) & 0xffff;
- if ((var->reserved[2] & 0xffff) <= dirty.xoffset)
- return -EINVAL;
- if (((var->reserved[2] >> 16) & 0xffff) <= dirty.yoffset)
- return -EINVAL;
- dirty.width = (var->reserved[2] & 0xffff) - dirty.xoffset;
- dirty.height =
- ((var->reserved[2] >> 16) & 0xffff) - dirty.yoffset;
- info->var.yoffset = var->yoffset;
- if (dirty.xoffset < 0)
- return -EINVAL;
- if (dirty.yoffset < 0)
- return -EINVAL;
- if ((dirty.xoffset + dirty.width) > info->var.xres)
- return -EINVAL;
- if ((dirty.yoffset + dirty.height) > info->var.yres)
- return -EINVAL;
- if ((dirty.width <= 0) || (dirty.height <= 0))
- return -EINVAL;
- dirtyPtr = &dirty;
- }
- complete(&mfd->msmfb_update_notify);
- mutex_lock(&msm_fb_notify_update_sem);
- if (mfd->msmfb_no_update_notify_timer.function)
- del_timer(&mfd->msmfb_no_update_notify_timer);
- mfd->msmfb_no_update_notify_timer.expires = jiffies + (2 * HZ);
- add_timer(&mfd->msmfb_no_update_notify_timer);
- mutex_unlock(&msm_fb_notify_update_sem);
- down(&msm_fb_pan_sem);
- msm_fb_wait_for_fence(mfd);
- if (info->node == 0 && !(mfd->cont_splash_done)) { /* primary */
- mdp_set_dma_pan_info(info, NULL, TRUE);
- if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) {
- pr_err("%s: can't turn on display!\n", __func__);
- if (mfd->timeline) {
- sw_sync_timeline_inc(mfd->timeline, 2);
- mfd->timeline_value += 2;
- }
- return -EINVAL;
- }
- }
- mdp_set_dma_pan_info(info, dirtyPtr,
- (var->activate & FB_ACTIVATE_VBL));
- /* async call */
- mdp_dma_pan_update(info);
- msm_fb_signal_timeline(mfd);
- up(&msm_fb_pan_sem);
- if (unset_bl_level && !bl_updated)
- schedule_delayed_work(&mfd->backlight_worker,
- backlight_duration);
- if (info->node == 0 && (mfd->cont_splash_done)) /* primary */
- mdp_free_splash_buffer(mfd);
- ++mfd->panel_info.frame_count;
- return 0;
- }
- static void msm_fb_commit_wq_handler(struct work_struct *work)
- {
- struct msm_fb_data_type *mfd;
- struct fb_var_screeninfo *var;
- struct fb_info *info;
- struct msm_fb_backup_type *fb_backup;
- mfd = container_of(work, struct msm_fb_data_type, commit_work);
- fb_backup = (struct msm_fb_backup_type *)mfd->msm_fb_backup;
- var = &fb_backup->var;
- info = &fb_backup->info;
- msm_fb_pan_display_sub(var, info);
- mutex_lock(&mfd->sync_mutex);
- mfd->is_committing = 0;
- complete_all(&mfd->commit_comp);
- mutex_unlock(&mfd->sync_mutex);
- }
- static int msm_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
- {
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- msm_fb_pan_idle(mfd);
- if (var->rotate != FB_ROTATE_UR)
- return -EINVAL;
- if (var->grayscale != info->var.grayscale)
- return -EINVAL;
- switch (var->bits_per_pixel) {
- case 16:
- if ((var->green.offset != 5) ||
- !((var->blue.offset == 11)
- || (var->blue.offset == 0)) ||
- !((var->red.offset == 11)
- || (var->red.offset == 0)) ||
- (var->blue.length != 5) ||
- (var->green.length != 6) ||
- (var->red.length != 5) ||
- (var->blue.msb_right != 0) ||
- (var->green.msb_right != 0) ||
- (var->red.msb_right != 0) ||
- (var->transp.offset != 0) ||
- (var->transp.length != 0))
- return -EINVAL;
- break;
- case 24:
- if ((var->blue.offset != 0) ||
- (var->green.offset != 8) ||
- (var->red.offset != 16) ||
- (var->blue.length != 8) ||
- (var->green.length != 8) ||
- (var->red.length != 8) ||
- (var->blue.msb_right != 0) ||
- (var->green.msb_right != 0) ||
- (var->red.msb_right != 0) ||
- !(((var->transp.offset == 0) &&
- (var->transp.length == 0)) ||
- ((var->transp.offset == 24) &&
- (var->transp.length == 8))))
- return -EINVAL;
- break;
- case 32:
- /* Figure out if the user meant RGBA or ARGB
- and verify the position of the RGB components */
- if (var->transp.offset == 24) {
- if ((var->blue.offset != 0) ||
- (var->green.offset != 8) ||
- (var->red.offset != 16))
- return -EINVAL;
- } else if (var->transp.offset == 0) {
- if ((var->blue.offset != 8) ||
- (var->green.offset != 16) ||
- (var->red.offset != 24))
- return -EINVAL;
- } else
- return -EINVAL;
- /* Check the common values for both RGBA and ARGB */
- if ((var->blue.length != 8) ||
- (var->green.length != 8) ||
- (var->red.length != 8) ||
- (var->transp.length != 8) ||
- (var->blue.msb_right != 0) ||
- (var->green.msb_right != 0) ||
- (var->red.msb_right != 0))
- return -EINVAL;
- break;
- default:
- return -EINVAL;
- }
- if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0))
- return -EINVAL;
- if (!bf_supported ||
- (info->node != 1 && info->node != 2))
- if (info->fix.smem_len <
- (var->xres_virtual*
- var->yres_virtual*
- (var->bits_per_pixel/8)))
- return -EINVAL;
- if ((var->xres == 0) || (var->yres == 0))
- return -EINVAL;
- if (var->xoffset > (var->xres_virtual - var->xres))
- return -EINVAL;
- if (var->yoffset > (var->yres_virtual - var->yres))
- return -EINVAL;
- return 0;
- }
- int msm_fb_check_frame_rate(struct msm_fb_data_type *mfd
- , struct fb_info *info)
- {
- int panel_height, panel_width, var_frame_rate, fps_mod;
- struct fb_var_screeninfo *var = &info->var;
- fps_mod = 0;
- if ((mfd->panel_info.type == DTV_PANEL) ||
- (mfd->panel_info.type == HDMI_PANEL)) {
- panel_height = var->yres + var->upper_margin +
- var->vsync_len + var->lower_margin;
- panel_width = var->xres + var->right_margin +
- var->hsync_len + var->left_margin;
- var_frame_rate = ((var->pixclock)/(panel_height * panel_width));
- if (mfd->var_frame_rate != var_frame_rate) {
- fps_mod = 1;
- mfd->var_frame_rate = var_frame_rate;
- }
- }
- return fps_mod;
- }
- static int msm_fb_set_par(struct fb_info *info)
- {
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- struct fb_var_screeninfo *var = &info->var;
- int old_imgType;
- int blank = 0;
- msm_fb_pan_idle(mfd);
- old_imgType = mfd->fb_imgType;
- switch (var->bits_per_pixel) {
- case 16:
- if (var->red.offset == 0)
- mfd->fb_imgType = MDP_BGR_565;
- else
- mfd->fb_imgType = MDP_RGB_565;
- break;
- case 24:
- if ((var->transp.offset == 0) && (var->transp.length == 0))
- mfd->fb_imgType = MDP_RGB_888;
- else if ((var->transp.offset == 24) &&
- (var->transp.length == 8)) {
- mfd->fb_imgType = MDP_ARGB_8888;
- info->var.bits_per_pixel = 32;
- }
- break;
- case 32:
- if ((var->transp.offset == 24) && (var->blue.offset == 0))
- mfd->fb_imgType = MDP_BGRA_8888;
- else if (var->transp.offset == 24)
- mfd->fb_imgType = MDP_ARGB_8888;
- else
- mfd->fb_imgType = MDP_RGBA_8888;
- break;
- default:
- return -EINVAL;
- }
- if ((mfd->var_pixclock != var->pixclock) ||
- (mfd->hw_refresh && ((mfd->fb_imgType != old_imgType) ||
- (mfd->var_pixclock != var->pixclock) ||
- (mfd->var_xres != var->xres) ||
- (mfd->var_yres != var->yres) ||
- (msm_fb_check_frame_rate(mfd, info))))) {
- mfd->var_xres = var->xres;
- mfd->var_yres = var->yres;
- mfd->var_pixclock = var->pixclock;
- blank = 1;
- }
- mfd->fbi->fix.line_length = msm_fb_line_length(mfd->index, var->xres,
- var->bits_per_pixel/8);
- if (blank) {
- msm_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable);
- if (mfd->update_panel_info)
- mfd->update_panel_info(mfd);
- msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable);
- }
- return 0;
- }
- static int msm_fb_stop_sw_refresher(struct msm_fb_data_type *mfd)
- {
- if (mfd->hw_refresh)
- return -EPERM;
- if (mfd->sw_currently_refreshing) {
- down(&mfd->sem);
- mfd->sw_currently_refreshing = FALSE;
- up(&mfd->sem);
- /* wait until the refresher finishes the last job */
- wait_for_completion_killable(&mfd->refresher_comp);
- }
- return 0;
- }
- int msm_fb_resume_sw_refresher(struct msm_fb_data_type *mfd)
- {
- boolean do_refresh;
- if (mfd->hw_refresh)
- return -EPERM;
- down(&mfd->sem);
- if ((!mfd->sw_currently_refreshing) && (mfd->sw_refreshing_enable)) {
- do_refresh = TRUE;
- mfd->sw_currently_refreshing = TRUE;
- } else {
- do_refresh = FALSE;
- }
- up(&mfd->sem);
- if (do_refresh)
- mdp_refresh_screen((unsigned long)mfd);
- return 0;
- }
- #if defined CONFIG_FB_MSM_MDP31
- static int mdp_blit_split_height(struct fb_info *info,
- struct mdp_blit_req *req)
- {
- int ret;
- struct mdp_blit_req splitreq;
- int s_x_0, s_x_1, s_w_0, s_w_1, s_y_0, s_y_1, s_h_0, s_h_1;
- int d_x_0, d_x_1, d_w_0, d_w_1, d_y_0, d_y_1, d_h_0, d_h_1;
- splitreq = *req;
- /* break dest roi at height*/
- d_x_0 = d_x_1 = req->dst_rect.x;
- d_w_0 = d_w_1 = req->dst_rect.w;
- d_y_0 = req->dst_rect.y;
- if (req->dst_rect.h % 32 == 3)
- d_h_1 = (req->dst_rect.h - 3) / 2 - 1;
- else if (req->dst_rect.h % 32 == 2)
- d_h_1 = (req->dst_rect.h - 2) / 2 - 6;
- else
- d_h_1 = (req->dst_rect.h - 1) / 2 - 1;
- d_h_0 = req->dst_rect.h - d_h_1;
- d_y_1 = d_y_0 + d_h_0;
- if (req->dst_rect.h == 3) {
- d_h_1 = 2;
- d_h_0 = 2;
- d_y_1 = d_y_0 + 1;
- }
- /* blit first region */
- if (((splitreq.flags & 0x07) == 0x04) ||
- ((splitreq.flags & 0x07) == 0x0)) {
- if (splitreq.flags & MDP_ROT_90) {
- s_y_0 = s_y_1 = req->src_rect.y;
- s_h_0 = s_h_1 = req->src_rect.h;
- s_x_0 = req->src_rect.x;
- s_w_1 = (req->src_rect.w * d_h_1) / req->dst_rect.h;
- s_w_0 = req->src_rect.w - s_w_1;
- s_x_1 = s_x_0 + s_w_0;
- if (d_h_1 >= 8 * s_w_1) {
- s_w_1++;
- s_x_1--;
- }
- } else {
- s_x_0 = s_x_1 = req->src_rect.x;
- s_w_0 = s_w_1 = req->src_rect.w;
- s_y_0 = req->src_rect.y;
- s_h_1 = (req->src_rect.h * d_h_1) / req->dst_rect.h;
- s_h_0 = req->src_rect.h - s_h_1;
- s_y_1 = s_y_0 + s_h_0;
- if (d_h_1 >= 8 * s_h_1) {
- s_h_1++;
- s_y_1--;
- }
- }
- splitreq.src_rect.h = s_h_0;
- splitreq.src_rect.y = s_y_0;
- splitreq.dst_rect.h = d_h_0;
- splitreq.dst_rect.y = d_y_0;
- splitreq.src_rect.x = s_x_0;
- splitreq.src_rect.w = s_w_0;
- splitreq.dst_rect.x = d_x_0;
- splitreq.dst_rect.w = d_w_0;
- } else {
- if (splitreq.flags & MDP_ROT_90) {
- s_y_0 = s_y_1 = req->src_rect.y;
- s_h_0 = s_h_1 = req->src_rect.h;
- s_x_0 = req->src_rect.x;
- s_w_1 = (req->src_rect.w * d_h_0) / req->dst_rect.h;
- s_w_0 = req->src_rect.w - s_w_1;
- s_x_1 = s_x_0 + s_w_0;
- if (d_h_0 >= 8 * s_w_1) {
- s_w_1++;
- s_x_1--;
- }
- } else {
- s_x_0 = s_x_1 = req->src_rect.x;
- s_w_0 = s_w_1 = req->src_rect.w;
- s_y_0 = req->src_rect.y;
- s_h_1 = (req->src_rect.h * d_h_0) / req->dst_rect.h;
- s_h_0 = req->src_rect.h - s_h_1;
- s_y_1 = s_y_0 + s_h_0;
- if (d_h_0 >= 8 * s_h_1) {
- s_h_1++;
- s_y_1--;
- }
- }
- splitreq.src_rect.h = s_h_0;
- splitreq.src_rect.y = s_y_0;
- splitreq.dst_rect.h = d_h_1;
- splitreq.dst_rect.y = d_y_1;
- splitreq.src_rect.x = s_x_0;
- splitreq.src_rect.w = s_w_0;
- splitreq.dst_rect.x = d_x_1;
- splitreq.dst_rect.w = d_w_1;
- }
- ret = mdp_ppp_blit(info, &splitreq);
- if (ret)
- return ret;
- /* blit second region */
- if (((splitreq.flags & 0x07) == 0x04) ||
- ((splitreq.flags & 0x07) == 0x0)) {
- splitreq.src_rect.h = s_h_1;
- splitreq.src_rect.y = s_y_1;
- splitreq.dst_rect.h = d_h_1;
- splitreq.dst_rect.y = d_y_1;
- splitreq.src_rect.x = s_x_1;
- splitreq.src_rect.w = s_w_1;
- splitreq.dst_rect.x = d_x_1;
- splitreq.dst_rect.w = d_w_1;
- } else {
- splitreq.src_rect.h = s_h_1;
- splitreq.src_rect.y = s_y_1;
- splitreq.dst_rect.h = d_h_0;
- splitreq.dst_rect.y = d_y_0;
- splitreq.src_rect.x = s_x_1;
- splitreq.src_rect.w = s_w_1;
- splitreq.dst_rect.x = d_x_0;
- splitreq.dst_rect.w = d_w_0;
- }
- ret = mdp_ppp_blit(info, &splitreq);
- return ret;
- }
- #endif
- int mdp_blit(struct fb_info *info, struct mdp_blit_req *req)
- {
- int ret;
- #if defined CONFIG_FB_MSM_MDP31 || defined CONFIG_FB_MSM_MDP30
- unsigned int remainder = 0, is_bpp_4 = 0;
- struct mdp_blit_req splitreq;
- int s_x_0, s_x_1, s_w_0, s_w_1, s_y_0, s_y_1, s_h_0, s_h_1;
- int d_x_0, d_x_1, d_w_0, d_w_1, d_y_0, d_y_1, d_h_0, d_h_1;
- if (req->flags & MDP_ROT_90) {
- if (((req->dst_rect.h == 1) && ((req->src_rect.w != 1) ||
- (req->dst_rect.w != req->src_rect.h))) ||
- ((req->dst_rect.w == 1) && ((req->src_rect.h != 1) ||
- (req->dst_rect.h != req->src_rect.w)))) {
- printk(KERN_ERR "mpd_ppp: error scaling when size is 1!\n");
- return -EINVAL;
- }
- } else {
- if (((req->dst_rect.w == 1) && ((req->src_rect.w != 1) ||
- (req->dst_rect.h != req->src_rect.h))) ||
- ((req->dst_rect.h == 1) && ((req->src_rect.h != 1) ||
- (req->dst_rect.w != req->src_rect.w)))) {
- printk(KERN_ERR "mpd_ppp: error scaling when size is 1!\n");
- return -EINVAL;
- }
- }
- #endif
- if (unlikely(req->src_rect.h == 0 || req->src_rect.w == 0)) {
- printk(KERN_ERR "mpd_ppp: src img of zero size!\n");
- return -EINVAL;
- }
- if (unlikely(req->dst_rect.h == 0 || req->dst_rect.w == 0))
- return 0;
- #if defined CONFIG_FB_MSM_MDP31
- /* MDP width split workaround */
- remainder = (req->dst_rect.w)%32;
- ret = mdp_get_bytes_per_pixel(req->dst.format,
- (struct msm_fb_data_type *)info->par);
- if (ret <= 0) {
- printk(KERN_ERR "mdp_ppp: incorrect bpp!\n");
- return -EINVAL;
- }
- is_bpp_4 = (ret == 4) ? 1 : 0;
- if ((is_bpp_4 && (remainder == 6 || remainder == 14 ||
- remainder == 22 || remainder == 30)) || remainder == 3 ||
- (remainder == 1 && req->dst_rect.w != 1) ||
- (remainder == 2 && req->dst_rect.w != 2)) {
- /* make new request as provide by user */
- splitreq = *req;
- /* break dest roi at width*/
- d_y_0 = d_y_1 = req->dst_rect.y;
- d_h_0 = d_h_1 = req->dst_rect.h;
- d_x_0 = req->dst_rect.x;
- if (remainder == 14)
- d_w_1 = (req->dst_rect.w - 14) / 2 + 4;
- else if (remainder == 22)
- d_w_1 = (req->dst_rect.w - 22) / 2 + 10;
- else if (remainder == 30)
- d_w_1 = (req->dst_rect.w - 30) / 2 + 10;
- else if (remainder == 6)
- d_w_1 = req->dst_rect.w / 2 - 1;
- else if (remainder == 3)
- d_w_1 = (req->dst_rect.w - 3) / 2 - 1;
- else if (remainder == 2)
- d_w_1 = (req->dst_rect.w - 2) / 2 - 6;
- else
- d_w_1 = (req->dst_rect.w - 1) / 2 - 1;
- d_w_0 = req->dst_rect.w - d_w_1;
- d_x_1 = d_x_0 + d_w_0;
- if (req->dst_rect.w == 3) {
- d_w_1 = 2;
- d_w_0 = 2;
- d_x_1 = d_x_0 + 1;
- }
- /* blit first region */
- if (((splitreq.flags & 0x07) == 0x07) ||
- ((splitreq.flags & 0x07) == 0x0)) {
- if (splitreq.flags & MDP_ROT_90) {
- s_x_0 = s_x_1 = req->src_rect.x;
- s_w_0 = s_w_1 = req->src_rect.w;
- s_y_0 = req->src_rect.y;
- s_h_1 = (req->src_rect.h * d_w_1) /
- req->dst_rect.w;
- s_h_0 = req->src_rect.h - s_h_1;
- s_y_1 = s_y_0 + s_h_0;
- if (d_w_1 >= 8 * s_h_1) {
- s_h_1++;
- s_y_1--;
- }
- } else {
- s_y_0 = s_y_1 = req->src_rect.y;
- s_h_0 = s_h_1 = req->src_rect.h;
- s_x_0 = req->src_rect.x;
- s_w_1 = (req->src_rect.w * d_w_1) /
- req->dst_rect.w;
- s_w_0 = req->src_rect.w - s_w_1;
- s_x_1 = s_x_0 + s_w_0;
- if (d_w_1 >= 8 * s_w_1) {
- s_w_1++;
- s_x_1--;
- }
- }
- splitreq.src_rect.h = s_h_0;
- splitreq.src_rect.y = s_y_0;
- splitreq.dst_rect.h = d_h_0;
- splitreq.dst_rect.y = d_y_0;
- splitreq.src_rect.x = s_x_0;
- splitreq.src_rect.w = s_w_0;
- splitreq.dst_rect.x = d_x_0;
- splitreq.dst_rect.w = d_w_0;
- } else {
- if (splitreq.flags & MDP_ROT_90) {
- s_x_0 = s_x_1 = req->src_rect.x;
- s_w_0 = s_w_1 = req->src_rect.w;
- s_y_0 = req->src_rect.y;
- s_h_1 = (req->src_rect.h * d_w_0) /
- req->dst_rect.w;
- s_h_0 = req->src_rect.h - s_h_1;
- s_y_1 = s_y_0 + s_h_0;
- if (d_w_0 >= 8 * s_h_1) {
- s_h_1++;
- s_y_1--;
- }
- } else {
- s_y_0 = s_y_1 = req->src_rect.y;
- s_h_0 = s_h_1 = req->src_rect.h;
- s_x_0 = req->src_rect.x;
- s_w_1 = (req->src_rect.w * d_w_0) /
- req->dst_rect.w;
- s_w_0 = req->src_rect.w - s_w_1;
- s_x_1 = s_x_0 + s_w_0;
- if (d_w_0 >= 8 * s_w_1) {
- s_w_1++;
- s_x_1--;
- }
- }
- splitreq.src_rect.h = s_h_0;
- splitreq.src_rect.y = s_y_0;
- splitreq.dst_rect.h = d_h_1;
- splitreq.dst_rect.y = d_y_1;
- splitreq.src_rect.x = s_x_0;
- splitreq.src_rect.w = s_w_0;
- splitreq.dst_rect.x = d_x_1;
- splitreq.dst_rect.w = d_w_1;
- }
- if ((splitreq.dst_rect.h % 32 == 3) ||
- ((req->dst_rect.h % 32) == 1 && req->dst_rect.h != 1) ||
- ((req->dst_rect.h % 32) == 2 && req->dst_rect.h != 2))
- ret = mdp_blit_split_height(info, &splitreq);
- else
- ret = mdp_ppp_blit(info, &splitreq);
- if (ret)
- return ret;
- /* blit second region */
- if (((splitreq.flags & 0x07) == 0x07) ||
- ((splitreq.flags & 0x07) == 0x0)) {
- splitreq.src_rect.h = s_h_1;
- splitreq.src_rect.y = s_y_1;
- splitreq.dst_rect.h = d_h_1;
- splitreq.dst_rect.y = d_y_1;
- splitreq.src_rect.x = s_x_1;
- splitreq.src_rect.w = s_w_1;
- splitreq.dst_rect.x = d_x_1;
- splitreq.dst_rect.w = d_w_1;
- } else {
- splitreq.src_rect.h = s_h_1;
- splitreq.src_rect.y = s_y_1;
- splitreq.dst_rect.h = d_h_0;
- splitreq.dst_rect.y = d_y_0;
- splitreq.src_rect.x = s_x_1;
- splitreq.src_rect.w = s_w_1;
- splitreq.dst_rect.x = d_x_0;
- splitreq.dst_rect.w = d_w_0;
- }
- if (((splitreq.dst_rect.h % 32) == 3) ||
- ((req->dst_rect.h % 32) == 1 && req->dst_rect.h != 1) ||
- ((req->dst_rect.h % 32) == 2 && req->dst_rect.h != 2))
- ret = mdp_blit_split_height(info, &splitreq);
- else
- ret = mdp_ppp_blit(info, &splitreq);
- if (ret)
- return ret;
- } else if ((req->dst_rect.h % 32) == 3 ||
- ((req->dst_rect.h % 32) == 1 && req->dst_rect.h != 1) ||
- ((req->dst_rect.h % 32) == 2 && req->dst_rect.h != 2))
- ret = mdp_blit_split_height(info, req);
- else
- ret = mdp_ppp_blit(info, req);
- return ret;
- #elif defined CONFIG_FB_MSM_MDP30
- /* MDP width split workaround */
- remainder = (req->dst_rect.w)%16;
- ret = mdp_get_bytes_per_pixel(req->dst.format,
- (struct msm_fb_data_type *)info->par);
- if (ret <= 0) {
- printk(KERN_ERR "mdp_ppp: incorrect bpp!\n");
- return -EINVAL;
- }
- is_bpp_4 = (ret == 4) ? 1 : 0;
- if ((is_bpp_4 && (remainder == 6 || remainder == 14))) {
- /* make new request as provide by user */
- splitreq = *req;
- /* break dest roi at width*/
- d_y_0 = d_y_1 = req->dst_rect.y;
- d_h_0 = d_h_1 = req->dst_rect.h;
- d_x_0 = req->dst_rect.x;
- if (remainder == 14 || remainder == 6)
- d_w_1 = req->dst_rect.w / 2;
- else
- d_w_1 = (req->dst_rect.w - 1) / 2 - 1;
- d_w_0 = req->dst_rect.w - d_w_1;
- d_x_1 = d_x_0 + d_w_0;
- /* blit first region */
- if (((splitreq.flags & 0x07) == 0x07) ||
- ((splitreq.flags & 0x07) == 0x05) ||
- ((splitreq.flags & 0x07) == 0x02) ||
- ((splitreq.flags & 0x07) == 0x0)) {
- if (splitreq.flags & MDP_ROT_90) {
- s_x_0 = s_x_1 = req->src_rect.x;
- s_w_0 = s_w_1 = req->src_rect.w;
- s_y_0 = req->src_rect.y;
- s_h_1 = (req->src_rect.h * d_w_1) /
- req->dst_rect.w;
- s_h_0 = req->src_rect.h - s_h_1;
- s_y_1 = s_y_0 + s_h_0;
- if (d_w_1 >= 8 * s_h_1) {
- s_h_1++;
- s_y_1--;
- }
- } else {
- s_y_0 = s_y_1 = req->src_rect.y;
- s_h_0 = s_h_1 = req->src_rect.h;
- s_x_0 = req->src_rect.x;
- s_w_1 = (req->src_rect.w * d_w_1) /
- req->dst_rect.w;
- s_w_0 = req->src_rect.w - s_w_1;
- s_x_1 = s_x_0 + s_w_0;
- if (d_w_1 >= 8 * s_w_1) {
- s_w_1++;
- s_x_1--;
- }
- }
- splitreq.src_rect.h = s_h_0;
- splitreq.src_rect.y = s_y_0;
- splitreq.dst_rect.h = d_h_0;
- splitreq.dst_rect.y = d_y_0;
- splitreq.src_rect.x = s_x_0;
- splitreq.src_rect.w = s_w_0;
- splitreq.dst_rect.x = d_x_0;
- splitreq.dst_rect.w = d_w_0;
- } else {
- if (splitreq.flags & MDP_ROT_90) {
- s_x_0 = s_x_1 = req->src_rect.x;
- s_w_0 = s_w_1 = req->src_rect.w;
- s_y_0 = req->src_rect.y;
- s_h_1 = (req->src_rect.h * d_w_0) /
- req->dst_rect.w;
- s_h_0 = req->src_rect.h - s_h_1;
- s_y_1 = s_y_0 + s_h_0;
- if (d_w_0 >= 8 * s_h_1) {
- s_h_1++;
- s_y_1--;
- }
- } else {
- s_y_0 = s_y_1 = req->src_rect.y;
- s_h_0 = s_h_1 = req->src_rect.h;
- s_x_0 = req->src_rect.x;
- s_w_1 = (req->src_rect.w * d_w_0) /
- req->dst_rect.w;
- s_w_0 = req->src_rect.w - s_w_1;
- s_x_1 = s_x_0 + s_w_0;
- if (d_w_0 >= 8 * s_w_1) {
- s_w_1++;
- s_x_1--;
- }
- }
- splitreq.src_rect.h = s_h_0;
- splitreq.src_rect.y = s_y_0;
- splitreq.dst_rect.h = d_h_1;
- splitreq.dst_rect.y = d_y_1;
- splitreq.src_rect.x = s_x_0;
- splitreq.src_rect.w = s_w_0;
- splitreq.dst_rect.x = d_x_1;
- splitreq.dst_rect.w = d_w_1;
- }
- /* No need to split in height */
- ret = mdp_ppp_blit(info, &splitreq);
- if (ret)
- return ret;
- /* blit second region */
- if (((splitreq.flags & 0x07) == 0x07) ||
- ((splitreq.flags & 0x07) == 0x05) ||
- ((splitreq.flags & 0x07) == 0x02) ||
- ((splitreq.flags & 0x07) == 0x0)) {
- splitreq.src_rect.h = s_h_1;
- splitreq.src_rect.y = s_y_1;
- splitreq.dst_rect.h = d_h_1;
- splitreq.dst_rect.y = d_y_1;
- splitreq.src_rect.x = s_x_1;
- splitreq.src_rect.w = s_w_1;
- splitreq.dst_rect.x = d_x_1;
- splitreq.dst_rect.w = d_w_1;
- } else {
- splitreq.src_rect.h = s_h_1;
- splitreq.src_rect.y = s_y_1;
- splitreq.dst_rect.h = d_h_0;
- splitreq.dst_rect.y = d_y_0;
- splitreq.src_rect.x = s_x_1;
- splitreq.src_rect.w = s_w_1;
- splitreq.dst_rect.x = d_x_0;
- splitreq.dst_rect.w = d_w_0;
- }
- /* No need to split in height ... just width */
- ret = mdp_ppp_blit(info, &splitreq);
- if (ret)
- return ret;
- } else
- ret = mdp_ppp_blit(info, req);
- return ret;
- #else
- ret = mdp_ppp_blit(info, req);
- return ret;
- #endif
- }
- typedef void (*msm_dma_barrier_function_pointer) (void *, size_t);
- static inline void msm_fb_dma_barrier_for_rect(struct fb_info *info,
- struct mdp_img *img, struct mdp_rect *rect,
- msm_dma_barrier_function_pointer dma_barrier_fp
- )
- {
- /*
- * Compute the start and end addresses of the rectangles.
- * NOTE: As currently implemented, the data between
- * the end of one row and the start of the next is
- * included in the address range rather than
- * doing multiple calls for each row.
- */
- unsigned long start;
- size_t size;
- char * const pmem_start = info->screen_base;
- int bytes_per_pixel = mdp_get_bytes_per_pixel(img->format,
- (struct msm_fb_data_type *)info->par);
- if (bytes_per_pixel <= 0) {
- printk(KERN_ERR "%s incorrect bpp!\n", __func__);
- return;
- }
- start = (unsigned long)pmem_start + img->offset +
- (img->width * rect->y + rect->x) * bytes_per_pixel;
- size = (rect->h * img->width + rect->w) * bytes_per_pixel;
- (*dma_barrier_fp) ((void *) start, size);
- }
- static inline void msm_dma_nc_pre(void)
- {
- dmb();
- }
- static inline void msm_dma_wt_pre(void)
- {
- dmb();
- }
- static inline void msm_dma_todevice_wb_pre(void *start, size_t size)
- {
- dma_cache_pre_ops(start, size, DMA_TO_DEVICE);
- }
- static inline void msm_dma_fromdevice_wb_pre(void *start, size_t size)
- {
- dma_cache_pre_ops(start, size, DMA_FROM_DEVICE);
- }
- static inline void msm_dma_nc_post(void)
- {
- dmb();
- }
- static inline void msm_dma_fromdevice_wt_post(void *start, size_t size)
- {
- dma_cache_post_ops(start, size, DMA_FROM_DEVICE);
- }
- static inline void msm_dma_todevice_wb_post(void *start, size_t size)
- {
- dma_cache_post_ops(start, size, DMA_TO_DEVICE);
- }
- static inline void msm_dma_fromdevice_wb_post(void *start, size_t size)
- {
- dma_cache_post_ops(start, size, DMA_FROM_DEVICE);
- }
- /*
- * Do the write barriers required to guarantee data is committed to RAM
- * (from CPU cache or internal buffers) before a DMA operation starts.
- * NOTE: As currently implemented, the data between
- * the end of one row and the start of the next is
- * included in the address range rather than
- * doing multiple calls for each row.
- */
- static void msm_fb_ensure_memory_coherency_before_dma(struct fb_info *info,
- struct mdp_blit_req *req_list,
- int req_list_count)
- {
- #ifdef CONFIG_ARCH_QSD8X50
- int i;
- /*
- * Normally, do the requested barriers for each address
- * range that corresponds to a rectangle.
- *
- * But if at least one write barrier is requested for data
- * going to or from the device but no address range is
- * needed for that barrier, then do the barrier, but do it
- * only once, no matter how many requests there are.
- */
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- switch (mfd->mdp_fb_page_protection) {
- default:
- case MDP_FB_PAGE_PROTECTION_NONCACHED:
- case MDP_FB_PAGE_PROTECTION_WRITECOMBINE:
- /*
- * The following barrier is only done at most once,
- * since further calls would be redundant.
- */
- for (i = 0; i < req_list_count; i++) {
- if (!(req_list[i].flags
- & MDP_NO_DMA_BARRIER_START)) {
- msm_dma_nc_pre();
- break;
- }
- }
- break;
- case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE:
- /*
- * The following barrier is only done at most once,
- * since further calls would be redundant.
- */
- for (i = 0; i < req_list_count; i++) {
- if (!(req_list[i].flags
- & MDP_NO_DMA_BARRIER_START)) {
- msm_dma_wt_pre();
- break;
- }
- }
- break;
- case MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE:
- case MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE:
- for (i = 0; i < req_list_count; i++) {
- if (!(req_list[i].flags &
- MDP_NO_DMA_BARRIER_START)) {
- msm_fb_dma_barrier_for_rect(info,
- &(req_list[i].src),
- &(req_list[i].src_rect),
- msm_dma_todevice_wb_pre
- );
- msm_fb_dma_barrier_for_rect(info,
- &(req_list[i].dst),
- &(req_list[i].dst_rect),
- msm_dma_todevice_wb_pre
- );
- }
- }
- break;
- }
- #else
- dmb();
- #endif
- }
- /*
- * Do the write barriers required to guarantee data will be re-read from RAM by
- * the CPU after a DMA operation ends.
- * NOTE: As currently implemented, the data between
- * the end of one row and the start of the next is
- * included in the address range rather than
- * doing multiple calls for each row.
- */
- static void msm_fb_ensure_memory_coherency_after_dma(struct fb_info *info,
- struct mdp_blit_req *req_list,
- int req_list_count)
- {
- #ifdef CONFIG_ARCH_QSD8X50
- int i;
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- switch (mfd->mdp_fb_page_protection) {
- default:
- case MDP_FB_PAGE_PROTECTION_NONCACHED:
- case MDP_FB_PAGE_PROTECTION_WRITECOMBINE:
- /*
- * The following barrier is only done at most once,
- * since further calls would be redundant.
- */
- for (i = 0; i < req_list_count; i++) {
- if (!(req_list[i].flags
- & MDP_NO_DMA_BARRIER_END)) {
- msm_dma_nc_post();
- break;
- }
- }
- break;
- case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE:
- for (i = 0; i < req_list_count; i++) {
- if (!(req_list[i].flags &
- MDP_NO_DMA_BARRIER_END)) {
- msm_fb_dma_barrier_for_rect(info,
- &(req_list[i].dst),
- &(req_list[i].dst_rect),
- msm_dma_fromdevice_wt_post
- );
- }
- }
- break;
- case MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE:
- case MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE:
- for (i = 0; i < req_list_count; i++) {
- if (!(req_list[i].flags &
- MDP_NO_DMA_BARRIER_END)) {
- msm_fb_dma_barrier_for_rect(info,
- &(req_list[i].dst),
- &(req_list[i].dst_rect),
- msm_dma_fromdevice_wb_post
- );
- }
- }
- break;
- }
- #else
- dmb();
- #endif
- }
- /*
- * NOTE: The userspace issues blit operations in a sequence, the sequence
- * start with a operation marked START and ends in an operation marked
- * END. It is guranteed by the userspace that all the blit operations
- * between START and END are only within the regions of areas designated
- * by the START and END operations and that the userspace doesnt modify
- * those areas. Hence it would be enough to perform barrier/cache operations
- * only on the START and END operations.
- */
- static int msmfb_blit(struct fb_info *info, void __user *p)
- {
- /*
- * CAUTION: The names of the struct types intentionally *DON'T* match
- * the names of the variables declared -- they appear to be swapped.
- * Read the code carefully and you should see that the variable names
- * make sense.
- */
- const int MAX_LIST_WINDOW = 16;
- struct mdp_blit_req req_list[MAX_LIST_WINDOW];
- struct mdp_blit_req_list req_list_header;
- int count, i, req_list_count;
- if (bf_supported &&
- (info->node == 1 || info->node == 2)) {
- pr_err("%s: no pan display for fb%d.",
- __func__, info->node);
- return -EPERM;
- }
- /* Get the count size for the total BLIT request. */
- if (copy_from_user(&req_list_header, p, sizeof(req_list_header)))
- return -EFAULT;
- p += sizeof(req_list_header);
- count = req_list_header.count;
- if (count < 0 || count >= MAX_BLIT_REQ)
- return -EINVAL;
- while (count > 0) {
- /*
- * Access the requests through a narrow window to decrease copy
- * overhead and make larger requests accessible to the
- * coherency management code.
- * NOTE: The window size is intended to be larger than the
- * typical request size, but not require more than 2
- * kbytes of stack storage.
- */
- req_list_count = count;
- if (req_list_count > MAX_LIST_WINDOW)
- req_list_count = MAX_LIST_WINDOW;
- if (copy_from_user(&req_list, p,
- sizeof(struct mdp_blit_req)*req_list_count))
- return -EFAULT;
- /*
- * Ensure that any data CPU may have previously written to
- * internal state (but not yet committed to memory) is
- * guaranteed to be committed to memory now.
- */
- msm_fb_ensure_memory_coherency_before_dma(info,
- req_list, req_list_count);
- /*
- * Do the blit DMA, if required -- returning early only if
- * there is a failure.
- */
- for (i = 0; i < req_list_count; i++) {
- if (!(req_list[i].flags & MDP_NO_BLIT)) {
- /* Do the actual blit. */
- int ret = mdp_blit(info, &(req_list[i]));
- /*
- * Note that early returns don't guarantee
- * memory coherency.
- */
- if (ret)
- return ret;
- }
- }
- /*
- * Ensure that CPU cache and other internal CPU state is
- * updated to reflect any change in memory modified by MDP blit
- * DMA.
- */
- msm_fb_ensure_memory_coherency_after_dma(info,
- req_list,
- req_list_count);
- /* Go to next window of requests. */
- count -= req_list_count;
- p += sizeof(struct mdp_blit_req)*req_list_count;
- }
- return 0;
- }
- static int msmfb_vsync_ctrl(struct fb_info *info, void __user *argp)
- {
- int enable, ret;
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- ret = copy_from_user(&enable, argp, sizeof(enable));
- if (ret) {
- pr_err("%s:msmfb_overlay_vsync ioctl failed", __func__);
- return ret;
- }
- if (mfd->vsync_ctrl)
- mfd->vsync_ctrl(enable);
- else {
- pr_err("%s: Vsync IOCTL not supported", __func__);
- return -EINVAL;
- }
- return 0;
- }
- #ifdef CONFIG_FB_MSM_OVERLAY
- static int msmfb_overlay_get(struct fb_info *info, void __user *p)
- {
- struct mdp_overlay req;
- int ret;
- if (copy_from_user(&req, p, sizeof(req)))
- return -EFAULT;
- ret = mdp4_overlay_get(info, &req);
- if (ret) {
- printk(KERN_ERR "%s: ioctl failed \n",
- __func__);
- return ret;
- }
- if (copy_to_user(p, &req, sizeof(req))) {
- printk(KERN_ERR "%s: copy2user failed \n",
- __func__);
- return -EFAULT;
- }
- return 0;
- }
- static int msmfb_overlay_set(struct fb_info *info, void __user *p)
- {
- struct mdp_overlay req;
- int ret;
- if (copy_from_user(&req, p, sizeof(req)))
- return -EFAULT;
- ret = mdp4_overlay_set(info, &req);
- if (ret) {
- printk(KERN_ERR "%s: ioctl failed, rc=%d\n",
- __func__, ret);
- return ret;
- }
- if (copy_to_user(p, &req, sizeof(req))) {
- printk(KERN_ERR "%s: copy2user failed \n",
- __func__);
- return -EFAULT;
- }
- return 0;
- }
- static int msmfb_overlay_unset(struct fb_info *info, unsigned long *argp)
- {
- int ret, ndx;
- struct msm_fb_data_type *mfd;
- if (info == NULL || info->par == NULL) {
- pr_err("%s info=%p or par is NULL\n", __func__, info);
- return -ENODEV;
- }
- mfd = (struct msm_fb_data_type *)info->par;
- ret = copy_from_user(&ndx, argp, sizeof(ndx));
- if (ret) {
- printk(KERN_ERR "%s:msmfb_overlay_unset ioctl failed \n",
- __func__);
- return ret;
- }
- /*
- * If previous commit hasn't finished yet, unset cannot be started
- * otherwise, previous scene will be corrupted.
- */
- msm_fb_pan_idle(mfd);
- return mdp4_overlay_unset(info, ndx);
- }
- static int msmfb_overlay_vsync_ctrl(struct fb_info *info, void __user *argp)
- {
- int ret;
- int enable;
- ret = copy_from_user(&enable, argp, sizeof(enable));
- if (ret) {
- pr_err("%s:msmfb_overlay_vsync ioctl failed", __func__);
- return ret;
- }
- ret = mdp4_overlay_vsync_ctrl(info, enable);
- return ret;
- }
- static int msmfb_overlay_play_wait(struct fb_info *info, unsigned long *argp)
- {
- int ret;
- struct msmfb_overlay_data req;
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- if (mfd->overlay_play_enable == 0) /* nothing to do */
- return 0;
- ret = copy_from_user(&req, argp, sizeof(req));
- if (ret) {
- pr_err("%s:msmfb_overlay_wait ioctl failed", __func__);
- return ret;
- }
- ret = mdp4_overlay_play_wait(info, &req);
- return ret;
- }
- static int msmfb_overlay_commit(struct fb_info *info)
- {
- return mdp4_overlay_commit(info);
- }
- static int msmfb_overlay_play(struct fb_info *info, unsigned long *argp)
- {
- int ret;
- struct msmfb_overlay_data req;
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- if (mfd->overlay_play_enable == 0) /* nothing to do */
- return 0;
- ret = copy_from_user(&req, argp, sizeof(req));
- if (ret) {
- printk(KERN_ERR "%s:msmfb_overlay_play ioctl failed \n",
- __func__);
- return ret;
- }
- complete(&mfd->msmfb_update_notify);
- mutex_lock(&msm_fb_notify_update_sem);
- if (mfd->msmfb_no_update_notify_timer.function)
- del_timer(&mfd->msmfb_no_update_notify_timer);
- mfd->msmfb_no_update_notify_timer.expires = jiffies + (2 * HZ);
- add_timer(&mfd->msmfb_no_update_notify_timer);
- mutex_unlock(&msm_fb_notify_update_sem);
- if (info->node == 0 && !(mfd->cont_splash_done)) { /* primary */
- mdp_set_dma_pan_info(info, NULL, TRUE);
- if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) {
- pr_err("%s: can't turn on display!\n", __func__);
- return -EINVAL;
- }
- }
- ret = mdp4_overlay_play(info, &req);
- if (unset_bl_level && !bl_updated)
- schedule_delayed_work(&mfd->backlight_worker,
- backlight_duration);
- if (info->node == 0 && (mfd->cont_splash_done)) /* primary */
- mdp_free_splash_buffer(mfd);
- return ret;
- }
- static int msmfb_overlay_play_enable(struct fb_info *info, unsigned long *argp)
- {
- int ret, enable;
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- ret = copy_from_user(&enable, argp, sizeof(enable));
- if (ret) {
- printk(KERN_ERR "%s:msmfb_overlay_play_enable ioctl failed \n",
- __func__);
- return ret;
- }
- mfd->overlay_play_enable = enable;
- return 0;
- }
- static int msmfb_overlay_blt(struct fb_info *info, unsigned long *argp)
- {
- int ret;
- struct msmfb_overlay_blt req;
- ret = copy_from_user(&req, argp, sizeof(req));
- if (ret) {
- pr_err("%s: failed\n", __func__);
- return ret;
- }
- ret = mdp4_overlay_blt(info, &req);
- return ret;
- }
- #ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
- static int msmfb_overlay_ioctl_writeback_init(struct fb_info *info)
- {
- return mdp4_writeback_init(info);
- }
- static int msmfb_overlay_ioctl_writeback_start(
- struct fb_info *info)
- {
- int ret = 0;
- ret = mdp4_writeback_start(info);
- if (ret)
- goto error;
- error:
- if (ret)
- pr_err("%s:msmfb_writeback_start "
- " ioctl failed\n", __func__);
- return ret;
- }
- static int msmfb_overlay_ioctl_writeback_stop(
- struct fb_info *info)
- {
- int ret = 0;
- ret = mdp4_writeback_stop(info);
- if (ret)
- goto error;
- error:
- if (ret)
- pr_err("%s:msmfb_writeback_stop ioctl failed\n",
- __func__);
- return ret;
- }
- static int msmfb_overlay_ioctl_writeback_queue_buffer(
- struct fb_info *info, unsigned long *argp)
- {
- int ret = 0;
- struct msmfb_data data;
- ret = copy_from_user(&data, argp, sizeof(data));
- if (ret)
- goto error;
- ret = mdp4_writeback_queue_buffer(info, &data);
- if (ret)
- goto error;
- error:
- if (ret)
- pr_err("%s:msmfb_writeback_queue_buffer ioctl failed\n",
- __func__);
- return ret;
- }
- static int msmfb_overlay_ioctl_writeback_dequeue_buffer(
- struct fb_info *info, unsigned long *argp)
- {
- int ret = 0;
- struct msmfb_data data;
- ret = copy_from_user(&data, argp, sizeof(data));
- if (ret)
- goto error;
- ret = mdp4_writeback_dequeue_buffer(info, &data);
- if (ret)
- goto error;
- ret = copy_to_user(argp, &data, sizeof(data));
- if (ret)
- goto error;
- error:
- if (ret)
- pr_err("%s:msmfb_writeback_dequeue_buffer ioctl failed\n",
- __func__);
- return ret;
- }
- static int msmfb_overlay_ioctl_writeback_terminate(struct fb_info *info)
- {
- return mdp4_writeback_terminate(info);
- }
- static int msmfb_overlay_ioctl_writeback_set_mirr_hint(struct fb_info *
- info, void *argp)
- {
- int ret = 0, hint;
- if (!info) {
- ret = -EINVAL;
- goto error;
- }
- ret = copy_from_user(&hint, argp, sizeof(hint));
- if (ret)
- goto error;
- ret = mdp4_writeback_set_mirroring_hint(info, hint);
- if (ret)
- goto error;
- error:
- if (ret)
- pr_err("%s: ioctl failed\n", __func__);
- return ret;
- }
- #else
- static int msmfb_overlay_ioctl_writeback_init(struct fb_info *info)
- {
- return -ENOTSUPP;
- }
- static int msmfb_overlay_ioctl_writeback_start(
- struct fb_info *info)
- {
- return -ENOTSUPP;
- }
- static int msmfb_overlay_ioctl_writeback_stop(
- struct fb_info *info)
- {
- return -ENOTSUPP;
- }
- static int msmfb_overlay_ioctl_writeback_queue_buffer(
- struct fb_info *info, unsigned long *argp)
- {
- return -ENOTSUPP;
- }
- static int msmfb_overlay_ioctl_writeback_dequeue_buffer(
- struct fb_info *info, unsigned long *argp)
- {
- return -ENOTSUPP;
- }
- static int msmfb_overlay_ioctl_writeback_terminate(struct fb_info *info)
- {
- return -ENOTSUPP;
- }
- static int msmfb_overlay_ioctl_writeback_set_mirr_hint(struct fb_info *
- info, void *argp)
- {
- return -ENOTSUPP;
- }
- #endif
- static int msmfb_overlay_3d_sbys(struct fb_info *info, unsigned long *argp)
- {
- int ret;
- struct msmfb_overlay_3d req;
- ret = copy_from_user(&req, argp, sizeof(req));
- if (ret) {
- pr_err("%s:msmfb_overlay_3d_ctrl ioctl failed\n",
- __func__);
- return ret;
- }
- ret = mdp4_overlay_3d_sbys(info, &req);
- return ret;
- }
- static int msmfb_mixer_info(struct fb_info *info, unsigned long *argp)
- {
- int ret, cnt;
- struct msmfb_mixer_info_req req;
- ret = copy_from_user(&req, argp, sizeof(req));
- if (ret) {
- pr_err("%s: failed\n", __func__);
- return ret;
- }
- cnt = mdp4_mixer_info(req.mixer_num, req.info);
- req.cnt = cnt;
- ret = copy_to_user(argp, &req, sizeof(req));
- if (ret)
- pr_err("%s:msmfb_overlay_blt_off ioctl failed\n",
- __func__);
- return cnt;
- }
- #endif
- DEFINE_SEMAPHORE(msm_fb_ioctl_ppp_sem);
- DEFINE_SEMAPHORE(msm_fb_ioctl_vsync_sem);
- DEFINE_MUTEX(msm_fb_ioctl_lut_sem);
- /* Set color conversion matrix from user space */
- #ifndef CONFIG_FB_MSM_MDP40
- static void msmfb_set_color_conv(struct mdp_ccs *p)
- {
- int i;
- if (p->direction == MDP_CCS_RGB2YUV) {
- /* MDP cmd block enable */
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- /* RGB->YUV primary forward matrix */
- for (i = 0; i < MDP_CCS_SIZE; i++)
- writel(p->ccs[i], MDP_CSC_PFMVn(i));
- #ifdef CONFIG_FB_MSM_MDP31
- for (i = 0; i < MDP_BV_SIZE; i++)
- writel(p->bv[i], MDP_CSC_POST_BV2n(i));
- #endif
- /* MDP cmd block disable */
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
- } else {
- /* MDP cmd block enable */
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- /* YUV->RGB primary reverse matrix */
- for (i = 0; i < MDP_CCS_SIZE; i++)
- writel(p->ccs[i], MDP_CSC_PRMVn(i));
- for (i = 0; i < MDP_BV_SIZE; i++)
- writel(p->bv[i], MDP_CSC_PRE_BV1n(i));
- /* MDP cmd block disable */
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
- }
- }
- #else
- static void msmfb_set_color_conv(struct mdp_csc *p)
- {
- mdp4_vg_csc_update(p);
- }
- #endif
- static int msmfb_notify_update(struct fb_info *info, unsigned long *argp)
- {
- int ret, notify;
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- ret = copy_from_user(¬ify, argp, sizeof(int));
- if (ret) {
- pr_err("%s:ioctl failed\n", __func__);
- return ret;
- }
- if (notify > NOTIFY_UPDATE_STOP)
- return -EINVAL;
- if (notify == NOTIFY_UPDATE_START) {
- INIT_COMPLETION(mfd->msmfb_update_notify);
- ret = wait_for_completion_interruptible_timeout(
- &mfd->msmfb_update_notify, 4*HZ);
- } else {
- INIT_COMPLETION(mfd->msmfb_no_update_notify);
- ret = wait_for_completion_interruptible_timeout(
- &mfd->msmfb_no_update_notify, 4*HZ);
- }
- if (ret == 0)
- ret = -ETIMEDOUT;
- return (ret > 0) ? 0 : ret;
- }
- static int msmfb_handle_pp_ioctl(struct msm_fb_data_type *mfd,
- struct msmfb_mdp_pp *pp_ptr)
- {
- int ret = -1;
- #ifdef CONFIG_FB_MSM_MDP40
- int i = 0;
- #endif
- if (!pp_ptr)
- return ret;
- switch (pp_ptr->op) {
- #ifdef CONFIG_FB_MSM_MDP40
- case mdp_op_csc_cfg:
- ret = mdp4_csc_config(&(pp_ptr->data.csc_cfg_data));
- for (i = 0; i < CSC_MAX_BLOCKS; i++) {
- if (pp_ptr->data.csc_cfg_data.block ==
- csc_cfg_matrix[i].block) {
- memcpy(&csc_cfg_matrix[i].csc_data,
- &(pp_ptr->data.csc_cfg_data.csc_data),
- sizeof(struct mdp_csc_cfg));
- break;
- }
- }
- break;
- case mdp_op_pcc_cfg:
- ret = mdp4_pcc_cfg(&(pp_ptr->data.pcc_cfg_data));
- break;
- case mdp_op_lut_cfg:
- switch (pp_ptr->data.lut_cfg_data.lut_type) {
- case mdp_lut_igc:
- ret = mdp4_igc_lut_config(
- (struct mdp_igc_lut_data *)
- &pp_ptr->data.lut_cfg_data.data);
- break;
- case mdp_lut_pgc:
- ret = mdp4_argc_cfg(
- &pp_ptr->data.lut_cfg_data.data.pgc_lut_data);
- break;
- case mdp_lut_hist:
- ret = mdp_hist_lut_config(
- (struct mdp_hist_lut_data *)
- &pp_ptr->data.lut_cfg_data.data);
- break;
- default:
- break;
- }
- break;
- case mdp_op_qseed_cfg:
- ret = mdp4_qseed_cfg((struct mdp_qseed_cfg_data *)
- &pp_ptr->data.qseed_cfg_data);
- break;
- case mdp_op_calib_cfg:
- ret = mdp4_calib_config((struct mdp_calib_config_data *)
- &pp_ptr->data.calib_cfg);
- break;
- #endif
- case mdp_bl_scale_cfg:
- ret = mdp_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
- &pp_ptr->data.bl_scale_data);
- break;
- default:
- pr_warn("Unsupported request to MDP_PP IOCTL.\n");
- ret = -EINVAL;
- break;
- }
- return ret;
- }
- static int msmfb_handle_metadata_ioctl(struct msm_fb_data_type *mfd,
- struct msmfb_metadata *metadata_ptr)
- {
- int ret;
- switch (metadata_ptr->op) {
- #ifdef CONFIG_FB_MSM_MDP40
- case metadata_op_base_blend:
- ret = mdp4_update_base_blend(mfd,
- &metadata_ptr->data.blend_cfg);
- break;
- case metadata_op_wb_format:
- ret = mdp4_update_writeback_format(mfd,
- &metadata_ptr->data.mixer_cfg);
- break;
- #endif
- default:
- pr_warn("Unsupported request to MDP META IOCTL.\n");
- ret = -EINVAL;
- break;
- }
- return ret;
- }
- static int msmfb_get_metadata(struct msm_fb_data_type *mfd,
- struct msmfb_metadata *metadata_ptr)
- {
- int ret = 0;
- switch (metadata_ptr->op) {
- case metadata_op_frame_rate:
- metadata_ptr->data.panel_frame_rate =
- mdp_get_panel_framerate(mfd);
- break;
- default:
- pr_warn("Unsupported request to MDP META IOCTL.\n");
- ret = -EINVAL;
- break;
- }
- return ret;
- }
- static int msmfb_handle_buf_sync_ioctl(struct msm_fb_data_type *mfd,
- struct mdp_buf_sync *buf_sync)
- {
- int i, fence_cnt = 0, ret = 0;
- int acq_fen_fd[MDP_MAX_FENCE_FD];
- struct sync_fence *fence;
- if ((buf_sync->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) ||
- (mfd->timeline == NULL))
- return -EINVAL;
- if (buf_sync->acq_fen_fd_cnt)
- ret = copy_from_user(acq_fen_fd, buf_sync->acq_fen_fd,
- buf_sync->acq_fen_fd_cnt * sizeof(int));
- if (ret) {
- pr_err("%s:copy_from_user failed", __func__);
- return ret;
- }
- mutex_lock(&mfd->sync_mutex);
- for (i = 0; i < buf_sync->acq_fen_fd_cnt; i++) {
- fence = sync_fence_fdget(acq_fen_fd[i]);
- if (fence == NULL) {
- pr_info("%s: null fence! i=%d fd=%d\n", __func__, i,
- acq_fen_fd[i]);
- ret = -EINVAL;
- break;
- }
- mfd->acq_fen[i] = fence;
- }
- fence_cnt = i;
- if (ret)
- goto buf_sync_err_1;
- mfd->acq_fen_cnt = fence_cnt;
- if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT)
- msm_fb_wait_for_fence(mfd);
- mfd->cur_rel_sync_pt = sw_sync_pt_create(mfd->timeline,
- mfd->timeline_value + 2);
- if (mfd->cur_rel_sync_pt == NULL) {
- pr_err("%s: cannot create sync point", __func__);
- ret = -ENOMEM;
- goto buf_sync_err_1;
- }
- /* create fence */
- mfd->cur_rel_fence = sync_fence_create("mdp-fence",
- mfd->cur_rel_sync_pt);
- if (mfd->cur_rel_fence == NULL) {
- sync_pt_free(mfd->cur_rel_sync_pt);
- mfd->cur_rel_sync_pt = NULL;
- pr_err("%s: cannot create fence", __func__);
- ret = -ENOMEM;
- goto buf_sync_err_1;
- }
- /* create fd */
- mfd->cur_rel_fen_fd = get_unused_fd_flags(0);
- sync_fence_install(mfd->cur_rel_fence, mfd->cur_rel_fen_fd);
- ret = copy_to_user(buf_sync->rel_fen_fd,
- &mfd->cur_rel_fen_fd, sizeof(int));
- if (ret) {
- pr_err("%s:copy_to_user failed", __func__);
- goto buf_sync_err_2;
- }
- mutex_unlock(&mfd->sync_mutex);
- return ret;
- buf_sync_err_2:
- sync_fence_put(mfd->cur_rel_fence);
- put_unused_fd(mfd->cur_rel_fen_fd);
- mfd->cur_rel_fence = NULL;
- mfd->cur_rel_fen_fd = 0;
- buf_sync_err_1:
- for (i = 0; i < fence_cnt; i++)
- sync_fence_put(mfd->acq_fen[i]);
- mfd->acq_fen_cnt = 0;
- mutex_unlock(&mfd->sync_mutex);
- return ret;
- }
- static int buf_fence_process(struct msm_fb_data_type *mfd,
- struct mdp_buf_fence *buf_fence)
- {
- int i, fence_cnt = 0, ret;
- struct sync_fence *fence;
- if ((buf_fence->acq_fen_fd_cnt == 0) ||
- (buf_fence->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) ||
- (mfd->timeline == NULL))
- return -EINVAL;
- mutex_lock(&mfd->sync_mutex);
- for (i = 0; i < buf_fence->acq_fen_fd_cnt; i++) {
- fence = sync_fence_fdget(buf_fence->acq_fen_fd[i]);
- if (fence == NULL) {
- pr_info("%s: null fence! i=%d fd=%d\n", __func__, i,
- buf_fence->acq_fen_fd[i]);
- ret = -EINVAL;
- break;
- }
- mfd->acq_fen[i] = fence;
- }
- fence_cnt = i;
- if (ret)
- goto buf_fence_err_1;
- mfd->cur_rel_sync_pt = sw_sync_pt_create(mfd->timeline,
- mfd->timeline_value + 2);
- if (mfd->cur_rel_sync_pt == NULL) {
- pr_err("%s: cannot create sync point", __func__);
- ret = -ENOMEM;
- goto buf_fence_err_1;
- }
- /* create fence */
- mfd->cur_rel_fence = sync_fence_create("mdp-fence",
- mfd->cur_rel_sync_pt);
- if (mfd->cur_rel_fence == NULL) {
- sync_pt_free(mfd->cur_rel_sync_pt);
- mfd->cur_rel_sync_pt = NULL;
- pr_err("%s: cannot create fence", __func__);
- ret = -ENOMEM;
- goto buf_fence_err_1;
- }
- /* create fd */
- mfd->cur_rel_fen_fd = get_unused_fd_flags(0);
- sync_fence_install(mfd->cur_rel_fence, mfd->cur_rel_fen_fd);
- buf_fence->rel_fen_fd[0] = mfd->cur_rel_fen_fd;
- /* Only one released fd for now, -1 indicates an end */
- buf_fence->rel_fen_fd[1] = -1;
- mfd->acq_fen_cnt = buf_fence->acq_fen_fd_cnt;
- mutex_unlock(&mfd->sync_mutex);
- return ret;
- buf_fence_err_1:
- for (i = 0; i < fence_cnt; i++)
- sync_fence_put(mfd->acq_fen[i]);
- mfd->acq_fen_cnt = 0;
- mutex_unlock(&mfd->sync_mutex);
- return ret;
- }
- static int msmfb_display_commit(struct fb_info *info,
- unsigned long *argp)
- {
- int ret;
- u32 copy_back = FALSE;
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- struct mdp_display_commit disp_commit;
- struct mdp_buf_fence *buf_fence;
- ret = copy_from_user(&disp_commit, argp,
- sizeof(disp_commit));
- if (ret) {
- pr_err("%s:copy_from_user failed", __func__);
- return ret;
- }
- buf_fence = &disp_commit.buf_fence;
- if (buf_fence->acq_fen_fd_cnt > 0)
- ret = buf_fence_process(mfd, buf_fence);
- if ((!ret) && (buf_fence->rel_fen_fd[0] > 0))
- copy_back = TRUE;
- ret = msm_fb_pan_display_ex(&disp_commit.var,
- info, disp_commit.wait_for_finish);
- if (copy_back) {
- ret = copy_to_user(argp,
- &disp_commit, sizeof(disp_commit));
- if (ret)
- pr_err("%s:copy_to_user failed", __func__);
- }
- return ret;
- }
- static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd,
- unsigned long arg)
- {
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- void __user *argp = (void __user *)arg;
- struct fb_cursor cursor;
- struct fb_cmap cmap;
- struct mdp_histogram_data hist;
- struct mdp_histogram_start_req hist_req;
- uint32_t block;
- #ifndef CONFIG_FB_MSM_MDP40
- struct mdp_ccs ccs_matrix;
- #else
- struct mdp_csc csc_matrix;
- #endif
- struct mdp_page_protection fb_page_protection;
- struct msmfb_mdp_pp mdp_pp;
- struct msmfb_metadata mdp_metadata;
- struct mdp_buf_sync buf_sync;
- int ret = 0;
- msm_fb_pan_idle(mfd);
- switch (cmd) {
- #ifdef CONFIG_FB_MSM_OVERLAY
- case MSMFB_OVERLAY_GET:
- ret = msmfb_overlay_get(info, argp);
- break;
- case MSMFB_OVERLAY_SET:
- ret = msmfb_overlay_set(info, argp);
- break;
- case MSMFB_OVERLAY_UNSET:
- ret = msmfb_overlay_unset(info, argp);
- break;
- case MSMFB_OVERLAY_COMMIT:
- down(&msm_fb_ioctl_ppp_sem);
- ret = msmfb_overlay_commit(info);
- up(&msm_fb_ioctl_ppp_sem);
- break;
- case MSMFB_OVERLAY_PLAY:
- ret = msmfb_overlay_play(info, argp);
- break;
- case MSMFB_OVERLAY_PLAY_ENABLE:
- ret = msmfb_overlay_play_enable(info, argp);
- break;
- case MSMFB_OVERLAY_PLAY_WAIT:
- ret = msmfb_overlay_play_wait(info, argp);
- break;
- case MSMFB_OVERLAY_BLT:
- ret = msmfb_overlay_blt(info, argp);
- break;
- case MSMFB_OVERLAY_3D:
- ret = msmfb_overlay_3d_sbys(info, argp);
- break;
- case MSMFB_MIXER_INFO:
- ret = msmfb_mixer_info(info, argp);
- break;
- case MSMFB_WRITEBACK_INIT:
- ret = msmfb_overlay_ioctl_writeback_init(info);
- break;
- case MSMFB_WRITEBACK_START:
- ret = msmfb_overlay_ioctl_writeback_start(
- info);
- break;
- case MSMFB_WRITEBACK_STOP:
- ret = msmfb_overlay_ioctl_writeback_stop(
- info);
- break;
- case MSMFB_WRITEBACK_QUEUE_BUFFER:
- ret = msmfb_overlay_ioctl_writeback_queue_buffer(
- info, argp);
- break;
- case MSMFB_WRITEBACK_DEQUEUE_BUFFER:
- ret = msmfb_overlay_ioctl_writeback_dequeue_buffer(
- info, argp);
- break;
- case MSMFB_WRITEBACK_TERMINATE:
- ret = msmfb_overlay_ioctl_writeback_terminate(info);
- break;
- case MSMFB_WRITEBACK_SET_MIRRORING_HINT:
- ret = msmfb_overlay_ioctl_writeback_set_mirr_hint(
- info, argp);
- break;
- #endif
- case MSMFB_VSYNC_CTRL:
- case MSMFB_OVERLAY_VSYNC_CTRL:
- down(&msm_fb_ioctl_vsync_sem);
- if (mdp_rev >= MDP_REV_40)
- ret = msmfb_overlay_vsync_ctrl(info, argp);
- else
- ret = msmfb_vsync_ctrl(info, argp);
- up(&msm_fb_ioctl_vsync_sem);
- break;
- case MSMFB_BLIT:
- down(&msm_fb_ioctl_ppp_sem);
- ret = msmfb_blit(info, argp);
- up(&msm_fb_ioctl_ppp_sem);
- break;
- /* Ioctl for setting ccs matrix from user space */
- case MSMFB_SET_CCS_MATRIX:
- #ifndef CONFIG_FB_MSM_MDP40
- ret = copy_from_user(&ccs_matrix, argp, sizeof(ccs_matrix));
- if (ret) {
- printk(KERN_ERR
- "%s:MSMFB_SET_CCS_MATRIX ioctl failed \n",
- __func__);
- return ret;
- }
- down(&msm_fb_ioctl_ppp_sem);
- if (ccs_matrix.direction == MDP_CCS_RGB2YUV)
- mdp_ccs_rgb2yuv = ccs_matrix;
- else
- mdp_ccs_yuv2rgb = ccs_matrix;
- msmfb_set_color_conv(&ccs_matrix) ;
- up(&msm_fb_ioctl_ppp_sem);
- #else
- ret = copy_from_user(&csc_matrix, argp, sizeof(csc_matrix));
- if (ret) {
- pr_err("%s:MSMFB_SET_CSC_MATRIX ioctl failed\n",
- __func__);
- return ret;
- }
- down(&msm_fb_ioctl_ppp_sem);
- msmfb_set_color_conv(&csc_matrix);
- up(&msm_fb_ioctl_ppp_sem);
- #endif
- break;
- /* Ioctl for getting ccs matrix to user space */
- case MSMFB_GET_CCS_MATRIX:
- #ifndef CONFIG_FB_MSM_MDP40
- ret = copy_from_user(&ccs_matrix, argp, sizeof(ccs_matrix)) ;
- if (ret) {
- printk(KERN_ERR
- "%s:MSMFB_GET_CCS_MATRIX ioctl failed \n",
- __func__);
- return ret;
- }
- down(&msm_fb_ioctl_ppp_sem);
- if (ccs_matrix.direction == MDP_CCS_RGB2YUV)
- ccs_matrix = mdp_ccs_rgb2yuv;
- else
- ccs_matrix = mdp_ccs_yuv2rgb;
- ret = copy_to_user(argp, &ccs_matrix, sizeof(ccs_matrix));
- if (ret) {
- printk(KERN_ERR
- "%s:MSMFB_GET_CCS_MATRIX ioctl failed \n",
- __func__);
- return ret ;
- }
- up(&msm_fb_ioctl_ppp_sem);
- #else
- ret = -EINVAL;
- #endif
- break;
- case MSMFB_GRP_DISP:
- #ifdef CONFIG_FB_MSM_MDP22
- {
- unsigned long grp_id;
- ret = copy_from_user(&grp_id, argp, sizeof(grp_id));
- if (ret)
- return ret;
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- writel(grp_id, MDP_FULL_BYPASS_WORD43);
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF,
- FALSE);
- break;
- }
- #else
- return -EFAULT;
- #endif
- case MSMFB_SUSPEND_SW_REFRESHER:
- if (!mfd->panel_power_on)
- return -EPERM;
- mfd->sw_refreshing_enable = FALSE;
- ret = msm_fb_stop_sw_refresher(mfd);
- break;
- case MSMFB_RESUME_SW_REFRESHER:
- if (!mfd->panel_power_on)
- return -EPERM;
- mfd->sw_refreshing_enable = TRUE;
- ret = msm_fb_resume_sw_refresher(mfd);
- break;
- case MSMFB_CURSOR:
- ret = copy_from_user(&cursor, argp, sizeof(cursor));
- if (ret)
- return ret;
- ret = msm_fb_cursor(info, &cursor);
- break;
- case MSMFB_SET_LUT:
- ret = copy_from_user(&cmap, argp, sizeof(cmap));
- if (ret)
- return ret;
- mutex_lock(&msm_fb_ioctl_lut_sem);
- ret = msm_fb_set_lut(&cmap, info);
- mutex_unlock(&msm_fb_ioctl_lut_sem);
- break;
- case MSMFB_HISTOGRAM:
- if (!mfd->panel_power_on)
- return -EPERM;
- if (!mfd->do_histogram)
- return -ENODEV;
- ret = copy_from_user(&hist, argp, sizeof(hist));
- if (ret)
- return ret;
- ret = mfd->do_histogram(info, &hist);
- break;
- case MSMFB_HISTOGRAM_START:
- if (!mfd->panel_power_on)
- return -EPERM;
- if (!mfd->start_histogram)
- return -ENODEV;
- ret = copy_from_user(&hist_req, argp, sizeof(hist_req));
- if (ret)
- return ret;
- ret = mfd->start_histogram(&hist_req);
- break;
- case MSMFB_HISTOGRAM_STOP:
- if (!mfd->stop_histogram)
- return -ENODEV;
- ret = copy_from_user(&block, argp, sizeof(int));
- if (ret)
- return ret;
- ret = mfd->stop_histogram(info, block);
- break;
- case MSMFB_GET_PAGE_PROTECTION:
- fb_page_protection.page_protection
- = mfd->mdp_fb_page_protection;
- ret = copy_to_user(argp, &fb_page_protection,
- sizeof(fb_page_protection));
- if (ret)
- return ret;
- break;
- case MSMFB_NOTIFY_UPDATE:
- ret = msmfb_notify_update(info, argp);
- break;
- case MSMFB_SET_PAGE_PROTECTION:
- #if defined CONFIG_ARCH_QSD8X50 || defined CONFIG_ARCH_MSM8X60
- ret = copy_from_user(&fb_page_protection, argp,
- sizeof(fb_page_protection));
- if (ret)
- return ret;
- /* Validate the proposed page protection settings. */
- switch (fb_page_protection.page_protection) {
- case MDP_FB_PAGE_PROTECTION_NONCACHED:
- case MDP_FB_PAGE_PROTECTION_WRITECOMBINE:
- case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE:
- /* Write-back cache (read allocate) */
- case MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE:
- /* Write-back cache (write allocate) */
- case MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE:
- mfd->mdp_fb_page_protection =
- fb_page_protection.page_protection;
- break;
- default:
- ret = -EINVAL;
- break;
- }
- #else
- /*
- * Don't allow caching until 7k DMA cache operations are
- * available.
- */
- ret = -EINVAL;
- #endif
- break;
- case MSMFB_MDP_PP:
- ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp));
- if (ret)
- return ret;
- ret = msmfb_handle_pp_ioctl(mfd, &mdp_pp);
- if (ret == 1)
- ret = copy_to_user(argp, &mdp_pp, sizeof(mdp_pp));
- break;
- case MSMFB_BUFFER_SYNC:
- ret = copy_from_user(&buf_sync, argp, sizeof(buf_sync));
- if (ret)
- return ret;
- ret = msmfb_handle_buf_sync_ioctl(mfd, &buf_sync);
- if (!ret)
- ret = copy_to_user(argp, &buf_sync, sizeof(buf_sync));
- break;
- case MSMFB_METADATA_SET:
- ret = copy_from_user(&mdp_metadata, argp, sizeof(mdp_metadata));
- if (ret)
- return ret;
- ret = msmfb_handle_metadata_ioctl(mfd, &mdp_metadata);
- case MSMFB_DISPLAY_COMMIT:
- ret = msmfb_display_commit(info, argp);
- break;
- case MSMFB_METADATA_GET:
- ret = copy_from_user(&mdp_metadata, argp, sizeof(mdp_metadata));
- if (ret)
- return ret;
- ret = msmfb_get_metadata(mfd, &mdp_metadata);
- if (!ret)
- ret = copy_to_user(argp, &mdp_metadata,
- sizeof(mdp_metadata));
- break;
- default:
- MSM_FB_INFO("MDP: unknown ioctl (cmd=%x) received!\n", cmd);
- ret = -EINVAL;
- break;
- }
- return ret;
- }
- static int msm_fb_register_driver(void)
- {
- return platform_driver_register(&msm_fb_driver);
- }
- #ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
- struct fb_info *msm_fb_get_writeback_fb(void)
- {
- int c = 0;
- for (c = 0; c < fbi_list_index; ++c) {
- struct msm_fb_data_type *mfd;
- mfd = (struct msm_fb_data_type *)fbi_list[c]->par;
- if (mfd->panel.type == WRITEBACK_PANEL)
- return fbi_list[c];
- }
- return NULL;
- }
- EXPORT_SYMBOL(msm_fb_get_writeback_fb);
- int msm_fb_writeback_start(struct fb_info *info)
- {
- return mdp4_writeback_start(info);
- }
- EXPORT_SYMBOL(msm_fb_writeback_start);
- int msm_fb_writeback_queue_buffer(struct fb_info *info,
- struct msmfb_data *data)
- {
- return mdp4_writeback_queue_buffer(info, data);
- }
- EXPORT_SYMBOL(msm_fb_writeback_queue_buffer);
- int msm_fb_writeback_dequeue_buffer(struct fb_info *info,
- struct msmfb_data *data)
- {
- return mdp4_writeback_dequeue_buffer(info, data);
- }
- EXPORT_SYMBOL(msm_fb_writeback_dequeue_buffer);
- int msm_fb_writeback_stop(struct fb_info *info)
- {
- return mdp4_writeback_stop(info);
- }
- EXPORT_SYMBOL(msm_fb_writeback_stop);
- int msm_fb_writeback_init(struct fb_info *info)
- {
- return mdp4_writeback_init(info);
- }
- EXPORT_SYMBOL(msm_fb_writeback_init);
- int msm_fb_writeback_terminate(struct fb_info *info)
- {
- return mdp4_writeback_terminate(info);
- }
- EXPORT_SYMBOL(msm_fb_writeback_terminate);
- #endif
- struct platform_device *msm_fb_add_device(struct platform_device *pdev)
- {
- struct msm_fb_panel_data *pdata;
- struct platform_device *this_dev = NULL;
- struct fb_info *fbi;
- struct msm_fb_data_type *mfd = NULL;
- u32 type, id, fb_num;
- if (!pdev)
- return NULL;
- id = pdev->id;
- pdata = pdev->dev.platform_data;
- if (!pdata)
- return NULL;
- type = pdata->panel_info.type;
- #if defined MSM_FB_NUM
- /*
- * over written fb_num which defined
- * at panel_info
- *
- */
- if (type == HDMI_PANEL || type == DTV_PANEL ||
- type == TV_PANEL || type == WRITEBACK_PANEL) {
- if (hdmi_prim_display)
- pdata->panel_info.fb_num = 2;
- else
- pdata->panel_info.fb_num = 1;
- }
- else
- pdata->panel_info.fb_num = MSM_FB_NUM;
- MSM_FB_INFO("setting pdata->panel_info.fb_num to %d. type: %d\n",
- pdata->panel_info.fb_num, type);
- #endif
- fb_num = pdata->panel_info.fb_num;
- if (fb_num <= 0)
- return NULL;
- if (fbi_list_index >= MAX_FBI_LIST) {
- printk(KERN_ERR "msm_fb: no more framebuffer info list!\n");
- return NULL;
- }
- /*
- * alloc panel device data
- */
- this_dev = msm_fb_device_alloc(pdata, type, id);
- if (!this_dev) {
- printk(KERN_ERR
- "%s: msm_fb_device_alloc failed!\n", __func__);
- return NULL;
- }
- /*
- * alloc framebuffer info + par data
- */
- fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), NULL);
- if (fbi == NULL) {
- platform_device_put(this_dev);
- printk(KERN_ERR "msm_fb: can't alloca framebuffer info data!\n");
- return NULL;
- }
- mfd = (struct msm_fb_data_type *)fbi->par;
- mfd->key = MFD_KEY;
- mfd->fbi = fbi;
- mfd->panel.type = type;
- mfd->panel.id = id;
- mfd->fb_page = fb_num;
- mfd->index = fbi_list_index;
- mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE;
- mfd->iclient = iclient;
- /* link to the latest pdev */
- mfd->pdev = this_dev;
- mfd_list[mfd_list_index++] = mfd;
- fbi_list[fbi_list_index++] = fbi;
- /*
- * set driver data
- */
- platform_set_drvdata(this_dev, mfd);
- if (platform_device_add(this_dev)) {
- printk(KERN_ERR "msm_fb: platform_device_add failed!\n");
- platform_device_put(this_dev);
- framebuffer_release(fbi);
- fbi_list_index--;
- return NULL;
- }
- #ifdef CONFIG_SEC_DEBUG
- if (fbi_list_index == 1) {
- sec_getlog_supply_fbinfo((void *)(fbi->fix.smem_start),
- ALIGN(fbi->var.xres, 32),
- fbi->var.yres,
- fbi->var.bits_per_pixel,
- 2);
- }
- #endif
- return this_dev;
- }
- EXPORT_SYMBOL(msm_fb_add_device);
- #ifdef CONFIG_SEC_DEBUG_SUBSYS
- void get_fbinfo(int fb_num, unsigned int *fb_paddr, unsigned int *xres,
- unsigned int *yres, unsigned int *bpp,
- unsigned char *roff, unsigned char *rlen,
- unsigned char *goff, unsigned char *glen,
- unsigned char *boff, unsigned char *blen,
- unsigned char *aoff, unsigned char *alen)
- {
- struct fb_info *info;
- if (fb_num >= MAX_FBI_LIST)
- return;
- info = fbi_list[fb_num];
- if (!info)
- return;
- *fb_paddr = (unsigned int)info->fix.smem_start;
- *xres = ALIGN(info->var.xres, 32);
- *yres = info->var.yres;
- *bpp = info->var.bits_per_pixel;
- *roff = info->var.red.offset;
- *rlen = info->var.red.length;
- *goff = info->var.green.offset;
- *glen = info->var.green.length;
- *boff = info->var.blue.offset;
- *blen = info->var.blue.length;
- *aoff = info->var.transp.offset;
- *alen = info->var.transp.length;
- return;
- }
- #endif
- int get_fb_phys_info(unsigned long *start, unsigned long *len, int fb_num,
- int subsys_id)
- {
- struct fb_info *info;
- struct msm_fb_data_type *mfd;
- if (fb_num > MAX_FBI_LIST ||
- (subsys_id != DISPLAY_SUBSYSTEM_ID &&
- subsys_id != ROTATOR_SUBSYSTEM_ID)) {
- pr_err("%s(): Invalid parameters\n", __func__);
- return -1;
- }
- info = fbi_list[fb_num];
- if (!info) {
- pr_err("%s(): info is NULL\n", __func__);
- return -1;
- }
- mfd = (struct msm_fb_data_type *)info->par;
- if (subsys_id == DISPLAY_SUBSYSTEM_ID) {
- if (mfd->display_iova)
- *start = mfd->display_iova;
- else
- *start = info->fix.smem_start;
- } else {
- if (mfd->rotator_iova)
- *start = mfd->rotator_iova;
- else
- *start = info->fix.smem_start;
- }
- *len = info->fix.smem_len;
- return 0;
- }
- EXPORT_SYMBOL(get_fb_phys_info);
- int __init msm_fb_init(void)
- {
- int rc = -ENODEV;
- if (msm_fb_register_driver())
- return rc;
- #ifdef MSM_FB_ENABLE_DBGFS
- {
- struct dentry *root;
- if ((root = msm_fb_get_debugfs_root()) != NULL) {
- msm_fb_debugfs_file_create(root,
- "msm_fb_msg_printing_level",
- (u32 *) &msm_fb_msg_level);
- msm_fb_debugfs_file_create(root,
- "mddi_msg_printing_level",
- (u32 *) &mddi_msg_level);
- msm_fb_debugfs_file_create(root, "msm_fb_debug_enabled",
- (u32 *) &msm_fb_debug_enabled);
- }
- }
- #endif
- return 0;
- }
- /* Called by v4l2 driver to enable/disable overlay pipe */
- int msm_fb_v4l2_enable(struct mdp_overlay *req, bool enable, void **par)
- {
- int err = 0;
- #ifdef CONFIG_FB_MSM_MDP40
- struct mdp4_overlay_pipe *pipe;
- if (enable) {
- err = mdp4_v4l2_overlay_set(fbi_list[0], req, &pipe);
- *(struct mdp4_overlay_pipe **)par = pipe;
- } else {
- pipe = *(struct mdp4_overlay_pipe **)par;
- mdp4_v4l2_overlay_clear(pipe);
- }
- #else
- #ifdef CONFIG_FB_MSM_MDP30
- if (enable)
- err = mdp_ppp_v4l2_overlay_set(fbi_list[0], req);
- else
- err = mdp_ppp_v4l2_overlay_clear();
- #else
- err = -EINVAL;
- #endif
- #endif
- return err;
- }
- EXPORT_SYMBOL(msm_fb_v4l2_enable);
- /* Called by v4l2 driver to provide a frame for display */
- int msm_fb_v4l2_update(void *par, bool bUserPtr,
- unsigned long srcp0_addr, unsigned long srcp0_size,
- unsigned long srcp1_addr, unsigned long srcp1_size,
- unsigned long srcp2_addr, unsigned long srcp2_size)
- {
- #ifdef CONFIG_FB_MSM_MDP40
- struct mdp4_overlay_pipe *pipe = (struct mdp4_overlay_pipe *)par;
- return mdp4_v4l2_overlay_play(fbi_list[0], pipe,
- srcp0_addr, srcp1_addr,
- srcp2_addr);
- #else
- #ifdef CONFIG_FB_MSM_MDP30
- if (bUserPtr)
- return mdp_ppp_v4l2_overlay_play(fbi_list[0], true,
- srcp0_addr, srcp0_size,
- srcp1_addr, srcp1_size);
- else
- return mdp_ppp_v4l2_overlay_play(fbi_list[0], false,
- srcp0_addr, srcp0_size,
- srcp1_addr, srcp1_size);
- #else
- return -EINVAL;
- #endif
- #endif
- }
- EXPORT_SYMBOL(msm_fb_v4l2_update);
- module_init(msm_fb_init);
|