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

dcss-dpr.c (13224B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright 2019 NXP.
      4 */
      5
      6#include <linux/device.h>
      7#include <linux/slab.h>
      8
      9#include "dcss-dev.h"
     10
     11#define DCSS_DPR_SYSTEM_CTRL0			0x000
     12#define   RUN_EN				BIT(0)
     13#define   SOFT_RESET				BIT(1)
     14#define   REPEAT_EN				BIT(2)
     15#define   SHADOW_LOAD_EN			BIT(3)
     16#define   SW_SHADOW_LOAD_SEL			BIT(4)
     17#define   BCMD2AXI_MSTR_ID_CTRL			BIT(16)
     18#define DCSS_DPR_IRQ_MASK			0x020
     19#define DCSS_DPR_IRQ_MASK_STATUS		0x030
     20#define DCSS_DPR_IRQ_NONMASK_STATUS		0x040
     21#define   IRQ_DPR_CTRL_DONE			BIT(0)
     22#define   IRQ_DPR_RUN				BIT(1)
     23#define   IRQ_DPR_SHADOW_LOADED			BIT(2)
     24#define   IRQ_AXI_READ_ERR			BIT(3)
     25#define   DPR2RTR_YRGB_FIFO_OVFL		BIT(4)
     26#define   DPR2RTR_UV_FIFO_OVFL			BIT(5)
     27#define   DPR2RTR_FIFO_LD_BUF_RDY_YRGB_ERR	BIT(6)
     28#define   DPR2RTR_FIFO_LD_BUF_RDY_UV_ERR	BIT(7)
     29#define DCSS_DPR_MODE_CTRL0			0x050
     30#define   RTR_3BUF_EN				BIT(0)
     31#define   RTR_4LINE_BUF_EN			BIT(1)
     32#define   TILE_TYPE_POS				2
     33#define   TILE_TYPE_MASK			GENMASK(4, 2)
     34#define   YUV_EN				BIT(6)
     35#define   COMP_2PLANE_EN			BIT(7)
     36#define   PIX_SIZE_POS				8
     37#define   PIX_SIZE_MASK				GENMASK(9, 8)
     38#define   PIX_LUMA_UV_SWAP			BIT(10)
     39#define   PIX_UV_SWAP				BIT(11)
     40#define   B_COMP_SEL_POS			12
     41#define   B_COMP_SEL_MASK			GENMASK(13, 12)
     42#define   G_COMP_SEL_POS			14
     43#define   G_COMP_SEL_MASK			GENMASK(15, 14)
     44#define   R_COMP_SEL_POS			16
     45#define   R_COMP_SEL_MASK			GENMASK(17, 16)
     46#define   A_COMP_SEL_POS			18
     47#define   A_COMP_SEL_MASK			GENMASK(19, 18)
     48#define DCSS_DPR_FRAME_CTRL0			0x070
     49#define   HFLIP_EN				BIT(0)
     50#define   VFLIP_EN				BIT(1)
     51#define   ROT_ENC_POS				2
     52#define   ROT_ENC_MASK				GENMASK(3, 2)
     53#define   ROT_FLIP_ORDER_EN			BIT(4)
     54#define   PITCH_POS				16
     55#define   PITCH_MASK				GENMASK(31, 16)
     56#define DCSS_DPR_FRAME_1P_CTRL0			0x090
     57#define DCSS_DPR_FRAME_1P_PIX_X_CTRL		0x0A0
     58#define DCSS_DPR_FRAME_1P_PIX_Y_CTRL		0x0B0
     59#define DCSS_DPR_FRAME_1P_BASE_ADDR		0x0C0
     60#define DCSS_DPR_FRAME_2P_CTRL0			0x0E0
     61#define DCSS_DPR_FRAME_2P_PIX_X_CTRL		0x0F0
     62#define DCSS_DPR_FRAME_2P_PIX_Y_CTRL		0x100
     63#define DCSS_DPR_FRAME_2P_BASE_ADDR		0x110
     64#define DCSS_DPR_STATUS_CTRL0			0x130
     65#define   STATUS_MUX_SEL_MASK			GENMASK(2, 0)
     66#define   STATUS_SRC_SEL_POS			16
     67#define   STATUS_SRC_SEL_MASK			GENMASK(18, 16)
     68#define DCSS_DPR_STATUS_CTRL1			0x140
     69#define DCSS_DPR_RTRAM_CTRL0			0x200
     70#define   NUM_ROWS_ACTIVE			BIT(0)
     71#define   THRES_HIGH_POS			1
     72#define   THRES_HIGH_MASK			GENMASK(3, 1)
     73#define   THRES_LOW_POS				4
     74#define   THRES_LOW_MASK			GENMASK(6, 4)
     75#define   ABORT_SEL				BIT(7)
     76
     77enum dcss_tile_type {
     78	TILE_LINEAR = 0,
     79	TILE_GPU_STANDARD,
     80	TILE_GPU_SUPER,
     81	TILE_VPU_YUV420,
     82	TILE_VPU_VP9,
     83};
     84
     85enum dcss_pix_size {
     86	PIX_SIZE_8,
     87	PIX_SIZE_16,
     88	PIX_SIZE_32,
     89};
     90
     91struct dcss_dpr_ch {
     92	struct dcss_dpr *dpr;
     93	void __iomem *base_reg;
     94	u32 base_ofs;
     95
     96	struct drm_format_info format;
     97	enum dcss_pix_size pix_size;
     98	enum dcss_tile_type tile;
     99	bool rtram_4line_en;
    100	bool rtram_3buf_en;
    101
    102	u32 frame_ctrl;
    103	u32 mode_ctrl;
    104	u32 sys_ctrl;
    105	u32 rtram_ctrl;
    106
    107	bool sys_ctrl_chgd;
    108
    109	int ch_num;
    110	int irq;
    111};
    112
    113struct dcss_dpr {
    114	struct device *dev;
    115	struct dcss_ctxld *ctxld;
    116	u32  ctx_id;
    117
    118	struct dcss_dpr_ch ch[3];
    119};
    120
    121static void dcss_dpr_write(struct dcss_dpr_ch *ch, u32 val, u32 ofs)
    122{
    123	struct dcss_dpr *dpr = ch->dpr;
    124
    125	dcss_ctxld_write(dpr->ctxld, dpr->ctx_id, val, ch->base_ofs + ofs);
    126}
    127
    128static int dcss_dpr_ch_init_all(struct dcss_dpr *dpr, unsigned long dpr_base)
    129{
    130	struct dcss_dpr_ch *ch;
    131	int i;
    132
    133	for (i = 0; i < 3; i++) {
    134		ch = &dpr->ch[i];
    135
    136		ch->base_ofs = dpr_base + i * 0x1000;
    137
    138		ch->base_reg = ioremap(ch->base_ofs, SZ_4K);
    139		if (!ch->base_reg) {
    140			dev_err(dpr->dev, "dpr: unable to remap ch %d base\n",
    141				i);
    142			return -ENOMEM;
    143		}
    144
    145		ch->dpr = dpr;
    146		ch->ch_num = i;
    147
    148		dcss_writel(0xff, ch->base_reg + DCSS_DPR_IRQ_MASK);
    149	}
    150
    151	return 0;
    152}
    153
    154int dcss_dpr_init(struct dcss_dev *dcss, unsigned long dpr_base)
    155{
    156	struct dcss_dpr *dpr;
    157
    158	dpr = kzalloc(sizeof(*dpr), GFP_KERNEL);
    159	if (!dpr)
    160		return -ENOMEM;
    161
    162	dcss->dpr = dpr;
    163	dpr->dev = dcss->dev;
    164	dpr->ctxld = dcss->ctxld;
    165	dpr->ctx_id = CTX_SB_HP;
    166
    167	if (dcss_dpr_ch_init_all(dpr, dpr_base)) {
    168		int i;
    169
    170		for (i = 0; i < 3; i++) {
    171			if (dpr->ch[i].base_reg)
    172				iounmap(dpr->ch[i].base_reg);
    173		}
    174
    175		kfree(dpr);
    176
    177		return -ENOMEM;
    178	}
    179
    180	return 0;
    181}
    182
    183void dcss_dpr_exit(struct dcss_dpr *dpr)
    184{
    185	int ch_no;
    186
    187	/* stop DPR on all channels */
    188	for (ch_no = 0; ch_no < 3; ch_no++) {
    189		struct dcss_dpr_ch *ch = &dpr->ch[ch_no];
    190
    191		dcss_writel(0, ch->base_reg + DCSS_DPR_SYSTEM_CTRL0);
    192
    193		if (ch->base_reg)
    194			iounmap(ch->base_reg);
    195	}
    196
    197	kfree(dpr);
    198}
    199
    200static u32 dcss_dpr_x_pix_wide_adjust(struct dcss_dpr_ch *ch, u32 pix_wide,
    201				      u32 pix_format)
    202{
    203	u8 pix_in_64byte_map[3][5] = {
    204		/* LIN, GPU_STD, GPU_SUP, VPU_YUV420, VPU_VP9 */
    205		{   64,       8,       8,          8,     16}, /* PIX_SIZE_8  */
    206		{   32,       8,       8,          8,      8}, /* PIX_SIZE_16 */
    207		{   16,       4,       4,          8,      8}, /* PIX_SIZE_32 */
    208	};
    209	u32 offset;
    210	u32 div_64byte_mod, pix_in_64byte;
    211
    212	pix_in_64byte = pix_in_64byte_map[ch->pix_size][ch->tile];
    213
    214	div_64byte_mod = pix_wide % pix_in_64byte;
    215	offset = (div_64byte_mod == 0) ? 0 : (pix_in_64byte - div_64byte_mod);
    216
    217	return pix_wide + offset;
    218}
    219
    220static u32 dcss_dpr_y_pix_high_adjust(struct dcss_dpr_ch *ch, u32 pix_high,
    221				      u32 pix_format)
    222{
    223	u8 num_rows_buf = ch->rtram_4line_en ? 4 : 8;
    224	u32 offset, pix_y_mod;
    225
    226	pix_y_mod = pix_high % num_rows_buf;
    227	offset = pix_y_mod ? (num_rows_buf - pix_y_mod) : 0;
    228
    229	return pix_high + offset;
    230}
    231
    232void dcss_dpr_set_res(struct dcss_dpr *dpr, int ch_num, u32 xres, u32 yres)
    233{
    234	struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
    235	u32 pix_format = ch->format.format;
    236	u32 gap = DCSS_DPR_FRAME_2P_BASE_ADDR - DCSS_DPR_FRAME_1P_BASE_ADDR;
    237	int plane, max_planes = 1;
    238	u32 pix_x_wide, pix_y_high;
    239
    240	if (pix_format == DRM_FORMAT_NV12 ||
    241	    pix_format == DRM_FORMAT_NV21)
    242		max_planes = 2;
    243
    244	for (plane = 0; plane < max_planes; plane++) {
    245		yres = plane == 1 ? yres >> 1 : yres;
    246
    247		pix_x_wide = dcss_dpr_x_pix_wide_adjust(ch, xres, pix_format);
    248		pix_y_high = dcss_dpr_y_pix_high_adjust(ch, yres, pix_format);
    249
    250		dcss_dpr_write(ch, pix_x_wide,
    251			       DCSS_DPR_FRAME_1P_PIX_X_CTRL + plane * gap);
    252		dcss_dpr_write(ch, pix_y_high,
    253			       DCSS_DPR_FRAME_1P_PIX_Y_CTRL + plane * gap);
    254
    255		dcss_dpr_write(ch, 2, DCSS_DPR_FRAME_1P_CTRL0 + plane * gap);
    256	}
    257}
    258
    259void dcss_dpr_addr_set(struct dcss_dpr *dpr, int ch_num, u32 luma_base_addr,
    260		       u32 chroma_base_addr, u16 pitch)
    261{
    262	struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
    263
    264	dcss_dpr_write(ch, luma_base_addr, DCSS_DPR_FRAME_1P_BASE_ADDR);
    265
    266	dcss_dpr_write(ch, chroma_base_addr, DCSS_DPR_FRAME_2P_BASE_ADDR);
    267
    268	ch->frame_ctrl &= ~PITCH_MASK;
    269	ch->frame_ctrl |= (((u32)pitch << PITCH_POS) & PITCH_MASK);
    270}
    271
    272static void dcss_dpr_argb_comp_sel(struct dcss_dpr_ch *ch, int a_sel, int r_sel,
    273				   int g_sel, int b_sel)
    274{
    275	u32 sel;
    276
    277	sel = ((a_sel << A_COMP_SEL_POS) & A_COMP_SEL_MASK) |
    278	      ((r_sel << R_COMP_SEL_POS) & R_COMP_SEL_MASK) |
    279	      ((g_sel << G_COMP_SEL_POS) & G_COMP_SEL_MASK) |
    280	      ((b_sel << B_COMP_SEL_POS) & B_COMP_SEL_MASK);
    281
    282	ch->mode_ctrl &= ~(A_COMP_SEL_MASK | R_COMP_SEL_MASK |
    283			   G_COMP_SEL_MASK | B_COMP_SEL_MASK);
    284	ch->mode_ctrl |= sel;
    285}
    286
    287static void dcss_dpr_pix_size_set(struct dcss_dpr_ch *ch,
    288				  const struct drm_format_info *format)
    289{
    290	u32 val;
    291
    292	switch (format->format) {
    293	case DRM_FORMAT_NV12:
    294	case DRM_FORMAT_NV21:
    295		val = PIX_SIZE_8;
    296		break;
    297
    298	case DRM_FORMAT_UYVY:
    299	case DRM_FORMAT_VYUY:
    300	case DRM_FORMAT_YUYV:
    301	case DRM_FORMAT_YVYU:
    302		val = PIX_SIZE_16;
    303		break;
    304
    305	default:
    306		val = PIX_SIZE_32;
    307		break;
    308	}
    309
    310	ch->pix_size = val;
    311
    312	ch->mode_ctrl &= ~PIX_SIZE_MASK;
    313	ch->mode_ctrl |= ((val << PIX_SIZE_POS) & PIX_SIZE_MASK);
    314}
    315
    316static void dcss_dpr_uv_swap(struct dcss_dpr_ch *ch, bool swap)
    317{
    318	ch->mode_ctrl &= ~PIX_UV_SWAP;
    319	ch->mode_ctrl |= (swap ? PIX_UV_SWAP : 0);
    320}
    321
    322static void dcss_dpr_y_uv_swap(struct dcss_dpr_ch *ch, bool swap)
    323{
    324	ch->mode_ctrl &= ~PIX_LUMA_UV_SWAP;
    325	ch->mode_ctrl |= (swap ? PIX_LUMA_UV_SWAP : 0);
    326}
    327
    328static void dcss_dpr_2plane_en(struct dcss_dpr_ch *ch, bool en)
    329{
    330	ch->mode_ctrl &= ~COMP_2PLANE_EN;
    331	ch->mode_ctrl |= (en ? COMP_2PLANE_EN : 0);
    332}
    333
    334static void dcss_dpr_yuv_en(struct dcss_dpr_ch *ch, bool en)
    335{
    336	ch->mode_ctrl &= ~YUV_EN;
    337	ch->mode_ctrl |= (en ? YUV_EN : 0);
    338}
    339
    340void dcss_dpr_enable(struct dcss_dpr *dpr, int ch_num, bool en)
    341{
    342	struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
    343	u32 sys_ctrl;
    344
    345	sys_ctrl = (en ? REPEAT_EN | RUN_EN : 0);
    346
    347	if (en) {
    348		dcss_dpr_write(ch, ch->mode_ctrl, DCSS_DPR_MODE_CTRL0);
    349		dcss_dpr_write(ch, ch->frame_ctrl, DCSS_DPR_FRAME_CTRL0);
    350		dcss_dpr_write(ch, ch->rtram_ctrl, DCSS_DPR_RTRAM_CTRL0);
    351	}
    352
    353	if (ch->sys_ctrl != sys_ctrl)
    354		ch->sys_ctrl_chgd = true;
    355
    356	ch->sys_ctrl = sys_ctrl;
    357}
    358
    359struct rgb_comp_sel {
    360	u32 drm_format;
    361	int a_sel;
    362	int r_sel;
    363	int g_sel;
    364	int b_sel;
    365};
    366
    367static struct rgb_comp_sel comp_sel_map[] = {
    368	{DRM_FORMAT_ARGB8888, 3, 2, 1, 0},
    369	{DRM_FORMAT_XRGB8888, 3, 2, 1, 0},
    370	{DRM_FORMAT_ABGR8888, 3, 0, 1, 2},
    371	{DRM_FORMAT_XBGR8888, 3, 0, 1, 2},
    372	{DRM_FORMAT_RGBA8888, 0, 3, 2, 1},
    373	{DRM_FORMAT_RGBX8888, 0, 3, 2, 1},
    374	{DRM_FORMAT_BGRA8888, 0, 1, 2, 3},
    375	{DRM_FORMAT_BGRX8888, 0, 1, 2, 3},
    376};
    377
    378static int to_comp_sel(u32 pix_fmt, int *a_sel, int *r_sel, int *g_sel,
    379		       int *b_sel)
    380{
    381	int i;
    382
    383	for (i = 0; i < ARRAY_SIZE(comp_sel_map); i++) {
    384		if (comp_sel_map[i].drm_format == pix_fmt) {
    385			*a_sel = comp_sel_map[i].a_sel;
    386			*r_sel = comp_sel_map[i].r_sel;
    387			*g_sel = comp_sel_map[i].g_sel;
    388			*b_sel = comp_sel_map[i].b_sel;
    389
    390			return 0;
    391		}
    392	}
    393
    394	return -1;
    395}
    396
    397static void dcss_dpr_rtram_set(struct dcss_dpr_ch *ch, u32 pix_format)
    398{
    399	u32 val, mask;
    400
    401	switch (pix_format) {
    402	case DRM_FORMAT_NV21:
    403	case DRM_FORMAT_NV12:
    404		ch->rtram_3buf_en = true;
    405		ch->rtram_4line_en = false;
    406		break;
    407
    408	default:
    409		ch->rtram_3buf_en = true;
    410		ch->rtram_4line_en = true;
    411		break;
    412	}
    413
    414	val = (ch->rtram_4line_en ? RTR_4LINE_BUF_EN : 0);
    415	val |= (ch->rtram_3buf_en ? RTR_3BUF_EN : 0);
    416	mask = RTR_4LINE_BUF_EN | RTR_3BUF_EN;
    417
    418	ch->mode_ctrl &= ~mask;
    419	ch->mode_ctrl |= (val & mask);
    420
    421	val = (ch->rtram_4line_en ? 0 : NUM_ROWS_ACTIVE);
    422	val |= (3 << THRES_LOW_POS) & THRES_LOW_MASK;
    423	val |= (4 << THRES_HIGH_POS) & THRES_HIGH_MASK;
    424	mask = THRES_LOW_MASK | THRES_HIGH_MASK | NUM_ROWS_ACTIVE;
    425
    426	ch->rtram_ctrl &= ~mask;
    427	ch->rtram_ctrl |= (val & mask);
    428}
    429
    430static void dcss_dpr_setup_components(struct dcss_dpr_ch *ch,
    431				      const struct drm_format_info *format)
    432{
    433	int a_sel, r_sel, g_sel, b_sel;
    434	bool uv_swap, y_uv_swap;
    435
    436	switch (format->format) {
    437	case DRM_FORMAT_YVYU:
    438		uv_swap = true;
    439		y_uv_swap = true;
    440		break;
    441
    442	case DRM_FORMAT_VYUY:
    443	case DRM_FORMAT_NV21:
    444		uv_swap = true;
    445		y_uv_swap = false;
    446		break;
    447
    448	case DRM_FORMAT_YUYV:
    449		uv_swap = false;
    450		y_uv_swap = true;
    451		break;
    452
    453	default:
    454		uv_swap = false;
    455		y_uv_swap = false;
    456		break;
    457	}
    458
    459	dcss_dpr_uv_swap(ch, uv_swap);
    460
    461	dcss_dpr_y_uv_swap(ch, y_uv_swap);
    462
    463	if (!format->is_yuv) {
    464		if (!to_comp_sel(format->format, &a_sel, &r_sel,
    465				 &g_sel, &b_sel)) {
    466			dcss_dpr_argb_comp_sel(ch, a_sel, r_sel, g_sel, b_sel);
    467		} else {
    468			dcss_dpr_argb_comp_sel(ch, 3, 2, 1, 0);
    469		}
    470	} else {
    471		dcss_dpr_argb_comp_sel(ch, 0, 0, 0, 0);
    472	}
    473}
    474
    475static void dcss_dpr_tile_set(struct dcss_dpr_ch *ch, uint64_t modifier)
    476{
    477	switch (ch->ch_num) {
    478	case 0:
    479		switch (modifier) {
    480		case DRM_FORMAT_MOD_LINEAR:
    481			ch->tile = TILE_LINEAR;
    482			break;
    483		case DRM_FORMAT_MOD_VIVANTE_TILED:
    484			ch->tile = TILE_GPU_STANDARD;
    485			break;
    486		case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
    487			ch->tile = TILE_GPU_SUPER;
    488			break;
    489		default:
    490			WARN_ON(1);
    491			break;
    492		}
    493		break;
    494	case 1:
    495	case 2:
    496		ch->tile = TILE_LINEAR;
    497		break;
    498	default:
    499		WARN_ON(1);
    500		return;
    501	}
    502
    503	ch->mode_ctrl &= ~TILE_TYPE_MASK;
    504	ch->mode_ctrl |= ((ch->tile << TILE_TYPE_POS) & TILE_TYPE_MASK);
    505}
    506
    507void dcss_dpr_format_set(struct dcss_dpr *dpr, int ch_num,
    508			 const struct drm_format_info *format, u64 modifier)
    509{
    510	struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
    511
    512	ch->format = *format;
    513
    514	dcss_dpr_yuv_en(ch, format->is_yuv);
    515
    516	dcss_dpr_pix_size_set(ch, format);
    517
    518	dcss_dpr_setup_components(ch, format);
    519
    520	dcss_dpr_2plane_en(ch, format->num_planes == 2);
    521
    522	dcss_dpr_rtram_set(ch, format->format);
    523
    524	dcss_dpr_tile_set(ch, modifier);
    525}
    526
    527/* This function will be called from interrupt context. */
    528void dcss_dpr_write_sysctrl(struct dcss_dpr *dpr)
    529{
    530	int chnum;
    531
    532	dcss_ctxld_assert_locked(dpr->ctxld);
    533
    534	for (chnum = 0; chnum < 3; chnum++) {
    535		struct dcss_dpr_ch *ch = &dpr->ch[chnum];
    536
    537		if (ch->sys_ctrl_chgd) {
    538			dcss_ctxld_write_irqsafe(dpr->ctxld, dpr->ctx_id,
    539						 ch->sys_ctrl,
    540						 ch->base_ofs +
    541						 DCSS_DPR_SYSTEM_CTRL0);
    542			ch->sys_ctrl_chgd = false;
    543		}
    544	}
    545}
    546
    547void dcss_dpr_set_rotation(struct dcss_dpr *dpr, int ch_num, u32 rotation)
    548{
    549	struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
    550
    551	ch->frame_ctrl &= ~(HFLIP_EN | VFLIP_EN | ROT_ENC_MASK);
    552
    553	ch->frame_ctrl |= rotation & DRM_MODE_REFLECT_X ? HFLIP_EN : 0;
    554	ch->frame_ctrl |= rotation & DRM_MODE_REFLECT_Y ? VFLIP_EN : 0;
    555
    556	if (rotation & DRM_MODE_ROTATE_90)
    557		ch->frame_ctrl |= 1 << ROT_ENC_POS;
    558	else if (rotation & DRM_MODE_ROTATE_180)
    559		ch->frame_ctrl |= 2 << ROT_ENC_POS;
    560	else if (rotation & DRM_MODE_ROTATE_270)
    561		ch->frame_ctrl |= 3 << ROT_ENC_POS;
    562}