18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
48c2ecf20Sopenharmony_ci * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/export.h>
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/types.h>
108c2ecf20Sopenharmony_ci#include <linux/errno.h>
118c2ecf20Sopenharmony_ci#include <linux/delay.h>
128c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
138c2ecf20Sopenharmony_ci#include <linux/io.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <video/imx-ipu-v3.h>
168c2ecf20Sopenharmony_ci#include "ipu-prv.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define DC_MAP_CONF_PTR(n)	(0x108 + ((n) & ~0x1) * 2)
198c2ecf20Sopenharmony_ci#define DC_MAP_CONF_VAL(n)	(0x144 + ((n) & ~0x1) * 2)
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define DC_EVT_NF		0
228c2ecf20Sopenharmony_ci#define DC_EVT_NL		1
238c2ecf20Sopenharmony_ci#define DC_EVT_EOF		2
248c2ecf20Sopenharmony_ci#define DC_EVT_NFIELD		3
258c2ecf20Sopenharmony_ci#define DC_EVT_EOL		4
268c2ecf20Sopenharmony_ci#define DC_EVT_EOFIELD		5
278c2ecf20Sopenharmony_ci#define DC_EVT_NEW_ADDR		6
288c2ecf20Sopenharmony_ci#define DC_EVT_NEW_CHAN		7
298c2ecf20Sopenharmony_ci#define DC_EVT_NEW_DATA		8
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define DC_EVT_NEW_ADDR_W_0	0
328c2ecf20Sopenharmony_ci#define DC_EVT_NEW_ADDR_W_1	1
338c2ecf20Sopenharmony_ci#define DC_EVT_NEW_CHAN_W_0	2
348c2ecf20Sopenharmony_ci#define DC_EVT_NEW_CHAN_W_1	3
358c2ecf20Sopenharmony_ci#define DC_EVT_NEW_DATA_W_0	4
368c2ecf20Sopenharmony_ci#define DC_EVT_NEW_DATA_W_1	5
378c2ecf20Sopenharmony_ci#define DC_EVT_NEW_ADDR_R_0	6
388c2ecf20Sopenharmony_ci#define DC_EVT_NEW_ADDR_R_1	7
398c2ecf20Sopenharmony_ci#define DC_EVT_NEW_CHAN_R_0	8
408c2ecf20Sopenharmony_ci#define DC_EVT_NEW_CHAN_R_1	9
418c2ecf20Sopenharmony_ci#define DC_EVT_NEW_DATA_R_0	10
428c2ecf20Sopenharmony_ci#define DC_EVT_NEW_DATA_R_1	11
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#define DC_WR_CH_CONF		0x0
458c2ecf20Sopenharmony_ci#define DC_WR_CH_ADDR		0x4
468c2ecf20Sopenharmony_ci#define DC_RL_CH(evt)		(8 + ((evt) & ~0x1) * 2)
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#define DC_GEN			0xd4
498c2ecf20Sopenharmony_ci#define DC_DISP_CONF1(disp)	(0xd8 + (disp) * 4)
508c2ecf20Sopenharmony_ci#define DC_DISP_CONF2(disp)	(0xe8 + (disp) * 4)
518c2ecf20Sopenharmony_ci#define DC_STAT			0x1c8
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define WROD(lf)		(0x18 | ((lf) << 1))
548c2ecf20Sopenharmony_ci#define WRG			0x01
558c2ecf20Sopenharmony_ci#define WCLK			0xc9
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#define SYNC_WAVE 0
588c2ecf20Sopenharmony_ci#define NULL_WAVE (-1)
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#define DC_GEN_SYNC_1_6_SYNC	(2 << 1)
618c2ecf20Sopenharmony_ci#define DC_GEN_SYNC_PRIORITY_1	(1 << 7)
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci#define DC_WR_CH_CONF_WORD_SIZE_8		(0 << 0)
648c2ecf20Sopenharmony_ci#define DC_WR_CH_CONF_WORD_SIZE_16		(1 << 0)
658c2ecf20Sopenharmony_ci#define DC_WR_CH_CONF_WORD_SIZE_24		(2 << 0)
668c2ecf20Sopenharmony_ci#define DC_WR_CH_CONF_WORD_SIZE_32		(3 << 0)
678c2ecf20Sopenharmony_ci#define DC_WR_CH_CONF_DISP_ID_PARALLEL(i)	(((i) & 0x1) << 3)
688c2ecf20Sopenharmony_ci#define DC_WR_CH_CONF_DISP_ID_SERIAL		(2 << 3)
698c2ecf20Sopenharmony_ci#define DC_WR_CH_CONF_DISP_ID_ASYNC		(3 << 4)
708c2ecf20Sopenharmony_ci#define DC_WR_CH_CONF_FIELD_MODE		(1 << 9)
718c2ecf20Sopenharmony_ci#define DC_WR_CH_CONF_PROG_TYPE_NORMAL		(4 << 5)
728c2ecf20Sopenharmony_ci#define DC_WR_CH_CONF_PROG_TYPE_MASK		(7 << 5)
738c2ecf20Sopenharmony_ci#define DC_WR_CH_CONF_PROG_DI_ID		(1 << 2)
748c2ecf20Sopenharmony_ci#define DC_WR_CH_CONF_PROG_DISP_ID(i)		(((i) & 0x1) << 3)
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci#define IPU_DC_NUM_CHANNELS	10
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistruct ipu_dc_priv;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cienum ipu_dc_map {
818c2ecf20Sopenharmony_ci	IPU_DC_MAP_RGB24,
828c2ecf20Sopenharmony_ci	IPU_DC_MAP_RGB565,
838c2ecf20Sopenharmony_ci	IPU_DC_MAP_GBR24, /* TVEv2 */
848c2ecf20Sopenharmony_ci	IPU_DC_MAP_BGR666,
858c2ecf20Sopenharmony_ci	IPU_DC_MAP_LVDS666,
868c2ecf20Sopenharmony_ci	IPU_DC_MAP_BGR24,
878c2ecf20Sopenharmony_ci};
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistruct ipu_dc {
908c2ecf20Sopenharmony_ci	/* The display interface number assigned to this dc channel */
918c2ecf20Sopenharmony_ci	unsigned int		di;
928c2ecf20Sopenharmony_ci	void __iomem		*base;
938c2ecf20Sopenharmony_ci	struct ipu_dc_priv	*priv;
948c2ecf20Sopenharmony_ci	int			chno;
958c2ecf20Sopenharmony_ci	bool			in_use;
968c2ecf20Sopenharmony_ci};
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistruct ipu_dc_priv {
998c2ecf20Sopenharmony_ci	void __iomem		*dc_reg;
1008c2ecf20Sopenharmony_ci	void __iomem		*dc_tmpl_reg;
1018c2ecf20Sopenharmony_ci	struct ipu_soc		*ipu;
1028c2ecf20Sopenharmony_ci	struct device		*dev;
1038c2ecf20Sopenharmony_ci	struct ipu_dc		channels[IPU_DC_NUM_CHANNELS];
1048c2ecf20Sopenharmony_ci	struct mutex		mutex;
1058c2ecf20Sopenharmony_ci	struct completion	comp;
1068c2ecf20Sopenharmony_ci	int			use_count;
1078c2ecf20Sopenharmony_ci};
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	u32 reg;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	reg = readl(dc->base + DC_RL_CH(event));
1148c2ecf20Sopenharmony_ci	reg &= ~(0xffff << (16 * (event & 0x1)));
1158c2ecf20Sopenharmony_ci	reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
1168c2ecf20Sopenharmony_ci	writel(reg, dc->base + DC_RL_CH(event));
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic void dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand,
1208c2ecf20Sopenharmony_ci		int map, int wave, int glue, int sync, int stop)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	struct ipu_dc_priv *priv = dc->priv;
1238c2ecf20Sopenharmony_ci	u32 reg1, reg2;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	if (opcode == WCLK) {
1268c2ecf20Sopenharmony_ci		reg1 = (operand << 20) & 0xfff00000;
1278c2ecf20Sopenharmony_ci		reg2 = operand >> 12 | opcode << 1 | stop << 9;
1288c2ecf20Sopenharmony_ci	} else if (opcode == WRG) {
1298c2ecf20Sopenharmony_ci		reg1 = sync | glue << 4 | ++wave << 11 | ((operand << 15) & 0xffff8000);
1308c2ecf20Sopenharmony_ci		reg2 = operand >> 17 | opcode << 7 | stop << 9;
1318c2ecf20Sopenharmony_ci	} else {
1328c2ecf20Sopenharmony_ci		reg1 = sync | glue << 4 | ++wave << 11 | ++map << 15 | ((operand << 20) & 0xfff00000);
1338c2ecf20Sopenharmony_ci		reg2 = operand >> 12 | opcode << 4 | stop << 9;
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci	writel(reg1, priv->dc_tmpl_reg + word * 8);
1368c2ecf20Sopenharmony_ci	writel(reg2, priv->dc_tmpl_reg + word * 8 + 4);
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic int ipu_bus_format_to_map(u32 fmt)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	switch (fmt) {
1428c2ecf20Sopenharmony_ci	default:
1438c2ecf20Sopenharmony_ci		WARN_ON(1);
1448c2ecf20Sopenharmony_ci		fallthrough;
1458c2ecf20Sopenharmony_ci	case MEDIA_BUS_FMT_RGB888_1X24:
1468c2ecf20Sopenharmony_ci		return IPU_DC_MAP_RGB24;
1478c2ecf20Sopenharmony_ci	case MEDIA_BUS_FMT_RGB565_1X16:
1488c2ecf20Sopenharmony_ci		return IPU_DC_MAP_RGB565;
1498c2ecf20Sopenharmony_ci	case MEDIA_BUS_FMT_GBR888_1X24:
1508c2ecf20Sopenharmony_ci		return IPU_DC_MAP_GBR24;
1518c2ecf20Sopenharmony_ci	case MEDIA_BUS_FMT_RGB666_1X18:
1528c2ecf20Sopenharmony_ci		return IPU_DC_MAP_BGR666;
1538c2ecf20Sopenharmony_ci	case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
1548c2ecf20Sopenharmony_ci		return IPU_DC_MAP_LVDS666;
1558c2ecf20Sopenharmony_ci	case MEDIA_BUS_FMT_BGR888_1X24:
1568c2ecf20Sopenharmony_ci		return IPU_DC_MAP_BGR24;
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ciint ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
1618c2ecf20Sopenharmony_ci		u32 bus_format, u32 width)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	struct ipu_dc_priv *priv = dc->priv;
1648c2ecf20Sopenharmony_ci	int addr, sync;
1658c2ecf20Sopenharmony_ci	u32 reg = 0;
1668c2ecf20Sopenharmony_ci	int map;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	dc->di = ipu_di_get_num(di);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	map = ipu_bus_format_to_map(bus_format);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	/*
1738c2ecf20Sopenharmony_ci	 * In interlaced mode we need more counters to create the asymmetric
1748c2ecf20Sopenharmony_ci	 * per-field VSYNC signals. The pixel active signal synchronising DC
1758c2ecf20Sopenharmony_ci	 * to DI moves to signal generator #6 (see ipu-di.c). In progressive
1768c2ecf20Sopenharmony_ci	 * mode counter #5 is used.
1778c2ecf20Sopenharmony_ci	 */
1788c2ecf20Sopenharmony_ci	sync = interlaced ? 6 : 5;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	/* Reserve 5 microcode template words for each DI */
1818c2ecf20Sopenharmony_ci	if (dc->di)
1828c2ecf20Sopenharmony_ci		addr = 5;
1838c2ecf20Sopenharmony_ci	else
1848c2ecf20Sopenharmony_ci		addr = 0;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	if (interlaced) {
1878c2ecf20Sopenharmony_ci		dc_link_event(dc, DC_EVT_NL, addr, 3);
1888c2ecf20Sopenharmony_ci		dc_link_event(dc, DC_EVT_EOL, addr, 2);
1898c2ecf20Sopenharmony_ci		dc_link_event(dc, DC_EVT_NEW_DATA, addr, 1);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci		/* Init template microcode */
1928c2ecf20Sopenharmony_ci		dc_write_tmpl(dc, addr, WROD(0), 0, map, SYNC_WAVE, 0, sync, 1);
1938c2ecf20Sopenharmony_ci	} else {
1948c2ecf20Sopenharmony_ci		dc_link_event(dc, DC_EVT_NL, addr + 2, 3);
1958c2ecf20Sopenharmony_ci		dc_link_event(dc, DC_EVT_EOL, addr + 3, 2);
1968c2ecf20Sopenharmony_ci		dc_link_event(dc, DC_EVT_NEW_DATA, addr + 1, 1);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci		/* Init template microcode */
1998c2ecf20Sopenharmony_ci		dc_write_tmpl(dc, addr + 2, WROD(0), 0, map, SYNC_WAVE, 8, sync, 1);
2008c2ecf20Sopenharmony_ci		dc_write_tmpl(dc, addr + 3, WROD(0), 0, map, SYNC_WAVE, 4, sync, 0);
2018c2ecf20Sopenharmony_ci		dc_write_tmpl(dc, addr + 4, WRG, 0, map, NULL_WAVE, 0, 0, 1);
2028c2ecf20Sopenharmony_ci		dc_write_tmpl(dc, addr + 1, WROD(0), 0, map, SYNC_WAVE, 0, sync, 1);
2038c2ecf20Sopenharmony_ci	}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	dc_link_event(dc, DC_EVT_NF, 0, 0);
2068c2ecf20Sopenharmony_ci	dc_link_event(dc, DC_EVT_NFIELD, 0, 0);
2078c2ecf20Sopenharmony_ci	dc_link_event(dc, DC_EVT_EOF, 0, 0);
2088c2ecf20Sopenharmony_ci	dc_link_event(dc, DC_EVT_EOFIELD, 0, 0);
2098c2ecf20Sopenharmony_ci	dc_link_event(dc, DC_EVT_NEW_CHAN, 0, 0);
2108c2ecf20Sopenharmony_ci	dc_link_event(dc, DC_EVT_NEW_ADDR, 0, 0);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	reg = readl(dc->base + DC_WR_CH_CONF);
2138c2ecf20Sopenharmony_ci	if (interlaced)
2148c2ecf20Sopenharmony_ci		reg |= DC_WR_CH_CONF_FIELD_MODE;
2158c2ecf20Sopenharmony_ci	else
2168c2ecf20Sopenharmony_ci		reg &= ~DC_WR_CH_CONF_FIELD_MODE;
2178c2ecf20Sopenharmony_ci	writel(reg, dc->base + DC_WR_CH_CONF);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	writel(0x0, dc->base + DC_WR_CH_ADDR);
2208c2ecf20Sopenharmony_ci	writel(width, priv->dc_reg + DC_DISP_CONF2(dc->di));
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	return 0;
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_dc_init_sync);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_civoid ipu_dc_enable(struct ipu_soc *ipu)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	struct ipu_dc_priv *priv = ipu->dc_priv;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	mutex_lock(&priv->mutex);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	if (!priv->use_count)
2338c2ecf20Sopenharmony_ci		ipu_module_enable(priv->ipu, IPU_CONF_DC_EN);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	priv->use_count++;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	mutex_unlock(&priv->mutex);
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_dc_enable);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_civoid ipu_dc_enable_channel(struct ipu_dc *dc)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	u32 reg;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	reg = readl(dc->base + DC_WR_CH_CONF);
2468c2ecf20Sopenharmony_ci	reg |= DC_WR_CH_CONF_PROG_TYPE_NORMAL;
2478c2ecf20Sopenharmony_ci	writel(reg, dc->base + DC_WR_CH_CONF);
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_dc_enable_channel);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_civoid ipu_dc_disable_channel(struct ipu_dc *dc)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	u32 val;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	val = readl(dc->base + DC_WR_CH_CONF);
2568c2ecf20Sopenharmony_ci	val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
2578c2ecf20Sopenharmony_ci	writel(val, dc->base + DC_WR_CH_CONF);
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_dc_disable_channel);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_civoid ipu_dc_disable(struct ipu_soc *ipu)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct ipu_dc_priv *priv = ipu->dc_priv;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	mutex_lock(&priv->mutex);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	priv->use_count--;
2688c2ecf20Sopenharmony_ci	if (!priv->use_count)
2698c2ecf20Sopenharmony_ci		ipu_module_disable(priv->ipu, IPU_CONF_DC_EN);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	if (priv->use_count < 0)
2728c2ecf20Sopenharmony_ci		priv->use_count = 0;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	mutex_unlock(&priv->mutex);
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_dc_disable);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_cistatic void ipu_dc_map_config(struct ipu_dc_priv *priv, enum ipu_dc_map map,
2798c2ecf20Sopenharmony_ci		int byte_num, int offset, int mask)
2808c2ecf20Sopenharmony_ci{
2818c2ecf20Sopenharmony_ci	int ptr = map * 3 + byte_num;
2828c2ecf20Sopenharmony_ci	u32 reg;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	reg = readl(priv->dc_reg + DC_MAP_CONF_VAL(ptr));
2858c2ecf20Sopenharmony_ci	reg &= ~(0xffff << (16 * (ptr & 0x1)));
2868c2ecf20Sopenharmony_ci	reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
2878c2ecf20Sopenharmony_ci	writel(reg, priv->dc_reg + DC_MAP_CONF_VAL(ptr));
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
2908c2ecf20Sopenharmony_ci	reg &= ~(0x1f << ((16 * (map & 0x1)) + (5 * byte_num)));
2918c2ecf20Sopenharmony_ci	reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
2928c2ecf20Sopenharmony_ci	writel(reg, priv->dc_reg + DC_MAP_CONF_PTR(map));
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic void ipu_dc_map_clear(struct ipu_dc_priv *priv, int map)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	u32 reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	writel(reg & ~(0xffff << (16 * (map & 0x1))),
3008c2ecf20Sopenharmony_ci		     priv->dc_reg + DC_MAP_CONF_PTR(map));
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistruct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel)
3048c2ecf20Sopenharmony_ci{
3058c2ecf20Sopenharmony_ci	struct ipu_dc_priv *priv = ipu->dc_priv;
3068c2ecf20Sopenharmony_ci	struct ipu_dc *dc;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	if (channel >= IPU_DC_NUM_CHANNELS)
3098c2ecf20Sopenharmony_ci		return ERR_PTR(-ENODEV);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	dc = &priv->channels[channel];
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	mutex_lock(&priv->mutex);
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	if (dc->in_use) {
3168c2ecf20Sopenharmony_ci		mutex_unlock(&priv->mutex);
3178c2ecf20Sopenharmony_ci		return ERR_PTR(-EBUSY);
3188c2ecf20Sopenharmony_ci	}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	dc->in_use = true;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	mutex_unlock(&priv->mutex);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	return dc;
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_dc_get);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_civoid ipu_dc_put(struct ipu_dc *dc)
3298c2ecf20Sopenharmony_ci{
3308c2ecf20Sopenharmony_ci	struct ipu_dc_priv *priv = dc->priv;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	mutex_lock(&priv->mutex);
3338c2ecf20Sopenharmony_ci	dc->in_use = false;
3348c2ecf20Sopenharmony_ci	mutex_unlock(&priv->mutex);
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_dc_put);
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ciint ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
3398c2ecf20Sopenharmony_ci		unsigned long base, unsigned long template_base)
3408c2ecf20Sopenharmony_ci{
3418c2ecf20Sopenharmony_ci	struct ipu_dc_priv *priv;
3428c2ecf20Sopenharmony_ci	static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c,
3438c2ecf20Sopenharmony_ci		0x78, 0, 0x94, 0xb4};
3448c2ecf20Sopenharmony_ci	int i;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
3478c2ecf20Sopenharmony_ci	if (!priv)
3488c2ecf20Sopenharmony_ci		return -ENOMEM;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	mutex_init(&priv->mutex);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	priv->dev = dev;
3538c2ecf20Sopenharmony_ci	priv->ipu = ipu;
3548c2ecf20Sopenharmony_ci	priv->dc_reg = devm_ioremap(dev, base, PAGE_SIZE);
3558c2ecf20Sopenharmony_ci	priv->dc_tmpl_reg = devm_ioremap(dev, template_base, PAGE_SIZE);
3568c2ecf20Sopenharmony_ci	if (!priv->dc_reg || !priv->dc_tmpl_reg)
3578c2ecf20Sopenharmony_ci		return -ENOMEM;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	for (i = 0; i < IPU_DC_NUM_CHANNELS; i++) {
3608c2ecf20Sopenharmony_ci		priv->channels[i].chno = i;
3618c2ecf20Sopenharmony_ci		priv->channels[i].priv = priv;
3628c2ecf20Sopenharmony_ci		priv->channels[i].base = priv->dc_reg + channel_offsets[i];
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) |
3668c2ecf20Sopenharmony_ci			DC_WR_CH_CONF_PROG_DI_ID,
3678c2ecf20Sopenharmony_ci			priv->channels[1].base + DC_WR_CH_CONF);
3688c2ecf20Sopenharmony_ci	writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(0),
3698c2ecf20Sopenharmony_ci			priv->channels[5].base + DC_WR_CH_CONF);
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	writel(DC_GEN_SYNC_1_6_SYNC | DC_GEN_SYNC_PRIORITY_1,
3728c2ecf20Sopenharmony_ci		priv->dc_reg + DC_GEN);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	ipu->dc_priv = priv;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	dev_dbg(dev, "DC base: 0x%08lx template base: 0x%08lx\n",
3778c2ecf20Sopenharmony_ci			base, template_base);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	/* rgb24 */
3808c2ecf20Sopenharmony_ci	ipu_dc_map_clear(priv, IPU_DC_MAP_RGB24);
3818c2ecf20Sopenharmony_ci	ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 0, 7, 0xff); /* blue */
3828c2ecf20Sopenharmony_ci	ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 1, 15, 0xff); /* green */
3838c2ecf20Sopenharmony_ci	ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 2, 23, 0xff); /* red */
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	/* rgb565 */
3868c2ecf20Sopenharmony_ci	ipu_dc_map_clear(priv, IPU_DC_MAP_RGB565);
3878c2ecf20Sopenharmony_ci	ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 0, 4, 0xf8); /* blue */
3888c2ecf20Sopenharmony_ci	ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 1, 10, 0xfc); /* green */
3898c2ecf20Sopenharmony_ci	ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 2, 15, 0xf8); /* red */
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	/* gbr24 */
3928c2ecf20Sopenharmony_ci	ipu_dc_map_clear(priv, IPU_DC_MAP_GBR24);
3938c2ecf20Sopenharmony_ci	ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 2, 15, 0xff); /* green */
3948c2ecf20Sopenharmony_ci	ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 1, 7, 0xff); /* blue */
3958c2ecf20Sopenharmony_ci	ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 0, 23, 0xff); /* red */
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	/* bgr666 */
3988c2ecf20Sopenharmony_ci	ipu_dc_map_clear(priv, IPU_DC_MAP_BGR666);
3998c2ecf20Sopenharmony_ci	ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 0, 5, 0xfc); /* blue */
4008c2ecf20Sopenharmony_ci	ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 1, 11, 0xfc); /* green */
4018c2ecf20Sopenharmony_ci	ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 2, 17, 0xfc); /* red */
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	/* lvds666 */
4048c2ecf20Sopenharmony_ci	ipu_dc_map_clear(priv, IPU_DC_MAP_LVDS666);
4058c2ecf20Sopenharmony_ci	ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 0, 5, 0xfc); /* blue */
4068c2ecf20Sopenharmony_ci	ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 1, 13, 0xfc); /* green */
4078c2ecf20Sopenharmony_ci	ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 2, 21, 0xfc); /* red */
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	/* bgr24 */
4108c2ecf20Sopenharmony_ci	ipu_dc_map_clear(priv, IPU_DC_MAP_BGR24);
4118c2ecf20Sopenharmony_ci	ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 2, 7, 0xff); /* red */
4128c2ecf20Sopenharmony_ci	ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 1, 15, 0xff); /* green */
4138c2ecf20Sopenharmony_ci	ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 0, 23, 0xff); /* blue */
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	return 0;
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_civoid ipu_dc_exit(struct ipu_soc *ipu)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci}
421