···11-/*22- * Copyright (C) 2011 Texas Instruments33- * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>44- *55- * This program is free software; you can redistribute it and/or modify it66- * under the terms of the GNU General Public License version 2 as published by77- * the Free Software Foundation.88- *99- * This program is distributed in the hope that it will be useful, but WITHOUT1010- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1111- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1212- * more details.1313- *1414- * You should have received a copy of the GNU General Public License along with1515- * this program. If not, see <http://www.gnu.org/licenses/>.1616- */1717-1818-#define DSS_SUBSYS_NAME "APPLY"1919-2020-#include <linux/kernel.h>2121-#include <linux/module.h>2222-#include <linux/slab.h>2323-#include <linux/spinlock.h>2424-#include <linux/jiffies.h>2525-2626-#include <video/omapdss.h>2727-2828-#include "dss.h"2929-#include "dss_features.h"3030-#include "dispc-compat.h"3131-3232-/*3333- * We have 4 levels of cache for the dispc settings. First two are in SW and3434- * the latter two in HW.3535- *3636- * set_info()3737- * v3838- * +--------------------+3939- * | user_info |4040- * +--------------------+4141- * v4242- * apply()4343- * v4444- * +--------------------+4545- * | info |4646- * +--------------------+4747- * v4848- * write_regs()4949- * v5050- * +--------------------+5151- * | shadow registers |5252- * +--------------------+5353- * v5454- * VFP or lcd/digit_enable5555- * v5656- * +--------------------+5757- * | registers |5858- * +--------------------+5959- */6060-6161-struct ovl_priv_data {6262-6363- bool user_info_dirty;6464- struct omap_overlay_info user_info;6565-6666- bool info_dirty;6767- struct omap_overlay_info info;6868-6969- bool shadow_info_dirty;7070-7171- bool extra_info_dirty;7272- bool shadow_extra_info_dirty;7373-7474- bool enabled;7575- u32 fifo_low, fifo_high;7676-7777- /*7878- * True if overlay is to be enabled. Used to check and calculate configs7979- * for the overlay before it is enabled in the HW.8080- */8181- bool enabling;8282-};8383-8484-struct mgr_priv_data {8585-8686- bool user_info_dirty;8787- struct omap_overlay_manager_info user_info;8888-8989- bool info_dirty;9090- struct omap_overlay_manager_info info;9191-9292- bool shadow_info_dirty;9393-9494- /* If true, GO bit is up and shadow registers cannot be written.9595- * Never true for manual update displays */9696- bool busy;9797-9898- /* If true, dispc output is enabled */9999- bool updating;100100-101101- /* If true, a display is enabled using this manager */102102- bool enabled;103103-104104- bool extra_info_dirty;105105- bool shadow_extra_info_dirty;106106-107107- struct omap_video_timings timings;108108- struct dss_lcd_mgr_config lcd_config;109109-110110- void (*framedone_handler)(void *);111111- void *framedone_handler_data;112112-};113113-114114-static struct {115115- struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];116116- struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];117117-118118- bool irq_enabled;119119-} dss_data;120120-121121-/* protects dss_data */122122-static spinlock_t data_lock;123123-/* lock for blocking functions */124124-static DEFINE_MUTEX(apply_lock);125125-static DECLARE_COMPLETION(extra_updated_completion);126126-127127-static void dss_register_vsync_isr(void);128128-129129-static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)130130-{131131- return &dss_data.ovl_priv_data_array[ovl->id];132132-}133133-134134-static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)135135-{136136- return &dss_data.mgr_priv_data_array[mgr->id];137137-}138138-139139-static void apply_init_priv(void)140140-{141141- const int num_ovls = dss_feat_get_num_ovls();142142- struct mgr_priv_data *mp;143143- int i;144144-145145- spin_lock_init(&data_lock);146146-147147- for (i = 0; i < num_ovls; ++i) {148148- struct ovl_priv_data *op;149149-150150- op = &dss_data.ovl_priv_data_array[i];151151-152152- op->info.color_mode = OMAP_DSS_COLOR_RGB16;153153- op->info.rotation_type = OMAP_DSS_ROT_DMA;154154-155155- op->info.global_alpha = 255;156156-157157- switch (i) {158158- case 0:159159- op->info.zorder = 0;160160- break;161161- case 1:162162- op->info.zorder =163163- dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;164164- break;165165- case 2:166166- op->info.zorder =167167- dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;168168- break;169169- case 3:170170- op->info.zorder =171171- dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;172172- break;173173- }174174-175175- op->user_info = op->info;176176- }177177-178178- /*179179- * Initialize some of the lcd_config fields for TV manager, this lets180180- * us prevent checking if the manager is LCD or TV at some places181181- */182182- mp = &dss_data.mgr_priv_data_array[OMAP_DSS_CHANNEL_DIGIT];183183-184184- mp->lcd_config.video_port_width = 24;185185- mp->lcd_config.clock_info.lck_div = 1;186186- mp->lcd_config.clock_info.pck_div = 1;187187-}188188-189189-/*190190- * A LCD manager's stallmode decides whether it is in manual or auto update. TV191191- * manager is always auto update, stallmode field for TV manager is false by192192- * default193193- */194194-static bool ovl_manual_update(struct omap_overlay *ovl)195195-{196196- struct mgr_priv_data *mp = get_mgr_priv(ovl->manager);197197-198198- return mp->lcd_config.stallmode;199199-}200200-201201-static bool mgr_manual_update(struct omap_overlay_manager *mgr)202202-{203203- struct mgr_priv_data *mp = get_mgr_priv(mgr);204204-205205- return mp->lcd_config.stallmode;206206-}207207-208208-static int dss_check_settings_low(struct omap_overlay_manager *mgr,209209- bool applying)210210-{211211- struct omap_overlay_info *oi;212212- struct omap_overlay_manager_info *mi;213213- struct omap_overlay *ovl;214214- struct omap_overlay_info *ois[MAX_DSS_OVERLAYS];215215- struct ovl_priv_data *op;216216- struct mgr_priv_data *mp;217217-218218- mp = get_mgr_priv(mgr);219219-220220- if (!mp->enabled)221221- return 0;222222-223223- if (applying && mp->user_info_dirty)224224- mi = &mp->user_info;225225- else226226- mi = &mp->info;227227-228228- /* collect the infos to be tested into the array */229229- list_for_each_entry(ovl, &mgr->overlays, list) {230230- op = get_ovl_priv(ovl);231231-232232- if (!op->enabled && !op->enabling)233233- oi = NULL;234234- else if (applying && op->user_info_dirty)235235- oi = &op->user_info;236236- else237237- oi = &op->info;238238-239239- ois[ovl->id] = oi;240240- }241241-242242- return dss_mgr_check(mgr, mi, &mp->timings, &mp->lcd_config, ois);243243-}244244-245245-/*246246- * check manager and overlay settings using overlay_info from data->info247247- */248248-static int dss_check_settings(struct omap_overlay_manager *mgr)249249-{250250- return dss_check_settings_low(mgr, false);251251-}252252-253253-/*254254- * check manager and overlay settings using overlay_info from ovl->info if255255- * dirty and from data->info otherwise256256- */257257-static int dss_check_settings_apply(struct omap_overlay_manager *mgr)258258-{259259- return dss_check_settings_low(mgr, true);260260-}261261-262262-static bool need_isr(void)263263-{264264- const int num_mgrs = dss_feat_get_num_mgrs();265265- int i;266266-267267- for (i = 0; i < num_mgrs; ++i) {268268- struct omap_overlay_manager *mgr;269269- struct mgr_priv_data *mp;270270- struct omap_overlay *ovl;271271-272272- mgr = omap_dss_get_overlay_manager(i);273273- mp = get_mgr_priv(mgr);274274-275275- if (!mp->enabled)276276- continue;277277-278278- if (mgr_manual_update(mgr)) {279279- /* to catch FRAMEDONE */280280- if (mp->updating)281281- return true;282282- } else {283283- /* to catch GO bit going down */284284- if (mp->busy)285285- return true;286286-287287- /* to write new values to registers */288288- if (mp->info_dirty)289289- return true;290290-291291- /* to set GO bit */292292- if (mp->shadow_info_dirty)293293- return true;294294-295295- /*296296- * NOTE: we don't check extra_info flags for disabled297297- * managers, once the manager is enabled, the extra_info298298- * related manager changes will be taken in by HW.299299- */300300-301301- /* to write new values to registers */302302- if (mp->extra_info_dirty)303303- return true;304304-305305- /* to set GO bit */306306- if (mp->shadow_extra_info_dirty)307307- return true;308308-309309- list_for_each_entry(ovl, &mgr->overlays, list) {310310- struct ovl_priv_data *op;311311-312312- op = get_ovl_priv(ovl);313313-314314- /*315315- * NOTE: we check extra_info flags even for316316- * disabled overlays, as extra_infos need to be317317- * always written.318318- */319319-320320- /* to write new values to registers */321321- if (op->extra_info_dirty)322322- return true;323323-324324- /* to set GO bit */325325- if (op->shadow_extra_info_dirty)326326- return true;327327-328328- if (!op->enabled)329329- continue;330330-331331- /* to write new values to registers */332332- if (op->info_dirty)333333- return true;334334-335335- /* to set GO bit */336336- if (op->shadow_info_dirty)337337- return true;338338- }339339- }340340- }341341-342342- return false;343343-}344344-345345-static bool need_go(struct omap_overlay_manager *mgr)346346-{347347- struct omap_overlay *ovl;348348- struct mgr_priv_data *mp;349349- struct ovl_priv_data *op;350350-351351- mp = get_mgr_priv(mgr);352352-353353- if (mp->shadow_info_dirty || mp->shadow_extra_info_dirty)354354- return true;355355-356356- list_for_each_entry(ovl, &mgr->overlays, list) {357357- op = get_ovl_priv(ovl);358358- if (op->shadow_info_dirty || op->shadow_extra_info_dirty)359359- return true;360360- }361361-362362- return false;363363-}364364-365365-/* returns true if an extra_info field is currently being updated */366366-static bool extra_info_update_ongoing(void)367367-{368368- const int num_mgrs = dss_feat_get_num_mgrs();369369- int i;370370-371371- for (i = 0; i < num_mgrs; ++i) {372372- struct omap_overlay_manager *mgr;373373- struct omap_overlay *ovl;374374- struct mgr_priv_data *mp;375375-376376- mgr = omap_dss_get_overlay_manager(i);377377- mp = get_mgr_priv(mgr);378378-379379- if (!mp->enabled)380380- continue;381381-382382- if (!mp->updating)383383- continue;384384-385385- if (mp->extra_info_dirty || mp->shadow_extra_info_dirty)386386- return true;387387-388388- list_for_each_entry(ovl, &mgr->overlays, list) {389389- struct ovl_priv_data *op = get_ovl_priv(ovl);390390-391391- if (op->extra_info_dirty || op->shadow_extra_info_dirty)392392- return true;393393- }394394- }395395-396396- return false;397397-}398398-399399-/* wait until no extra_info updates are pending */400400-static void wait_pending_extra_info_updates(void)401401-{402402- bool updating;403403- unsigned long flags;404404- unsigned long t;405405- int r;406406-407407- spin_lock_irqsave(&data_lock, flags);408408-409409- updating = extra_info_update_ongoing();410410-411411- if (!updating) {412412- spin_unlock_irqrestore(&data_lock, flags);413413- return;414414- }415415-416416- init_completion(&extra_updated_completion);417417-418418- spin_unlock_irqrestore(&data_lock, flags);419419-420420- t = msecs_to_jiffies(500);421421- r = wait_for_completion_timeout(&extra_updated_completion, t);422422- if (r == 0)423423- DSSWARN("timeout in wait_pending_extra_info_updates\n");424424-}425425-426426-static struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr)427427-{428428- struct omap_dss_device *dssdev;429429-430430- dssdev = mgr->output;431431- if (dssdev == NULL)432432- return NULL;433433-434434- while (dssdev->dst)435435- dssdev = dssdev->dst;436436-437437- if (dssdev->driver)438438- return dssdev;439439- else440440- return NULL;441441-}442442-443443-static struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl)444444-{445445- return ovl->manager ? dss_mgr_get_device(ovl->manager) : NULL;446446-}447447-448448-static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)449449-{450450- unsigned long timeout = msecs_to_jiffies(500);451451- u32 irq;452452- int r;453453-454454- if (mgr->output == NULL)455455- return -ENODEV;456456-457457- r = dispc_runtime_get();458458- if (r)459459- return r;460460-461461- switch (mgr->output->id) {462462- case OMAP_DSS_OUTPUT_VENC:463463- irq = DISPC_IRQ_EVSYNC_ODD;464464- break;465465- case OMAP_DSS_OUTPUT_HDMI:466466- irq = DISPC_IRQ_EVSYNC_EVEN;467467- break;468468- default:469469- irq = dispc_mgr_get_vsync_irq(mgr->id);470470- break;471471- }472472-473473- r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);474474-475475- dispc_runtime_put();476476-477477- return r;478478-}479479-480480-static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)481481-{482482- unsigned long timeout = msecs_to_jiffies(500);483483- struct mgr_priv_data *mp = get_mgr_priv(mgr);484484- u32 irq;485485- unsigned long flags;486486- int r;487487- int i;488488-489489- spin_lock_irqsave(&data_lock, flags);490490-491491- if (mgr_manual_update(mgr)) {492492- spin_unlock_irqrestore(&data_lock, flags);493493- return 0;494494- }495495-496496- if (!mp->enabled) {497497- spin_unlock_irqrestore(&data_lock, flags);498498- return 0;499499- }500500-501501- spin_unlock_irqrestore(&data_lock, flags);502502-503503- r = dispc_runtime_get();504504- if (r)505505- return r;506506-507507- irq = dispc_mgr_get_vsync_irq(mgr->id);508508-509509- i = 0;510510- while (1) {511511- bool shadow_dirty, dirty;512512-513513- spin_lock_irqsave(&data_lock, flags);514514- dirty = mp->info_dirty;515515- shadow_dirty = mp->shadow_info_dirty;516516- spin_unlock_irqrestore(&data_lock, flags);517517-518518- if (!dirty && !shadow_dirty) {519519- r = 0;520520- break;521521- }522522-523523- /* 4 iterations is the worst case:524524- * 1 - initial iteration, dirty = true (between VFP and VSYNC)525525- * 2 - first VSYNC, dirty = true526526- * 3 - dirty = false, shadow_dirty = true527527- * 4 - shadow_dirty = false */528528- if (i++ == 3) {529529- DSSERR("mgr(%d)->wait_for_go() not finishing\n",530530- mgr->id);531531- r = 0;532532- break;533533- }534534-535535- r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);536536- if (r == -ERESTARTSYS)537537- break;538538-539539- if (r) {540540- DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);541541- break;542542- }543543- }544544-545545- dispc_runtime_put();546546-547547- return r;548548-}549549-550550-static int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)551551-{552552- unsigned long timeout = msecs_to_jiffies(500);553553- struct ovl_priv_data *op;554554- struct mgr_priv_data *mp;555555- u32 irq;556556- unsigned long flags;557557- int r;558558- int i;559559-560560- if (!ovl->manager)561561- return 0;562562-563563- mp = get_mgr_priv(ovl->manager);564564-565565- spin_lock_irqsave(&data_lock, flags);566566-567567- if (ovl_manual_update(ovl)) {568568- spin_unlock_irqrestore(&data_lock, flags);569569- return 0;570570- }571571-572572- if (!mp->enabled) {573573- spin_unlock_irqrestore(&data_lock, flags);574574- return 0;575575- }576576-577577- spin_unlock_irqrestore(&data_lock, flags);578578-579579- r = dispc_runtime_get();580580- if (r)581581- return r;582582-583583- irq = dispc_mgr_get_vsync_irq(ovl->manager->id);584584-585585- op = get_ovl_priv(ovl);586586- i = 0;587587- while (1) {588588- bool shadow_dirty, dirty;589589-590590- spin_lock_irqsave(&data_lock, flags);591591- dirty = op->info_dirty;592592- shadow_dirty = op->shadow_info_dirty;593593- spin_unlock_irqrestore(&data_lock, flags);594594-595595- if (!dirty && !shadow_dirty) {596596- r = 0;597597- break;598598- }599599-600600- /* 4 iterations is the worst case:601601- * 1 - initial iteration, dirty = true (between VFP and VSYNC)602602- * 2 - first VSYNC, dirty = true603603- * 3 - dirty = false, shadow_dirty = true604604- * 4 - shadow_dirty = false */605605- if (i++ == 3) {606606- DSSERR("ovl(%d)->wait_for_go() not finishing\n",607607- ovl->id);608608- r = 0;609609- break;610610- }611611-612612- r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);613613- if (r == -ERESTARTSYS)614614- break;615615-616616- if (r) {617617- DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);618618- break;619619- }620620- }621621-622622- dispc_runtime_put();623623-624624- return r;625625-}626626-627627-static void dss_ovl_write_regs(struct omap_overlay *ovl)628628-{629629- struct ovl_priv_data *op = get_ovl_priv(ovl);630630- struct omap_overlay_info *oi;631631- bool replication;632632- struct mgr_priv_data *mp;633633- int r;634634-635635- DSSDBG("writing ovl %d regs\n", ovl->id);636636-637637- if (!op->enabled || !op->info_dirty)638638- return;639639-640640- oi = &op->info;641641-642642- mp = get_mgr_priv(ovl->manager);643643-644644- replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode);645645-646646- r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings, false);647647- if (r) {648648- /*649649- * We can't do much here, as this function can be called from650650- * vsync interrupt.651651- */652652- DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);653653-654654- /* This will leave fifo configurations in a nonoptimal state */655655- op->enabled = false;656656- dispc_ovl_enable(ovl->id, false);657657- return;658658- }659659-660660- op->info_dirty = false;661661- if (mp->updating)662662- op->shadow_info_dirty = true;663663-}664664-665665-static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)666666-{667667- struct ovl_priv_data *op = get_ovl_priv(ovl);668668- struct mgr_priv_data *mp;669669-670670- DSSDBG("writing ovl %d regs extra\n", ovl->id);671671-672672- if (!op->extra_info_dirty)673673- return;674674-675675- /* note: write also when op->enabled == false, so that the ovl gets676676- * disabled */677677-678678- dispc_ovl_enable(ovl->id, op->enabled);679679- dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);680680-681681- mp = get_mgr_priv(ovl->manager);682682-683683- op->extra_info_dirty = false;684684- if (mp->updating)685685- op->shadow_extra_info_dirty = true;686686-}687687-688688-static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)689689-{690690- struct mgr_priv_data *mp = get_mgr_priv(mgr);691691- struct omap_overlay *ovl;692692-693693- DSSDBG("writing mgr %d regs\n", mgr->id);694694-695695- if (!mp->enabled)696696- return;697697-698698- WARN_ON(mp->busy);699699-700700- /* Commit overlay settings */701701- list_for_each_entry(ovl, &mgr->overlays, list) {702702- dss_ovl_write_regs(ovl);703703- dss_ovl_write_regs_extra(ovl);704704- }705705-706706- if (mp->info_dirty) {707707- dispc_mgr_setup(mgr->id, &mp->info);708708-709709- mp->info_dirty = false;710710- if (mp->updating)711711- mp->shadow_info_dirty = true;712712- }713713-}714714-715715-static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr)716716-{717717- struct mgr_priv_data *mp = get_mgr_priv(mgr);718718-719719- DSSDBG("writing mgr %d regs extra\n", mgr->id);720720-721721- if (!mp->extra_info_dirty)722722- return;723723-724724- dispc_mgr_set_timings(mgr->id, &mp->timings);725725-726726- /* lcd_config parameters */727727- if (dss_mgr_is_lcd(mgr->id))728728- dispc_mgr_set_lcd_config(mgr->id, &mp->lcd_config);729729-730730- mp->extra_info_dirty = false;731731- if (mp->updating)732732- mp->shadow_extra_info_dirty = true;733733-}734734-735735-static void dss_write_regs(void)736736-{737737- const int num_mgrs = omap_dss_get_num_overlay_managers();738738- int i;739739-740740- for (i = 0; i < num_mgrs; ++i) {741741- struct omap_overlay_manager *mgr;742742- struct mgr_priv_data *mp;743743- int r;744744-745745- mgr = omap_dss_get_overlay_manager(i);746746- mp = get_mgr_priv(mgr);747747-748748- if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)749749- continue;750750-751751- r = dss_check_settings(mgr);752752- if (r) {753753- DSSERR("cannot write registers for manager %s: "754754- "illegal configuration\n", mgr->name);755755- continue;756756- }757757-758758- dss_mgr_write_regs(mgr);759759- dss_mgr_write_regs_extra(mgr);760760- }761761-}762762-763763-static void dss_set_go_bits(void)764764-{765765- const int num_mgrs = omap_dss_get_num_overlay_managers();766766- int i;767767-768768- for (i = 0; i < num_mgrs; ++i) {769769- struct omap_overlay_manager *mgr;770770- struct mgr_priv_data *mp;771771-772772- mgr = omap_dss_get_overlay_manager(i);773773- mp = get_mgr_priv(mgr);774774-775775- if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)776776- continue;777777-778778- if (!need_go(mgr))779779- continue;780780-781781- mp->busy = true;782782-783783- if (!dss_data.irq_enabled && need_isr())784784- dss_register_vsync_isr();785785-786786- dispc_mgr_go(mgr->id);787787- }788788-789789-}790790-791791-static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)792792-{793793- struct omap_overlay *ovl;794794- struct mgr_priv_data *mp;795795- struct ovl_priv_data *op;796796-797797- mp = get_mgr_priv(mgr);798798- mp->shadow_info_dirty = false;799799- mp->shadow_extra_info_dirty = false;800800-801801- list_for_each_entry(ovl, &mgr->overlays, list) {802802- op = get_ovl_priv(ovl);803803- op->shadow_info_dirty = false;804804- op->shadow_extra_info_dirty = false;805805- }806806-}807807-808808-static int dss_mgr_connect_compat(enum omap_channel channel,809809- struct omap_dss_device *dst)810810-{811811- struct omap_overlay_manager *mgr = omap_dss_get_overlay_manager(channel);812812- return mgr->set_output(mgr, dst);813813-}814814-815815-static void dss_mgr_disconnect_compat(enum omap_channel channel,816816- struct omap_dss_device *dst)817817-{818818- struct omap_overlay_manager *mgr = omap_dss_get_overlay_manager(channel);819819- mgr->unset_output(mgr);820820-}821821-822822-static void dss_mgr_start_update_compat(enum omap_channel channel)823823-{824824- struct omap_overlay_manager *mgr = omap_dss_get_overlay_manager(channel);825825- struct mgr_priv_data *mp = get_mgr_priv(mgr);826826- unsigned long flags;827827- int r;828828-829829- spin_lock_irqsave(&data_lock, flags);830830-831831- WARN_ON(mp->updating);832832-833833- r = dss_check_settings(mgr);834834- if (r) {835835- DSSERR("cannot start manual update: illegal configuration\n");836836- spin_unlock_irqrestore(&data_lock, flags);837837- return;838838- }839839-840840- dss_mgr_write_regs(mgr);841841- dss_mgr_write_regs_extra(mgr);842842-843843- mp->updating = true;844844-845845- if (!dss_data.irq_enabled && need_isr())846846- dss_register_vsync_isr();847847-848848- dispc_mgr_enable_sync(mgr->id);849849-850850- spin_unlock_irqrestore(&data_lock, flags);851851-}852852-853853-static void dss_apply_irq_handler(void *data, u32 mask);854854-855855-static void dss_register_vsync_isr(void)856856-{857857- const int num_mgrs = dss_feat_get_num_mgrs();858858- u32 mask;859859- int r, i;860860-861861- mask = 0;862862- for (i = 0; i < num_mgrs; ++i)863863- mask |= dispc_mgr_get_vsync_irq(i);864864-865865- for (i = 0; i < num_mgrs; ++i)866866- mask |= dispc_mgr_get_framedone_irq(i);867867-868868- r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);869869- WARN_ON(r);870870-871871- dss_data.irq_enabled = true;872872-}873873-874874-static void dss_unregister_vsync_isr(void)875875-{876876- const int num_mgrs = dss_feat_get_num_mgrs();877877- u32 mask;878878- int r, i;879879-880880- mask = 0;881881- for (i = 0; i < num_mgrs; ++i)882882- mask |= dispc_mgr_get_vsync_irq(i);883883-884884- for (i = 0; i < num_mgrs; ++i)885885- mask |= dispc_mgr_get_framedone_irq(i);886886-887887- r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);888888- WARN_ON(r);889889-890890- dss_data.irq_enabled = false;891891-}892892-893893-static void dss_apply_irq_handler(void *data, u32 mask)894894-{895895- const int num_mgrs = dss_feat_get_num_mgrs();896896- int i;897897- bool extra_updating;898898-899899- spin_lock(&data_lock);900900-901901- /* clear busy, updating flags, shadow_dirty flags */902902- for (i = 0; i < num_mgrs; i++) {903903- struct omap_overlay_manager *mgr;904904- struct mgr_priv_data *mp;905905-906906- mgr = omap_dss_get_overlay_manager(i);907907- mp = get_mgr_priv(mgr);908908-909909- if (!mp->enabled)910910- continue;911911-912912- mp->updating = dispc_mgr_is_enabled(i);913913-914914- if (!mgr_manual_update(mgr)) {915915- bool was_busy = mp->busy;916916- mp->busy = dispc_mgr_go_busy(i);917917-918918- if (was_busy && !mp->busy)919919- mgr_clear_shadow_dirty(mgr);920920- }921921- }922922-923923- dss_write_regs();924924- dss_set_go_bits();925925-926926- extra_updating = extra_info_update_ongoing();927927- if (!extra_updating)928928- complete_all(&extra_updated_completion);929929-930930- /* call framedone handlers for manual update displays */931931- for (i = 0; i < num_mgrs; i++) {932932- struct omap_overlay_manager *mgr;933933- struct mgr_priv_data *mp;934934-935935- mgr = omap_dss_get_overlay_manager(i);936936- mp = get_mgr_priv(mgr);937937-938938- if (!mgr_manual_update(mgr) || !mp->framedone_handler)939939- continue;940940-941941- if (mask & dispc_mgr_get_framedone_irq(i))942942- mp->framedone_handler(mp->framedone_handler_data);943943- }944944-945945- if (!need_isr())946946- dss_unregister_vsync_isr();947947-948948- spin_unlock(&data_lock);949949-}950950-951951-static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)952952-{953953- struct ovl_priv_data *op;954954-955955- op = get_ovl_priv(ovl);956956-957957- if (!op->user_info_dirty)958958- return;959959-960960- op->user_info_dirty = false;961961- op->info_dirty = true;962962- op->info = op->user_info;963963-}964964-965965-static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)966966-{967967- struct mgr_priv_data *mp;968968-969969- mp = get_mgr_priv(mgr);970970-971971- if (!mp->user_info_dirty)972972- return;973973-974974- mp->user_info_dirty = false;975975- mp->info_dirty = true;976976- mp->info = mp->user_info;977977-}978978-979979-static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)980980-{981981- unsigned long flags;982982- struct omap_overlay *ovl;983983- int r;984984-985985- DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);986986-987987- spin_lock_irqsave(&data_lock, flags);988988-989989- r = dss_check_settings_apply(mgr);990990- if (r) {991991- spin_unlock_irqrestore(&data_lock, flags);992992- DSSERR("failed to apply settings: illegal configuration.\n");993993- return r;994994- }995995-996996- /* Configure overlays */997997- list_for_each_entry(ovl, &mgr->overlays, list)998998- omap_dss_mgr_apply_ovl(ovl);999999-10001000- /* Configure manager */10011001- omap_dss_mgr_apply_mgr(mgr);10021002-10031003- dss_write_regs();10041004- dss_set_go_bits();10051005-10061006- spin_unlock_irqrestore(&data_lock, flags);10071007-10081008- return 0;10091009-}10101010-10111011-static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable)10121012-{10131013- struct ovl_priv_data *op;10141014-10151015- op = get_ovl_priv(ovl);10161016-10171017- if (op->enabled == enable)10181018- return;10191019-10201020- op->enabled = enable;10211021- op->extra_info_dirty = true;10221022-}10231023-10241024-static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl,10251025- u32 fifo_low, u32 fifo_high)10261026-{10271027- struct ovl_priv_data *op = get_ovl_priv(ovl);10281028-10291029- if (op->fifo_low == fifo_low && op->fifo_high == fifo_high)10301030- return;10311031-10321032- op->fifo_low = fifo_low;10331033- op->fifo_high = fifo_high;10341034- op->extra_info_dirty = true;10351035-}10361036-10371037-static void dss_ovl_setup_fifo(struct omap_overlay *ovl)10381038-{10391039- struct ovl_priv_data *op = get_ovl_priv(ovl);10401040- u32 fifo_low, fifo_high;10411041- bool use_fifo_merge = false;10421042-10431043- if (!op->enabled && !op->enabling)10441044- return;10451045-10461046- dispc_ovl_compute_fifo_thresholds(ovl->id, &fifo_low, &fifo_high,10471047- use_fifo_merge, ovl_manual_update(ovl));10481048-10491049- dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);10501050-}10511051-10521052-static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)10531053-{10541054- struct omap_overlay *ovl;10551055- struct mgr_priv_data *mp;10561056-10571057- mp = get_mgr_priv(mgr);10581058-10591059- if (!mp->enabled)10601060- return;10611061-10621062- list_for_each_entry(ovl, &mgr->overlays, list)10631063- dss_ovl_setup_fifo(ovl);10641064-}10651065-10661066-static void dss_setup_fifos(void)10671067-{10681068- const int num_mgrs = omap_dss_get_num_overlay_managers();10691069- struct omap_overlay_manager *mgr;10701070- int i;10711071-10721072- for (i = 0; i < num_mgrs; ++i) {10731073- mgr = omap_dss_get_overlay_manager(i);10741074- dss_mgr_setup_fifos(mgr);10751075- }10761076-}10771077-10781078-static int dss_mgr_enable_compat(enum omap_channel channel)10791079-{10801080- struct omap_overlay_manager *mgr = omap_dss_get_overlay_manager(channel);10811081- struct mgr_priv_data *mp = get_mgr_priv(mgr);10821082- unsigned long flags;10831083- int r;10841084-10851085- mutex_lock(&apply_lock);10861086-10871087- if (mp->enabled)10881088- goto out;10891089-10901090- spin_lock_irqsave(&data_lock, flags);10911091-10921092- mp->enabled = true;10931093-10941094- r = dss_check_settings(mgr);10951095- if (r) {10961096- DSSERR("failed to enable manager %d: check_settings failed\n",10971097- mgr->id);10981098- goto err;10991099- }11001100-11011101- dss_setup_fifos();11021102-11031103- dss_write_regs();11041104- dss_set_go_bits();11051105-11061106- if (!mgr_manual_update(mgr))11071107- mp->updating = true;11081108-11091109- if (!dss_data.irq_enabled && need_isr())11101110- dss_register_vsync_isr();11111111-11121112- spin_unlock_irqrestore(&data_lock, flags);11131113-11141114- if (!mgr_manual_update(mgr))11151115- dispc_mgr_enable_sync(mgr->id);11161116-11171117-out:11181118- mutex_unlock(&apply_lock);11191119-11201120- return 0;11211121-11221122-err:11231123- mp->enabled = false;11241124- spin_unlock_irqrestore(&data_lock, flags);11251125- mutex_unlock(&apply_lock);11261126- return r;11271127-}11281128-11291129-static void dss_mgr_disable_compat(enum omap_channel channel)11301130-{11311131- struct omap_overlay_manager *mgr = omap_dss_get_overlay_manager(channel);11321132- struct mgr_priv_data *mp = get_mgr_priv(mgr);11331133- unsigned long flags;11341134-11351135- mutex_lock(&apply_lock);11361136-11371137- if (!mp->enabled)11381138- goto out;11391139-11401140- wait_pending_extra_info_updates();11411141-11421142- if (!mgr_manual_update(mgr))11431143- dispc_mgr_disable_sync(mgr->id);11441144-11451145- spin_lock_irqsave(&data_lock, flags);11461146-11471147- mp->updating = false;11481148- mp->enabled = false;11491149-11501150- spin_unlock_irqrestore(&data_lock, flags);11511151-11521152-out:11531153- mutex_unlock(&apply_lock);11541154-}11551155-11561156-static int dss_mgr_set_info(struct omap_overlay_manager *mgr,11571157- struct omap_overlay_manager_info *info)11581158-{11591159- struct mgr_priv_data *mp = get_mgr_priv(mgr);11601160- unsigned long flags;11611161- int r;11621162-11631163- r = dss_mgr_simple_check(mgr, info);11641164- if (r)11651165- return r;11661166-11671167- spin_lock_irqsave(&data_lock, flags);11681168-11691169- mp->user_info = *info;11701170- mp->user_info_dirty = true;11711171-11721172- spin_unlock_irqrestore(&data_lock, flags);11731173-11741174- return 0;11751175-}11761176-11771177-static void dss_mgr_get_info(struct omap_overlay_manager *mgr,11781178- struct omap_overlay_manager_info *info)11791179-{11801180- struct mgr_priv_data *mp = get_mgr_priv(mgr);11811181- unsigned long flags;11821182-11831183- spin_lock_irqsave(&data_lock, flags);11841184-11851185- *info = mp->user_info;11861186-11871187- spin_unlock_irqrestore(&data_lock, flags);11881188-}11891189-11901190-static int dss_mgr_set_output(struct omap_overlay_manager *mgr,11911191- struct omap_dss_device *output)11921192-{11931193- int r;11941194-11951195- mutex_lock(&apply_lock);11961196-11971197- if (mgr->output) {11981198- DSSERR("manager %s is already connected to an output\n",11991199- mgr->name);12001200- r = -EINVAL;12011201- goto err;12021202- }12031203-12041204- if ((mgr->supported_outputs & output->id) == 0) {12051205- DSSERR("output does not support manager %s\n",12061206- mgr->name);12071207- r = -EINVAL;12081208- goto err;12091209- }12101210-12111211- output->manager = mgr;12121212- mgr->output = output;12131213-12141214- mutex_unlock(&apply_lock);12151215-12161216- return 0;12171217-err:12181218- mutex_unlock(&apply_lock);12191219- return r;12201220-}12211221-12221222-static int dss_mgr_unset_output(struct omap_overlay_manager *mgr)12231223-{12241224- int r;12251225- struct mgr_priv_data *mp = get_mgr_priv(mgr);12261226- unsigned long flags;12271227-12281228- mutex_lock(&apply_lock);12291229-12301230- if (!mgr->output) {12311231- DSSERR("failed to unset output, output not set\n");12321232- r = -EINVAL;12331233- goto err;12341234- }12351235-12361236- spin_lock_irqsave(&data_lock, flags);12371237-12381238- if (mp->enabled) {12391239- DSSERR("output can't be unset when manager is enabled\n");12401240- r = -EINVAL;12411241- goto err1;12421242- }12431243-12441244- spin_unlock_irqrestore(&data_lock, flags);12451245-12461246- mgr->output->manager = NULL;12471247- mgr->output = NULL;12481248-12491249- mutex_unlock(&apply_lock);12501250-12511251- return 0;12521252-err1:12531253- spin_unlock_irqrestore(&data_lock, flags);12541254-err:12551255- mutex_unlock(&apply_lock);12561256-12571257- return r;12581258-}12591259-12601260-static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr,12611261- const struct omap_video_timings *timings)12621262-{12631263- struct mgr_priv_data *mp = get_mgr_priv(mgr);12641264-12651265- mp->timings = *timings;12661266- mp->extra_info_dirty = true;12671267-}12681268-12691269-static void dss_mgr_set_timings_compat(enum omap_channel channel,12701270- const struct omap_video_timings *timings)12711271-{12721272- struct omap_overlay_manager *mgr = omap_dss_get_overlay_manager(channel);12731273- unsigned long flags;12741274- struct mgr_priv_data *mp = get_mgr_priv(mgr);12751275-12761276- spin_lock_irqsave(&data_lock, flags);12771277-12781278- if (mp->updating) {12791279- DSSERR("cannot set timings for %s: manager needs to be disabled\n",12801280- mgr->name);12811281- goto out;12821282- }12831283-12841284- dss_apply_mgr_timings(mgr, timings);12851285-out:12861286- spin_unlock_irqrestore(&data_lock, flags);12871287-}12881288-12891289-static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr,12901290- const struct dss_lcd_mgr_config *config)12911291-{12921292- struct mgr_priv_data *mp = get_mgr_priv(mgr);12931293-12941294- mp->lcd_config = *config;12951295- mp->extra_info_dirty = true;12961296-}12971297-12981298-static void dss_mgr_set_lcd_config_compat(enum omap_channel channel,12991299- const struct dss_lcd_mgr_config *config)13001300-{13011301- struct omap_overlay_manager *mgr = omap_dss_get_overlay_manager(channel);13021302- unsigned long flags;13031303- struct mgr_priv_data *mp = get_mgr_priv(mgr);13041304-13051305- spin_lock_irqsave(&data_lock, flags);13061306-13071307- if (mp->enabled) {13081308- DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n",13091309- mgr->name);13101310- goto out;13111311- }13121312-13131313- dss_apply_mgr_lcd_config(mgr, config);13141314-out:13151315- spin_unlock_irqrestore(&data_lock, flags);13161316-}13171317-13181318-static int dss_ovl_set_info(struct omap_overlay *ovl,13191319- struct omap_overlay_info *info)13201320-{13211321- struct ovl_priv_data *op = get_ovl_priv(ovl);13221322- unsigned long flags;13231323- int r;13241324-13251325- r = dss_ovl_simple_check(ovl, info);13261326- if (r)13271327- return r;13281328-13291329- spin_lock_irqsave(&data_lock, flags);13301330-13311331- op->user_info = *info;13321332- op->user_info_dirty = true;13331333-13341334- spin_unlock_irqrestore(&data_lock, flags);13351335-13361336- return 0;13371337-}13381338-13391339-static void dss_ovl_get_info(struct omap_overlay *ovl,13401340- struct omap_overlay_info *info)13411341-{13421342- struct ovl_priv_data *op = get_ovl_priv(ovl);13431343- unsigned long flags;13441344-13451345- spin_lock_irqsave(&data_lock, flags);13461346-13471347- *info = op->user_info;13481348-13491349- spin_unlock_irqrestore(&data_lock, flags);13501350-}13511351-13521352-static int dss_ovl_set_manager(struct omap_overlay *ovl,13531353- struct omap_overlay_manager *mgr)13541354-{13551355- struct ovl_priv_data *op = get_ovl_priv(ovl);13561356- unsigned long flags;13571357- int r;13581358-13591359- if (!mgr)13601360- return -EINVAL;13611361-13621362- mutex_lock(&apply_lock);13631363-13641364- if (ovl->manager) {13651365- DSSERR("overlay '%s' already has a manager '%s'\n",13661366- ovl->name, ovl->manager->name);13671367- r = -EINVAL;13681368- goto err;13691369- }13701370-13711371- r = dispc_runtime_get();13721372- if (r)13731373- goto err;13741374-13751375- spin_lock_irqsave(&data_lock, flags);13761376-13771377- if (op->enabled) {13781378- spin_unlock_irqrestore(&data_lock, flags);13791379- DSSERR("overlay has to be disabled to change the manager\n");13801380- r = -EINVAL;13811381- goto err1;13821382- }13831383-13841384- dispc_ovl_set_channel_out(ovl->id, mgr->id);13851385-13861386- ovl->manager = mgr;13871387- list_add_tail(&ovl->list, &mgr->overlays);13881388-13891389- spin_unlock_irqrestore(&data_lock, flags);13901390-13911391- dispc_runtime_put();13921392-13931393- mutex_unlock(&apply_lock);13941394-13951395- return 0;13961396-13971397-err1:13981398- dispc_runtime_put();13991399-err:14001400- mutex_unlock(&apply_lock);14011401- return r;14021402-}14031403-14041404-static int dss_ovl_unset_manager(struct omap_overlay *ovl)14051405-{14061406- struct ovl_priv_data *op = get_ovl_priv(ovl);14071407- unsigned long flags;14081408- int r;14091409-14101410- mutex_lock(&apply_lock);14111411-14121412- if (!ovl->manager) {14131413- DSSERR("failed to detach overlay: manager not set\n");14141414- r = -EINVAL;14151415- goto err;14161416- }14171417-14181418- spin_lock_irqsave(&data_lock, flags);14191419-14201420- if (op->enabled) {14211421- spin_unlock_irqrestore(&data_lock, flags);14221422- DSSERR("overlay has to be disabled to unset the manager\n");14231423- r = -EINVAL;14241424- goto err;14251425- }14261426-14271427- spin_unlock_irqrestore(&data_lock, flags);14281428-14291429- /* wait for pending extra_info updates to ensure the ovl is disabled */14301430- wait_pending_extra_info_updates();14311431-14321432- /*14331433- * For a manual update display, there is no guarantee that the overlay14341434- * is really disabled in HW, we may need an extra update from this14351435- * manager before the configurations can go in. Return an error if the14361436- * overlay needed an update from the manager.14371437- *14381438- * TODO: Instead of returning an error, try to do a dummy manager update14391439- * here to disable the overlay in hardware. Use the *GATED fields in14401440- * the DISPC_CONFIG registers to do a dummy update.14411441- */14421442- spin_lock_irqsave(&data_lock, flags);14431443-14441444- if (ovl_manual_update(ovl) && op->extra_info_dirty) {14451445- spin_unlock_irqrestore(&data_lock, flags);14461446- DSSERR("need an update to change the manager\n");14471447- r = -EINVAL;14481448- goto err;14491449- }14501450-14511451- ovl->manager = NULL;14521452- list_del(&ovl->list);14531453-14541454- spin_unlock_irqrestore(&data_lock, flags);14551455-14561456- mutex_unlock(&apply_lock);14571457-14581458- return 0;14591459-err:14601460- mutex_unlock(&apply_lock);14611461- return r;14621462-}14631463-14641464-static bool dss_ovl_is_enabled(struct omap_overlay *ovl)14651465-{14661466- struct ovl_priv_data *op = get_ovl_priv(ovl);14671467- unsigned long flags;14681468- bool e;14691469-14701470- spin_lock_irqsave(&data_lock, flags);14711471-14721472- e = op->enabled;14731473-14741474- spin_unlock_irqrestore(&data_lock, flags);14751475-14761476- return e;14771477-}14781478-14791479-static int dss_ovl_enable(struct omap_overlay *ovl)14801480-{14811481- struct ovl_priv_data *op = get_ovl_priv(ovl);14821482- unsigned long flags;14831483- int r;14841484-14851485- mutex_lock(&apply_lock);14861486-14871487- if (op->enabled) {14881488- r = 0;14891489- goto err1;14901490- }14911491-14921492- if (ovl->manager == NULL || ovl->manager->output == NULL) {14931493- r = -EINVAL;14941494- goto err1;14951495- }14961496-14971497- spin_lock_irqsave(&data_lock, flags);14981498-14991499- op->enabling = true;15001500-15011501- r = dss_check_settings(ovl->manager);15021502- if (r) {15031503- DSSERR("failed to enable overlay %d: check_settings failed\n",15041504- ovl->id);15051505- goto err2;15061506- }15071507-15081508- dss_setup_fifos();15091509-15101510- op->enabling = false;15111511- dss_apply_ovl_enable(ovl, true);15121512-15131513- dss_write_regs();15141514- dss_set_go_bits();15151515-15161516- spin_unlock_irqrestore(&data_lock, flags);15171517-15181518- mutex_unlock(&apply_lock);15191519-15201520- return 0;15211521-err2:15221522- op->enabling = false;15231523- spin_unlock_irqrestore(&data_lock, flags);15241524-err1:15251525- mutex_unlock(&apply_lock);15261526- return r;15271527-}15281528-15291529-static int dss_ovl_disable(struct omap_overlay *ovl)15301530-{15311531- struct ovl_priv_data *op = get_ovl_priv(ovl);15321532- unsigned long flags;15331533- int r;15341534-15351535- mutex_lock(&apply_lock);15361536-15371537- if (!op->enabled) {15381538- r = 0;15391539- goto err;15401540- }15411541-15421542- if (ovl->manager == NULL || ovl->manager->output == NULL) {15431543- r = -EINVAL;15441544- goto err;15451545- }15461546-15471547- spin_lock_irqsave(&data_lock, flags);15481548-15491549- dss_apply_ovl_enable(ovl, false);15501550- dss_write_regs();15511551- dss_set_go_bits();15521552-15531553- spin_unlock_irqrestore(&data_lock, flags);15541554-15551555- mutex_unlock(&apply_lock);15561556-15571557- return 0;15581558-15591559-err:15601560- mutex_unlock(&apply_lock);15611561- return r;15621562-}15631563-15641564-static int dss_mgr_register_framedone_handler_compat(enum omap_channel channel,15651565- void (*handler)(void *), void *data)15661566-{15671567- struct omap_overlay_manager *mgr = omap_dss_get_overlay_manager(channel);15681568- struct mgr_priv_data *mp = get_mgr_priv(mgr);15691569-15701570- if (mp->framedone_handler)15711571- return -EBUSY;15721572-15731573- mp->framedone_handler = handler;15741574- mp->framedone_handler_data = data;15751575-15761576- return 0;15771577-}15781578-15791579-static void dss_mgr_unregister_framedone_handler_compat(enum omap_channel channel,15801580- void (*handler)(void *), void *data)15811581-{15821582- struct omap_overlay_manager *mgr = omap_dss_get_overlay_manager(channel);15831583- struct mgr_priv_data *mp = get_mgr_priv(mgr);15841584-15851585- WARN_ON(mp->framedone_handler != handler ||15861586- mp->framedone_handler_data != data);15871587-15881588- mp->framedone_handler = NULL;15891589- mp->framedone_handler_data = NULL;15901590-}15911591-15921592-static const struct dss_mgr_ops apply_mgr_ops = {15931593- .connect = dss_mgr_connect_compat,15941594- .disconnect = dss_mgr_disconnect_compat,15951595- .start_update = dss_mgr_start_update_compat,15961596- .enable = dss_mgr_enable_compat,15971597- .disable = dss_mgr_disable_compat,15981598- .set_timings = dss_mgr_set_timings_compat,15991599- .set_lcd_config = dss_mgr_set_lcd_config_compat,16001600- .register_framedone_handler = dss_mgr_register_framedone_handler_compat,16011601- .unregister_framedone_handler = dss_mgr_unregister_framedone_handler_compat,16021602-};16031603-16041604-static int compat_refcnt;16051605-static DEFINE_MUTEX(compat_init_lock);16061606-16071607-int omapdss_compat_init(void)16081608-{16091609- struct platform_device *pdev = dss_get_core_pdev();16101610- int i, r;16111611-16121612- mutex_lock(&compat_init_lock);16131613-16141614- if (compat_refcnt++ > 0)16151615- goto out;16161616-16171617- apply_init_priv();16181618-16191619- dss_init_overlay_managers_sysfs(pdev);16201620- dss_init_overlays(pdev);16211621-16221622- for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) {16231623- struct omap_overlay_manager *mgr;16241624-16251625- mgr = omap_dss_get_overlay_manager(i);16261626-16271627- mgr->set_output = &dss_mgr_set_output;16281628- mgr->unset_output = &dss_mgr_unset_output;16291629- mgr->apply = &omap_dss_mgr_apply;16301630- mgr->set_manager_info = &dss_mgr_set_info;16311631- mgr->get_manager_info = &dss_mgr_get_info;16321632- mgr->wait_for_go = &dss_mgr_wait_for_go;16331633- mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;16341634- mgr->get_device = &dss_mgr_get_device;16351635- }16361636-16371637- for (i = 0; i < omap_dss_get_num_overlays(); i++) {16381638- struct omap_overlay *ovl = omap_dss_get_overlay(i);16391639-16401640- ovl->is_enabled = &dss_ovl_is_enabled;16411641- ovl->enable = &dss_ovl_enable;16421642- ovl->disable = &dss_ovl_disable;16431643- ovl->set_manager = &dss_ovl_set_manager;16441644- ovl->unset_manager = &dss_ovl_unset_manager;16451645- ovl->set_overlay_info = &dss_ovl_set_info;16461646- ovl->get_overlay_info = &dss_ovl_get_info;16471647- ovl->wait_for_go = &dss_mgr_wait_for_go_ovl;16481648- ovl->get_device = &dss_ovl_get_device;16491649- }16501650-16511651- r = dss_install_mgr_ops(&apply_mgr_ops);16521652- if (r)16531653- goto err_mgr_ops;16541654-16551655- r = display_init_sysfs(pdev);16561656- if (r)16571657- goto err_disp_sysfs;16581658-16591659- dispc_runtime_get();16601660-16611661- r = dss_dispc_initialize_irq();16621662- if (r)16631663- goto err_init_irq;16641664-16651665- dispc_runtime_put();16661666-16671667-out:16681668- mutex_unlock(&compat_init_lock);16691669-16701670- return 0;16711671-16721672-err_init_irq:16731673- dispc_runtime_put();16741674- display_uninit_sysfs(pdev);16751675-16761676-err_disp_sysfs:16771677- dss_uninstall_mgr_ops();16781678-16791679-err_mgr_ops:16801680- dss_uninit_overlay_managers_sysfs(pdev);16811681- dss_uninit_overlays(pdev);16821682-16831683- compat_refcnt--;16841684-16851685- mutex_unlock(&compat_init_lock);16861686-16871687- return r;16881688-}16891689-EXPORT_SYMBOL(omapdss_compat_init);16901690-16911691-void omapdss_compat_uninit(void)16921692-{16931693- struct platform_device *pdev = dss_get_core_pdev();16941694-16951695- mutex_lock(&compat_init_lock);16961696-16971697- if (--compat_refcnt > 0)16981698- goto out;16991699-17001700- dss_dispc_uninitialize_irq();17011701-17021702- display_uninit_sysfs(pdev);17031703-17041704- dss_uninstall_mgr_ops();17051705-17061706- dss_uninit_overlay_managers_sysfs(pdev);17071707- dss_uninit_overlays(pdev);17081708-out:17091709- mutex_unlock(&compat_init_lock);17101710-}17111711-EXPORT_SYMBOL(omapdss_compat_uninit);
-667
drivers/gpu/drm/omapdrm/dss/dispc-compat.c
···11-/*22- * Copyright (C) 2012 Texas Instruments33- * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>44- *55- * This program is free software; you can redistribute it and/or modify it66- * under the terms of the GNU General Public License version 2 as published by77- * the Free Software Foundation.88- *99- * This program is distributed in the hope that it will be useful, but WITHOUT1010- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1111- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1212- * more details.1313- *1414- * You should have received a copy of the GNU General Public License along with1515- * this program. If not, see <http://www.gnu.org/licenses/>.1616- */1717-1818-#define DSS_SUBSYS_NAME "APPLY"1919-2020-#include <linux/kernel.h>2121-#include <linux/module.h>2222-#include <linux/slab.h>2323-#include <linux/spinlock.h>2424-#include <linux/jiffies.h>2525-#include <linux/delay.h>2626-#include <linux/interrupt.h>2727-#include <linux/seq_file.h>2828-2929-#include <video/omapdss.h>3030-3131-#include "dss.h"3232-#include "dss_features.h"3333-#include "dispc-compat.h"3434-3535-#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \3636- DISPC_IRQ_OCP_ERR | \3737- DISPC_IRQ_VID1_FIFO_UNDERFLOW | \3838- DISPC_IRQ_VID2_FIFO_UNDERFLOW | \3939- DISPC_IRQ_SYNC_LOST | \4040- DISPC_IRQ_SYNC_LOST_DIGIT)4141-4242-#define DISPC_MAX_NR_ISRS 84343-4444-struct omap_dispc_isr_data {4545- omap_dispc_isr_t isr;4646- void *arg;4747- u32 mask;4848-};4949-5050-struct dispc_irq_stats {5151- unsigned long last_reset;5252- unsigned irq_count;5353- unsigned irqs[32];5454-};5555-5656-static struct {5757- spinlock_t irq_lock;5858- u32 irq_error_mask;5959- struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];6060- u32 error_irqs;6161- struct work_struct error_work;6262-6363-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS6464- spinlock_t irq_stats_lock;6565- struct dispc_irq_stats irq_stats;6666-#endif6767-} dispc_compat;6868-6969-7070-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS7171-static void dispc_dump_irqs(struct seq_file *s)7272-{7373- unsigned long flags;7474- struct dispc_irq_stats stats;7575-7676- spin_lock_irqsave(&dispc_compat.irq_stats_lock, flags);7777-7878- stats = dispc_compat.irq_stats;7979- memset(&dispc_compat.irq_stats, 0, sizeof(dispc_compat.irq_stats));8080- dispc_compat.irq_stats.last_reset = jiffies;8181-8282- spin_unlock_irqrestore(&dispc_compat.irq_stats_lock, flags);8383-8484- seq_printf(s, "period %u ms\n",8585- jiffies_to_msecs(jiffies - stats.last_reset));8686-8787- seq_printf(s, "irqs %d\n", stats.irq_count);8888-#define PIS(x) \8989- seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]);9090-9191- PIS(FRAMEDONE);9292- PIS(VSYNC);9393- PIS(EVSYNC_EVEN);9494- PIS(EVSYNC_ODD);9595- PIS(ACBIAS_COUNT_STAT);9696- PIS(PROG_LINE_NUM);9797- PIS(GFX_FIFO_UNDERFLOW);9898- PIS(GFX_END_WIN);9999- PIS(PAL_GAMMA_MASK);100100- PIS(OCP_ERR);101101- PIS(VID1_FIFO_UNDERFLOW);102102- PIS(VID1_END_WIN);103103- PIS(VID2_FIFO_UNDERFLOW);104104- PIS(VID2_END_WIN);105105- if (dss_feat_get_num_ovls() > 3) {106106- PIS(VID3_FIFO_UNDERFLOW);107107- PIS(VID3_END_WIN);108108- }109109- PIS(SYNC_LOST);110110- PIS(SYNC_LOST_DIGIT);111111- PIS(WAKEUP);112112- if (dss_has_feature(FEAT_MGR_LCD2)) {113113- PIS(FRAMEDONE2);114114- PIS(VSYNC2);115115- PIS(ACBIAS_COUNT_STAT2);116116- PIS(SYNC_LOST2);117117- }118118- if (dss_has_feature(FEAT_MGR_LCD3)) {119119- PIS(FRAMEDONE3);120120- PIS(VSYNC3);121121- PIS(ACBIAS_COUNT_STAT3);122122- PIS(SYNC_LOST3);123123- }124124-#undef PIS125125-}126126-#endif127127-128128-/* dispc.irq_lock has to be locked by the caller */129129-static void _omap_dispc_set_irqs(void)130130-{131131- u32 mask;132132- int i;133133- struct omap_dispc_isr_data *isr_data;134134-135135- mask = dispc_compat.irq_error_mask;136136-137137- for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {138138- isr_data = &dispc_compat.registered_isr[i];139139-140140- if (isr_data->isr == NULL)141141- continue;142142-143143- mask |= isr_data->mask;144144- }145145-146146- dispc_write_irqenable(mask);147147-}148148-149149-int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)150150-{151151- int i;152152- int ret;153153- unsigned long flags;154154- struct omap_dispc_isr_data *isr_data;155155-156156- if (isr == NULL)157157- return -EINVAL;158158-159159- spin_lock_irqsave(&dispc_compat.irq_lock, flags);160160-161161- /* check for duplicate entry */162162- for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {163163- isr_data = &dispc_compat.registered_isr[i];164164- if (isr_data->isr == isr && isr_data->arg == arg &&165165- isr_data->mask == mask) {166166- ret = -EINVAL;167167- goto err;168168- }169169- }170170-171171- isr_data = NULL;172172- ret = -EBUSY;173173-174174- for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {175175- isr_data = &dispc_compat.registered_isr[i];176176-177177- if (isr_data->isr != NULL)178178- continue;179179-180180- isr_data->isr = isr;181181- isr_data->arg = arg;182182- isr_data->mask = mask;183183- ret = 0;184184-185185- break;186186- }187187-188188- if (ret)189189- goto err;190190-191191- _omap_dispc_set_irqs();192192-193193- spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);194194-195195- return 0;196196-err:197197- spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);198198-199199- return ret;200200-}201201-EXPORT_SYMBOL(omap_dispc_register_isr);202202-203203-int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)204204-{205205- int i;206206- unsigned long flags;207207- int ret = -EINVAL;208208- struct omap_dispc_isr_data *isr_data;209209-210210- spin_lock_irqsave(&dispc_compat.irq_lock, flags);211211-212212- for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {213213- isr_data = &dispc_compat.registered_isr[i];214214- if (isr_data->isr != isr || isr_data->arg != arg ||215215- isr_data->mask != mask)216216- continue;217217-218218- /* found the correct isr */219219-220220- isr_data->isr = NULL;221221- isr_data->arg = NULL;222222- isr_data->mask = 0;223223-224224- ret = 0;225225- break;226226- }227227-228228- if (ret == 0)229229- _omap_dispc_set_irqs();230230-231231- spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);232232-233233- return ret;234234-}235235-EXPORT_SYMBOL(omap_dispc_unregister_isr);236236-237237-static void print_irq_status(u32 status)238238-{239239- if ((status & dispc_compat.irq_error_mask) == 0)240240- return;241241-242242-#define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : ""243243-244244- pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n",245245- status,246246- PIS(OCP_ERR),247247- PIS(GFX_FIFO_UNDERFLOW),248248- PIS(VID1_FIFO_UNDERFLOW),249249- PIS(VID2_FIFO_UNDERFLOW),250250- dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW) : "",251251- PIS(SYNC_LOST),252252- PIS(SYNC_LOST_DIGIT),253253- dss_has_feature(FEAT_MGR_LCD2) ? PIS(SYNC_LOST2) : "",254254- dss_has_feature(FEAT_MGR_LCD3) ? PIS(SYNC_LOST3) : "");255255-#undef PIS256256-}257257-258258-/* Called from dss.c. Note that we don't touch clocks here,259259- * but we presume they are on because we got an IRQ. However,260260- * an irq handler may turn the clocks off, so we may not have261261- * clock later in the function. */262262-static irqreturn_t omap_dispc_irq_handler(int irq, void *arg)263263-{264264- int i;265265- u32 irqstatus, irqenable;266266- u32 handledirqs = 0;267267- u32 unhandled_errors;268268- struct omap_dispc_isr_data *isr_data;269269- struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];270270-271271- spin_lock(&dispc_compat.irq_lock);272272-273273- irqstatus = dispc_read_irqstatus();274274- irqenable = dispc_read_irqenable();275275-276276- /* IRQ is not for us */277277- if (!(irqstatus & irqenable)) {278278- spin_unlock(&dispc_compat.irq_lock);279279- return IRQ_NONE;280280- }281281-282282-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS283283- spin_lock(&dispc_compat.irq_stats_lock);284284- dispc_compat.irq_stats.irq_count++;285285- dss_collect_irq_stats(irqstatus, dispc_compat.irq_stats.irqs);286286- spin_unlock(&dispc_compat.irq_stats_lock);287287-#endif288288-289289- print_irq_status(irqstatus);290290-291291- /* Ack the interrupt. Do it here before clocks are possibly turned292292- * off */293293- dispc_clear_irqstatus(irqstatus);294294- /* flush posted write */295295- dispc_read_irqstatus();296296-297297- /* make a copy and unlock, so that isrs can unregister298298- * themselves */299299- memcpy(registered_isr, dispc_compat.registered_isr,300300- sizeof(registered_isr));301301-302302- spin_unlock(&dispc_compat.irq_lock);303303-304304- for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {305305- isr_data = ®istered_isr[i];306306-307307- if (!isr_data->isr)308308- continue;309309-310310- if (isr_data->mask & irqstatus) {311311- isr_data->isr(isr_data->arg, irqstatus);312312- handledirqs |= isr_data->mask;313313- }314314- }315315-316316- spin_lock(&dispc_compat.irq_lock);317317-318318- unhandled_errors = irqstatus & ~handledirqs & dispc_compat.irq_error_mask;319319-320320- if (unhandled_errors) {321321- dispc_compat.error_irqs |= unhandled_errors;322322-323323- dispc_compat.irq_error_mask &= ~unhandled_errors;324324- _omap_dispc_set_irqs();325325-326326- schedule_work(&dispc_compat.error_work);327327- }328328-329329- spin_unlock(&dispc_compat.irq_lock);330330-331331- return IRQ_HANDLED;332332-}333333-334334-static void dispc_error_worker(struct work_struct *work)335335-{336336- int i;337337- u32 errors;338338- unsigned long flags;339339- static const unsigned fifo_underflow_bits[] = {340340- DISPC_IRQ_GFX_FIFO_UNDERFLOW,341341- DISPC_IRQ_VID1_FIFO_UNDERFLOW,342342- DISPC_IRQ_VID2_FIFO_UNDERFLOW,343343- DISPC_IRQ_VID3_FIFO_UNDERFLOW,344344- };345345-346346- spin_lock_irqsave(&dispc_compat.irq_lock, flags);347347- errors = dispc_compat.error_irqs;348348- dispc_compat.error_irqs = 0;349349- spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);350350-351351- dispc_runtime_get();352352-353353- for (i = 0; i < omap_dss_get_num_overlays(); ++i) {354354- struct omap_overlay *ovl;355355- unsigned bit;356356-357357- ovl = omap_dss_get_overlay(i);358358- bit = fifo_underflow_bits[i];359359-360360- if (bit & errors) {361361- DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",362362- ovl->name);363363- ovl->disable(ovl);364364- msleep(50);365365- }366366- }367367-368368- for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {369369- struct omap_overlay_manager *mgr;370370- unsigned bit;371371-372372- mgr = omap_dss_get_overlay_manager(i);373373- bit = dispc_mgr_get_sync_lost_irq(i);374374-375375- if (bit & errors) {376376- int j;377377-378378- DSSERR("SYNC_LOST on channel %s, restarting the output "379379- "with video overlays disabled\n",380380- mgr->name);381381-382382- dss_mgr_disable(mgr->id);383383-384384- for (j = 0; j < omap_dss_get_num_overlays(); ++j) {385385- struct omap_overlay *ovl;386386- ovl = omap_dss_get_overlay(j);387387-388388- if (ovl->id != OMAP_DSS_GFX &&389389- ovl->manager == mgr)390390- ovl->disable(ovl);391391- }392392-393393- dss_mgr_enable(mgr->id);394394- }395395- }396396-397397- if (errors & DISPC_IRQ_OCP_ERR) {398398- DSSERR("OCP_ERR\n");399399- for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {400400- struct omap_overlay_manager *mgr;401401-402402- mgr = omap_dss_get_overlay_manager(i);403403- dss_mgr_disable(mgr->id);404404- }405405- }406406-407407- spin_lock_irqsave(&dispc_compat.irq_lock, flags);408408- dispc_compat.irq_error_mask |= errors;409409- _omap_dispc_set_irqs();410410- spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);411411-412412- dispc_runtime_put();413413-}414414-415415-int dss_dispc_initialize_irq(void)416416-{417417- int r;418418-419419-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS420420- spin_lock_init(&dispc_compat.irq_stats_lock);421421- dispc_compat.irq_stats.last_reset = jiffies;422422- dss_debugfs_create_file("dispc_irq", dispc_dump_irqs);423423-#endif424424-425425- spin_lock_init(&dispc_compat.irq_lock);426426-427427- memset(dispc_compat.registered_isr, 0,428428- sizeof(dispc_compat.registered_isr));429429-430430- dispc_compat.irq_error_mask = DISPC_IRQ_MASK_ERROR;431431- if (dss_has_feature(FEAT_MGR_LCD2))432432- dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;433433- if (dss_has_feature(FEAT_MGR_LCD3))434434- dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST3;435435- if (dss_feat_get_num_ovls() > 3)436436- dispc_compat.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW;437437-438438- /*439439- * there's SYNC_LOST_DIGIT waiting after enabling the DSS,440440- * so clear it441441- */442442- dispc_clear_irqstatus(dispc_read_irqstatus());443443-444444- INIT_WORK(&dispc_compat.error_work, dispc_error_worker);445445-446446- _omap_dispc_set_irqs();447447-448448- r = dispc_request_irq(omap_dispc_irq_handler, &dispc_compat);449449- if (r) {450450- DSSERR("dispc_request_irq failed\n");451451- return r;452452- }453453-454454- return 0;455455-}456456-457457-void dss_dispc_uninitialize_irq(void)458458-{459459- dispc_free_irq(&dispc_compat);460460-}461461-462462-static void dispc_mgr_disable_isr(void *data, u32 mask)463463-{464464- struct completion *compl = data;465465- complete(compl);466466-}467467-468468-static void dispc_mgr_enable_lcd_out(enum omap_channel channel)469469-{470470- dispc_mgr_enable(channel, true);471471-}472472-473473-static void dispc_mgr_disable_lcd_out(enum omap_channel channel)474474-{475475- DECLARE_COMPLETION_ONSTACK(framedone_compl);476476- int r;477477- u32 irq;478478-479479- if (!dispc_mgr_is_enabled(channel))480480- return;481481-482482- /*483483- * When we disable LCD output, we need to wait for FRAMEDONE to know484484- * that DISPC has finished with the LCD output.485485- */486486-487487- irq = dispc_mgr_get_framedone_irq(channel);488488-489489- r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,490490- irq);491491- if (r)492492- DSSERR("failed to register FRAMEDONE isr\n");493493-494494- dispc_mgr_enable(channel, false);495495-496496- /* if we couldn't register for framedone, just sleep and exit */497497- if (r) {498498- msleep(100);499499- return;500500- }501501-502502- if (!wait_for_completion_timeout(&framedone_compl,503503- msecs_to_jiffies(100)))504504- DSSERR("timeout waiting for FRAME DONE\n");505505-506506- r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,507507- irq);508508- if (r)509509- DSSERR("failed to unregister FRAMEDONE isr\n");510510-}511511-512512-static void dispc_digit_out_enable_isr(void *data, u32 mask)513513-{514514- struct completion *compl = data;515515-516516- /* ignore any sync lost interrupts */517517- if (mask & (DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD))518518- complete(compl);519519-}520520-521521-static void dispc_mgr_enable_digit_out(void)522522-{523523- DECLARE_COMPLETION_ONSTACK(vsync_compl);524524- int r;525525- u32 irq_mask;526526-527527- if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT))528528- return;529529-530530- /*531531- * Digit output produces some sync lost interrupts during the first532532- * frame when enabling. Those need to be ignored, so we register for the533533- * sync lost irq to prevent the error handler from triggering.534534- */535535-536536- irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT) |537537- dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT);538538-539539- r = omap_dispc_register_isr(dispc_digit_out_enable_isr, &vsync_compl,540540- irq_mask);541541- if (r) {542542- DSSERR("failed to register %x isr\n", irq_mask);543543- return;544544- }545545-546546- dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, true);547547-548548- /* wait for the first evsync */549549- if (!wait_for_completion_timeout(&vsync_compl, msecs_to_jiffies(100)))550550- DSSERR("timeout waiting for digit out to start\n");551551-552552- r = omap_dispc_unregister_isr(dispc_digit_out_enable_isr, &vsync_compl,553553- irq_mask);554554- if (r)555555- DSSERR("failed to unregister %x isr\n", irq_mask);556556-}557557-558558-static void dispc_mgr_disable_digit_out(void)559559-{560560- DECLARE_COMPLETION_ONSTACK(framedone_compl);561561- int r, i;562562- u32 irq_mask;563563- int num_irqs;564564-565565- if (!dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT))566566- return;567567-568568- /*569569- * When we disable the digit output, we need to wait for FRAMEDONE to570570- * know that DISPC has finished with the output.571571- */572572-573573- irq_mask = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT);574574- num_irqs = 1;575575-576576- if (!irq_mask) {577577- /*578578- * omap 2/3 don't have framedone irq for TV, so we need to use579579- * vsyncs for this.580580- */581581-582582- irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT);583583- /*584584- * We need to wait for both even and odd vsyncs. Note that this585585- * is not totally reliable, as we could get a vsync interrupt586586- * before we disable the output, which leads to timeout in the587587- * wait_for_completion.588588- */589589- num_irqs = 2;590590- }591591-592592- r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,593593- irq_mask);594594- if (r)595595- DSSERR("failed to register %x isr\n", irq_mask);596596-597597- dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, false);598598-599599- /* if we couldn't register the irq, just sleep and exit */600600- if (r) {601601- msleep(100);602602- return;603603- }604604-605605- for (i = 0; i < num_irqs; ++i) {606606- if (!wait_for_completion_timeout(&framedone_compl,607607- msecs_to_jiffies(100)))608608- DSSERR("timeout waiting for digit out to stop\n");609609- }610610-611611- r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,612612- irq_mask);613613- if (r)614614- DSSERR("failed to unregister %x isr\n", irq_mask);615615-}616616-617617-void dispc_mgr_enable_sync(enum omap_channel channel)618618-{619619- if (dss_mgr_is_lcd(channel))620620- dispc_mgr_enable_lcd_out(channel);621621- else if (channel == OMAP_DSS_CHANNEL_DIGIT)622622- dispc_mgr_enable_digit_out();623623- else624624- WARN_ON(1);625625-}626626-627627-void dispc_mgr_disable_sync(enum omap_channel channel)628628-{629629- if (dss_mgr_is_lcd(channel))630630- dispc_mgr_disable_lcd_out(channel);631631- else if (channel == OMAP_DSS_CHANNEL_DIGIT)632632- dispc_mgr_disable_digit_out();633633- else634634- WARN_ON(1);635635-}636636-637637-static inline void dispc_irq_wait_handler(void *data, u32 mask)638638-{639639- complete((struct completion *)data);640640-}641641-642642-int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,643643- unsigned long timeout)644644-{645645-646646- int r;647647- DECLARE_COMPLETION_ONSTACK(completion);648648-649649- r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,650650- irqmask);651651-652652- if (r)653653- return r;654654-655655- timeout = wait_for_completion_interruptible_timeout(&completion,656656- timeout);657657-658658- omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);659659-660660- if (timeout == 0)661661- return -ETIMEDOUT;662662-663663- if (timeout == -ERESTARTSYS)664664- return -ERESTARTSYS;665665-666666- return 0;667667-}
-30
drivers/gpu/drm/omapdrm/dss/dispc-compat.h
···11-/*22- * Copyright (C) 2012 Texas Instruments33- * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>44- *55- * This program is free software; you can redistribute it and/or modify it66- * under the terms of the GNU General Public License version 2 as published by77- * the Free Software Foundation.88- *99- * This program is distributed in the hope that it will be useful, but WITHOUT1010- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1111- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1212- * more details.1313- *1414- * You should have received a copy of the GNU General Public License along with1515- * this program. If not, see <http://www.gnu.org/licenses/>.1616- */1717-1818-#ifndef __OMAP2_DSS_DISPC_COMPAT_H1919-#define __OMAP2_DSS_DISPC_COMPAT_H2020-2121-void dispc_mgr_enable_sync(enum omap_channel channel);2222-void dispc_mgr_disable_sync(enum omap_channel channel);2323-2424-int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,2525- unsigned long timeout);2626-2727-int dss_dispc_initialize_irq(void);2828-void dss_dispc_uninitialize_irq(void);2929-3030-#endif
···11-/*22- * Copyright (C) 2009 Nokia Corporation33- * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>44- *55- * Some code and ideas taken from drivers/video/omap/ driver66- * by Imre Deak.77- *88- * This program is free software; you can redistribute it and/or modify it99- * under the terms of the GNU General Public License version 2 as published by1010- * the Free Software Foundation.1111- *1212- * This program is distributed in the hope that it will be useful, but WITHOUT1313- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1414- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1515- * more details.1616- *1717- * You should have received a copy of the GNU General Public License along with1818- * this program. If not, see <http://www.gnu.org/licenses/>.1919- */2020-2121-#define DSS_SUBSYS_NAME "MANAGER"2222-2323-#include <linux/kernel.h>2424-#include <linux/slab.h>2525-#include <linux/module.h>2626-#include <linux/platform_device.h>2727-#include <linux/jiffies.h>2828-2929-#include <video/omapdss.h>3030-3131-#include "dss.h"3232-#include "dss_features.h"3333-3434-static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)3535-{3636- return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);3737-}3838-3939-static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)4040-{4141- struct omap_dss_device *dssdev = mgr->get_device(mgr);4242-4343- return snprintf(buf, PAGE_SIZE, "%s\n", dssdev ?4444- dssdev->name : "<none>");4545-}4646-4747-static int manager_display_match(struct omap_dss_device *dssdev, void *data)4848-{4949- const char *str = data;5050-5151- return sysfs_streq(dssdev->name, str);5252-}5353-5454-static ssize_t manager_display_store(struct omap_overlay_manager *mgr,5555- const char *buf, size_t size)5656-{5757- int r = 0;5858- size_t len = size;5959- struct omap_dss_device *dssdev = NULL;6060- struct omap_dss_device *old_dssdev;6161-6262- if (buf[size-1] == '\n')6363- --len;6464-6565- if (len > 0)6666- dssdev = omap_dss_find_device((void *)buf,6767- manager_display_match);6868-6969- if (len > 0 && dssdev == NULL)7070- return -EINVAL;7171-7272- if (dssdev) {7373- DSSDBG("display %s found\n", dssdev->name);7474-7575- if (omapdss_device_is_connected(dssdev)) {7676- DSSERR("new display is already connected\n");7777- r = -EINVAL;7878- goto put_device;7979- }8080-8181- if (omapdss_device_is_enabled(dssdev)) {8282- DSSERR("new display is not disabled\n");8383- r = -EINVAL;8484- goto put_device;8585- }8686- }8787-8888- old_dssdev = mgr->get_device(mgr);8989- if (old_dssdev) {9090- if (omapdss_device_is_enabled(old_dssdev)) {9191- DSSERR("old display is not disabled\n");9292- r = -EINVAL;9393- goto put_device;9494- }9595-9696- old_dssdev->driver->disconnect(old_dssdev);9797- }9898-9999- if (dssdev) {100100- r = dssdev->driver->connect(dssdev);101101- if (r) {102102- DSSERR("failed to connect new device\n");103103- goto put_device;104104- }105105-106106- old_dssdev = mgr->get_device(mgr);107107- if (old_dssdev != dssdev) {108108- DSSERR("failed to connect device to this manager\n");109109- dssdev->driver->disconnect(dssdev);110110- goto put_device;111111- }112112-113113- r = mgr->apply(mgr);114114- if (r) {115115- DSSERR("failed to apply dispc config\n");116116- goto put_device;117117- }118118- }119119-120120-put_device:121121- if (dssdev)122122- omap_dss_put_device(dssdev);123123-124124- return r ? r : size;125125-}126126-127127-static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,128128- char *buf)129129-{130130- struct omap_overlay_manager_info info;131131-132132- mgr->get_manager_info(mgr, &info);133133-134134- return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color);135135-}136136-137137-static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,138138- const char *buf, size_t size)139139-{140140- struct omap_overlay_manager_info info;141141- u32 color;142142- int r;143143-144144- r = kstrtouint(buf, 0, &color);145145- if (r)146146- return r;147147-148148- mgr->get_manager_info(mgr, &info);149149-150150- info.default_color = color;151151-152152- r = mgr->set_manager_info(mgr, &info);153153- if (r)154154- return r;155155-156156- r = mgr->apply(mgr);157157- if (r)158158- return r;159159-160160- return size;161161-}162162-163163-static const char *trans_key_type_str[] = {164164- "gfx-destination",165165- "video-source",166166-};167167-168168-static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,169169- char *buf)170170-{171171- enum omap_dss_trans_key_type key_type;172172- struct omap_overlay_manager_info info;173173-174174- mgr->get_manager_info(mgr, &info);175175-176176- key_type = info.trans_key_type;177177- BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));178178-179179- return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);180180-}181181-182182-static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,183183- const char *buf, size_t size)184184-{185185- enum omap_dss_trans_key_type key_type;186186- struct omap_overlay_manager_info info;187187- int r;188188-189189- for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;190190- key_type < ARRAY_SIZE(trans_key_type_str); key_type++) {191191- if (sysfs_streq(buf, trans_key_type_str[key_type]))192192- break;193193- }194194-195195- if (key_type == ARRAY_SIZE(trans_key_type_str))196196- return -EINVAL;197197-198198- mgr->get_manager_info(mgr, &info);199199-200200- info.trans_key_type = key_type;201201-202202- r = mgr->set_manager_info(mgr, &info);203203- if (r)204204- return r;205205-206206- r = mgr->apply(mgr);207207- if (r)208208- return r;209209-210210- return size;211211-}212212-213213-static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,214214- char *buf)215215-{216216- struct omap_overlay_manager_info info;217217-218218- mgr->get_manager_info(mgr, &info);219219-220220- return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key);221221-}222222-223223-static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,224224- const char *buf, size_t size)225225-{226226- struct omap_overlay_manager_info info;227227- u32 key_value;228228- int r;229229-230230- r = kstrtouint(buf, 0, &key_value);231231- if (r)232232- return r;233233-234234- mgr->get_manager_info(mgr, &info);235235-236236- info.trans_key = key_value;237237-238238- r = mgr->set_manager_info(mgr, &info);239239- if (r)240240- return r;241241-242242- r = mgr->apply(mgr);243243- if (r)244244- return r;245245-246246- return size;247247-}248248-249249-static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,250250- char *buf)251251-{252252- struct omap_overlay_manager_info info;253253-254254- mgr->get_manager_info(mgr, &info);255255-256256- return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled);257257-}258258-259259-static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,260260- const char *buf, size_t size)261261-{262262- struct omap_overlay_manager_info info;263263- bool enable;264264- int r;265265-266266- r = strtobool(buf, &enable);267267- if (r)268268- return r;269269-270270- mgr->get_manager_info(mgr, &info);271271-272272- info.trans_enabled = enable;273273-274274- r = mgr->set_manager_info(mgr, &info);275275- if (r)276276- return r;277277-278278- r = mgr->apply(mgr);279279- if (r)280280- return r;281281-282282- return size;283283-}284284-285285-static ssize_t manager_alpha_blending_enabled_show(286286- struct omap_overlay_manager *mgr, char *buf)287287-{288288- struct omap_overlay_manager_info info;289289-290290- if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))291291- return -ENODEV;292292-293293- mgr->get_manager_info(mgr, &info);294294-295295- return snprintf(buf, PAGE_SIZE, "%d\n",296296- info.partial_alpha_enabled);297297-}298298-299299-static ssize_t manager_alpha_blending_enabled_store(300300- struct omap_overlay_manager *mgr,301301- const char *buf, size_t size)302302-{303303- struct omap_overlay_manager_info info;304304- bool enable;305305- int r;306306-307307- if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))308308- return -ENODEV;309309-310310- r = strtobool(buf, &enable);311311- if (r)312312- return r;313313-314314- mgr->get_manager_info(mgr, &info);315315-316316- info.partial_alpha_enabled = enable;317317-318318- r = mgr->set_manager_info(mgr, &info);319319- if (r)320320- return r;321321-322322- r = mgr->apply(mgr);323323- if (r)324324- return r;325325-326326- return size;327327-}328328-329329-static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr,330330- char *buf)331331-{332332- struct omap_overlay_manager_info info;333333-334334- mgr->get_manager_info(mgr, &info);335335-336336- return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable);337337-}338338-339339-static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr,340340- const char *buf, size_t size)341341-{342342- struct omap_overlay_manager_info info;343343- int r;344344- bool enable;345345-346346- if (!dss_has_feature(FEAT_CPR))347347- return -ENODEV;348348-349349- r = strtobool(buf, &enable);350350- if (r)351351- return r;352352-353353- mgr->get_manager_info(mgr, &info);354354-355355- if (info.cpr_enable == enable)356356- return size;357357-358358- info.cpr_enable = enable;359359-360360- r = mgr->set_manager_info(mgr, &info);361361- if (r)362362- return r;363363-364364- r = mgr->apply(mgr);365365- if (r)366366- return r;367367-368368- return size;369369-}370370-371371-static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr,372372- char *buf)373373-{374374- struct omap_overlay_manager_info info;375375-376376- mgr->get_manager_info(mgr, &info);377377-378378- return snprintf(buf, PAGE_SIZE,379379- "%d %d %d %d %d %d %d %d %d\n",380380- info.cpr_coefs.rr,381381- info.cpr_coefs.rg,382382- info.cpr_coefs.rb,383383- info.cpr_coefs.gr,384384- info.cpr_coefs.gg,385385- info.cpr_coefs.gb,386386- info.cpr_coefs.br,387387- info.cpr_coefs.bg,388388- info.cpr_coefs.bb);389389-}390390-391391-static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr,392392- const char *buf, size_t size)393393-{394394- struct omap_overlay_manager_info info;395395- struct omap_dss_cpr_coefs coefs;396396- int r, i;397397- s16 *arr;398398-399399- if (!dss_has_feature(FEAT_CPR))400400- return -ENODEV;401401-402402- if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd",403403- &coefs.rr, &coefs.rg, &coefs.rb,404404- &coefs.gr, &coefs.gg, &coefs.gb,405405- &coefs.br, &coefs.bg, &coefs.bb) != 9)406406- return -EINVAL;407407-408408- arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb,409409- coefs.gr, coefs.gg, coefs.gb,410410- coefs.br, coefs.bg, coefs.bb };411411-412412- for (i = 0; i < 9; ++i) {413413- if (arr[i] < -512 || arr[i] > 511)414414- return -EINVAL;415415- }416416-417417- mgr->get_manager_info(mgr, &info);418418-419419- info.cpr_coefs = coefs;420420-421421- r = mgr->set_manager_info(mgr, &info);422422- if (r)423423- return r;424424-425425- r = mgr->apply(mgr);426426- if (r)427427- return r;428428-429429- return size;430430-}431431-432432-struct manager_attribute {433433- struct attribute attr;434434- ssize_t (*show)(struct omap_overlay_manager *, char *);435435- ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t);436436-};437437-438438-#define MANAGER_ATTR(_name, _mode, _show, _store) \439439- struct manager_attribute manager_attr_##_name = \440440- __ATTR(_name, _mode, _show, _store)441441-442442-static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);443443-static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,444444- manager_display_show, manager_display_store);445445-static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,446446- manager_default_color_show, manager_default_color_store);447447-static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR,448448- manager_trans_key_type_show, manager_trans_key_type_store);449449-static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR,450450- manager_trans_key_value_show, manager_trans_key_value_store);451451-static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,452452- manager_trans_key_enabled_show,453453- manager_trans_key_enabled_store);454454-static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,455455- manager_alpha_blending_enabled_show,456456- manager_alpha_blending_enabled_store);457457-static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR,458458- manager_cpr_enable_show,459459- manager_cpr_enable_store);460460-static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR,461461- manager_cpr_coef_show,462462- manager_cpr_coef_store);463463-464464-465465-static struct attribute *manager_sysfs_attrs[] = {466466- &manager_attr_name.attr,467467- &manager_attr_display.attr,468468- &manager_attr_default_color.attr,469469- &manager_attr_trans_key_type.attr,470470- &manager_attr_trans_key_value.attr,471471- &manager_attr_trans_key_enabled.attr,472472- &manager_attr_alpha_blending_enabled.attr,473473- &manager_attr_cpr_enable.attr,474474- &manager_attr_cpr_coef.attr,475475- NULL476476-};477477-478478-static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,479479- char *buf)480480-{481481- struct omap_overlay_manager *manager;482482- struct manager_attribute *manager_attr;483483-484484- manager = container_of(kobj, struct omap_overlay_manager, kobj);485485- manager_attr = container_of(attr, struct manager_attribute, attr);486486-487487- if (!manager_attr->show)488488- return -ENOENT;489489-490490- return manager_attr->show(manager, buf);491491-}492492-493493-static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,494494- const char *buf, size_t size)495495-{496496- struct omap_overlay_manager *manager;497497- struct manager_attribute *manager_attr;498498-499499- manager = container_of(kobj, struct omap_overlay_manager, kobj);500500- manager_attr = container_of(attr, struct manager_attribute, attr);501501-502502- if (!manager_attr->store)503503- return -ENOENT;504504-505505- return manager_attr->store(manager, buf, size);506506-}507507-508508-static const struct sysfs_ops manager_sysfs_ops = {509509- .show = manager_attr_show,510510- .store = manager_attr_store,511511-};512512-513513-static struct kobj_type manager_ktype = {514514- .sysfs_ops = &manager_sysfs_ops,515515- .default_attrs = manager_sysfs_attrs,516516-};517517-518518-int dss_manager_kobj_init(struct omap_overlay_manager *mgr,519519- struct platform_device *pdev)520520-{521521- return kobject_init_and_add(&mgr->kobj, &manager_ktype,522522- &pdev->dev.kobj, "manager%d", mgr->id);523523-}524524-525525-void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr)526526-{527527- kobject_del(&mgr->kobj);528528- kobject_put(&mgr->kobj);529529-530530- memset(&mgr->kobj, 0, sizeof(mgr->kobj));531531-}
-263
drivers/gpu/drm/omapdrm/dss/manager.c
···11-/*22- * linux/drivers/video/omap2/dss/manager.c33- *44- * Copyright (C) 2009 Nokia Corporation55- * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>66- *77- * Some code and ideas taken from drivers/video/omap/ driver88- * by Imre Deak.99- *1010- * This program is free software; you can redistribute it and/or modify it1111- * under the terms of the GNU General Public License version 2 as published by1212- * the Free Software Foundation.1313- *1414- * This program is distributed in the hope that it will be useful, but WITHOUT1515- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1616- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1717- * more details.1818- *1919- * You should have received a copy of the GNU General Public License along with2020- * this program. If not, see <http://www.gnu.org/licenses/>.2121- */2222-2323-#define DSS_SUBSYS_NAME "MANAGER"2424-2525-#include <linux/kernel.h>2626-#include <linux/slab.h>2727-#include <linux/module.h>2828-#include <linux/platform_device.h>2929-#include <linux/jiffies.h>3030-3131-#include <video/omapdss.h>3232-3333-#include "dss.h"3434-#include "dss_features.h"3535-3636-static int num_managers;3737-static struct omap_overlay_manager *managers;3838-3939-int dss_init_overlay_managers(void)4040-{4141- int i;4242-4343- num_managers = dss_feat_get_num_mgrs();4444-4545- managers = kzalloc(sizeof(struct omap_overlay_manager) * num_managers,4646- GFP_KERNEL);4747-4848- BUG_ON(managers == NULL);4949-5050- for (i = 0; i < num_managers; ++i) {5151- struct omap_overlay_manager *mgr = &managers[i];5252-5353- switch (i) {5454- case 0:5555- mgr->name = "lcd";5656- mgr->id = OMAP_DSS_CHANNEL_LCD;5757- break;5858- case 1:5959- mgr->name = "tv";6060- mgr->id = OMAP_DSS_CHANNEL_DIGIT;6161- break;6262- case 2:6363- mgr->name = "lcd2";6464- mgr->id = OMAP_DSS_CHANNEL_LCD2;6565- break;6666- case 3:6767- mgr->name = "lcd3";6868- mgr->id = OMAP_DSS_CHANNEL_LCD3;6969- break;7070- }7171-7272- mgr->caps = 0;7373- mgr->supported_displays =7474- dss_feat_get_supported_displays(mgr->id);7575- mgr->supported_outputs =7676- dss_feat_get_supported_outputs(mgr->id);7777-7878- INIT_LIST_HEAD(&mgr->overlays);7979- }8080-8181- return 0;8282-}8383-8484-int dss_init_overlay_managers_sysfs(struct platform_device *pdev)8585-{8686- int i, r;8787-8888- for (i = 0; i < num_managers; ++i) {8989- struct omap_overlay_manager *mgr = &managers[i];9090-9191- r = dss_manager_kobj_init(mgr, pdev);9292- if (r)9393- DSSERR("failed to create sysfs file\n");9494- }9595-9696- return 0;9797-}9898-9999-void dss_uninit_overlay_managers(void)100100-{101101- kfree(managers);102102- managers = NULL;103103- num_managers = 0;104104-}105105-106106-void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev)107107-{108108- int i;109109-110110- for (i = 0; i < num_managers; ++i) {111111- struct omap_overlay_manager *mgr = &managers[i];112112-113113- dss_manager_kobj_uninit(mgr);114114- }115115-}116116-117117-int omap_dss_get_num_overlay_managers(void)118118-{119119- return num_managers;120120-}121121-EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);122122-123123-struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)124124-{125125- if (num >= num_managers)126126- return NULL;127127-128128- return &managers[num];129129-}130130-EXPORT_SYMBOL(omap_dss_get_overlay_manager);131131-132132-int dss_mgr_simple_check(struct omap_overlay_manager *mgr,133133- const struct omap_overlay_manager_info *info)134134-{135135- if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) {136136- /*137137- * OMAP3 supports only graphics source transparency color key138138- * and alpha blending simultaneously. See TRM 15.4.2.4.2.2139139- * Alpha Mode.140140- */141141- if (info->partial_alpha_enabled && info->trans_enabled142142- && info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) {143143- DSSERR("check_manager: illegal transparency key\n");144144- return -EINVAL;145145- }146146- }147147-148148- return 0;149149-}150150-151151-static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr,152152- struct omap_overlay_info **overlay_infos)153153-{154154- struct omap_overlay *ovl1, *ovl2;155155- struct omap_overlay_info *info1, *info2;156156-157157- list_for_each_entry(ovl1, &mgr->overlays, list) {158158- info1 = overlay_infos[ovl1->id];159159-160160- if (info1 == NULL)161161- continue;162162-163163- list_for_each_entry(ovl2, &mgr->overlays, list) {164164- if (ovl1 == ovl2)165165- continue;166166-167167- info2 = overlay_infos[ovl2->id];168168-169169- if (info2 == NULL)170170- continue;171171-172172- if (info1->zorder == info2->zorder) {173173- DSSERR("overlays %d and %d have the same "174174- "zorder %d\n",175175- ovl1->id, ovl2->id, info1->zorder);176176- return -EINVAL;177177- }178178- }179179- }180180-181181- return 0;182182-}183183-184184-int dss_mgr_check_timings(struct omap_overlay_manager *mgr,185185- const struct omap_video_timings *timings)186186-{187187- if (!dispc_mgr_timings_ok(mgr->id, timings)) {188188- DSSERR("check_manager: invalid timings\n");189189- return -EINVAL;190190- }191191-192192- return 0;193193-}194194-195195-static int dss_mgr_check_lcd_config(struct omap_overlay_manager *mgr,196196- const struct dss_lcd_mgr_config *config)197197-{198198- struct dispc_clock_info cinfo = config->clock_info;199199- int dl = config->video_port_width;200200- bool stallmode = config->stallmode;201201- bool fifohandcheck = config->fifohandcheck;202202-203203- if (cinfo.lck_div < 1 || cinfo.lck_div > 255)204204- return -EINVAL;205205-206206- if (cinfo.pck_div < 1 || cinfo.pck_div > 255)207207- return -EINVAL;208208-209209- if (dl != 12 && dl != 16 && dl != 18 && dl != 24)210210- return -EINVAL;211211-212212- /* fifohandcheck should be used only with stallmode */213213- if (!stallmode && fifohandcheck)214214- return -EINVAL;215215-216216- /*217217- * io pad mode can be only checked by using dssdev connected to the218218- * manager. Ignore checking these for now, add checks when manager219219- * is capable of holding information related to the connected interface220220- */221221-222222- return 0;223223-}224224-225225-int dss_mgr_check(struct omap_overlay_manager *mgr,226226- struct omap_overlay_manager_info *info,227227- const struct omap_video_timings *mgr_timings,228228- const struct dss_lcd_mgr_config *lcd_config,229229- struct omap_overlay_info **overlay_infos)230230-{231231- struct omap_overlay *ovl;232232- int r;233233-234234- if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) {235235- r = dss_mgr_check_zorder(mgr, overlay_infos);236236- if (r)237237- return r;238238- }239239-240240- r = dss_mgr_check_timings(mgr, mgr_timings);241241- if (r)242242- return r;243243-244244- r = dss_mgr_check_lcd_config(mgr, lcd_config);245245- if (r)246246- return r;247247-248248- list_for_each_entry(ovl, &mgr->overlays, list) {249249- struct omap_overlay_info *oi;250250- int r;251251-252252- oi = overlay_infos[ovl->id];253253-254254- if (oi == NULL)255255- continue;256256-257257- r = dss_ovl_check(ovl, oi, mgr_timings);258258- if (r)259259- return r;260260- }261261-262262- return 0;263263-}
-456
drivers/gpu/drm/omapdrm/dss/overlay-sysfs.c
···11-/*22- * Copyright (C) 2009 Nokia Corporation33- * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>44- *55- * Some code and ideas taken from drivers/video/omap/ driver66- * by Imre Deak.77- *88- * This program is free software; you can redistribute it and/or modify it99- * under the terms of the GNU General Public License version 2 as published by1010- * the Free Software Foundation.1111- *1212- * This program is distributed in the hope that it will be useful, but WITHOUT1313- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1414- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1515- * more details.1616- *1717- * You should have received a copy of the GNU General Public License along with1818- * this program. If not, see <http://www.gnu.org/licenses/>.1919- */2020-2121-#define DSS_SUBSYS_NAME "OVERLAY"2222-2323-#include <linux/module.h>2424-#include <linux/err.h>2525-#include <linux/sysfs.h>2626-#include <linux/kobject.h>2727-#include <linux/platform_device.h>2828-2929-#include <video/omapdss.h>3030-3131-#include "dss.h"3232-#include "dss_features.h"3333-3434-static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)3535-{3636- return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name);3737-}3838-3939-static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)4040-{4141- return snprintf(buf, PAGE_SIZE, "%s\n",4242- ovl->manager ? ovl->manager->name : "<none>");4343-}4444-4545-static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,4646- size_t size)4747-{4848- int i, r;4949- struct omap_overlay_manager *mgr = NULL;5050- struct omap_overlay_manager *old_mgr;5151- int len = size;5252-5353- if (buf[size-1] == '\n')5454- --len;5555-5656- if (len > 0) {5757- for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {5858- mgr = omap_dss_get_overlay_manager(i);5959-6060- if (sysfs_streq(buf, mgr->name))6161- break;6262-6363- mgr = NULL;6464- }6565- }6666-6767- if (len > 0 && mgr == NULL)6868- return -EINVAL;6969-7070- if (mgr)7171- DSSDBG("manager %s found\n", mgr->name);7272-7373- if (mgr == ovl->manager)7474- return size;7575-7676- old_mgr = ovl->manager;7777-7878- r = dispc_runtime_get();7979- if (r)8080- return r;8181-8282- /* detach old manager */8383- if (old_mgr) {8484- r = ovl->unset_manager(ovl);8585- if (r) {8686- DSSERR("detach failed\n");8787- goto err;8888- }8989-9090- r = old_mgr->apply(old_mgr);9191- if (r)9292- goto err;9393- }9494-9595- if (mgr) {9696- r = ovl->set_manager(ovl, mgr);9797- if (r) {9898- DSSERR("Failed to attach overlay\n");9999- goto err;100100- }101101-102102- r = mgr->apply(mgr);103103- if (r)104104- goto err;105105- }106106-107107- dispc_runtime_put();108108-109109- return size;110110-111111-err:112112- dispc_runtime_put();113113- return r;114114-}115115-116116-static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)117117-{118118- struct omap_overlay_info info;119119-120120- ovl->get_overlay_info(ovl, &info);121121-122122- return snprintf(buf, PAGE_SIZE, "%d,%d\n",123123- info.width, info.height);124124-}125125-126126-static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)127127-{128128- struct omap_overlay_info info;129129-130130- ovl->get_overlay_info(ovl, &info);131131-132132- return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width);133133-}134134-135135-static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)136136-{137137- struct omap_overlay_info info;138138-139139- ovl->get_overlay_info(ovl, &info);140140-141141- return snprintf(buf, PAGE_SIZE, "%d,%d\n",142142- info.pos_x, info.pos_y);143143-}144144-145145-static ssize_t overlay_position_store(struct omap_overlay *ovl,146146- const char *buf, size_t size)147147-{148148- int r;149149- char *last;150150- struct omap_overlay_info info;151151-152152- ovl->get_overlay_info(ovl, &info);153153-154154- info.pos_x = simple_strtoul(buf, &last, 10);155155- ++last;156156- if (last - buf >= size)157157- return -EINVAL;158158-159159- info.pos_y = simple_strtoul(last, &last, 10);160160-161161- r = ovl->set_overlay_info(ovl, &info);162162- if (r)163163- return r;164164-165165- if (ovl->manager) {166166- r = ovl->manager->apply(ovl->manager);167167- if (r)168168- return r;169169- }170170-171171- return size;172172-}173173-174174-static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)175175-{176176- struct omap_overlay_info info;177177-178178- ovl->get_overlay_info(ovl, &info);179179-180180- return snprintf(buf, PAGE_SIZE, "%d,%d\n",181181- info.out_width, info.out_height);182182-}183183-184184-static ssize_t overlay_output_size_store(struct omap_overlay *ovl,185185- const char *buf, size_t size)186186-{187187- int r;188188- char *last;189189- struct omap_overlay_info info;190190-191191- ovl->get_overlay_info(ovl, &info);192192-193193- info.out_width = simple_strtoul(buf, &last, 10);194194- ++last;195195- if (last - buf >= size)196196- return -EINVAL;197197-198198- info.out_height = simple_strtoul(last, &last, 10);199199-200200- r = ovl->set_overlay_info(ovl, &info);201201- if (r)202202- return r;203203-204204- if (ovl->manager) {205205- r = ovl->manager->apply(ovl->manager);206206- if (r)207207- return r;208208- }209209-210210- return size;211211-}212212-213213-static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)214214-{215215- return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl));216216-}217217-218218-static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,219219- size_t size)220220-{221221- int r;222222- bool enable;223223-224224- r = strtobool(buf, &enable);225225- if (r)226226- return r;227227-228228- if (enable)229229- r = ovl->enable(ovl);230230- else231231- r = ovl->disable(ovl);232232-233233- if (r)234234- return r;235235-236236- return size;237237-}238238-239239-static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)240240-{241241- struct omap_overlay_info info;242242-243243- ovl->get_overlay_info(ovl, &info);244244-245245- return snprintf(buf, PAGE_SIZE, "%d\n",246246- info.global_alpha);247247-}248248-249249-static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,250250- const char *buf, size_t size)251251-{252252- int r;253253- u8 alpha;254254- struct omap_overlay_info info;255255-256256- if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)257257- return -ENODEV;258258-259259- r = kstrtou8(buf, 0, &alpha);260260- if (r)261261- return r;262262-263263- ovl->get_overlay_info(ovl, &info);264264-265265- info.global_alpha = alpha;266266-267267- r = ovl->set_overlay_info(ovl, &info);268268- if (r)269269- return r;270270-271271- if (ovl->manager) {272272- r = ovl->manager->apply(ovl->manager);273273- if (r)274274- return r;275275- }276276-277277- return size;278278-}279279-280280-static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl,281281- char *buf)282282-{283283- struct omap_overlay_info info;284284-285285- ovl->get_overlay_info(ovl, &info);286286-287287- return snprintf(buf, PAGE_SIZE, "%d\n",288288- info.pre_mult_alpha);289289-}290290-291291-static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,292292- const char *buf, size_t size)293293-{294294- int r;295295- u8 alpha;296296- struct omap_overlay_info info;297297-298298- if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)299299- return -ENODEV;300300-301301- r = kstrtou8(buf, 0, &alpha);302302- if (r)303303- return r;304304-305305- ovl->get_overlay_info(ovl, &info);306306-307307- info.pre_mult_alpha = alpha;308308-309309- r = ovl->set_overlay_info(ovl, &info);310310- if (r)311311- return r;312312-313313- if (ovl->manager) {314314- r = ovl->manager->apply(ovl->manager);315315- if (r)316316- return r;317317- }318318-319319- return size;320320-}321321-322322-static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf)323323-{324324- struct omap_overlay_info info;325325-326326- ovl->get_overlay_info(ovl, &info);327327-328328- return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder);329329-}330330-331331-static ssize_t overlay_zorder_store(struct omap_overlay *ovl,332332- const char *buf, size_t size)333333-{334334- int r;335335- u8 zorder;336336- struct omap_overlay_info info;337337-338338- if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)339339- return -ENODEV;340340-341341- r = kstrtou8(buf, 0, &zorder);342342- if (r)343343- return r;344344-345345- ovl->get_overlay_info(ovl, &info);346346-347347- info.zorder = zorder;348348-349349- r = ovl->set_overlay_info(ovl, &info);350350- if (r)351351- return r;352352-353353- if (ovl->manager) {354354- r = ovl->manager->apply(ovl->manager);355355- if (r)356356- return r;357357- }358358-359359- return size;360360-}361361-362362-struct overlay_attribute {363363- struct attribute attr;364364- ssize_t (*show)(struct omap_overlay *, char *);365365- ssize_t (*store)(struct omap_overlay *, const char *, size_t);366366-};367367-368368-#define OVERLAY_ATTR(_name, _mode, _show, _store) \369369- struct overlay_attribute overlay_attr_##_name = \370370- __ATTR(_name, _mode, _show, _store)371371-372372-static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL);373373-static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR,374374- overlay_manager_show, overlay_manager_store);375375-static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL);376376-static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL);377377-static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR,378378- overlay_position_show, overlay_position_store);379379-static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR,380380- overlay_output_size_show, overlay_output_size_store);381381-static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,382382- overlay_enabled_show, overlay_enabled_store);383383-static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,384384- overlay_global_alpha_show, overlay_global_alpha_store);385385-static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR,386386- overlay_pre_mult_alpha_show,387387- overlay_pre_mult_alpha_store);388388-static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR,389389- overlay_zorder_show, overlay_zorder_store);390390-391391-static struct attribute *overlay_sysfs_attrs[] = {392392- &overlay_attr_name.attr,393393- &overlay_attr_manager.attr,394394- &overlay_attr_input_size.attr,395395- &overlay_attr_screen_width.attr,396396- &overlay_attr_position.attr,397397- &overlay_attr_output_size.attr,398398- &overlay_attr_enabled.attr,399399- &overlay_attr_global_alpha.attr,400400- &overlay_attr_pre_mult_alpha.attr,401401- &overlay_attr_zorder.attr,402402- NULL403403-};404404-405405-static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,406406- char *buf)407407-{408408- struct omap_overlay *overlay;409409- struct overlay_attribute *overlay_attr;410410-411411- overlay = container_of(kobj, struct omap_overlay, kobj);412412- overlay_attr = container_of(attr, struct overlay_attribute, attr);413413-414414- if (!overlay_attr->show)415415- return -ENOENT;416416-417417- return overlay_attr->show(overlay, buf);418418-}419419-420420-static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,421421- const char *buf, size_t size)422422-{423423- struct omap_overlay *overlay;424424- struct overlay_attribute *overlay_attr;425425-426426- overlay = container_of(kobj, struct omap_overlay, kobj);427427- overlay_attr = container_of(attr, struct overlay_attribute, attr);428428-429429- if (!overlay_attr->store)430430- return -ENOENT;431431-432432- return overlay_attr->store(overlay, buf, size);433433-}434434-435435-static const struct sysfs_ops overlay_sysfs_ops = {436436- .show = overlay_attr_show,437437- .store = overlay_attr_store,438438-};439439-440440-static struct kobj_type overlay_ktype = {441441- .sysfs_ops = &overlay_sysfs_ops,442442- .default_attrs = overlay_sysfs_attrs,443443-};444444-445445-int dss_overlay_kobj_init(struct omap_overlay *ovl,446446- struct platform_device *pdev)447447-{448448- return kobject_init_and_add(&ovl->kobj, &overlay_ktype,449449- &pdev->dev.kobj, "overlay%d", ovl->id);450450-}451451-452452-void dss_overlay_kobj_uninit(struct omap_overlay *ovl)453453-{454454- kobject_del(&ovl->kobj);455455- kobject_put(&ovl->kobj);456456-}
-202
drivers/gpu/drm/omapdrm/dss/overlay.c
···11-/*22- * linux/drivers/video/omap2/dss/overlay.c33- *44- * Copyright (C) 2009 Nokia Corporation55- * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>66- *77- * Some code and ideas taken from drivers/video/omap/ driver88- * by Imre Deak.99- *1010- * This program is free software; you can redistribute it and/or modify it1111- * under the terms of the GNU General Public License version 2 as published by1212- * the Free Software Foundation.1313- *1414- * This program is distributed in the hope that it will be useful, but WITHOUT1515- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1616- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1717- * more details.1818- *1919- * You should have received a copy of the GNU General Public License along with2020- * this program. If not, see <http://www.gnu.org/licenses/>.2121- */2222-2323-#define DSS_SUBSYS_NAME "OVERLAY"2424-2525-#include <linux/kernel.h>2626-#include <linux/module.h>2727-#include <linux/err.h>2828-#include <linux/sysfs.h>2929-#include <linux/platform_device.h>3030-#include <linux/delay.h>3131-#include <linux/slab.h>3232-3333-#include <video/omapdss.h>3434-3535-#include "dss.h"3636-#include "dss_features.h"3737-3838-static int num_overlays;3939-static struct omap_overlay *overlays;4040-4141-int omap_dss_get_num_overlays(void)4242-{4343- return num_overlays;4444-}4545-EXPORT_SYMBOL(omap_dss_get_num_overlays);4646-4747-struct omap_overlay *omap_dss_get_overlay(int num)4848-{4949- if (num >= num_overlays)5050- return NULL;5151-5252- return &overlays[num];5353-}5454-EXPORT_SYMBOL(omap_dss_get_overlay);5555-5656-void dss_init_overlays(struct platform_device *pdev)5757-{5858- int i, r;5959-6060- num_overlays = dss_feat_get_num_ovls();6161-6262- overlays = kzalloc(sizeof(struct omap_overlay) * num_overlays,6363- GFP_KERNEL);6464-6565- BUG_ON(overlays == NULL);6666-6767- for (i = 0; i < num_overlays; ++i) {6868- struct omap_overlay *ovl = &overlays[i];6969-7070- switch (i) {7171- case 0:7272- ovl->name = "gfx";7373- ovl->id = OMAP_DSS_GFX;7474- break;7575- case 1:7676- ovl->name = "vid1";7777- ovl->id = OMAP_DSS_VIDEO1;7878- break;7979- case 2:8080- ovl->name = "vid2";8181- ovl->id = OMAP_DSS_VIDEO2;8282- break;8383- case 3:8484- ovl->name = "vid3";8585- ovl->id = OMAP_DSS_VIDEO3;8686- break;8787- }8888-8989- ovl->caps = dss_feat_get_overlay_caps(ovl->id);9090- ovl->supported_modes =9191- dss_feat_get_supported_color_modes(ovl->id);9292-9393- r = dss_overlay_kobj_init(ovl, pdev);9494- if (r)9595- DSSERR("failed to create sysfs file\n");9696- }9797-}9898-9999-void dss_uninit_overlays(struct platform_device *pdev)100100-{101101- int i;102102-103103- for (i = 0; i < num_overlays; ++i) {104104- struct omap_overlay *ovl = &overlays[i];105105- dss_overlay_kobj_uninit(ovl);106106- }107107-108108- kfree(overlays);109109- overlays = NULL;110110- num_overlays = 0;111111-}112112-113113-int dss_ovl_simple_check(struct omap_overlay *ovl,114114- const struct omap_overlay_info *info)115115-{116116- if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {117117- if (info->out_width != 0 && info->width != info->out_width) {118118- DSSERR("check_overlay: overlay %d doesn't support "119119- "scaling\n", ovl->id);120120- return -EINVAL;121121- }122122-123123- if (info->out_height != 0 && info->height != info->out_height) {124124- DSSERR("check_overlay: overlay %d doesn't support "125125- "scaling\n", ovl->id);126126- return -EINVAL;127127- }128128- }129129-130130- if ((ovl->supported_modes & info->color_mode) == 0) {131131- DSSERR("check_overlay: overlay %d doesn't support mode %d\n",132132- ovl->id, info->color_mode);133133- return -EINVAL;134134- }135135-136136- if (info->zorder >= omap_dss_get_num_overlays()) {137137- DSSERR("check_overlay: zorder %d too high\n", info->zorder);138138- return -EINVAL;139139- }140140-141141- if (dss_feat_rotation_type_supported(info->rotation_type) == 0) {142142- DSSERR("check_overlay: rotation type %d not supported\n",143143- info->rotation_type);144144- return -EINVAL;145145- }146146-147147- return 0;148148-}149149-150150-int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info,151151- const struct omap_video_timings *mgr_timings)152152-{153153- u16 outw, outh;154154- u16 dw, dh;155155-156156- dw = mgr_timings->x_res;157157- dh = mgr_timings->y_res;158158-159159- if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {160160- outw = info->width;161161- outh = info->height;162162- } else {163163- if (info->out_width == 0)164164- outw = info->width;165165- else166166- outw = info->out_width;167167-168168- if (info->out_height == 0)169169- outh = info->height;170170- else171171- outh = info->out_height;172172- }173173-174174- if (dw < info->pos_x + outw) {175175- DSSERR("overlay %d horizontally not inside the display area "176176- "(%d + %d >= %d)\n",177177- ovl->id, info->pos_x, outw, dw);178178- return -EINVAL;179179- }180180-181181- if (dh < info->pos_y + outh) {182182- DSSERR("overlay %d vertically not inside the display area "183183- "(%d + %d >= %d)\n",184184- ovl->id, info->pos_y, outh, dh);185185- return -EINVAL;186186- }187187-188188- return 0;189189-}190190-191191-/*192192- * Checks if replication logic should be used. Only use when overlay is in193193- * RGB12U or RGB16 mode, and video port width interface is 18bpp or 24bpp194194- */195195-bool dss_ovl_use_replication(struct dss_lcd_mgr_config config,196196- enum omap_color_mode mode)197197-{198198- if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16)199199- return false;200200-201201- return config.video_port_width > 16;202202-}