brintos

brintos / linux-shallow public Read only

0
0
Text · 18.9 KiB · 8097397 Raw
644 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.4 * Author: James.Qian.Wang <james.qian.wang@arm.com>5 *6 */7 8#include <drm/drm_blend.h>9#include <drm/drm_print.h>10#include "d71_dev.h"11#include "malidp_io.h"12 13static u64 get_lpu_event(struct d71_pipeline *d71_pipeline)14{15	u32 __iomem *reg = d71_pipeline->lpu_addr;16	u32 status, raw_status;17	u64 evts = 0ULL;18 19	raw_status = malidp_read32(reg, BLK_IRQ_RAW_STATUS);20	if (raw_status & LPU_IRQ_IBSY)21		evts |= KOMEDA_EVENT_IBSY;22	if (raw_status & LPU_IRQ_EOW)23		evts |= KOMEDA_EVENT_EOW;24	if (raw_status & LPU_IRQ_OVR)25		evts |= KOMEDA_EVENT_OVR;26 27	if (raw_status & (LPU_IRQ_ERR | LPU_IRQ_IBSY | LPU_IRQ_OVR)) {28		u32 restore = 0, tbu_status;29		/* Check error of LPU status */30		status = malidp_read32(reg, BLK_STATUS);31		if (status & LPU_STATUS_AXIE) {32			restore |= LPU_STATUS_AXIE;33			evts |= KOMEDA_ERR_AXIE;34		}35		if (status & LPU_STATUS_ACE0) {36			restore |= LPU_STATUS_ACE0;37			evts |= KOMEDA_ERR_ACE0;38		}39		if (status & LPU_STATUS_ACE1) {40			restore |= LPU_STATUS_ACE1;41			evts |= KOMEDA_ERR_ACE1;42		}43		if (status & LPU_STATUS_ACE2) {44			restore |= LPU_STATUS_ACE2;45			evts |= KOMEDA_ERR_ACE2;46		}47		if (status & LPU_STATUS_ACE3) {48			restore |= LPU_STATUS_ACE3;49			evts |= KOMEDA_ERR_ACE3;50		}51		if (status & LPU_STATUS_FEMPTY) {52			restore |= LPU_STATUS_FEMPTY;53			evts |= KOMEDA_EVENT_EMPTY;54		}55		if (status & LPU_STATUS_FFULL) {56			restore |= LPU_STATUS_FFULL;57			evts |= KOMEDA_EVENT_FULL;58		}59 60		if (restore != 0)61			malidp_write32_mask(reg, BLK_STATUS, restore, 0);62 63		restore = 0;64		/* Check errors of TBU status */65		tbu_status = malidp_read32(reg, LPU_TBU_STATUS);66		if (tbu_status & LPU_TBU_STATUS_TCF) {67			restore |= LPU_TBU_STATUS_TCF;68			evts |= KOMEDA_ERR_TCF;69		}70		if (tbu_status & LPU_TBU_STATUS_TTNG) {71			restore |= LPU_TBU_STATUS_TTNG;72			evts |= KOMEDA_ERR_TTNG;73		}74		if (tbu_status & LPU_TBU_STATUS_TITR) {75			restore |= LPU_TBU_STATUS_TITR;76			evts |= KOMEDA_ERR_TITR;77		}78		if (tbu_status & LPU_TBU_STATUS_TEMR) {79			restore |= LPU_TBU_STATUS_TEMR;80			evts |= KOMEDA_ERR_TEMR;81		}82		if (tbu_status & LPU_TBU_STATUS_TTF) {83			restore |= LPU_TBU_STATUS_TTF;84			evts |= KOMEDA_ERR_TTF;85		}86		if (restore != 0)87			malidp_write32_mask(reg, LPU_TBU_STATUS, restore, 0);88	}89 90	malidp_write32(reg, BLK_IRQ_CLEAR, raw_status);91	return evts;92}93 94static u64 get_cu_event(struct d71_pipeline *d71_pipeline)95{96	u32 __iomem *reg = d71_pipeline->cu_addr;97	u32 status, raw_status;98	u64 evts = 0ULL;99 100	raw_status = malidp_read32(reg, BLK_IRQ_RAW_STATUS);101	if (raw_status & CU_IRQ_OVR)102		evts |= KOMEDA_EVENT_OVR;103 104	if (raw_status & (CU_IRQ_ERR | CU_IRQ_OVR)) {105		status = malidp_read32(reg, BLK_STATUS) & 0x7FFFFFFF;106		if (status & CU_STATUS_CPE)107			evts |= KOMEDA_ERR_CPE;108		if (status & CU_STATUS_ZME)109			evts |= KOMEDA_ERR_ZME;110		if (status & CU_STATUS_CFGE)111			evts |= KOMEDA_ERR_CFGE;112		if (status)113			malidp_write32_mask(reg, BLK_STATUS, status, 0);114	}115 116	malidp_write32(reg, BLK_IRQ_CLEAR, raw_status);117 118	return evts;119}120 121static u64 get_dou_event(struct d71_pipeline *d71_pipeline)122{123	u32 __iomem *reg = d71_pipeline->dou_addr;124	u32 status, raw_status;125	u64 evts = 0ULL;126 127	raw_status = malidp_read32(reg, BLK_IRQ_RAW_STATUS);128	if (raw_status & DOU_IRQ_PL0)129		evts |= KOMEDA_EVENT_VSYNC;130	if (raw_status & DOU_IRQ_UND)131		evts |= KOMEDA_EVENT_URUN;132 133	if (raw_status & (DOU_IRQ_ERR | DOU_IRQ_UND)) {134		u32 restore  = 0;135 136		status = malidp_read32(reg, BLK_STATUS);137		if (status & DOU_STATUS_DRIFTTO) {138			restore |= DOU_STATUS_DRIFTTO;139			evts |= KOMEDA_ERR_DRIFTTO;140		}141		if (status & DOU_STATUS_FRAMETO) {142			restore |= DOU_STATUS_FRAMETO;143			evts |= KOMEDA_ERR_FRAMETO;144		}145		if (status & DOU_STATUS_TETO) {146			restore |= DOU_STATUS_TETO;147			evts |= KOMEDA_ERR_TETO;148		}149		if (status & DOU_STATUS_CSCE) {150			restore |= DOU_STATUS_CSCE;151			evts |= KOMEDA_ERR_CSCE;152		}153 154		if (restore != 0)155			malidp_write32_mask(reg, BLK_STATUS, restore, 0);156	}157 158	malidp_write32(reg, BLK_IRQ_CLEAR, raw_status);159	return evts;160}161 162static u64 get_pipeline_event(struct d71_pipeline *d71_pipeline, u32 gcu_status)163{164	u32 evts = 0ULL;165 166	if (gcu_status & (GLB_IRQ_STATUS_LPU0 | GLB_IRQ_STATUS_LPU1))167		evts |= get_lpu_event(d71_pipeline);168 169	if (gcu_status & (GLB_IRQ_STATUS_CU0 | GLB_IRQ_STATUS_CU1))170		evts |= get_cu_event(d71_pipeline);171 172	if (gcu_status & (GLB_IRQ_STATUS_DOU0 | GLB_IRQ_STATUS_DOU1))173		evts |= get_dou_event(d71_pipeline);174 175	return evts;176}177 178static irqreturn_t179d71_irq_handler(struct komeda_dev *mdev, struct komeda_events *evts)180{181	struct d71_dev *d71 = mdev->chip_data;182	u32 status, gcu_status, raw_status;183 184	gcu_status = malidp_read32(d71->gcu_addr, GLB_IRQ_STATUS);185 186	if (gcu_status & GLB_IRQ_STATUS_GCU) {187		raw_status = malidp_read32(d71->gcu_addr, BLK_IRQ_RAW_STATUS);188		if (raw_status & GCU_IRQ_CVAL0)189			evts->pipes[0] |= KOMEDA_EVENT_FLIP;190		if (raw_status & GCU_IRQ_CVAL1)191			evts->pipes[1] |= KOMEDA_EVENT_FLIP;192		if (raw_status & GCU_IRQ_ERR) {193			status = malidp_read32(d71->gcu_addr, BLK_STATUS);194			if (status & GCU_STATUS_MERR) {195				evts->global |= KOMEDA_ERR_MERR;196				malidp_write32_mask(d71->gcu_addr, BLK_STATUS,197						    GCU_STATUS_MERR, 0);198			}199		}200 201		malidp_write32(d71->gcu_addr, BLK_IRQ_CLEAR, raw_status);202	}203 204	if (gcu_status & GLB_IRQ_STATUS_PIPE0)205		evts->pipes[0] |= get_pipeline_event(d71->pipes[0], gcu_status);206 207	if (gcu_status & GLB_IRQ_STATUS_PIPE1)208		evts->pipes[1] |= get_pipeline_event(d71->pipes[1], gcu_status);209 210	return IRQ_RETVAL(gcu_status);211}212 213#define ENABLED_GCU_IRQS	(GCU_IRQ_CVAL0 | GCU_IRQ_CVAL1 | \214				 GCU_IRQ_MODE | GCU_IRQ_ERR)215#define ENABLED_LPU_IRQS	(LPU_IRQ_IBSY | LPU_IRQ_ERR | LPU_IRQ_EOW)216#define ENABLED_CU_IRQS		(CU_IRQ_OVR | CU_IRQ_ERR)217#define ENABLED_DOU_IRQS	(DOU_IRQ_UND | DOU_IRQ_ERR)218 219static int d71_enable_irq(struct komeda_dev *mdev)220{221	struct d71_dev *d71 = mdev->chip_data;222	struct d71_pipeline *pipe;223	u32 i;224 225	malidp_write32_mask(d71->gcu_addr, BLK_IRQ_MASK,226			    ENABLED_GCU_IRQS, ENABLED_GCU_IRQS);227	for (i = 0; i < d71->num_pipelines; i++) {228		pipe = d71->pipes[i];229		malidp_write32_mask(pipe->cu_addr,  BLK_IRQ_MASK,230				    ENABLED_CU_IRQS, ENABLED_CU_IRQS);231		malidp_write32_mask(pipe->lpu_addr, BLK_IRQ_MASK,232				    ENABLED_LPU_IRQS, ENABLED_LPU_IRQS);233		malidp_write32_mask(pipe->dou_addr, BLK_IRQ_MASK,234				    ENABLED_DOU_IRQS, ENABLED_DOU_IRQS);235	}236	return 0;237}238 239static int d71_disable_irq(struct komeda_dev *mdev)240{241	struct d71_dev *d71 = mdev->chip_data;242	struct d71_pipeline *pipe;243	u32 i;244 245	malidp_write32_mask(d71->gcu_addr, BLK_IRQ_MASK, ENABLED_GCU_IRQS, 0);246	for (i = 0; i < d71->num_pipelines; i++) {247		pipe = d71->pipes[i];248		malidp_write32_mask(pipe->cu_addr,  BLK_IRQ_MASK,249				    ENABLED_CU_IRQS, 0);250		malidp_write32_mask(pipe->lpu_addr, BLK_IRQ_MASK,251				    ENABLED_LPU_IRQS, 0);252		malidp_write32_mask(pipe->dou_addr, BLK_IRQ_MASK,253				    ENABLED_DOU_IRQS, 0);254	}255	return 0;256}257 258static void d71_on_off_vblank(struct komeda_dev *mdev, int master_pipe, bool on)259{260	struct d71_dev *d71 = mdev->chip_data;261	struct d71_pipeline *pipe = d71->pipes[master_pipe];262 263	malidp_write32_mask(pipe->dou_addr, BLK_IRQ_MASK,264			    DOU_IRQ_PL0, on ? DOU_IRQ_PL0 : 0);265}266 267static int to_d71_opmode(int core_mode)268{269	switch (core_mode) {270	case KOMEDA_MODE_DISP0:271		return DO0_ACTIVE_MODE;272	case KOMEDA_MODE_DISP1:273		return DO1_ACTIVE_MODE;274	case KOMEDA_MODE_DUAL_DISP:275		return DO01_ACTIVE_MODE;276	case KOMEDA_MODE_INACTIVE:277		return INACTIVE_MODE;278	default:279		WARN(1, "Unknown operation mode");280		return INACTIVE_MODE;281	}282}283 284static int d71_change_opmode(struct komeda_dev *mdev, int new_mode)285{286	struct d71_dev *d71 = mdev->chip_data;287	u32 opmode = to_d71_opmode(new_mode);288	int ret;289 290	malidp_write32_mask(d71->gcu_addr, BLK_CONTROL, 0x7, opmode);291 292	ret = dp_wait_cond(((malidp_read32(d71->gcu_addr, BLK_CONTROL) & 0x7) == opmode),293			   100, 1000, 10000);294 295	return ret;296}297 298static void d71_flush(struct komeda_dev *mdev,299		      int master_pipe, u32 active_pipes)300{301	struct d71_dev *d71 = mdev->chip_data;302	u32 reg_offset = (master_pipe == 0) ?303			 GCU_CONFIG_VALID0 : GCU_CONFIG_VALID1;304 305	malidp_write32(d71->gcu_addr, reg_offset, GCU_CONFIG_CVAL);306}307 308static int d71_reset(struct d71_dev *d71)309{310	u32 __iomem *gcu = d71->gcu_addr;311	int ret;312 313	malidp_write32(gcu, BLK_CONTROL, GCU_CONTROL_SRST);314 315	ret = dp_wait_cond(!(malidp_read32(gcu, BLK_CONTROL) & GCU_CONTROL_SRST),316			   100, 1000, 10000);317 318	return ret;319}320 321void d71_read_block_header(u32 __iomem *reg, struct block_header *blk)322{323	int i;324 325	blk->block_info = malidp_read32(reg, BLK_BLOCK_INFO);326	if (BLOCK_INFO_BLK_TYPE(blk->block_info) == D71_BLK_TYPE_RESERVED)327		return;328 329	blk->pipeline_info = malidp_read32(reg, BLK_PIPELINE_INFO);330 331	/* get valid input and output ids */332	for (i = 0; i < PIPELINE_INFO_N_VALID_INPUTS(blk->pipeline_info); i++)333		blk->input_ids[i] = malidp_read32(reg + i, BLK_VALID_INPUT_ID0);334	for (i = 0; i < PIPELINE_INFO_N_OUTPUTS(blk->pipeline_info); i++)335		blk->output_ids[i] = malidp_read32(reg + i, BLK_OUTPUT_ID0);336}337 338static void d71_cleanup(struct komeda_dev *mdev)339{340	struct d71_dev *d71 = mdev->chip_data;341 342	if (!d71)343		return;344 345	devm_kfree(mdev->dev, d71);346	mdev->chip_data = NULL;347}348 349static int d71_enum_resources(struct komeda_dev *mdev)350{351	struct d71_dev *d71;352	struct komeda_pipeline *pipe;353	struct block_header blk;354	u32 __iomem *blk_base;355	u32 i, value, offset;356	int err;357 358	d71 = devm_kzalloc(mdev->dev, sizeof(*d71), GFP_KERNEL);359	if (!d71)360		return -ENOMEM;361 362	mdev->chip_data = d71;363	d71->mdev = mdev;364	d71->gcu_addr = mdev->reg_base;365	d71->periph_addr = mdev->reg_base + (D71_BLOCK_OFFSET_PERIPH >> 2);366 367	err = d71_reset(d71);368	if (err) {369		DRM_ERROR("Fail to reset d71 device.\n");370		goto err_cleanup;371	}372 373	/* probe GCU */374	value = malidp_read32(d71->gcu_addr, GLB_CORE_INFO);375	d71->num_blocks = value & 0xFF;376	d71->num_pipelines = (value >> 8) & 0x7;377 378	if (d71->num_pipelines > D71_MAX_PIPELINE) {379		DRM_ERROR("d71 supports %d pipelines, but got: %d.\n",380			  D71_MAX_PIPELINE, d71->num_pipelines);381		err = -EINVAL;382		goto err_cleanup;383	}384 385	/* Only the legacy HW has the periph block, the newer merges the periph386	 * into GCU387	 */388	value = malidp_read32(d71->periph_addr, BLK_BLOCK_INFO);389	if (BLOCK_INFO_BLK_TYPE(value) != D71_BLK_TYPE_PERIPH)390		d71->periph_addr = NULL;391 392	if (d71->periph_addr) {393		/* probe PERIPHERAL in legacy HW */394		value = malidp_read32(d71->periph_addr, PERIPH_CONFIGURATION_ID);395 396		d71->max_line_size	= value & PERIPH_MAX_LINE_SIZE ? 4096 : 2048;397		d71->max_vsize		= 4096;398		d71->num_rich_layers	= value & PERIPH_NUM_RICH_LAYERS ? 2 : 1;399		d71->supports_dual_link	= !!(value & PERIPH_SPLIT_EN);400		d71->integrates_tbu	= !!(value & PERIPH_TBU_EN);401	} else {402		value = malidp_read32(d71->gcu_addr, GCU_CONFIGURATION_ID0);403		d71->max_line_size	= GCU_MAX_LINE_SIZE(value);404		d71->max_vsize		= GCU_MAX_NUM_LINES(value);405 406		value = malidp_read32(d71->gcu_addr, GCU_CONFIGURATION_ID1);407		d71->num_rich_layers	= GCU_NUM_RICH_LAYERS(value);408		d71->supports_dual_link	= GCU_DISPLAY_SPLIT_EN(value);409		d71->integrates_tbu	= GCU_DISPLAY_TBU_EN(value);410	}411 412	for (i = 0; i < d71->num_pipelines; i++) {413		pipe = komeda_pipeline_add(mdev, sizeof(struct d71_pipeline),414					   &d71_pipeline_funcs);415		if (IS_ERR(pipe)) {416			err = PTR_ERR(pipe);417			goto err_cleanup;418		}419 420		/* D71 HW doesn't update shadow registers when display output421		 * is turning off, so when we disable all pipeline components422		 * together with display output disable by one flush or one423		 * operation, the disable operation updated registers will not424		 * be flush to or valid in HW, which may leads problem.425		 * To workaround this problem, introduce a two phase disable.426		 * Phase1: Disabling components with display is on to make sure427		 *	   the disable can be flushed to HW.428		 * Phase2: Only turn-off display output.429		 */430		value = KOMEDA_PIPELINE_IMPROCS |431			BIT(KOMEDA_COMPONENT_TIMING_CTRLR);432 433		pipe->standalone_disabled_comps = value;434 435		d71->pipes[i] = to_d71_pipeline(pipe);436	}437 438	/* loop the register blks and probe.439	 * NOTE: d71->num_blocks includes reserved blocks.440	 * d71->num_blocks = GCU + valid blocks + reserved blocks441	 */442	i = 1; /* exclude GCU */443	offset = D71_BLOCK_SIZE; /* skip GCU */444	while (i < d71->num_blocks) {445		blk_base = mdev->reg_base + (offset >> 2);446 447		d71_read_block_header(blk_base, &blk);448		if (BLOCK_INFO_BLK_TYPE(blk.block_info) != D71_BLK_TYPE_RESERVED) {449			err = d71_probe_block(d71, &blk, blk_base);450			if (err)451				goto err_cleanup;452		}453 454		i++;455		offset += D71_BLOCK_SIZE;456	}457 458	DRM_DEBUG("total %d (out of %d) blocks are found.\n",459		  i, d71->num_blocks);460 461	return 0;462 463err_cleanup:464	d71_cleanup(mdev);465	return err;466}467 468#define __HW_ID(__group, __format) \469	((((__group) & 0x7) << 3) | ((__format) & 0x7))470 471#define RICH		KOMEDA_FMT_RICH_LAYER472#define SIMPLE		KOMEDA_FMT_SIMPLE_LAYER473#define RICH_SIMPLE	(KOMEDA_FMT_RICH_LAYER | KOMEDA_FMT_SIMPLE_LAYER)474#define RICH_WB		(KOMEDA_FMT_RICH_LAYER | KOMEDA_FMT_WB_LAYER)475#define RICH_SIMPLE_WB	(RICH_SIMPLE | KOMEDA_FMT_WB_LAYER)476 477#define Rot_0		DRM_MODE_ROTATE_0478#define Flip_H_V	(DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y | Rot_0)479#define Rot_ALL_H_V	(DRM_MODE_ROTATE_MASK | Flip_H_V)480 481#define LYT_NM		BIT(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16)482#define LYT_WB		BIT(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)483#define LYT_NM_WB	(LYT_NM | LYT_WB)484 485#define AFB_TH		AFBC(_TILED | _SPARSE)486#define AFB_TH_SC_YTR	AFBC(_TILED | _SC | _SPARSE | _YTR)487#define AFB_TH_SC_YTR_BS AFBC(_TILED | _SC | _SPARSE | _YTR | _SPLIT)488 489static struct komeda_format_caps d71_format_caps_table[] = {490	/*   HW_ID    |        fourcc         |   layer_types |   rots    | afbc_layouts | afbc_features */491	/* ABGR_2101010*/492	{__HW_ID(0, 0),	DRM_FORMAT_ARGB2101010,	RICH_SIMPLE_WB,	Flip_H_V,		0, 0},493	{__HW_ID(0, 1),	DRM_FORMAT_ABGR2101010,	RICH_SIMPLE_WB,	Flip_H_V,		0, 0},494	{__HW_ID(0, 1),	DRM_FORMAT_ABGR2101010,	RICH_SIMPLE,	Rot_ALL_H_V,	LYT_NM_WB, AFB_TH_SC_YTR_BS}, /* afbc */495	{__HW_ID(0, 2),	DRM_FORMAT_RGBA1010102,	RICH_SIMPLE_WB,	Flip_H_V,		0, 0},496	{__HW_ID(0, 3),	DRM_FORMAT_BGRA1010102,	RICH_SIMPLE_WB,	Flip_H_V,		0, 0},497	/* ABGR_8888*/498	{__HW_ID(1, 0),	DRM_FORMAT_ARGB8888,	RICH_SIMPLE_WB,	Flip_H_V,		0, 0},499	{__HW_ID(1, 1),	DRM_FORMAT_ABGR8888,	RICH_SIMPLE_WB,	Flip_H_V,		0, 0},500	{__HW_ID(1, 1),	DRM_FORMAT_ABGR8888,	RICH_SIMPLE,	Rot_ALL_H_V,	LYT_NM_WB, AFB_TH_SC_YTR_BS}, /* afbc */501	{__HW_ID(1, 2),	DRM_FORMAT_RGBA8888,	RICH_SIMPLE_WB,	Flip_H_V,		0, 0},502	{__HW_ID(1, 3),	DRM_FORMAT_BGRA8888,	RICH_SIMPLE_WB,	Flip_H_V,		0, 0},503	/* XBGB_8888 */504	{__HW_ID(2, 0),	DRM_FORMAT_XRGB8888,	RICH_SIMPLE_WB,	Flip_H_V,		0, 0},505	{__HW_ID(2, 1),	DRM_FORMAT_XBGR8888,	RICH_SIMPLE_WB,	Flip_H_V,		0, 0},506	{__HW_ID(2, 2),	DRM_FORMAT_RGBX8888,	RICH_SIMPLE_WB,	Flip_H_V,		0, 0},507	{__HW_ID(2, 3),	DRM_FORMAT_BGRX8888,	RICH_SIMPLE_WB,	Flip_H_V,		0, 0},508	/* BGR_888 */ /* none-afbc RGB888 doesn't support rotation and flip */509	{__HW_ID(3, 0),	DRM_FORMAT_RGB888,	RICH_SIMPLE_WB,	Rot_0,			0, 0},510	{__HW_ID(3, 1),	DRM_FORMAT_BGR888,	RICH_SIMPLE_WB,	Rot_0,			0, 0},511	{__HW_ID(3, 1),	DRM_FORMAT_BGR888,	RICH_SIMPLE,	Rot_ALL_H_V,	LYT_NM_WB, AFB_TH_SC_YTR_BS}, /* afbc */512	/* BGR 16bpp */513	{__HW_ID(4, 0),	DRM_FORMAT_RGBA5551,	RICH_SIMPLE,	Flip_H_V,		0, 0},514	{__HW_ID(4, 1),	DRM_FORMAT_ABGR1555,	RICH_SIMPLE,	Flip_H_V,		0, 0},515	{__HW_ID(4, 1),	DRM_FORMAT_ABGR1555,	RICH_SIMPLE,	Rot_ALL_H_V,	LYT_NM_WB, AFB_TH_SC_YTR}, /* afbc */516	{__HW_ID(4, 2),	DRM_FORMAT_RGB565,	RICH_SIMPLE,	Flip_H_V,		0, 0},517	{__HW_ID(4, 3),	DRM_FORMAT_BGR565,	RICH_SIMPLE,	Flip_H_V,		0, 0},518	{__HW_ID(4, 3),	DRM_FORMAT_BGR565,	RICH_SIMPLE,	Rot_ALL_H_V,	LYT_NM_WB, AFB_TH_SC_YTR}, /* afbc */519	{__HW_ID(4, 4), DRM_FORMAT_R8,		SIMPLE,		Rot_0,			0, 0},520	/* YUV 444/422/420 8bit  */521	{__HW_ID(5, 1),	DRM_FORMAT_YUYV,	RICH,		Rot_ALL_H_V,	LYT_NM, AFB_TH}, /* afbc */522	{__HW_ID(5, 2),	DRM_FORMAT_YUYV,	RICH,		Flip_H_V,		0, 0},523	{__HW_ID(5, 3),	DRM_FORMAT_UYVY,	RICH,		Flip_H_V,		0, 0},524	{__HW_ID(5, 6),	DRM_FORMAT_NV12,	RICH_WB,	Flip_H_V,		0, 0},525	{__HW_ID(5, 6),	DRM_FORMAT_YUV420_8BIT,	RICH,		Rot_ALL_H_V,	LYT_NM, AFB_TH}, /* afbc */526	{__HW_ID(5, 7),	DRM_FORMAT_YUV420,	RICH,		Flip_H_V,		0, 0},527	/* YUV 10bit*/528	{__HW_ID(6, 6),	DRM_FORMAT_X0L2,	RICH,		Flip_H_V,		0, 0},529	{__HW_ID(6, 7),	DRM_FORMAT_P010,	RICH,		Flip_H_V,		0, 0},530	{__HW_ID(6, 7),	DRM_FORMAT_YUV420_10BIT, RICH,		Rot_ALL_H_V,	LYT_NM, AFB_TH},531};532 533static bool d71_format_mod_supported(const struct komeda_format_caps *caps,534				     u32 layer_type, u64 modifier, u32 rot)535{536	uint64_t layout = modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK;537 538	if ((layout == AFBC_FORMAT_MOD_BLOCK_SIZE_32x8) &&539	    drm_rotation_90_or_270(rot)) {540		DRM_DEBUG_ATOMIC("D71 doesn't support ROT90 for WB-AFBC.\n");541		return false;542	}543 544	return true;545}546 547static void d71_init_fmt_tbl(struct komeda_dev *mdev)548{549	struct komeda_format_caps_table *table = &mdev->fmt_tbl;550 551	table->format_caps = d71_format_caps_table;552	table->format_mod_supported = d71_format_mod_supported;553	table->n_formats = ARRAY_SIZE(d71_format_caps_table);554}555 556static int d71_connect_iommu(struct komeda_dev *mdev)557{558	struct d71_dev *d71 = mdev->chip_data;559	u32 __iomem *reg = d71->gcu_addr;560	u32 check_bits = (d71->num_pipelines == 2) ?561			 GCU_STATUS_TCS0 | GCU_STATUS_TCS1 : GCU_STATUS_TCS0;562	int i, ret;563 564	if (!d71->integrates_tbu)565		return -1;566 567	malidp_write32_mask(reg, BLK_CONTROL, 0x7, TBU_CONNECT_MODE);568 569	ret = dp_wait_cond(has_bits(check_bits, malidp_read32(reg, BLK_STATUS)),570			100, 1000, 1000);571	if (ret < 0) {572		DRM_ERROR("timed out connecting to TCU!\n");573		malidp_write32_mask(reg, BLK_CONTROL, 0x7, INACTIVE_MODE);574		return ret;575	}576 577	for (i = 0; i < d71->num_pipelines; i++)578		malidp_write32_mask(d71->pipes[i]->lpu_addr, LPU_TBU_CONTROL,579				    LPU_TBU_CTRL_TLBPEN, LPU_TBU_CTRL_TLBPEN);580	return 0;581}582 583static int d71_disconnect_iommu(struct komeda_dev *mdev)584{585	struct d71_dev *d71 = mdev->chip_data;586	u32 __iomem *reg = d71->gcu_addr;587	u32 check_bits = (d71->num_pipelines == 2) ?588			 GCU_STATUS_TCS0 | GCU_STATUS_TCS1 : GCU_STATUS_TCS0;589	int ret;590 591	malidp_write32_mask(reg, BLK_CONTROL, 0x7, TBU_DISCONNECT_MODE);592 593	ret = dp_wait_cond(((malidp_read32(reg, BLK_STATUS) & check_bits) == 0),594			100, 1000, 1000);595	if (ret < 0) {596		DRM_ERROR("timed out disconnecting from TCU!\n");597		malidp_write32_mask(reg, BLK_CONTROL, 0x7, INACTIVE_MODE);598	}599 600	return ret;601}602 603static const struct komeda_dev_funcs d71_chip_funcs = {604	.init_format_table	= d71_init_fmt_tbl,605	.enum_resources		= d71_enum_resources,606	.cleanup		= d71_cleanup,607	.irq_handler		= d71_irq_handler,608	.enable_irq		= d71_enable_irq,609	.disable_irq		= d71_disable_irq,610	.on_off_vblank		= d71_on_off_vblank,611	.change_opmode		= d71_change_opmode,612	.flush			= d71_flush,613	.connect_iommu		= d71_connect_iommu,614	.disconnect_iommu	= d71_disconnect_iommu,615	.dump_register		= d71_dump,616};617 618const struct komeda_dev_funcs *619d71_identify(u32 __iomem *reg_base, struct komeda_chip_info *chip)620{621	const struct komeda_dev_funcs *funcs;622	u32 product_id;623 624	chip->core_id = malidp_read32(reg_base, GLB_CORE_ID);625 626	product_id = MALIDP_CORE_ID_PRODUCT_ID(chip->core_id);627 628	switch (product_id) {629	case MALIDP_D71_PRODUCT_ID:630	case MALIDP_D32_PRODUCT_ID:631		funcs = &d71_chip_funcs;632		break;633	default:634		DRM_ERROR("Unsupported product: 0x%x\n", product_id);635		return NULL;636	}637 638	chip->arch_id	= malidp_read32(reg_base, GLB_ARCH_ID);639	chip->core_info	= malidp_read32(reg_base, GLB_CORE_INFO);640	chip->bus_width	= D71_BUS_WIDTH_16_BYTES;641 642	return funcs;643}644