18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2012 Texas Instruments
48c2ecf20Sopenharmony_ci * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#define DSS_SUBSYS_NAME "APPLY"
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/slab.h>
128c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
138c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
148c2ecf20Sopenharmony_ci#include <linux/delay.h>
158c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
168c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <video/omapfb_dss.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "dss.h"
218c2ecf20Sopenharmony_ci#include "dss_features.h"
228c2ecf20Sopenharmony_ci#include "dispc-compat.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define DISPC_IRQ_MASK_ERROR            (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
258c2ecf20Sopenharmony_ci					 DISPC_IRQ_OCP_ERR | \
268c2ecf20Sopenharmony_ci					 DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
278c2ecf20Sopenharmony_ci					 DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
288c2ecf20Sopenharmony_ci					 DISPC_IRQ_SYNC_LOST | \
298c2ecf20Sopenharmony_ci					 DISPC_IRQ_SYNC_LOST_DIGIT)
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define DISPC_MAX_NR_ISRS		8
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistruct omap_dispc_isr_data {
348c2ecf20Sopenharmony_ci	omap_dispc_isr_t	isr;
358c2ecf20Sopenharmony_ci	void			*arg;
368c2ecf20Sopenharmony_ci	u32			mask;
378c2ecf20Sopenharmony_ci};
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistruct dispc_irq_stats {
408c2ecf20Sopenharmony_ci	unsigned long last_reset;
418c2ecf20Sopenharmony_ci	unsigned irq_count;
428c2ecf20Sopenharmony_ci	unsigned irqs[32];
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic struct {
468c2ecf20Sopenharmony_ci	spinlock_t irq_lock;
478c2ecf20Sopenharmony_ci	u32 irq_error_mask;
488c2ecf20Sopenharmony_ci	struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
498c2ecf20Sopenharmony_ci	u32 error_irqs;
508c2ecf20Sopenharmony_ci	struct work_struct error_work;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
538c2ecf20Sopenharmony_ci	spinlock_t irq_stats_lock;
548c2ecf20Sopenharmony_ci	struct dispc_irq_stats irq_stats;
558c2ecf20Sopenharmony_ci#endif
568c2ecf20Sopenharmony_ci} dispc_compat;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
608c2ecf20Sopenharmony_cistatic void dispc_dump_irqs(struct seq_file *s)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	unsigned long flags;
638c2ecf20Sopenharmony_ci	struct dispc_irq_stats stats;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dispc_compat.irq_stats_lock, flags);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	stats = dispc_compat.irq_stats;
688c2ecf20Sopenharmony_ci	memset(&dispc_compat.irq_stats, 0, sizeof(dispc_compat.irq_stats));
698c2ecf20Sopenharmony_ci	dispc_compat.irq_stats.last_reset = jiffies;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dispc_compat.irq_stats_lock, flags);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	seq_printf(s, "period %u ms\n",
748c2ecf20Sopenharmony_ci			jiffies_to_msecs(jiffies - stats.last_reset));
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	seq_printf(s, "irqs %d\n", stats.irq_count);
778c2ecf20Sopenharmony_ci#define PIS(x) \
788c2ecf20Sopenharmony_ci	seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	PIS(FRAMEDONE);
818c2ecf20Sopenharmony_ci	PIS(VSYNC);
828c2ecf20Sopenharmony_ci	PIS(EVSYNC_EVEN);
838c2ecf20Sopenharmony_ci	PIS(EVSYNC_ODD);
848c2ecf20Sopenharmony_ci	PIS(ACBIAS_COUNT_STAT);
858c2ecf20Sopenharmony_ci	PIS(PROG_LINE_NUM);
868c2ecf20Sopenharmony_ci	PIS(GFX_FIFO_UNDERFLOW);
878c2ecf20Sopenharmony_ci	PIS(GFX_END_WIN);
888c2ecf20Sopenharmony_ci	PIS(PAL_GAMMA_MASK);
898c2ecf20Sopenharmony_ci	PIS(OCP_ERR);
908c2ecf20Sopenharmony_ci	PIS(VID1_FIFO_UNDERFLOW);
918c2ecf20Sopenharmony_ci	PIS(VID1_END_WIN);
928c2ecf20Sopenharmony_ci	PIS(VID2_FIFO_UNDERFLOW);
938c2ecf20Sopenharmony_ci	PIS(VID2_END_WIN);
948c2ecf20Sopenharmony_ci	if (dss_feat_get_num_ovls() > 3) {
958c2ecf20Sopenharmony_ci		PIS(VID3_FIFO_UNDERFLOW);
968c2ecf20Sopenharmony_ci		PIS(VID3_END_WIN);
978c2ecf20Sopenharmony_ci	}
988c2ecf20Sopenharmony_ci	PIS(SYNC_LOST);
998c2ecf20Sopenharmony_ci	PIS(SYNC_LOST_DIGIT);
1008c2ecf20Sopenharmony_ci	PIS(WAKEUP);
1018c2ecf20Sopenharmony_ci	if (dss_has_feature(FEAT_MGR_LCD2)) {
1028c2ecf20Sopenharmony_ci		PIS(FRAMEDONE2);
1038c2ecf20Sopenharmony_ci		PIS(VSYNC2);
1048c2ecf20Sopenharmony_ci		PIS(ACBIAS_COUNT_STAT2);
1058c2ecf20Sopenharmony_ci		PIS(SYNC_LOST2);
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci	if (dss_has_feature(FEAT_MGR_LCD3)) {
1088c2ecf20Sopenharmony_ci		PIS(FRAMEDONE3);
1098c2ecf20Sopenharmony_ci		PIS(VSYNC3);
1108c2ecf20Sopenharmony_ci		PIS(ACBIAS_COUNT_STAT3);
1118c2ecf20Sopenharmony_ci		PIS(SYNC_LOST3);
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci#undef PIS
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci#endif
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci/* dispc.irq_lock has to be locked by the caller */
1188c2ecf20Sopenharmony_cistatic void _omap_dispc_set_irqs(void)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	u32 mask;
1218c2ecf20Sopenharmony_ci	int i;
1228c2ecf20Sopenharmony_ci	struct omap_dispc_isr_data *isr_data;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	mask = dispc_compat.irq_error_mask;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
1278c2ecf20Sopenharmony_ci		isr_data = &dispc_compat.registered_isr[i];
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci		if (isr_data->isr == NULL)
1308c2ecf20Sopenharmony_ci			continue;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci		mask |= isr_data->mask;
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	dispc_write_irqenable(mask);
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ciint omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	int i;
1418c2ecf20Sopenharmony_ci	int ret;
1428c2ecf20Sopenharmony_ci	unsigned long flags;
1438c2ecf20Sopenharmony_ci	struct omap_dispc_isr_data *isr_data;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	if (isr == NULL)
1468c2ecf20Sopenharmony_ci		return -EINVAL;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dispc_compat.irq_lock, flags);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	/* check for duplicate entry */
1518c2ecf20Sopenharmony_ci	for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
1528c2ecf20Sopenharmony_ci		isr_data = &dispc_compat.registered_isr[i];
1538c2ecf20Sopenharmony_ci		if (isr_data->isr == isr && isr_data->arg == arg &&
1548c2ecf20Sopenharmony_ci				isr_data->mask == mask) {
1558c2ecf20Sopenharmony_ci			ret = -EINVAL;
1568c2ecf20Sopenharmony_ci			goto err;
1578c2ecf20Sopenharmony_ci		}
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	isr_data = NULL;
1618c2ecf20Sopenharmony_ci	ret = -EBUSY;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
1648c2ecf20Sopenharmony_ci		isr_data = &dispc_compat.registered_isr[i];
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci		if (isr_data->isr != NULL)
1678c2ecf20Sopenharmony_ci			continue;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci		isr_data->isr = isr;
1708c2ecf20Sopenharmony_ci		isr_data->arg = arg;
1718c2ecf20Sopenharmony_ci		isr_data->mask = mask;
1728c2ecf20Sopenharmony_ci		ret = 0;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci		break;
1758c2ecf20Sopenharmony_ci	}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	if (ret)
1788c2ecf20Sopenharmony_ci		goto err;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	_omap_dispc_set_irqs();
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	return 0;
1858c2ecf20Sopenharmony_cierr:
1868c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	return ret;
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omap_dispc_register_isr);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ciint omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
1938c2ecf20Sopenharmony_ci{
1948c2ecf20Sopenharmony_ci	int i;
1958c2ecf20Sopenharmony_ci	unsigned long flags;
1968c2ecf20Sopenharmony_ci	int ret = -EINVAL;
1978c2ecf20Sopenharmony_ci	struct omap_dispc_isr_data *isr_data;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dispc_compat.irq_lock, flags);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2028c2ecf20Sopenharmony_ci		isr_data = &dispc_compat.registered_isr[i];
2038c2ecf20Sopenharmony_ci		if (isr_data->isr != isr || isr_data->arg != arg ||
2048c2ecf20Sopenharmony_ci				isr_data->mask != mask)
2058c2ecf20Sopenharmony_ci			continue;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci		/* found the correct isr */
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci		isr_data->isr = NULL;
2108c2ecf20Sopenharmony_ci		isr_data->arg = NULL;
2118c2ecf20Sopenharmony_ci		isr_data->mask = 0;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci		ret = 0;
2148c2ecf20Sopenharmony_ci		break;
2158c2ecf20Sopenharmony_ci	}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	if (ret == 0)
2188c2ecf20Sopenharmony_ci		_omap_dispc_set_irqs();
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	return ret;
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omap_dispc_unregister_isr);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cistatic void print_irq_status(u32 status)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	if ((status & dispc_compat.irq_error_mask) == 0)
2298c2ecf20Sopenharmony_ci		return;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci#define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : ""
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n",
2348c2ecf20Sopenharmony_ci		status,
2358c2ecf20Sopenharmony_ci		PIS(OCP_ERR),
2368c2ecf20Sopenharmony_ci		PIS(GFX_FIFO_UNDERFLOW),
2378c2ecf20Sopenharmony_ci		PIS(VID1_FIFO_UNDERFLOW),
2388c2ecf20Sopenharmony_ci		PIS(VID2_FIFO_UNDERFLOW),
2398c2ecf20Sopenharmony_ci		dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW) : "",
2408c2ecf20Sopenharmony_ci		PIS(SYNC_LOST),
2418c2ecf20Sopenharmony_ci		PIS(SYNC_LOST_DIGIT),
2428c2ecf20Sopenharmony_ci		dss_has_feature(FEAT_MGR_LCD2) ? PIS(SYNC_LOST2) : "",
2438c2ecf20Sopenharmony_ci		dss_has_feature(FEAT_MGR_LCD3) ? PIS(SYNC_LOST3) : "");
2448c2ecf20Sopenharmony_ci#undef PIS
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci/* Called from dss.c. Note that we don't touch clocks here,
2488c2ecf20Sopenharmony_ci * but we presume they are on because we got an IRQ. However,
2498c2ecf20Sopenharmony_ci * an irq handler may turn the clocks off, so we may not have
2508c2ecf20Sopenharmony_ci * clock later in the function. */
2518c2ecf20Sopenharmony_cistatic irqreturn_t omap_dispc_irq_handler(int irq, void *arg)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	int i;
2548c2ecf20Sopenharmony_ci	u32 irqstatus, irqenable;
2558c2ecf20Sopenharmony_ci	u32 handledirqs = 0;
2568c2ecf20Sopenharmony_ci	u32 unhandled_errors;
2578c2ecf20Sopenharmony_ci	struct omap_dispc_isr_data *isr_data;
2588c2ecf20Sopenharmony_ci	struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	spin_lock(&dispc_compat.irq_lock);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	irqstatus = dispc_read_irqstatus();
2638c2ecf20Sopenharmony_ci	irqenable = dispc_read_irqenable();
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	/* IRQ is not for us */
2668c2ecf20Sopenharmony_ci	if (!(irqstatus & irqenable)) {
2678c2ecf20Sopenharmony_ci		spin_unlock(&dispc_compat.irq_lock);
2688c2ecf20Sopenharmony_ci		return IRQ_NONE;
2698c2ecf20Sopenharmony_ci	}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
2728c2ecf20Sopenharmony_ci	spin_lock(&dispc_compat.irq_stats_lock);
2738c2ecf20Sopenharmony_ci	dispc_compat.irq_stats.irq_count++;
2748c2ecf20Sopenharmony_ci	dss_collect_irq_stats(irqstatus, dispc_compat.irq_stats.irqs);
2758c2ecf20Sopenharmony_ci	spin_unlock(&dispc_compat.irq_stats_lock);
2768c2ecf20Sopenharmony_ci#endif
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	print_irq_status(irqstatus);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	/* Ack the interrupt. Do it here before clocks are possibly turned
2818c2ecf20Sopenharmony_ci	 * off */
2828c2ecf20Sopenharmony_ci	dispc_clear_irqstatus(irqstatus);
2838c2ecf20Sopenharmony_ci	/* flush posted write */
2848c2ecf20Sopenharmony_ci	dispc_read_irqstatus();
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	/* make a copy and unlock, so that isrs can unregister
2878c2ecf20Sopenharmony_ci	 * themselves */
2888c2ecf20Sopenharmony_ci	memcpy(registered_isr, dispc_compat.registered_isr,
2898c2ecf20Sopenharmony_ci			sizeof(registered_isr));
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	spin_unlock(&dispc_compat.irq_lock);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2948c2ecf20Sopenharmony_ci		isr_data = &registered_isr[i];
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci		if (!isr_data->isr)
2978c2ecf20Sopenharmony_ci			continue;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci		if (isr_data->mask & irqstatus) {
3008c2ecf20Sopenharmony_ci			isr_data->isr(isr_data->arg, irqstatus);
3018c2ecf20Sopenharmony_ci			handledirqs |= isr_data->mask;
3028c2ecf20Sopenharmony_ci		}
3038c2ecf20Sopenharmony_ci	}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	spin_lock(&dispc_compat.irq_lock);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	unhandled_errors = irqstatus & ~handledirqs & dispc_compat.irq_error_mask;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	if (unhandled_errors) {
3108c2ecf20Sopenharmony_ci		dispc_compat.error_irqs |= unhandled_errors;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci		dispc_compat.irq_error_mask &= ~unhandled_errors;
3138c2ecf20Sopenharmony_ci		_omap_dispc_set_irqs();
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci		schedule_work(&dispc_compat.error_work);
3168c2ecf20Sopenharmony_ci	}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	spin_unlock(&dispc_compat.irq_lock);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_cistatic void dispc_error_worker(struct work_struct *work)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	int i;
3268c2ecf20Sopenharmony_ci	u32 errors;
3278c2ecf20Sopenharmony_ci	unsigned long flags;
3288c2ecf20Sopenharmony_ci	static const unsigned fifo_underflow_bits[] = {
3298c2ecf20Sopenharmony_ci		DISPC_IRQ_GFX_FIFO_UNDERFLOW,
3308c2ecf20Sopenharmony_ci		DISPC_IRQ_VID1_FIFO_UNDERFLOW,
3318c2ecf20Sopenharmony_ci		DISPC_IRQ_VID2_FIFO_UNDERFLOW,
3328c2ecf20Sopenharmony_ci		DISPC_IRQ_VID3_FIFO_UNDERFLOW,
3338c2ecf20Sopenharmony_ci	};
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dispc_compat.irq_lock, flags);
3368c2ecf20Sopenharmony_ci	errors = dispc_compat.error_irqs;
3378c2ecf20Sopenharmony_ci	dispc_compat.error_irqs = 0;
3388c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	dispc_runtime_get();
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
3438c2ecf20Sopenharmony_ci		struct omap_overlay *ovl;
3448c2ecf20Sopenharmony_ci		unsigned bit;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci		ovl = omap_dss_get_overlay(i);
3478c2ecf20Sopenharmony_ci		bit = fifo_underflow_bits[i];
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci		if (bit & errors) {
3508c2ecf20Sopenharmony_ci			DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",
3518c2ecf20Sopenharmony_ci					ovl->name);
3528c2ecf20Sopenharmony_ci			ovl->disable(ovl);
3538c2ecf20Sopenharmony_ci			msleep(50);
3548c2ecf20Sopenharmony_ci		}
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
3588c2ecf20Sopenharmony_ci		struct omap_overlay_manager *mgr;
3598c2ecf20Sopenharmony_ci		unsigned bit;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci		mgr = omap_dss_get_overlay_manager(i);
3628c2ecf20Sopenharmony_ci		bit = dispc_mgr_get_sync_lost_irq(i);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci		if (bit & errors) {
3658c2ecf20Sopenharmony_ci			int j;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci			DSSERR("SYNC_LOST on channel %s, restarting the output "
3688c2ecf20Sopenharmony_ci					"with video overlays disabled\n",
3698c2ecf20Sopenharmony_ci					mgr->name);
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci			dss_mgr_disable(mgr);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci			for (j = 0; j < omap_dss_get_num_overlays(); ++j) {
3748c2ecf20Sopenharmony_ci				struct omap_overlay *ovl;
3758c2ecf20Sopenharmony_ci				ovl = omap_dss_get_overlay(j);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci				if (ovl->id != OMAP_DSS_GFX &&
3788c2ecf20Sopenharmony_ci						ovl->manager == mgr)
3798c2ecf20Sopenharmony_ci					ovl->disable(ovl);
3808c2ecf20Sopenharmony_ci			}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci			dss_mgr_enable(mgr);
3838c2ecf20Sopenharmony_ci		}
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	if (errors & DISPC_IRQ_OCP_ERR) {
3878c2ecf20Sopenharmony_ci		DSSERR("OCP_ERR\n");
3888c2ecf20Sopenharmony_ci		for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
3898c2ecf20Sopenharmony_ci			struct omap_overlay_manager *mgr;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci			mgr = omap_dss_get_overlay_manager(i);
3928c2ecf20Sopenharmony_ci			dss_mgr_disable(mgr);
3938c2ecf20Sopenharmony_ci		}
3948c2ecf20Sopenharmony_ci	}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dispc_compat.irq_lock, flags);
3978c2ecf20Sopenharmony_ci	dispc_compat.irq_error_mask |= errors;
3988c2ecf20Sopenharmony_ci	_omap_dispc_set_irqs();
3998c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	dispc_runtime_put();
4028c2ecf20Sopenharmony_ci}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ciint dss_dispc_initialize_irq(void)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	int r;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
4098c2ecf20Sopenharmony_ci	spin_lock_init(&dispc_compat.irq_stats_lock);
4108c2ecf20Sopenharmony_ci	dispc_compat.irq_stats.last_reset = jiffies;
4118c2ecf20Sopenharmony_ci	dss_debugfs_create_file("dispc_irq", dispc_dump_irqs);
4128c2ecf20Sopenharmony_ci#endif
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	spin_lock_init(&dispc_compat.irq_lock);
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	memset(dispc_compat.registered_isr, 0,
4178c2ecf20Sopenharmony_ci			sizeof(dispc_compat.registered_isr));
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	dispc_compat.irq_error_mask = DISPC_IRQ_MASK_ERROR;
4208c2ecf20Sopenharmony_ci	if (dss_has_feature(FEAT_MGR_LCD2))
4218c2ecf20Sopenharmony_ci		dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
4228c2ecf20Sopenharmony_ci	if (dss_has_feature(FEAT_MGR_LCD3))
4238c2ecf20Sopenharmony_ci		dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST3;
4248c2ecf20Sopenharmony_ci	if (dss_feat_get_num_ovls() > 3)
4258c2ecf20Sopenharmony_ci		dispc_compat.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	/*
4288c2ecf20Sopenharmony_ci	 * there's SYNC_LOST_DIGIT waiting after enabling the DSS,
4298c2ecf20Sopenharmony_ci	 * so clear it
4308c2ecf20Sopenharmony_ci	 */
4318c2ecf20Sopenharmony_ci	dispc_clear_irqstatus(dispc_read_irqstatus());
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	INIT_WORK(&dispc_compat.error_work, dispc_error_worker);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	_omap_dispc_set_irqs();
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	r = dispc_request_irq(omap_dispc_irq_handler, &dispc_compat);
4388c2ecf20Sopenharmony_ci	if (r) {
4398c2ecf20Sopenharmony_ci		DSSERR("dispc_request_irq failed\n");
4408c2ecf20Sopenharmony_ci		return r;
4418c2ecf20Sopenharmony_ci	}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	return 0;
4448c2ecf20Sopenharmony_ci}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_civoid dss_dispc_uninitialize_irq(void)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	dispc_free_irq(&dispc_compat);
4498c2ecf20Sopenharmony_ci}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_cistatic void dispc_mgr_disable_isr(void *data, u32 mask)
4528c2ecf20Sopenharmony_ci{
4538c2ecf20Sopenharmony_ci	struct completion *compl = data;
4548c2ecf20Sopenharmony_ci	complete(compl);
4558c2ecf20Sopenharmony_ci}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_cistatic void dispc_mgr_enable_lcd_out(enum omap_channel channel)
4588c2ecf20Sopenharmony_ci{
4598c2ecf20Sopenharmony_ci	dispc_mgr_enable(channel, true);
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_cistatic void dispc_mgr_disable_lcd_out(enum omap_channel channel)
4638c2ecf20Sopenharmony_ci{
4648c2ecf20Sopenharmony_ci	DECLARE_COMPLETION_ONSTACK(framedone_compl);
4658c2ecf20Sopenharmony_ci	int r;
4668c2ecf20Sopenharmony_ci	u32 irq;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	if (!dispc_mgr_is_enabled(channel))
4698c2ecf20Sopenharmony_ci		return;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	/*
4728c2ecf20Sopenharmony_ci	 * When we disable LCD output, we need to wait for FRAMEDONE to know
4738c2ecf20Sopenharmony_ci	 * that DISPC has finished with the LCD output.
4748c2ecf20Sopenharmony_ci	 */
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	irq = dispc_mgr_get_framedone_irq(channel);
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
4798c2ecf20Sopenharmony_ci			irq);
4808c2ecf20Sopenharmony_ci	if (r)
4818c2ecf20Sopenharmony_ci		DSSERR("failed to register FRAMEDONE isr\n");
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	dispc_mgr_enable(channel, false);
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	/* if we couldn't register for framedone, just sleep and exit */
4868c2ecf20Sopenharmony_ci	if (r) {
4878c2ecf20Sopenharmony_ci		msleep(100);
4888c2ecf20Sopenharmony_ci		return;
4898c2ecf20Sopenharmony_ci	}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	if (!wait_for_completion_timeout(&framedone_compl,
4928c2ecf20Sopenharmony_ci				msecs_to_jiffies(100)))
4938c2ecf20Sopenharmony_ci		DSSERR("timeout waiting for FRAME DONE\n");
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
4968c2ecf20Sopenharmony_ci			irq);
4978c2ecf20Sopenharmony_ci	if (r)
4988c2ecf20Sopenharmony_ci		DSSERR("failed to unregister FRAMEDONE isr\n");
4998c2ecf20Sopenharmony_ci}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_cistatic void dispc_digit_out_enable_isr(void *data, u32 mask)
5028c2ecf20Sopenharmony_ci{
5038c2ecf20Sopenharmony_ci	struct completion *compl = data;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	/* ignore any sync lost interrupts */
5068c2ecf20Sopenharmony_ci	if (mask & (DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD))
5078c2ecf20Sopenharmony_ci		complete(compl);
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cistatic void dispc_mgr_enable_digit_out(void)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	DECLARE_COMPLETION_ONSTACK(vsync_compl);
5138c2ecf20Sopenharmony_ci	int r;
5148c2ecf20Sopenharmony_ci	u32 irq_mask;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT))
5178c2ecf20Sopenharmony_ci		return;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	/*
5208c2ecf20Sopenharmony_ci	 * Digit output produces some sync lost interrupts during the first
5218c2ecf20Sopenharmony_ci	 * frame when enabling. Those need to be ignored, so we register for the
5228c2ecf20Sopenharmony_ci	 * sync lost irq to prevent the error handler from triggering.
5238c2ecf20Sopenharmony_ci	 */
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT) |
5268c2ecf20Sopenharmony_ci		dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	r = omap_dispc_register_isr(dispc_digit_out_enable_isr, &vsync_compl,
5298c2ecf20Sopenharmony_ci			irq_mask);
5308c2ecf20Sopenharmony_ci	if (r) {
5318c2ecf20Sopenharmony_ci		DSSERR("failed to register %x isr\n", irq_mask);
5328c2ecf20Sopenharmony_ci		return;
5338c2ecf20Sopenharmony_ci	}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, true);
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	/* wait for the first evsync */
5388c2ecf20Sopenharmony_ci	if (!wait_for_completion_timeout(&vsync_compl, msecs_to_jiffies(100)))
5398c2ecf20Sopenharmony_ci		DSSERR("timeout waiting for digit out to start\n");
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	r = omap_dispc_unregister_isr(dispc_digit_out_enable_isr, &vsync_compl,
5428c2ecf20Sopenharmony_ci			irq_mask);
5438c2ecf20Sopenharmony_ci	if (r)
5448c2ecf20Sopenharmony_ci		DSSERR("failed to unregister %x isr\n", irq_mask);
5458c2ecf20Sopenharmony_ci}
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_cistatic void dispc_mgr_disable_digit_out(void)
5488c2ecf20Sopenharmony_ci{
5498c2ecf20Sopenharmony_ci	DECLARE_COMPLETION_ONSTACK(framedone_compl);
5508c2ecf20Sopenharmony_ci	int r, i;
5518c2ecf20Sopenharmony_ci	u32 irq_mask;
5528c2ecf20Sopenharmony_ci	int num_irqs;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	if (!dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT))
5558c2ecf20Sopenharmony_ci		return;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	/*
5588c2ecf20Sopenharmony_ci	 * When we disable the digit output, we need to wait for FRAMEDONE to
5598c2ecf20Sopenharmony_ci	 * know that DISPC has finished with the output.
5608c2ecf20Sopenharmony_ci	 */
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	irq_mask = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT);
5638c2ecf20Sopenharmony_ci	num_irqs = 1;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	if (!irq_mask) {
5668c2ecf20Sopenharmony_ci		/*
5678c2ecf20Sopenharmony_ci		 * omap 2/3 don't have framedone irq for TV, so we need to use
5688c2ecf20Sopenharmony_ci		 * vsyncs for this.
5698c2ecf20Sopenharmony_ci		 */
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci		irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT);
5728c2ecf20Sopenharmony_ci		/*
5738c2ecf20Sopenharmony_ci		 * We need to wait for both even and odd vsyncs. Note that this
5748c2ecf20Sopenharmony_ci		 * is not totally reliable, as we could get a vsync interrupt
5758c2ecf20Sopenharmony_ci		 * before we disable the output, which leads to timeout in the
5768c2ecf20Sopenharmony_ci		 * wait_for_completion.
5778c2ecf20Sopenharmony_ci		 */
5788c2ecf20Sopenharmony_ci		num_irqs = 2;
5798c2ecf20Sopenharmony_ci	}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
5828c2ecf20Sopenharmony_ci			irq_mask);
5838c2ecf20Sopenharmony_ci	if (r)
5848c2ecf20Sopenharmony_ci		DSSERR("failed to register %x isr\n", irq_mask);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, false);
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	/* if we couldn't register the irq, just sleep and exit */
5898c2ecf20Sopenharmony_ci	if (r) {
5908c2ecf20Sopenharmony_ci		msleep(100);
5918c2ecf20Sopenharmony_ci		return;
5928c2ecf20Sopenharmony_ci	}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	for (i = 0; i < num_irqs; ++i) {
5958c2ecf20Sopenharmony_ci		if (!wait_for_completion_timeout(&framedone_compl,
5968c2ecf20Sopenharmony_ci					msecs_to_jiffies(100)))
5978c2ecf20Sopenharmony_ci			DSSERR("timeout waiting for digit out to stop\n");
5988c2ecf20Sopenharmony_ci	}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
6018c2ecf20Sopenharmony_ci			irq_mask);
6028c2ecf20Sopenharmony_ci	if (r)
6038c2ecf20Sopenharmony_ci		DSSERR("failed to unregister %x isr\n", irq_mask);
6048c2ecf20Sopenharmony_ci}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_civoid dispc_mgr_enable_sync(enum omap_channel channel)
6078c2ecf20Sopenharmony_ci{
6088c2ecf20Sopenharmony_ci	if (dss_mgr_is_lcd(channel))
6098c2ecf20Sopenharmony_ci		dispc_mgr_enable_lcd_out(channel);
6108c2ecf20Sopenharmony_ci	else if (channel == OMAP_DSS_CHANNEL_DIGIT)
6118c2ecf20Sopenharmony_ci		dispc_mgr_enable_digit_out();
6128c2ecf20Sopenharmony_ci	else
6138c2ecf20Sopenharmony_ci		WARN_ON(1);
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_civoid dispc_mgr_disable_sync(enum omap_channel channel)
6178c2ecf20Sopenharmony_ci{
6188c2ecf20Sopenharmony_ci	if (dss_mgr_is_lcd(channel))
6198c2ecf20Sopenharmony_ci		dispc_mgr_disable_lcd_out(channel);
6208c2ecf20Sopenharmony_ci	else if (channel == OMAP_DSS_CHANNEL_DIGIT)
6218c2ecf20Sopenharmony_ci		dispc_mgr_disable_digit_out();
6228c2ecf20Sopenharmony_ci	else
6238c2ecf20Sopenharmony_ci		WARN_ON(1);
6248c2ecf20Sopenharmony_ci}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_cistatic inline void dispc_irq_wait_handler(void *data, u32 mask)
6278c2ecf20Sopenharmony_ci{
6288c2ecf20Sopenharmony_ci	complete((struct completion *)data);
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ciint omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
6328c2ecf20Sopenharmony_ci		unsigned long timeout)
6338c2ecf20Sopenharmony_ci{
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	int r;
6368c2ecf20Sopenharmony_ci	long time_left;
6378c2ecf20Sopenharmony_ci	DECLARE_COMPLETION_ONSTACK(completion);
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
6408c2ecf20Sopenharmony_ci			irqmask);
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	if (r)
6438c2ecf20Sopenharmony_ci		return r;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	time_left = wait_for_completion_interruptible_timeout(&completion,
6468c2ecf20Sopenharmony_ci			timeout);
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	if (time_left == 0)
6518c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	if (time_left == -ERESTARTSYS)
6548c2ecf20Sopenharmony_ci		return -ERESTARTSYS;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	return 0;
6578c2ecf20Sopenharmony_ci}
658