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