cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

d71_dev.c (19391B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      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_print.h>
      9#include "d71_dev.h"
     10#include "malidp_io.h"
     11
     12static u64 get_lpu_event(struct d71_pipeline *d71_pipeline)
     13{
     14	u32 __iomem *reg = d71_pipeline->lpu_addr;
     15	u32 status, raw_status;
     16	u64 evts = 0ULL;
     17
     18	raw_status = malidp_read32(reg, BLK_IRQ_RAW_STATUS);
     19	if (raw_status & LPU_IRQ_IBSY)
     20		evts |= KOMEDA_EVENT_IBSY;
     21	if (raw_status & LPU_IRQ_EOW)
     22		evts |= KOMEDA_EVENT_EOW;
     23	if (raw_status & LPU_IRQ_OVR)
     24		evts |= KOMEDA_EVENT_OVR;
     25
     26	if (raw_status & (LPU_IRQ_ERR | LPU_IRQ_IBSY | LPU_IRQ_OVR)) {
     27		u32 restore = 0, tbu_status;
     28		/* Check error of LPU status */
     29		status = malidp_read32(reg, BLK_STATUS);
     30		if (status & LPU_STATUS_AXIE) {
     31			restore |= LPU_STATUS_AXIE;
     32			evts |= KOMEDA_ERR_AXIE;
     33		}
     34		if (status & LPU_STATUS_ACE0) {
     35			restore |= LPU_STATUS_ACE0;
     36			evts |= KOMEDA_ERR_ACE0;
     37		}
     38		if (status & LPU_STATUS_ACE1) {
     39			restore |= LPU_STATUS_ACE1;
     40			evts |= KOMEDA_ERR_ACE1;
     41		}
     42		if (status & LPU_STATUS_ACE2) {
     43			restore |= LPU_STATUS_ACE2;
     44			evts |= KOMEDA_ERR_ACE2;
     45		}
     46		if (status & LPU_STATUS_ACE3) {
     47			restore |= LPU_STATUS_ACE3;
     48			evts |= KOMEDA_ERR_ACE3;
     49		}
     50		if (status & LPU_STATUS_FEMPTY) {
     51			restore |= LPU_STATUS_FEMPTY;
     52			evts |= KOMEDA_EVENT_EMPTY;
     53		}
     54		if (status & LPU_STATUS_FFULL) {
     55			restore |= LPU_STATUS_FFULL;
     56			evts |= KOMEDA_EVENT_FULL;
     57		}
     58
     59		if (restore != 0)
     60			malidp_write32_mask(reg, BLK_STATUS, restore, 0);
     61
     62		restore = 0;
     63		/* Check errors of TBU status */
     64		tbu_status = malidp_read32(reg, LPU_TBU_STATUS);
     65		if (tbu_status & LPU_TBU_STATUS_TCF) {
     66			restore |= LPU_TBU_STATUS_TCF;
     67			evts |= KOMEDA_ERR_TCF;
     68		}
     69		if (tbu_status & LPU_TBU_STATUS_TTNG) {
     70			restore |= LPU_TBU_STATUS_TTNG;
     71			evts |= KOMEDA_ERR_TTNG;
     72		}
     73		if (tbu_status & LPU_TBU_STATUS_TITR) {
     74			restore |= LPU_TBU_STATUS_TITR;
     75			evts |= KOMEDA_ERR_TITR;
     76		}
     77		if (tbu_status & LPU_TBU_STATUS_TEMR) {
     78			restore |= LPU_TBU_STATUS_TEMR;
     79			evts |= KOMEDA_ERR_TEMR;
     80		}
     81		if (tbu_status & LPU_TBU_STATUS_TTF) {
     82			restore |= LPU_TBU_STATUS_TTF;
     83			evts |= KOMEDA_ERR_TTF;
     84		}
     85		if (restore != 0)
     86			malidp_write32_mask(reg, LPU_TBU_STATUS, restore, 0);
     87	}
     88
     89	malidp_write32(reg, BLK_IRQ_CLEAR, raw_status);
     90	return evts;
     91}
     92
     93static u64 get_cu_event(struct d71_pipeline *d71_pipeline)
     94{
     95	u32 __iomem *reg = d71_pipeline->cu_addr;
     96	u32 status, raw_status;
     97	u64 evts = 0ULL;
     98
     99	raw_status = malidp_read32(reg, BLK_IRQ_RAW_STATUS);
    100	if (raw_status & CU_IRQ_OVR)
    101		evts |= KOMEDA_EVENT_OVR;
    102
    103	if (raw_status & (CU_IRQ_ERR | CU_IRQ_OVR)) {
    104		status = malidp_read32(reg, BLK_STATUS) & 0x7FFFFFFF;
    105		if (status & CU_STATUS_CPE)
    106			evts |= KOMEDA_ERR_CPE;
    107		if (status & CU_STATUS_ZME)
    108			evts |= KOMEDA_ERR_ZME;
    109		if (status & CU_STATUS_CFGE)
    110			evts |= KOMEDA_ERR_CFGE;
    111		if (status)
    112			malidp_write32_mask(reg, BLK_STATUS, status, 0);
    113	}
    114
    115	malidp_write32(reg, BLK_IRQ_CLEAR, raw_status);
    116
    117	return evts;
    118}
    119
    120static u64 get_dou_event(struct d71_pipeline *d71_pipeline)
    121{
    122	u32 __iomem *reg = d71_pipeline->dou_addr;
    123	u32 status, raw_status;
    124	u64 evts = 0ULL;
    125
    126	raw_status = malidp_read32(reg, BLK_IRQ_RAW_STATUS);
    127	if (raw_status & DOU_IRQ_PL0)
    128		evts |= KOMEDA_EVENT_VSYNC;
    129	if (raw_status & DOU_IRQ_UND)
    130		evts |= KOMEDA_EVENT_URUN;
    131
    132	if (raw_status & (DOU_IRQ_ERR | DOU_IRQ_UND)) {
    133		u32 restore  = 0;
    134
    135		status = malidp_read32(reg, BLK_STATUS);
    136		if (status & DOU_STATUS_DRIFTTO) {
    137			restore |= DOU_STATUS_DRIFTTO;
    138			evts |= KOMEDA_ERR_DRIFTTO;
    139		}
    140		if (status & DOU_STATUS_FRAMETO) {
    141			restore |= DOU_STATUS_FRAMETO;
    142			evts |= KOMEDA_ERR_FRAMETO;
    143		}
    144		if (status & DOU_STATUS_TETO) {
    145			restore |= DOU_STATUS_TETO;
    146			evts |= KOMEDA_ERR_TETO;
    147		}
    148		if (status & DOU_STATUS_CSCE) {
    149			restore |= DOU_STATUS_CSCE;
    150			evts |= KOMEDA_ERR_CSCE;
    151		}
    152
    153		if (restore != 0)
    154			malidp_write32_mask(reg, BLK_STATUS, restore, 0);
    155	}
    156
    157	malidp_write32(reg, BLK_IRQ_CLEAR, raw_status);
    158	return evts;
    159}
    160
    161static u64 get_pipeline_event(struct d71_pipeline *d71_pipeline, u32 gcu_status)
    162{
    163	u32 evts = 0ULL;
    164
    165	if (gcu_status & (GLB_IRQ_STATUS_LPU0 | GLB_IRQ_STATUS_LPU1))
    166		evts |= get_lpu_event(d71_pipeline);
    167
    168	if (gcu_status & (GLB_IRQ_STATUS_CU0 | GLB_IRQ_STATUS_CU1))
    169		evts |= get_cu_event(d71_pipeline);
    170
    171	if (gcu_status & (GLB_IRQ_STATUS_DOU0 | GLB_IRQ_STATUS_DOU1))
    172		evts |= get_dou_event(d71_pipeline);
    173
    174	return evts;
    175}
    176
    177static irqreturn_t
    178d71_irq_handler(struct komeda_dev *mdev, struct komeda_events *evts)
    179{
    180	struct d71_dev *d71 = mdev->chip_data;
    181	u32 status, gcu_status, raw_status;
    182
    183	gcu_status = malidp_read32(d71->gcu_addr, GLB_IRQ_STATUS);
    184
    185	if (gcu_status & GLB_IRQ_STATUS_GCU) {
    186		raw_status = malidp_read32(d71->gcu_addr, BLK_IRQ_RAW_STATUS);
    187		if (raw_status & GCU_IRQ_CVAL0)
    188			evts->pipes[0] |= KOMEDA_EVENT_FLIP;
    189		if (raw_status & GCU_IRQ_CVAL1)
    190			evts->pipes[1] |= KOMEDA_EVENT_FLIP;
    191		if (raw_status & GCU_IRQ_ERR) {
    192			status = malidp_read32(d71->gcu_addr, BLK_STATUS);
    193			if (status & GCU_STATUS_MERR) {
    194				evts->global |= KOMEDA_ERR_MERR;
    195				malidp_write32_mask(d71->gcu_addr, BLK_STATUS,
    196						    GCU_STATUS_MERR, 0);
    197			}
    198		}
    199
    200		malidp_write32(d71->gcu_addr, BLK_IRQ_CLEAR, raw_status);
    201	}
    202
    203	if (gcu_status & GLB_IRQ_STATUS_PIPE0)
    204		evts->pipes[0] |= get_pipeline_event(d71->pipes[0], gcu_status);
    205
    206	if (gcu_status & GLB_IRQ_STATUS_PIPE1)
    207		evts->pipes[1] |= get_pipeline_event(d71->pipes[1], gcu_status);
    208
    209	return IRQ_RETVAL(gcu_status);
    210}
    211
    212#define ENABLED_GCU_IRQS	(GCU_IRQ_CVAL0 | GCU_IRQ_CVAL1 | \
    213				 GCU_IRQ_MODE | GCU_IRQ_ERR)
    214#define ENABLED_LPU_IRQS	(LPU_IRQ_IBSY | LPU_IRQ_ERR | LPU_IRQ_EOW)
    215#define ENABLED_CU_IRQS		(CU_IRQ_OVR | CU_IRQ_ERR)
    216#define ENABLED_DOU_IRQS	(DOU_IRQ_UND | DOU_IRQ_ERR)
    217
    218static int d71_enable_irq(struct komeda_dev *mdev)
    219{
    220	struct d71_dev *d71 = mdev->chip_data;
    221	struct d71_pipeline *pipe;
    222	u32 i;
    223
    224	malidp_write32_mask(d71->gcu_addr, BLK_IRQ_MASK,
    225			    ENABLED_GCU_IRQS, ENABLED_GCU_IRQS);
    226	for (i = 0; i < d71->num_pipelines; i++) {
    227		pipe = d71->pipes[i];
    228		malidp_write32_mask(pipe->cu_addr,  BLK_IRQ_MASK,
    229				    ENABLED_CU_IRQS, ENABLED_CU_IRQS);
    230		malidp_write32_mask(pipe->lpu_addr, BLK_IRQ_MASK,
    231				    ENABLED_LPU_IRQS, ENABLED_LPU_IRQS);
    232		malidp_write32_mask(pipe->dou_addr, BLK_IRQ_MASK,
    233				    ENABLED_DOU_IRQS, ENABLED_DOU_IRQS);
    234	}
    235	return 0;
    236}
    237
    238static int d71_disable_irq(struct komeda_dev *mdev)
    239{
    240	struct d71_dev *d71 = mdev->chip_data;
    241	struct d71_pipeline *pipe;
    242	u32 i;
    243
    244	malidp_write32_mask(d71->gcu_addr, BLK_IRQ_MASK, ENABLED_GCU_IRQS, 0);
    245	for (i = 0; i < d71->num_pipelines; i++) {
    246		pipe = d71->pipes[i];
    247		malidp_write32_mask(pipe->cu_addr,  BLK_IRQ_MASK,
    248				    ENABLED_CU_IRQS, 0);
    249		malidp_write32_mask(pipe->lpu_addr, BLK_IRQ_MASK,
    250				    ENABLED_LPU_IRQS, 0);
    251		malidp_write32_mask(pipe->dou_addr, BLK_IRQ_MASK,
    252				    ENABLED_DOU_IRQS, 0);
    253	}
    254	return 0;
    255}
    256
    257static void d71_on_off_vblank(struct komeda_dev *mdev, int master_pipe, bool on)
    258{
    259	struct d71_dev *d71 = mdev->chip_data;
    260	struct d71_pipeline *pipe = d71->pipes[master_pipe];
    261
    262	malidp_write32_mask(pipe->dou_addr, BLK_IRQ_MASK,
    263			    DOU_IRQ_PL0, on ? DOU_IRQ_PL0 : 0);
    264}
    265
    266static int to_d71_opmode(int core_mode)
    267{
    268	switch (core_mode) {
    269	case KOMEDA_MODE_DISP0:
    270		return DO0_ACTIVE_MODE;
    271	case KOMEDA_MODE_DISP1:
    272		return DO1_ACTIVE_MODE;
    273	case KOMEDA_MODE_DUAL_DISP:
    274		return DO01_ACTIVE_MODE;
    275	case KOMEDA_MODE_INACTIVE:
    276		return INACTIVE_MODE;
    277	default:
    278		WARN(1, "Unknown operation mode");
    279		return INACTIVE_MODE;
    280	}
    281}
    282
    283static int d71_change_opmode(struct komeda_dev *mdev, int new_mode)
    284{
    285	struct d71_dev *d71 = mdev->chip_data;
    286	u32 opmode = to_d71_opmode(new_mode);
    287	int ret;
    288
    289	malidp_write32_mask(d71->gcu_addr, BLK_CONTROL, 0x7, opmode);
    290
    291	ret = dp_wait_cond(((malidp_read32(d71->gcu_addr, BLK_CONTROL) & 0x7) == opmode),
    292			   100, 1000, 10000);
    293
    294	return ret;
    295}
    296
    297static void d71_flush(struct komeda_dev *mdev,
    298		      int master_pipe, u32 active_pipes)
    299{
    300	struct d71_dev *d71 = mdev->chip_data;
    301	u32 reg_offset = (master_pipe == 0) ?
    302			 GCU_CONFIG_VALID0 : GCU_CONFIG_VALID1;
    303
    304	malidp_write32(d71->gcu_addr, reg_offset, GCU_CONFIG_CVAL);
    305}
    306
    307static int d71_reset(struct d71_dev *d71)
    308{
    309	u32 __iomem *gcu = d71->gcu_addr;
    310	int ret;
    311
    312	malidp_write32_mask(gcu, BLK_CONTROL,
    313			    GCU_CONTROL_SRST, 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 periph
    386	 * into GCU
    387	 */
    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 output
    421		 * is turning off, so when we disable all pipeline components
    422		 * together with display output disable by one flush or one
    423		 * operation, the disable operation updated registers will not
    424		 * 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 sure
    427		 *	   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 blocks
    441	 */
    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_LAYER
    472#define SIMPLE		KOMEDA_FMT_SIMPLE_LAYER
    473#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_0
    478#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,		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}